1 /*******************************************************************************
2 * Copyright 2019-2021 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16 
17 #ifndef SYCL_ENGINE_FACTORY_HPP
18 #define SYCL_ENGINE_FACTORY_HPP
19 
20 #include <algorithm>
21 #include <assert.h>
22 #include <cstdio>
23 #include <exception>
24 #include <memory>
25 #include <vector>
26 
27 #include "common/c_types_map.hpp"
28 #include "common/engine.hpp"
29 #include "common/utils.hpp"
30 #include "sycl/sycl_gpu_engine.hpp"
31 #include "sycl/sycl_utils.hpp"
32 
33 #if DNNL_CPU_RUNTIME != DNNL_RUNTIME_NONE
34 #include "sycl/sycl_cpu_engine.hpp"
35 #endif
36 
37 namespace dnnl {
38 namespace impl {
39 
40 #ifdef DNNL_SYCL_CUDA
41 // XXX: forward declarations to avoid cuda dependencies on sycl level.
42 namespace gpu {
43 namespace nvidia {
44 
45 bool is_nvidia_gpu(const cl::sycl::device &dev);
46 
47 status_t cuda_engine_create(engine_t **engine, engine_kind_t engine_kind,
48         const cl::sycl::device &dev, const cl::sycl::context &ctx,
49         size_t index);
50 
51 } // namespace nvidia
52 } // namespace gpu
53 #endif
54 
55 namespace sycl {
56 
get_sycl_devices(cl::sycl::info::device_type dev_type,backend_t backend=backend_t::unknown)57 inline std::vector<cl::sycl::device> get_sycl_devices(
58         cl::sycl::info::device_type dev_type,
59         backend_t backend = backend_t::unknown) {
60     const uint32_t intel_vendor_id = 0x8086;
61 #ifdef DNNL_SYCL_CUDA
62     const uint32_t vendor_id = ((dev_type == cl::sycl::info::device_type::gpu)
63                     ? 0x10DE
64                     : intel_vendor_id);
65 #else
66     const uint32_t vendor_id = intel_vendor_id;
67 #endif
68     auto gpu_backend
69             = backend == backend_t::unknown ? get_sycl_gpu_backend() : backend;
70 
71     std::vector<cl::sycl::device> devices;
72     auto platforms = cl::sycl::platform::get_platforms();
73 
74     for (const auto &p : platforms) {
75         auto p_devices = p.get_devices(dev_type);
76         devices.insert(devices.end(), p_devices.begin(), p_devices.end());
77     }
78 
79     devices.erase(
80             std::remove_if(devices.begin(), devices.end(),
81                     [=](const cl::sycl::device &dev) {
82                         auto _vendor_id = dev.get_info<
83                                 cl::sycl::info::device::vendor_id>();
84                         if (_vendor_id != vendor_id) return true;
85 
86                         auto _dev_type = dev.get_info<
87                                 cl::sycl::info::device::device_type>();
88                         if (_dev_type != dev_type) return true;
89 
90                         if (dev_type == cl::sycl::info::device_type::gpu) {
91                             auto _backend = get_sycl_backend(dev);
92                             if (_backend == backend_t::unknown
93                                     || _backend != gpu_backend)
94                                 return true;
95                         }
96 
97                         return false;
98                     }),
99             devices.end());
100     return devices;
101 }
102 
get_sycl_device_index(size_t * index,const cl::sycl::device & dev)103 inline status_t get_sycl_device_index(
104         size_t *index, const cl::sycl::device &dev) {
105     auto dev_type = dev.get_info<cl::sycl::info::device::device_type>();
106     auto backend = get_sycl_backend(dev);
107     auto devices = get_sycl_devices(dev_type, backend);
108 
109     auto is_subdevice = [&backend](const cl::sycl::device &d) {
110         // TODO: remove this work around once Level-Zero is fixed
111         if (backend == backend_t::level0) return false;
112         return d.get_info<cl::sycl::info::device::partition_type_property>()
113                 != cl::sycl::info::partition_property::no_partition;
114     };
115 
116     // Search the top level device
117     auto parent_device = dev;
118     while (is_subdevice(parent_device)) {
119         parent_device
120                 = parent_device
121                           .get_info<cl::sycl::info::device::parent_device>();
122     }
123 
124     // Find the top level device in the list
125     auto it = std::find(devices.begin(), devices.end(), parent_device);
126     if (it != devices.end()) {
127         *index = it - devices.begin();
128         return status::success;
129     } else {
130         *index = SIZE_MAX;
131         // TODO: remove this work around once Level-Zero is fixed
132         if (backend == backend_t::level0) return status::success;
133         return status::invalid_arguments;
134     }
135 }
136 
137 class sycl_engine_factory_t : public engine_factory_t {
138 public:
sycl_engine_factory_t(engine_kind_t engine_kind)139     sycl_engine_factory_t(engine_kind_t engine_kind)
140         : engine_kind_(engine_kind) {
141         assert(utils::one_of(engine_kind_, engine_kind::cpu, engine_kind::gpu));
142     }
143 
count() const144     size_t count() const override {
145 #if DNNL_CPU_RUNTIME == DNNL_RUNTIME_NONE
146         if (engine_kind_ == engine_kind::cpu) return 0;
147 #endif
148         auto dev_type = (engine_kind_ == engine_kind::cpu)
149                 ? cl::sycl::info::device_type::cpu
150                 : cl::sycl::info::device_type::gpu;
151         return get_sycl_devices(dev_type).size();
152     }
153 
154     status_t engine_create(engine_t **engine, size_t index) const override;
155 
156     status_t engine_create(engine_t **engine, const cl::sycl::device &dev,
157             const cl::sycl::context &ctx, size_t index) const;
158 
159 private:
160     engine_kind_t engine_kind_;
161 };
162 
get_engine_factory(engine_kind_t engine_kind)163 inline std::unique_ptr<sycl_engine_factory_t> get_engine_factory(
164         engine_kind_t engine_kind) {
165     return std::unique_ptr<sycl_engine_factory_t>(
166             new sycl_engine_factory_t(engine_kind));
167 }
168 
169 } // namespace sycl
170 } // namespace impl
171 } // namespace dnnl
172 
173 #endif
174