Skip to content

Commit 215f516

Browse files
committed
Apply CR comments
1 parent 18949a7 commit 215f516

File tree

9 files changed

+413
-365
lines changed

9 files changed

+413
-365
lines changed

sycl/doc/EnvironmentVariables.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ subject to change. Do not rely on these variables in production code.
2323
| SYCL_DISABLE_EXECUTION_GRAPH_CLEANUP | Any(\*) | Disable cleanup of finished command nodes at host-device synchronization points. |
2424
| SYCL_THROW_ON_BLOCK | Any(\*) | Throw an exception on attempt to wait for a blocked command. |
2525
| SYCL_DEVICELIB_INHIBIT_NATIVE | String of device library extensions (separated by a whitespace) | Do not rely on device native support for devicelib extensions listed in this option. |
26-
| SYCL_DEVICE_ALLOWLIST | A list of devices and their driver version following the pattern: BackendName:XXX,DeviceType:YYY,DeviceVendorId:ZZZ,DriverVersion:{{X.Y.Z.W}}. Also may contain PlatformVersion, DeviceName and PlatformName | Filter out devices that do not match the pattern specified. BackendName accepts `host`, `opencl`, `level_zero` or `cuda`. DeviceType accepts `host`, `cpu`, `gpu` or `acc`. DeviceVendorId accepts uint32_t in hex form (0xXYZW). DriverVersion, PlatformVersion, DeviceName and PlatformName accept regular expression. Special characters, such as parenthesis, must be escaped. DPC++ runtime will select only those devices which satisfy provided values above and regex. More than one device can be specified using the piping symbol "\|".|
26+
| SYCL_DEVICE_ALLOWLIST | A list of devices and their driver version following the pattern: BackendName:XXX,DeviceType:YYY,DeviceVendorId:0xXYZW,DriverVersion:{{X.Y.Z.W}}. Also may contain PlatformVersion, DeviceName and PlatformName. There is no fixed order of properties in the pattern. | Filter out devices that do not match the pattern specified. BackendName accepts `host`, `opencl`, `level_zero` or `cuda`. DeviceType accepts `host`, `cpu`, `gpu` or `acc`. DeviceVendorId accepts uint32_t in hex form (0xXYZW). DriverVersion, PlatformVersion, DeviceName and PlatformName accept regular expression. Special characters, such as parenthesis, must be escaped. DPC++ runtime will select only those devices which satisfy provided values above and regex. More than one device can be specified using the piping symbol "\|".|
2727
| SYCL_QUEUE_THREAD_POOL_SIZE | Positive integer | Number of threads in thread pool of queue. |
2828
| SYCL_DEVICELIB_NO_FALLBACK | Any(\*) | Disable loading and linking of device library images |
2929
| SYCL_PI_LEVEL_ZERO_MAX_COMMAND_LIST_CACHE | Positive integer | Maximum number of oneAPI Level Zero Command lists that can be allocated with no reuse before throwing an "out of resources" error. Default is 20000, threshold may be increased based on resource availabilty and workload demand. |

