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 
10 #include <CL/sycl/device.hpp>
12 #include <CL/sycl/exception.hpp>
13 #include <CL/sycl/stl.hpp>
14 #include <detail/device_impl.hpp>
16 
17 #include <cctype>
18 #include <regex>
19 #include <string>
20 #include <vector>
21 
23 namespace sycl {
24 namespace ext {
25 namespace oneapi {
26 namespace detail {
27 
28 std::vector<std::string> tokenize(const std::string &Filter,
29  const std::string &Delim) {
30  std::vector<std::string> Tokens;
31  size_t Pos = 0;
32  std::string Input = Filter;
33  std::string Tok;
34 
35  while ((Pos = Input.find(Delim)) != std::string::npos) {
36  Tok = Input.substr(0, Pos);
37  Input.erase(0, Pos + Delim.length());
38 
39  if (!Tok.empty()) {
40  Tokens.push_back(std::move(Tok));
41  }
42  }
43 
44  // Add remainder
45  if (!Input.empty())
46  Tokens.push_back(std::move(Input));
47 
48  return Tokens;
49 }
50 
51 filter create_filter(const std::string &Input) {
52  filter Result;
53  constexpr auto Error = "Invalid filter string! Valid strings conform to "
54  "BE:DeviceType:DeviceNum, where any are optional";
55 
56  std::vector<std::string> Tokens = tokenize(Input, ":");
57  std::regex IntegerExpr("[[:digit:]]+");
58 
59  // There should only be up to 3 tokens.
60  // BE:Device Type:Device Num
61  if (Tokens.size() > 3)
62  throw sycl::runtime_error(Error, PI_INVALID_VALUE);
63 
64  for (const std::string &Token : Tokens) {
65  if (Token == "cpu" && !Result.HasDeviceType) {
66  Result.DeviceType = info::device_type::cpu;
67  Result.HasDeviceType = true;
68  } else if (Token == "gpu" && !Result.HasDeviceType) {
69  Result.DeviceType = info::device_type::gpu;
70  Result.HasDeviceType = true;
71  } else if (Token == "accelerator" && !Result.HasDeviceType) {
72  Result.DeviceType = info::device_type::accelerator;
73  Result.HasDeviceType = true;
74  } else if (Token == "opencl" && !Result.HasBackend) {
75  Result.Backend = backend::opencl;
76  Result.HasBackend = true;
77  } else if (Token == "level_zero" && !Result.HasBackend) {
78  Result.Backend = backend::ext_oneapi_level_zero;
79  Result.HasBackend = true;
80  } else if (Token == "cuda" && !Result.HasBackend) {
81  Result.Backend = backend::ext_oneapi_cuda;
82  Result.HasBackend = true;
83  } else if (Token == "hip" && !Result.HasBackend) {
84  Result.Backend = backend::ext_oneapi_hip;
85  Result.HasBackend = true;
86  } else if (Token == "host") {
87  if (!Result.HasBackend) {
88  Result.Backend = backend::host;
89  Result.HasBackend = true;
90  } else if (!Result.HasDeviceType && Result.Backend != backend::host) {
91  // We already set everything earlier or it's an error.
92  throw sycl::runtime_error(
93  "Cannot specify host device with non-host backend.",
95  }
96  } else if (std::regex_match(Token, IntegerExpr) && !Result.HasDeviceNum) {
97  try {
98  Result.DeviceNum = std::stoi(Token);
99  } catch (std::logic_error &) {
100  throw sycl::runtime_error(Error, PI_INVALID_VALUE);
101  }
102  Result.HasDeviceNum = true;
103  } else {
104  throw sycl::runtime_error(Error, PI_INVALID_VALUE);
105  }
106  }
107 
108  return Result;
109 }
110 
111 filter_selector_impl::filter_selector_impl(const std::string &Input)
112  : mFilters(), mRanker(), mNumDevicesSeen(0), mMatchFound(false) {
113  std::vector<std::string> Filters = detail::tokenize(Input, ",");
114  mNumTotalDevices = device::get_devices().size();
115 
116  for (const std::string &Filter : Filters) {
118  mFilters.push_back(std::move(F));
119  }
120 }
121 
123  int Score = REJECT_DEVICE_SCORE;
124 
125  for (auto &Filter : mFilters) {
126  bool BackendOK = true;
127  bool DeviceTypeOK = true;
128  bool DeviceNumOK = true;
129 
130  // handle host device specially
131  if (Filter.HasBackend) {
132  backend BE;
133  if (Dev.is_host()) {
134  BE = backend::host;
135  } else {
136  BE = sycl::detail::getSyclObjImpl(Dev)->getPlugin().getBackend();
137  }
138  // Backend is okay if the filter BE is set 'all'.
139  if (Filter.Backend == backend::all)
140  BackendOK = true;
141  else
142  BackendOK = (BE == Filter.Backend);
143  }
144  if (Filter.HasDeviceType) {
146  // DeviceType is okay if the filter is set 'all'.
147  if (Filter.DeviceType == info::device_type::all)
148  DeviceTypeOK = true;
149  else
150  DeviceTypeOK = (DT == Filter.DeviceType);
151  }
152  if (Filter.HasDeviceNum) {
153  // Only check device number if we're good on the previous matches
154  if (BackendOK && DeviceTypeOK) {
155  // Do we match?
156  DeviceNumOK = (Filter.MatchesSeen == Filter.DeviceNum);
157  // Safe to increment matches even if we find it
158  Filter.MatchesSeen++;
159  }
160  }
161  if (BackendOK && DeviceTypeOK && DeviceNumOK) {
162  Score = mRanker(Dev);
163  mMatchFound = true;
164  break;
165  }
166  }
167 
168  mNumDevicesSeen++;
169  if ((mNumDevicesSeen == mNumTotalDevices) && !mMatchFound) {
170  throw sycl::runtime_error(
171  "Could not find a device that matches the specified filter(s)!",
173  }
174 
175  return Score;
176 }
177 
179  // This is a bit of an abuse of "const" method...
180  // Reset state if you want to reuse this selector.
181  for (auto &Filter : mFilters) {
182  Filter.MatchesSeen = 0;
183  }
184  mMatchFound = false;
185  mNumDevicesSeen = 0;
186 }
187 
188 } // namespace detail
189 } // namespace oneapi
190 } // namespace ext
191 
192 namespace __SYCL2020_DEPRECATED("use 'ext::oneapi' instead") ONEAPI {
193  using namespace ext::oneapi;
194 }
195 } // namespace sycl
196 } // __SYCL_INLINE_NAMESPACE(cl)
cl::sycl::backend
backend
Definition: backend_types.hpp:21
cl::sycl::detail::device_filter::HasDeviceNum
bool HasDeviceNum
Definition: device_filter.hpp:28
cl::sycl::detail::device_filter
Definition: device_filter.hpp:22
stl.hpp
device_selector.hpp
device.hpp
cl::sycl::device::get_devices
static std::vector< device > get_devices(info::device_type deviceType=info::device_type::all)
Query available SYCL devices.
Definition: device.cpp:51
cl::sycl::info::device_type
device_type
Definition: info_desc.hpp:180
sycl
Definition: invoke_simd.hpp:68
device_impl.hpp
cl::sycl::ext::oneapi::detail::tokenize
std::vector< std::string > tokenize(const std::string &Filter, const std::string &Delim)
Definition: filter_selector_impl.cpp:28
cl::sycl::detail::device_filter::DeviceType
info::device_type DeviceType
Definition: device_filter.hpp:24
cl::sycl::backend::host
@ host
cl::sycl::device
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:35
cl::sycl::__SYCL2020_DEPRECATED
class __SYCL2020_DEPRECATED("sycl::atomic is deprecated since SYCL 2020") atomic
Definition: atomic.hpp:171
cl::sycl::detail::device_filter::DeviceNum
int DeviceNum
Definition: device_filter.hpp:25
cl::sycl::info::device_type::all
@ all
PI_DEVICE_NOT_FOUND
@ PI_DEVICE_NOT_FOUND
Definition: pi.h:111
cl
We provide new interfaces for matrix muliply in this patch:
Definition: access.hpp:13
cl::sycl::ext::oneapi::detail::filter_selector_impl::operator()
int operator()(const device &dev) const
Definition: filter_selector_impl.cpp:122
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::backend::all
@ all
PI_INVALID_VALUE
@ PI_INVALID_VALUE
Definition: pi.h:91
cl::sycl::ext::oneapi::detail::create_filter
filter create_filter(const std::string &Input)
Definition: filter_selector_impl.cpp:51
cl::sycl::detail::getSyclObjImpl
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:198
backend_types.hpp
exception.hpp
cl::sycl::ext::oneapi::detail::filter_selector_impl::reset
void reset() const
Definition: filter_selector_impl.cpp:178
cl::sycl::detail::device_filter::HasBackend
bool HasBackend
Definition: device_filter.hpp:26
cl::sycl::instead
std::uint8_t instead
Definition: aliases.hpp:68
cl::sycl::detail::device_filter::Backend
backend Backend
Definition: device_filter.hpp:23
cl::sycl::detail::device_filter::HasDeviceType
bool HasDeviceType
Definition: device_filter.hpp:27
filter_selector_impl.hpp
cl::sycl::device::is_host
bool is_host() const
Get instance of device.
Definition: device.cpp:102
cl::sycl::info::device::device_type
@ device_type
__SYCL_INLINE_NAMESPACE
#define __SYCL_INLINE_NAMESPACE(X)
Definition: defines_elementary.hpp:12