DPC++ Runtime
Runtime libraries for oneAPI Data Parallel C++
device_selector.cpp
Go to the documentation of this file.
1 //==------ device_selector.cpp - SYCL device selector ----------------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
11 #include <CL/sycl/device.hpp>
13 #include <CL/sycl/exception.hpp>
14 #include <CL/sycl/stl.hpp>
15 #include <detail/config.hpp>
16 #include <detail/device_impl.hpp>
18 #include <detail/force_device.hpp>
21 // 4.6.1 Device selection class
22 
23 #include <algorithm>
24 #include <cctype>
25 #include <regex>
26 
28 namespace sycl {
29 
30 // Utility function to check if device is of the preferred backend.
31 // Currently preference is given to the level_zero backend.
32 static bool isDeviceOfPreferredSyclBe(const device &Device) {
33  if (Device.is_host())
34  return false;
35 
36  return detail::getSyclObjImpl(Device)->getPlugin().getBackend() ==
37  backend::level_zero;
38 }
39 
40 // Return true if the given device 'Dev' matches with any filter
41 static bool isForcedDevice(const device &Dev, int Index = -1) {
42  detail::device_filter_list *FilterList =
44 
45  if (!FilterList)
46  return false;
48  backend Backend;
49  if (Type == info::device_type::host)
50  Backend = backend::host;
51  else
52  Backend = detail::getSyclObjImpl(Dev)->getPlugin().getBackend();
53 
54  for (const detail::device_filter &Filter : FilterList->get()) {
55  if ((Filter.Backend == Backend || Filter.Backend == backend::all) &&
56  (Filter.DeviceType == Type ||
57  Filter.DeviceType == info::device_type::all)) {
58  if (Index < 0 || (Filter.HasDeviceNum && Filter.DeviceNum == Index))
59  return true;
60  }
61  }
62  return false;
63 }
64 
65 device device_selector::select_device() const {
66  std::vector<device> devices = device::get_devices();
67  int score = REJECT_DEVICE_SCORE;
68  const device *res = nullptr;
69 
70  for (const auto &dev : devices) {
71  int dev_score = (*this)(dev);
72 
74  std::string PlatformName = dev.get_info<info::device::platform>()
75  .get_info<info::platform::name>();
76  std::string DeviceName = dev.get_info<info::device::name>();
77  std::cout << "SYCL_PI_TRACE[all]: "
78  << "select_device(): -> score = " << dev_score
79  << ((dev_score < 0) ? " (REJECTED)" : "") << std::endl
80  << "SYCL_PI_TRACE[all]: "
81  << " platform: " << PlatformName << std::endl
82  << "SYCL_PI_TRACE[all]: "
83  << " device: " << DeviceName << std::endl;
84  }
85 
86  // A negative score means that a device must not be selected.
87  if (dev_score < 0)
88  continue;
89 
90  // If SYCL_DEVICE_FILTER is set, give a bonus point for the device
91  // whose index matches with desired device number.
92  int index = &dev - &devices[0];
93  if (isForcedDevice(dev, index)) {
94  dev_score += 1000;
95  }
96 
97  // SYCL spec says: "If more than one device receives the high score then
98  // one of those tied devices will be returned, but which of the devices
99  // from the tied set is to be returned is not defined". Here we give a
100  // preference to the device of the preferred BE.
101  //
102  if ((score < dev_score) ||
103  (score == dev_score && isDeviceOfPreferredSyclBe(dev))) {
104  res = &dev;
105  score = dev_score;
106  }
107  }
108 
109  if (res != nullptr) {
111  std::string PlatformName = res->get_info<info::device::platform>()
112  .get_info<info::platform::name>();
113  std::string DeviceName = res->get_info<info::device::name>();
114  std::cout << "SYCL_PI_TRACE[all]: "
115  << "Selected device ->" << std::endl
116  << "SYCL_PI_TRACE[all]: "
117  << " platform: " << PlatformName << std::endl
118  << "SYCL_PI_TRACE[all]: "
119  << " device: " << DeviceName << std::endl;
120  }
121  return *res;
122  }
123 
124  throw cl::sycl::runtime_error("No device of requested type available.",
126 }
127 
132 int default_selector::operator()(const device &dev) const {
133 
134  int Score = REJECT_DEVICE_SCORE;
135 
136  // Give preference to device of SYCL BE.
137  if (isDeviceOfPreferredSyclBe(dev))
138  Score = 50;
139 
140  // If SYCL_DEVICE_FILTER is set, filter device gets a high point.
141  // All unmatched devices should never be selected.
142  detail::device_filter_list *FilterList =
144  if (FilterList) {
145  if (isForcedDevice(dev))
146  Score = 1000;
147  else
148  return REJECT_DEVICE_SCORE;
149  }
150 
152  Score += 1000;
153 
154  if (dev.is_gpu())
155  Score += 500;
156 
157  if (dev.is_cpu())
158  Score += 300;
159 
160  if (dev.is_host())
161  Score += 100;
162 
163  // Since we deprecate SYCL_BE and SYCL_DEVICE_TYPE,
164  // we should not disallow accelerator to be chosen.
165  // But this device type gets the lowest heuristic point.
166  if (dev.is_accelerator())
167  Score += 75;
168 
169  return Score;
170 }
171 
172 int gpu_selector::operator()(const device &dev) const {
173  int Score = REJECT_DEVICE_SCORE;
174 
175  if (dev.is_gpu()) {
176  detail::device_filter_list *FilterList =
178  if (FilterList) {
179  if (isForcedDevice(dev))
180  Score = 1000;
181  else
182  return Score;
183  } else {
184  Score = 1000;
185  }
186  // Give preference to device of SYCL BE.
187  if (isDeviceOfPreferredSyclBe(dev))
188  Score += 50;
189  }
190  return Score;
191 }
192 
193 int cpu_selector::operator()(const device &dev) const {
194  int Score = REJECT_DEVICE_SCORE;
195 
196  if (dev.is_cpu()) {
197  detail::device_filter_list *FilterList =
199  if (FilterList) {
200  if (isForcedDevice(dev))
201  Score = 1000;
202  else
203  return Score;
204  } else {
205  Score = 1000;
206  }
207  // Give preference to device of SYCL BE.
208  if (isDeviceOfPreferredSyclBe(dev))
209  Score += 50;
210  }
211  return Score;
212 }
213 
214 int accelerator_selector::operator()(const device &dev) const {
215  int Score = REJECT_DEVICE_SCORE;
216 
217  if (dev.is_accelerator()) {
218  detail::device_filter_list *FilterList =
220  if (FilterList) {
221  if (isForcedDevice(dev))
222  Score = 1000;
223  else
224  return Score;
225  } else {
226  Score = 1000;
227  }
228  // Give preference to device of SYCL BE.
229  if (isDeviceOfPreferredSyclBe(dev))
230  Score += 50;
231  }
232  return Score;
233 }
234 
235 int host_selector::operator()(const device &dev) const {
236  int Score = REJECT_DEVICE_SCORE;
237 
238  if (dev.is_host()) {
239  Score = 1000;
240  // Give preference to device of SYCL BE.
241  if (isDeviceOfPreferredSyclBe(dev))
242  Score += 50;
243  }
244  return Score;
245 }
246 
247 namespace ext {
248 namespace oneapi {
249 
250 filter_selector::filter_selector(const std::string &Input)
251  : impl(std::make_shared<detail::filter_selector_impl>(Input)) {}
252 
253 int filter_selector::operator()(const device &Dev) const {
254  return impl->operator()(Dev);
255 }
256 
257 void filter_selector::reset() const { impl->reset(); }
258 
260  std::lock_guard<std::mutex> Guard(
261  sycl::detail::GlobalHandler::instance().getFilterMutex());
262 
264 
265  reset();
266 
267  return Result;
268 }
269 
270 } // namespace oneapi
271 } // namespace ext
272 
273 namespace __SYCL2020_DEPRECATED("use 'ext::oneapi' instead") ONEAPI {
274  using namespace ext::oneapi;
275  filter_selector::filter_selector(const std::string &Input)
276  : ext::oneapi::filter_selector(Input) {}
277 
278  int filter_selector::operator()(const device &Dev) const {
280  }
281 
283 
286  }
287 } // namespace ONEAPI
288 } // namespace sycl
289 } // __SYCL_INLINE_NAMESPACE(cl)
cl::sycl::backend
backend
Definition: backend_types.hpp:21
cl::sycl::isForcedDevice
static bool isForcedDevice(const device &Dev, int Index=-1)
Definition: device_selector.cpp:41
cl::sycl::ext::oneapi::filter_selector::operator()
int operator()(const device &dev) const override
Definition: device_selector.cpp:253
cl::sycl::info::device
device
Definition: info_desc.hpp:49
cl::sycl::detail::GlobalHandler::instance
static GlobalHandler & instance()
Definition: global_handler.cpp:33
cl::sycl::device_selector::select_device
virtual device select_device() const
Definition: device_selector.cpp:65
device_filter.hpp
cl::sycl::detail::device_filter
Definition: device_filter.hpp:22
config.hpp
cl::sycl::detail::device_filter_list::get
std::vector< device_filter > & get()
Definition: device_filter.hpp:45
cl::sycl::device::is_cpu
bool is_cpu() const
Check if device is a CPU device.
Definition: device.cpp:104
stl.hpp
device_selector.hpp
cl::sycl::detail::pi::PI_TRACE_ALL
@ PI_TRACE_ALL
Definition: pi.hpp:58
device.hpp
cl::sycl::device::is_gpu
bool is_gpu() const
Check if device is a GPU device.
Definition: device.cpp:106
cl::sycl::info::device_type
device_type
Definition: info_desc.hpp:170
cl::sycl::detail::pi::PI_TRACE_BASIC
@ PI_TRACE_BASIC
Definition: pi.hpp:56
device_impl.hpp
cl::sycl::device::is_accelerator
bool is_accelerator() const
Check if device is an accelerator device.
Definition: device.cpp:108
filter_selector.hpp
cl::sycl::detail::get_forced_type
info::device_type get_forced_type()
Definition: force_device.cpp:24
cl::sycl::device
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:34
cl::sycl::__SYCL2020_DEPRECATED
namespace __SYCL2020_DEPRECATED("use 'ext::intel' instead") intel
Definition: builtins.hpp:738
cl::sycl::detail::device_filter_list
Definition: device_filter.hpp:37
PI_DEVICE_NOT_FOUND
@ PI_DEVICE_NOT_FOUND
Definition: pi.h:107
force_device.hpp
cl
We provide new interfaces for matrix muliply in this patch:
Definition: access.hpp:13
global_handler.hpp
cl::sycl::ext::oneapi::filter_selector::select_device
device select_device() const override
Definition: device_selector.cpp:259
cl::sycl::isDeviceOfPreferredSyclBe
static bool isDeviceOfPreferredSyclBe(const device &Device)
Definition: device_selector.cpp:32
std::get
constexpr tuple_element< I, tuple< Types... > >::type & get(cl::sycl::detail::tuple< Types... > &Arg) noexcept
Definition: tuple.hpp:199
cl::sycl::device::get_info
info::param_traits< info::device, param >::return_type get_info() const
Queries this SYCL device for information requested by the template parameter param.
Definition: device.cpp:147
cl::sycl::detail::getSyclObjImpl
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:182
backend_types.hpp
exception.hpp
std
Definition: accessor.hpp:2358
cl::sycl::all
detail::enable_if_t< detail::is_sigeninteger< T >::value, int > all(T x) __NOEXC
Definition: builtins.hpp:1282
cl::sycl::info::platform
platform
Definition: info_desc.hpp:29
cl::sycl::instead
std::uint8_t instead
Definition: aliases.hpp:68
cl::sycl::detail::pi::trace
bool trace(TraceLevel level)
Definition: pi.cpp:354
filter_selector_impl.hpp
cl::sycl::ext::oneapi::filter_selector::reset
void reset() const
Definition: device_selector.cpp:257
cl::sycl::device::is_host
bool is_host() const
Get instance of device.
Definition: device.cpp:102
__SYCL_INLINE_NAMESPACE
#define __SYCL_INLINE_NAMESPACE(X)
Definition: defines_elementary.hpp:12