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