DPC++ Runtime
Runtime libraries for oneAPI DPC++
filter_selector_impl.cpp
Go to the documentation of this file.
1 //==------ filter_selector.cpp - oneapi filter 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 
9 #include <detail/device_impl.hpp>
11 #include <sycl/backend_types.hpp>
12 #include <sycl/device.hpp>
13 #include <sycl/device_selector.hpp>
14 #include <sycl/exception.hpp>
15 #include <sycl/stl.hpp>
16 
17 #include <cctype>
18 #include <regex>
19 #include <string>
20 #include <vector>
21 
22 namespace sycl {
23 inline namespace _V1 {
24 namespace ext::oneapi::detail {
25 
26 std::vector<std::string> tokenize(const std::string &Filter,
27  const std::string &Delim) {
28  std::vector<std::string> Tokens;
29  size_t Pos = 0;
30  std::string Input = Filter;
31  std::string Tok;
32 
33  while ((Pos = Input.find(Delim)) != std::string::npos) {
34  Tok = Input.substr(0, Pos);
35  Input.erase(0, Pos + Delim.length());
36 
37  if (!Tok.empty()) {
38  Tokens.push_back(std::move(Tok));
39  }
40  }
41 
42  // Add remainder
43  if (!Input.empty())
44  Tokens.push_back(std::move(Input));
45 
46  return Tokens;
47 }
48 
49 filter create_filter(const std::string &Input) {
50  filter Result;
51  constexpr auto Error = "Invalid filter string! Valid strings conform to "
52  "BE:DeviceType:DeviceNum, where any are optional";
53 
54  std::vector<std::string> Tokens = tokenize(Input, ":");
55  std::regex IntegerExpr("[[:digit:]]+");
56 
57  // There should only be up to 3 tokens.
58  // BE:Device Type:Device Num
59  if (Tokens.size() > 3)
60  throw sycl::runtime_error(Error, PI_ERROR_INVALID_VALUE);
61 
62  for (const std::string &Token : Tokens) {
63  if (Token == "cpu" && !Result.DeviceType) {
64  Result.DeviceType = sycl::info::device_type::cpu;
65  } else if (Token == "gpu" && !Result.DeviceType) {
66  Result.DeviceType = sycl::info::device_type::gpu;
67  } else if (Token == "accelerator" && !Result.DeviceType) {
68  Result.DeviceType = sycl::info::device_type::accelerator;
69  } else if (Token == "opencl" && !Result.Backend) {
70  Result.Backend = backend::opencl;
71  } else if (Token == "level_zero" && !Result.Backend) {
72  Result.Backend = backend::ext_oneapi_level_zero;
73  } else if (Token == "cuda" && !Result.Backend) {
74  Result.Backend = backend::ext_oneapi_cuda;
75  } else if (Token == "hip" && !Result.Backend) {
76  Result.Backend = backend::ext_oneapi_hip;
77  } else if (Token == "esimd_emulator" && !Result.Backend) {
78  Result.Backend = backend::ext_intel_esimd_emulator;
79  } else if (std::regex_match(Token, IntegerExpr) && !Result.DeviceNum) {
80  try {
81  Result.DeviceNum = std::stoi(Token);
82  } catch (std::logic_error &) {
83  throw sycl::runtime_error(Error, PI_ERROR_INVALID_VALUE);
84  }
85  } else {
86  throw sycl::runtime_error(Error, PI_ERROR_INVALID_VALUE);
87  }
88  }
89 
90  return Result;
91 }
92 
94  : mFilters(), mNumDevicesSeen(0), mMatchFound(false) {
95  std::vector<std::string> Filters = detail::tokenize(Input, ",");
96  mNumTotalDevices = device::get_devices().size();
97 
98  for (const std::string &Filter : Filters) {
100  mFilters.push_back(std::move(F));
101  }
102 }
103 
105  assert(!sycl::detail::getSyclObjImpl(Dev)->is_host() &&
106  "filter_selector_impl should not be used with host.");
107 
108  int Score = REJECT_DEVICE_SCORE;
109 
110  for (auto &Filter : mFilters) {
111  bool BackendOK = true;
112  bool DeviceTypeOK = true;
113  bool DeviceNumOK = true;
114 
115  if (Filter.Backend) {
116  backend BE = sycl::detail::getSyclObjImpl(Dev)->getBackend();
117  // Backend is okay if the filter BE is set 'all'.
118  if (Filter.Backend.value() == backend::all)
119  BackendOK = true;
120  else
121  BackendOK = (BE == Filter.Backend.value());
122  }
123  if (Filter.DeviceType) {
126  // DeviceType is okay if the filter is set 'all'.
127  if (Filter.DeviceType == sycl::info::device_type::all)
128  DeviceTypeOK = true;
129  else
130  DeviceTypeOK = (DT == Filter.DeviceType);
131  }
132  if (Filter.DeviceNum) {
133  // Only check device number if we're good on the previous matches
134  if (BackendOK && DeviceTypeOK) {
135  // Do we match?
136  DeviceNumOK = (Filter.MatchesSeen == Filter.DeviceNum.value());
137  // Safe to increment matches even if we find it
138  Filter.MatchesSeen++;
139  }
140  }
141  if (BackendOK && DeviceTypeOK && DeviceNumOK) {
142  Score = default_selector_v(Dev);
143  mMatchFound = true;
144  break;
145  }
146  }
147 
148  mNumDevicesSeen++;
149  if ((mNumDevicesSeen == mNumTotalDevices) && !mMatchFound) {
150  throw sycl::runtime_error(
151  "Could not find a device that matches the specified filter(s)!",
152  PI_ERROR_DEVICE_NOT_FOUND);
153  }
154 
155  return Score;
156 }
157 
159  // This is a bit of an abuse of "const" method...
160  // Reset state if you want to reuse this selector.
161  for (auto &Filter : mFilters) {
162  Filter.MatchesSeen = 0;
163  }
164  mMatchFound = false;
165  mNumDevicesSeen = 0;
166 }
167 
168 } // namespace ext::oneapi::detail
169 
170 namespace __SYCL2020_DEPRECATED("use 'ext::oneapi' instead") ONEAPI {
171 using namespace ext::oneapi;
172 }
173 } // namespace _V1
174 } // namespace sycl
sycl::_V1::__SYCL2020_DEPRECATED
signed char __SYCL2020_DEPRECATED
Definition: aliases.hpp:94
sycl::_V1::instead
std::uint8_t instead
Definition: aliases.hpp:93
sycl::_V1::backend
backend
Definition: backend_types.hpp:18
sycl::_V1::backend::ext_oneapi_level_zero
@ ext_oneapi_level_zero
stl.hpp
device_selector.hpp
device.hpp
sycl::_V1::ext::oneapi::detail::filter_selector_impl::filter_selector_impl
filter_selector_impl(const std::string &filter)
Definition: filter_selector_impl.cpp:93
sycl::_V1::backend::ext_oneapi_hip
@ ext_oneapi_hip
sycl::_V1::all
std::enable_if_t< detail::is_vigeninteger_v< T >, int > all(T x)
Definition: builtins_legacy_marray_vec.hpp:1108
sycl
Definition: access.hpp:18
sycl::_V1::backend::all
@ all
device_impl.hpp
sycl::_V1::backend::ext_oneapi_cuda
@ ext_oneapi_cuda
sycl::_V1::default_selector_v
class __SYCL2020_DEPRECATED("Host device is no longer supported.") host_selector int default_selector_v(const device &dev)
Selects SYCL host device.
Definition: device_selector.cpp:179
sycl::_V1::ext::oneapi::detail::tokenize
std::vector< std::string > tokenize(const std::string &Filter, const std::string &Delim)
Definition: filter_selector_impl.cpp:26
sycl::_V1::ext::oneapi::experimental::assert
assert(false)
sycl::_V1::device
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:59
sycl::_V1::info::device_type
device_type
Definition: info_desc.hpp:53
sycl::_V1::device::get_devices
static std::vector< device > get_devices(info::device_type deviceType=info::device_type::all)
Query available SYCL devices.
Definition: device.cpp:52
sycl::_V1::backend::opencl
@ opencl
backend_types.hpp
sycl::_V1::device::get_info
detail::is_device_info_desc< Param >::return_type get_info() const
Queries this SYCL device for information requested by the template parameter param.
Definition: device.cpp:136
exception.hpp
sycl::_V1::ext::oneapi::detail::filter_selector_impl::reset
void reset() const
Definition: filter_selector_impl.cpp:158
sycl::_V1::ext::oneapi::experimental::matrix::use
use
Definition: matrix-unified-utils.hpp:17
sycl::_V1::ext::oneapi::detail::filter
struct sycl::detail::device_filter filter
Definition: filter_selector_impl.hpp:26
sycl::_V1::ext::oneapi::detail::create_filter
filter create_filter(const std::string &Input)
Definition: filter_selector_impl.cpp:49
sycl::_V1::ext::oneapi::detail::filter_selector_impl::operator()
int operator()(const device &dev) const
Definition: filter_selector_impl.cpp:104
filter_selector_impl.hpp
sycl::_V1::detail::getSyclObjImpl
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:30