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 
16 #include <cctype>
17 #include <regex>
18 #include <string>
19 #include <vector>
20 
21 namespace sycl {
22 inline namespace _V1 {
23 namespace ext::oneapi::detail {
24 
25 std::vector<std::string> tokenize(const std::string &Filter,
26  const std::string &Delim) {
27  std::vector<std::string> Tokens;
28  size_t Pos = 0;
29  std::string Input = Filter;
30  std::string Tok;
31 
32  while ((Pos = Input.find(Delim)) != std::string::npos) {
33  Tok = Input.substr(0, Pos);
34  Input.erase(0, Pos + Delim.length());
35 
36  if (!Tok.empty()) {
37  Tokens.push_back(std::move(Tok));
38  }
39  }
40 
41  // Add remainder
42  if (!Input.empty())
43  Tokens.push_back(std::move(Input));
44 
45  return Tokens;
46 }
47 
48 filter create_filter(const std::string &Input) {
49  filter Result;
50  constexpr auto Error = "Invalid filter string! Valid strings conform to "
51  "BE:DeviceType:DeviceNum, where any are optional";
52 
53  std::vector<std::string> Tokens = tokenize(Input, ":");
54  std::regex IntegerExpr("[[:digit:]]+");
55 
56  // There should only be up to 3 tokens.
57  // BE:Device Type:Device Num
58  if (Tokens.size() > 3)
60 
61  for (const std::string &Token : Tokens) {
62  if (Token == "cpu" && !Result.DeviceType) {
63  Result.DeviceType = sycl::info::device_type::cpu;
64  } else if (Token == "gpu" && !Result.DeviceType) {
65  Result.DeviceType = sycl::info::device_type::gpu;
66  } else if (Token == "accelerator" && !Result.DeviceType) {
67  Result.DeviceType = sycl::info::device_type::accelerator;
68  } else if (Token == "opencl" && !Result.Backend) {
69  Result.Backend = backend::opencl;
70  } else if (Token == "level_zero" && !Result.Backend) {
71  Result.Backend = backend::ext_oneapi_level_zero;
72  } else if (Token == "cuda" && !Result.Backend) {
73  Result.Backend = backend::ext_oneapi_cuda;
74  } else if (Token == "hip" && !Result.Backend) {
75  Result.Backend = backend::ext_oneapi_hip;
76  } else if (std::regex_match(Token, IntegerExpr) && !Result.DeviceNum) {
77  try {
78  Result.DeviceNum = std::stoi(Token);
79  } catch (std::logic_error &) {
81  }
82  } else {
84  }
85  }
86 
87  return Result;
88 }
89 
91  : mFilters(), mNumDevicesSeen(0), mMatchFound(false) {
92  std::vector<std::string> Filters = detail::tokenize(Input, ",");
93  mNumTotalDevices = device::get_devices().size();
94 
95  for (const std::string &Filter : Filters) {
97  mFilters.push_back(std::move(F));
98  }
99 }
100 
102  int Score = REJECT_DEVICE_SCORE;
103 
104  for (auto &Filter : mFilters) {
105  bool BackendOK = true;
106  bool DeviceTypeOK = true;
107  bool DeviceNumOK = true;
108 
109  if (Filter.Backend) {
110  backend BE = sycl::detail::getSyclObjImpl(Dev)->getBackend();
111  // Backend is okay if the filter BE is set 'all'.
112  if (Filter.Backend.value() == backend::all)
113  BackendOK = true;
114  else
115  BackendOK = (BE == Filter.Backend.value());
116  }
117  if (Filter.DeviceType) {
120  // DeviceType is okay if the filter is set 'all'.
121  if (Filter.DeviceType == sycl::info::device_type::all)
122  DeviceTypeOK = true;
123  else
124  DeviceTypeOK = (DT == Filter.DeviceType);
125  }
126  if (Filter.DeviceNum) {
127  // Only check device number if we're good on the previous matches
128  if (BackendOK && DeviceTypeOK) {
129  // Do we match?
130  DeviceNumOK = (Filter.MatchesSeen == Filter.DeviceNum.value());
131  // Safe to increment matches even if we find it
132  Filter.MatchesSeen++;
133  }
134  }
135  if (BackendOK && DeviceTypeOK && DeviceNumOK) {
136  Score = default_selector_v(Dev);
137  mMatchFound = true;
138  break;
139  }
140  }
141 
142  mNumDevicesSeen++;
143  if ((mNumDevicesSeen == mNumTotalDevices) && !mMatchFound) {
144  throw exception(
146  "Could not find a device that matches the specified filter(s)!");
147  }
148 
149  return Score;
150 }
151 
153  // This is a bit of an abuse of "const" method...
154  // Reset state if you want to reuse this selector.
155  for (auto &Filter : mFilters) {
156  Filter.MatchesSeen = 0;
157  }
158  mMatchFound = false;
159  mNumDevicesSeen = 0;
160 }
161 
162 } // namespace ext::oneapi::detail
163 
164 namespace __SYCL2020_DEPRECATED("use 'ext::oneapi' instead") ONEAPI {
165 using namespace ext::oneapi;
166 }
167 } // namespace _V1
168 } // namespace sycl
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
static std::vector< device > get_devices(info::device_type deviceType=info::device_type::all)
Query available SYCL devices.
Definition: device.cpp:51
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.hpp:215
decltype(Obj::impl) const & getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:31
filter create_filter(const std::string &Input)
std::vector< std::string > tokenize(const std::string &Filter, const std::string &Delim)
signed char __SYCL2020_DEPRECATED
Definition: aliases.hpp:94
int default_selector_v(const device &dev)
std::uint8_t instead
Definition: aliases.hpp:93
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:64
Definition: access.hpp:18