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 {
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_ERROR_INVALID_VALUE);
63 
64  for (const std::string &Token : Tokens) {
65  if (Token == "cpu" && !Result.DeviceType) {
66  Result.DeviceType = sycl::info::device_type::cpu;
67  } else if (Token == "gpu" && !Result.DeviceType) {
68  Result.DeviceType = sycl::info::device_type::gpu;
69  } else if (Token == "accelerator" && !Result.DeviceType) {
70  Result.DeviceType = sycl::info::device_type::accelerator;
71  } else if (Token == "opencl" && !Result.Backend) {
72  Result.Backend = backend::opencl;
73  } else if (Token == "level_zero" && !Result.Backend) {
74  Result.Backend = backend::ext_oneapi_level_zero;
75  } else if (Token == "cuda" && !Result.Backend) {
76  Result.Backend = backend::ext_oneapi_cuda;
77  } else if (Token == "hip" && !Result.Backend) {
78  Result.Backend = backend::ext_oneapi_hip;
79  } else if (Token == "esimd_emulator" && !Result.Backend) {
80  Result.Backend = backend::ext_intel_esimd_emulator;
81  } else if (std::regex_match(Token, IntegerExpr) && !Result.DeviceNum) {
82  try {
83  Result.DeviceNum = std::stoi(Token);
84  } catch (std::logic_error &) {
85  throw sycl::runtime_error(Error, PI_ERROR_INVALID_VALUE);
86  }
87  } else {
88  throw sycl::runtime_error(Error, PI_ERROR_INVALID_VALUE);
89  }
90  }
91 
92  return Result;
93 }
94 
95 filter_selector_impl::filter_selector_impl(const std::string &Input)
96  : mFilters(), mRanker(), mNumDevicesSeen(0), mMatchFound(false) {
97  std::vector<std::string> Filters = detail::tokenize(Input, ",");
98  mNumTotalDevices = device::get_devices().size();
99 
100  for (const std::string &Filter : Filters) {
102  mFilters.push_back(std::move(F));
103  }
104 }
105 
107  assert(!sycl::detail::getSyclObjImpl(Dev)->is_host() &&
108  "filter_selector_impl should not be used with host.");
109 
110  int Score = REJECT_DEVICE_SCORE;
111 
112  for (auto &Filter : mFilters) {
113  bool BackendOK = true;
114  bool DeviceTypeOK = true;
115  bool DeviceNumOK = true;
116 
117  if (Filter.Backend) {
118  backend BE = sycl::detail::getSyclObjImpl(Dev)->getPlugin().getBackend();
119  // Backend is okay if the filter BE is set 'all'.
120  if (Filter.Backend.value() == backend::all)
121  BackendOK = true;
122  else
123  BackendOK = (BE == Filter.Backend.value());
124  }
125  if (Filter.DeviceType) {
128  // DeviceType is okay if the filter is set 'all'.
129  if (Filter.DeviceType == sycl::info::device_type::all)
130  DeviceTypeOK = true;
131  else
132  DeviceTypeOK = (DT == Filter.DeviceType);
133  }
134  if (Filter.DeviceNum) {
135  // Only check device number if we're good on the previous matches
136  if (BackendOK && DeviceTypeOK) {
137  // Do we match?
138  DeviceNumOK = (Filter.MatchesSeen == Filter.DeviceNum.value());
139  // Safe to increment matches even if we find it
140  Filter.MatchesSeen++;
141  }
142  }
143  if (BackendOK && DeviceTypeOK && DeviceNumOK) {
144  Score = mRanker(Dev);
145  mMatchFound = true;
146  break;
147  }
148  }
149 
150  mNumDevicesSeen++;
151  if ((mNumDevicesSeen == mNumTotalDevices) && !mMatchFound) {
152  throw sycl::runtime_error(
153  "Could not find a device that matches the specified filter(s)!",
154  PI_ERROR_DEVICE_NOT_FOUND);
155  }
156 
157  return Score;
158 }
159 
161  // This is a bit of an abuse of "const" method...
162  // Reset state if you want to reuse this selector.
163  for (auto &Filter : mFilters) {
164  Filter.MatchesSeen = 0;
165  }
166  mMatchFound = false;
167  mNumDevicesSeen = 0;
168 }
169 
170 } // namespace detail
171 } // namespace oneapi
172 } // namespace ext
173 
174 namespace __SYCL2020_DEPRECATED("use 'ext::oneapi' instead") ONEAPI {
175 using namespace ext::oneapi;
176 }
177 } // __SYCL_INLINE_VER_NAMESPACE(_V1)
178 } // namespace sycl
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:49
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:126
static std::vector< device > get_devices(info::device_type deviceType=info::device_type::all)
Query available SYCL devices.
Definition: device.cpp:50
#define __SYCL_INLINE_VER_NAMESPACE(X)
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:248
filter create_filter(const std::string &Input)
std::vector< std::string > tokenize(const std::string &Filter, const std::string &Delim)
struct sycl::detail::device_filter filter
class __SYCL2020_DEPRECATED("sycl::atomic is deprecated since SYCL 2020") atomic
Definition: atomic.hpp:174
std::uint8_t instead
Definition: aliases.hpp:69
---— Error handling, matching OpenCL plugin semantics.
Definition: access.hpp:14