sycl/source/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ set(SYCL_SOURCES
106106
"backend/level_zero.cpp"
107107
"backend.cpp"
108108
"detail/accessor_impl.cpp"
109+
"detail/allowlist.cpp"
109110
"detail/buffer_impl.cpp"
110111
"detail/builtins_common.cpp"
111112
"detail/builtins_geometric.cpp"

sycl/source/detail/allowlist.cpp

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
//==-------------- allowlist.cpp - SYCL_DEVICE_ALLOWLIST -------------------==//
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/config.hpp>
10+
#include <detail/allowlist.hpp>
11+
#include <detail/device_impl.hpp>
12+
#include <detail/platform_info.hpp>
13+
14+
#include <regex>
15+
16+
__SYCL_INLINE_NAMESPACE(cl) {
17+
namespace sycl {
18+
namespace detail {
19+
20+
constexpr char BackendNameKeyName[] = "BackendName";
21+
constexpr char DeviceTypeKeyName[] = "DeviceType";
22+
constexpr char DeviceVendorIdKeyName[] = "DeviceVendorId";
23+
constexpr char DriverVersionKeyName[] = "DriverVersion";
24+
constexpr char PlatformVersionKeyName[] = "PlatformVersion";
25+
constexpr char DeviceNameKeyName[] = "DeviceName";
26+
constexpr char PlatformNameKeyName[] = "PlatformName";
27+
28+
constexpr std::array<const char*, 7> SupportedAllowListKeyNames{
29+
BackendNameKeyName, DeviceTypeKeyName, DeviceVendorIdKeyName,
30+
DriverVersionKeyName, PlatformVersionKeyName, DeviceNameKeyName,
31+
PlatformNameKeyName};
32+
33+
// Parsing and validating SYCL_DEVICE_ALLOWLIST variable value.
34+
//
35+
// The value has the following form:
36+
// DeviceDesc1|DeviceDesc2|<...>|DeviceDescN
37+
// DeviceDescN is the set of descriptions for the device which should be
38+
// allowed. The sets of device descriptions are separated by '|' symbol. The set
39+
// of descriptions has the following structure:
40+
// DeviceDescN = Key1:Value1,Key2:Value2,...,KeyN:ValueN
41+
// Device descriptions are separated by ',' symbol.
42+
// Key and value of a device description are separated by ":" symbol.
43+
// KeyN is the key of a device description, it could be one of the following
44+
// from SupportedAllowListKeyNames vector above.
45+
// DeviceName and PlatformName device descriptions are deprecated and will be
46+
// removed in one of the future releases.
47+
// ValueN is the value of a device description, it could be regex and some fixed
48+
// string.
49+
// Function should return parsed SYCL_DEVICE_ALLOWLIST variable value as
50+
// AllowListParsedT type (vector of maps), e.g.:
51+
// {{Key1: Value1, Key2: Value2}, ..., {Key1: Value1, ..., KeyN: ValueN}}
52+
AllowListParsedT parseAllowList(const std::string &AllowListRaw) {
53+
if (AllowListRaw.empty())
54+
return {};
55+
56+
AllowListParsedT AllowListParsed;
57+
AllowListParsed.emplace_back();
58+
59+
constexpr std::array<const char *, 3> SupportedKeyNamesHaveFixedValue{
60+
BackendNameKeyName, DeviceTypeKeyName, DeviceVendorIdKeyName};
61+
constexpr std::array<const char *, 4> SupportedKeyNamesRequireRegexValue{
62+
DriverVersionKeyName, PlatformVersionKeyName, DeviceNameKeyName,
63+
PlatformNameKeyName};
64+
65+
size_t KeyStart = 0, KeyEnd = 0, ValueStart = 0, ValueEnd = 0,
66+
DeviceDescIndex = 0;
67+
68+
while ((KeyEnd = AllowListRaw.find(':', KeyStart)) != std::string::npos) {
69+
if ((ValueStart = AllowListRaw.find_first_not_of(":", KeyEnd)) ==
70+
std::string::npos)
71+
break;
72+
const std::string &Key = AllowListRaw.substr(KeyStart, KeyEnd - KeyStart);
73+
74+
// check that provided key is supported
75+
if (std::find(SupportedAllowListKeyNames.begin(),
76+
SupportedAllowListKeyNames.end(),
77+
Key) == SupportedAllowListKeyNames.end()) {
78+
throw sycl::runtime_error("Unrecognized key in SYCL_DEVICE_ALLOWLIST",
79+
PI_INVALID_VALUE);
80+
}
81+
82+
bool ShouldAllocateNewDeviceDescMap = false;
83+
84+
ValueEnd = AllowListRaw.find(',', ValueStart);
85+
if (ValueEnd == std::string::npos) {
86+
ValueEnd = AllowListRaw.length();
87+
}
88+
for (const auto &SupportedKeyName : SupportedAllowListKeyNames) {
89+
// check if it is the last Key:Value pair in the device description, and
90+
// correct end position of that value
91+
if (size_t ValueEndCand = AllowListRaw.find(
92+
"|" + std::string(SupportedKeyName), ValueStart);
93+
(ValueEndCand != std::string::npos) && (ValueEndCand < ValueEnd)) {
94+
ValueEnd = ValueEndCand;
95+
ShouldAllocateNewDeviceDescMap = true;
96+
}
97+
}
98+
99+
auto &DeviceDescMap = AllowListParsed[DeviceDescIndex];
100+
101+
// check if Key is not already defined in DeviceDescMap, e.g., caused by the
102+
// following invalid syntax: Key1:Value1,Key2:Value2,Key1:Value3
103+
if (DeviceDescMap.find(Key) == DeviceDescMap.end()) {
104+
// check that regex values have double curly braces at the beginning and
105+
// at the end
106+
size_t CurlyBracesStartSize = 0, CurlyBracesEndSize = 0;
107+
if (std::find(SupportedKeyNamesRequireRegexValue.begin(),
108+
SupportedKeyNamesRequireRegexValue.end(),
109+
Key) != SupportedKeyNamesRequireRegexValue.end()) {
110+
const std::string &ValueRaw =
111+
AllowListRaw.substr(ValueStart, ValueEnd - ValueStart);
112+
std::string Prefix("{{");
113+
// can be changed to string_view::starts_with after switching DPC++ RT
114+
// to C++20
115+
if (Prefix != ValueRaw.substr(0, Prefix.length())) {
116+
throw sycl::runtime_error("Key " + Key +
117+
" of SYCL_DEVICE_ALLOWLIST should have "
118+
"value which starts with {{",
119+
PI_INVALID_VALUE);
120+
}
121+
std::string Postfix("}}");
122+
// can be changed to string_view::ends_with after switching DPC++ RT to
123+
// C++20
124+
if (Postfix != ValueRaw.substr(ValueRaw.length() - Postfix.length(),
125+
ValueRaw.length())) {
126+
throw sycl::runtime_error("Key " + Key +
127+
" of SYCL_DEVICE_ALLOWLIST should have "
128+
"value which ends with }}",
129+
PI_INVALID_VALUE);
130+
}
131+
CurlyBracesStartSize = Prefix.length();
132+
CurlyBracesEndSize = Postfix.length();
133+
}
134+
// if value has curly braces {{ and }} at the beginning and at the end,
135+
// CurlyBracesStartSize and CurlyBracesEndSize != 0, so we move boundaries
136+
// to remove these braces
137+
const std::string &Value =
138+
AllowListRaw.substr(ValueStart + CurlyBracesStartSize,
139+
(ValueEnd - CurlyBracesEndSize) -
140+
(ValueStart + CurlyBracesStartSize));
141+
// check that values of keys, which should have some fixed format, are
142+
// valid. E.g., for BackendName key, the allowed values are only ones
143+
// described in SyclBeMap
144+
if (std::find(SupportedKeyNamesHaveFixedValue.begin(),
145+
SupportedKeyNamesHaveFixedValue.end(),
146+
Key) != SupportedKeyNamesHaveFixedValue.end()) {
147+
if (Key == BackendNameKeyName) {
148+
bool ValueForBackendNameIsValid = false;
149+
for (const auto &SyclBe : SyclBeMap) {
150+
if (Value == SyclBe.first) {
151+
ValueForBackendNameIsValid = true;
152+
break;
153+
}
154+
}
155+
if (!ValueForBackendNameIsValid) {
156+
throw sycl::runtime_error(
157+
"Value " + Value + " for key " + Key +
158+
" is not valid in "
159+
"SYCL_DEVICE_ALLOWLIST. For details, please refer to "
160+
"https://github.com/intel/llvm/blob/sycl/sycl/doc/"
161+
"EnvironmentVariables.md",
162+
PI_INVALID_VALUE);
163+
}
164+
}
165+
if (Key == DeviceTypeKeyName) {
166+
bool ValueForDeviceTypeIsValid = false;
167+
for (const auto &SyclDeviceType : SyclDeviceTypeMap) {
168+
if (Value == SyclDeviceType.first) {
169+
ValueForDeviceTypeIsValid = true;
170+
break;
171+
}
172+
}
173+
if (!ValueForDeviceTypeIsValid) {
174+
throw sycl::runtime_error(
175+
"Value " + Value + " for key " + Key +
176+
" is not valid in "
177+
"SYCL_DEVICE_ALLOWLIST. For details, please refer to "
178+
"https://github.com/intel/llvm/blob/sycl/sycl/doc/"
179+
"EnvironmentVariables.md",
180+
PI_INVALID_VALUE);
181+
}
182+
}
183+
if (Key == DeviceVendorIdKeyName) {
184+
// DeviceVendorId should have hex format
185+
if (!std::regex_match(Value, std::regex("0[xX][0-9a-fA-F]+"))) {
186+
throw sycl::runtime_error(
187+
"Value " + Value + " for key " + Key +
188+
" is not valid in "
189+
"SYCL_DEVICE_ALLOWLIST. It should have hex format. For "
190+
"details, please refer to "
191+
"https://github.com/intel/llvm/blob/sycl/sycl/doc/"
192+
"EnvironmentVariables.md",
193+
PI_INVALID_VALUE);
194+
}
195+
}
196+
}
197+
198+
// add key and value to the map
199+
DeviceDescMap.emplace(Key, Value);
200+
} else {
201+
throw sycl::runtime_error("Re-definition of key " + Key +
202+
" is not allowed in "
203+
"SYCL_DEVICE_ALLOWLIST",
204+
PI_INVALID_VALUE);
205+
}
206+
207+
KeyStart = ValueEnd;
208+
if (KeyStart != std::string::npos)
209+
++KeyStart;
210+
if (ShouldAllocateNewDeviceDescMap) {
211+
++DeviceDescIndex;
212+
AllowListParsed.emplace_back();
213+
}
214+
}
215+
216+
return AllowListParsed;
217+
}
218+
219+
// Checking if we can allow device with device description DeviceDesc
220+
bool deviceIsAllowed(const DeviceDescT &DeviceDesc,
221+
const AllowListParsedT &AllowListParsed) {
222+
for (const auto &SupportedKeyName : SupportedAllowListKeyNames)
223+
assert((DeviceDesc.find(SupportedKeyName) != DeviceDesc.end()) &&
224+
"DeviceDesc map should have all supported keys for "
225+
"SYCL_DEVICE_ALLOWLIST.");
226+
auto EqualityComp = [&](const std::string &KeyName,
227+
const DeviceDescT &AllowListDeviceDesc) {
228+
// change to map::contains after switching DPC++ RT to C++20
229+
if (AllowListDeviceDesc.find(KeyName) != AllowListDeviceDesc.end())
230+
if (AllowListDeviceDesc.at(KeyName) != DeviceDesc.at(KeyName))
231+
return false;
232+
return true;
233+
};
234+
auto RegexComp = [&](const std::string &KeyName,
235+
const DeviceDescT &AllowListDeviceDesc) {
236+
if (AllowListDeviceDesc.find(KeyName) != AllowListDeviceDesc.end())
237+
if (!std::regex_match(DeviceDesc.at(KeyName),
238+
std::regex(AllowListDeviceDesc.at(KeyName))))
239+
return false;
240+
return true;
241+
};
242+
243+
bool ShouldDeviceBeAllowed = false;
244+
245+
for (const auto &AllowListDeviceDesc : AllowListParsed) {
246+
if (!EqualityComp(BackendNameKeyName, AllowListDeviceDesc))
247+
continue;
248+
if (!EqualityComp(DeviceTypeKeyName, AllowListDeviceDesc))
249+
continue;
250+
if (!EqualityComp(DeviceVendorIdKeyName, AllowListDeviceDesc))
251+
continue;
252+
if (!RegexComp(DriverVersionKeyName, AllowListDeviceDesc))
253+
continue;
254+
if (!RegexComp(PlatformVersionKeyName, AllowListDeviceDesc))
255+
continue;
256+
if (!RegexComp(DeviceNameKeyName, AllowListDeviceDesc))
257+
continue;
258+
if (!RegexComp(PlatformNameKeyName, AllowListDeviceDesc))
259+
continue;
260+
261+
// no any continue was called on this iteration, so all parameters matched
262+
// successfully, so allow this device to use
263+
ShouldDeviceBeAllowed = true;
264+
break;
265+
}
266+
267+
return ShouldDeviceBeAllowed;
268+
}
269+
270+
void applyAllowList(std::vector<RT::PiDevice> &PiDevices,
271+
RT::PiPlatform PiPlatform, const plugin &Plugin) {
272+
AllowListParsedT AllowListParsed =
273+
parseAllowList(SYCLConfig<SYCL_DEVICE_ALLOWLIST>::get());
274+
if (AllowListParsed.empty())
275+
return;
276+
277+
DeviceDescT DeviceDesc;
278+
279+
// get BackendName value and put it to DeviceDesc
280+
sycl::backend Backend = Plugin.getBackend();
281+
for (const auto &SyclBe : SyclBeMap) {
282+
if (SyclBe.second == Backend) {
283+
DeviceDesc.emplace(BackendNameKeyName, SyclBe.first);
284+
}
285+
}
286+
// get PlatformVersion value and put it to DeviceDesc
287+
DeviceDesc.emplace(
288+
PlatformVersionKeyName,
289+
sycl::detail::get_platform_info<std::string,
290+
info::platform::version>::get(PiPlatform,
291+
Plugin));
292+
// get PlatformName value and put it to DeviceDesc
293+
DeviceDesc.emplace(
294+
PlatformNameKeyName,
295+
sycl::detail::get_platform_info<std::string, info::platform::name>::get(
296+
PiPlatform, Plugin));
297+
298+
int InsertIDx = 0;
299+
for (RT::PiDevice Device : PiDevices) {
300+
bool IsInserted = false;
301+
// get DeviceType value and put it to DeviceDesc
302+
RT::PiDeviceType PiDevType;
303+
Plugin.call<PiApiKind::piDeviceGetInfo>(Device, PI_DEVICE_INFO_TYPE,
304+
sizeof(RT::PiDeviceType),
305+
&PiDevType, nullptr);
306+
sycl::info::device_type DeviceType = pi::cast<info::device_type>(PiDevType);
307+
for (const auto &SyclDeviceType : SyclDeviceTypeMap) {
308+
if (SyclDeviceType.second == DeviceType) {
309+
const auto &DeviceTypeValue = SyclDeviceType.first;
310+
std::tie(std::ignore, IsInserted) =
311+
DeviceDesc.emplace(DeviceTypeKeyName, DeviceTypeValue);
312+
if (!IsInserted)
313+
DeviceDesc.at(DeviceTypeKeyName) = DeviceTypeValue;
314+
break;
315+
}
316+
}
317+
// get DeviceVendorId value and put it to DeviceDesc
318+
uint32_t DeviceVendorIdUInt =
319+
sycl::detail::get_device_info<uint32_t, info::device::vendor_id>::get(
320+
Device, Plugin);
321+
std::stringstream DeviceVendorIdHexStringStream;
322+
DeviceVendorIdHexStringStream << "0x" << std::hex << DeviceVendorIdUInt;
323+
const auto &DeviceVendorIdValue = DeviceVendorIdHexStringStream.str();
324+
std::tie(std::ignore, IsInserted) = DeviceDesc.emplace(
325+
DeviceVendorIdKeyName, DeviceVendorIdHexStringStream.str());
326+
if (!IsInserted)
327+
DeviceDesc.at(DeviceVendorIdKeyName) = DeviceVendorIdValue;
328+
// get DriverVersion value and put it to DeviceDesc
329+
const auto &DriverVersionValue = sycl::detail::get_device_info<
330+
std::string, info::device::driver_version>::get(Device, Plugin);
331+
std::tie(std::ignore, IsInserted) =
332+
DeviceDesc.emplace(DriverVersionKeyName, DriverVersionValue);
333+
if (!IsInserted)
334+
DeviceDesc.at(DriverVersionKeyName) = DriverVersionValue;
335+
// get DeviceName value and put it to DeviceDesc
336+
const auto &DeviceNameValue =
337+
sycl::detail::get_device_info<std::string, info::device::name>::get(
338+
Device, Plugin);
339+
std::tie(std::ignore, IsInserted) =
340+
DeviceDesc.emplace(DeviceNameKeyName, DeviceNameValue);
341+
if (!IsInserted)
342+
DeviceDesc.at(DeviceNameKeyName) = DeviceNameValue;
343+
344+
// check if we can allow device with such device description DeviceDesc
345+
if (deviceIsAllowed(DeviceDesc, AllowListParsed)) {
346+
PiDevices[InsertIDx++] = Device;
347+
}
348+
}
349+
PiDevices.resize(InsertIDx);
350+
}
351+
352+
} // namespace detail
353+
} // namespace sycl
354+
} // __SYCL_INLINE_NAMESPACE(cl)

0 commit comments

Comments
 (0)