diff --git a/sycl/doc/EnvironmentVariables.md b/sycl/doc/EnvironmentVariables.md index e38748fb0b6ba..44b7d5b0ac57d 100644 --- a/sycl/doc/EnvironmentVariables.md +++ b/sycl/doc/EnvironmentVariables.md @@ -23,7 +23,7 @@ subject to change. Do not rely on these variables in production code. | `SYCL_DISABLE_EXECUTION_GRAPH_CLEANUP` | Any(\*) | Disable cleanup of finished command nodes at host-device synchronization points. | | `SYCL_THROW_ON_BLOCK` | Any(\*) | Throw an exception on attempt to wait for a blocked command. | | `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. | -| `SYCL_DEVICE_ALLOWLIST` | A list of devices and their driver version following the pattern: DeviceName:{{XXX}},DriverVersion:{{X.Y.Z.W}}. Also may contain PlatformName and PlatformVersion | Filter out devices that do not match the pattern specified. Regular expression can be passed and the DPC++ runtime will select only those devices which satisfy the regex. Special characters, such as parenthesis, must be escaped. More than one device can be specified using the piping symbol "\|".| +| `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 "\|".| | `SYCL_QUEUE_THREAD_POOL_SIZE` | Positive integer | Number of threads in thread pool of queue. | | `SYCL_DEVICELIB_NO_FALLBACK` | Any(\*) | Disable loading and linking of device library images | | `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. | diff --git a/sycl/source/CMakeLists.txt b/sycl/source/CMakeLists.txt index 61486162b16d0..22adb1037bbb0 100644 --- a/sycl/source/CMakeLists.txt +++ b/sycl/source/CMakeLists.txt @@ -102,6 +102,7 @@ set(SYCL_SOURCES "backend/level_zero.cpp" "backend.cpp" "detail/accessor_impl.cpp" + "detail/allowlist.cpp" "detail/buffer_impl.cpp" "detail/builtins_common.cpp" "detail/builtins_geometric.cpp" diff --git a/sycl/source/detail/allowlist.cpp b/sycl/source/detail/allowlist.cpp new file mode 100644 index 0000000000000..a684e905194ef --- /dev/null +++ b/sycl/source/detail/allowlist.cpp @@ -0,0 +1,362 @@ +//==-------------- allowlist.cpp - SYCL_DEVICE_ALLOWLIST -------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +#include + +__SYCL_INLINE_NAMESPACE(cl) { +namespace sycl { +namespace detail { + +constexpr char BackendNameKeyName[] = "BackendName"; +constexpr char DeviceTypeKeyName[] = "DeviceType"; +constexpr char DeviceVendorIdKeyName[] = "DeviceVendorId"; +constexpr char DriverVersionKeyName[] = "DriverVersion"; +constexpr char PlatformVersionKeyName[] = "PlatformVersion"; +constexpr char DeviceNameKeyName[] = "DeviceName"; +constexpr char PlatformNameKeyName[] = "PlatformName"; + +constexpr std::array SupportedAllowListKeyNames{ + BackendNameKeyName, DeviceTypeKeyName, DeviceVendorIdKeyName, + DriverVersionKeyName, PlatformVersionKeyName, DeviceNameKeyName, + PlatformNameKeyName}; + +// Parsing and validating SYCL_DEVICE_ALLOWLIST variable value. +// +// The value has the following form: +// DeviceDesc1|DeviceDesc2|<...>|DeviceDescN +// DeviceDescN is the set of descriptions for the device which should be +// allowed. The sets of device descriptions are separated by '|' symbol. The set +// of descriptions has the following structure: +// DeviceDescN = Key1:Value1,Key2:Value2,...,KeyN:ValueN +// Device descriptions are separated by ',' symbol. +// Key and value of a device description are separated by ":" symbol. +// KeyN is the key of a device description, it could be one of the following +// from SupportedAllowListKeyNames vector above. +// DeviceName and PlatformName device descriptions are deprecated and will be +// removed in one of the future releases. +// ValueN is the value of a device description, it could be regex and some fixed +// string. +// Function should return parsed SYCL_DEVICE_ALLOWLIST variable value as +// AllowListParsedT type (vector of maps), e.g.: +// {{Key1: Value1, Key2: Value2}, ..., {Key1: Value1, ..., KeyN: ValueN}} +AllowListParsedT parseAllowList(const std::string &AllowListRaw) { + if (AllowListRaw.empty()) + return {}; + + AllowListParsedT AllowListParsed; + AllowListParsed.emplace_back(); + + constexpr std::array SupportedKeyNamesHaveFixedValue{ + BackendNameKeyName, DeviceTypeKeyName, DeviceVendorIdKeyName}; + constexpr std::array SupportedKeyNamesRequireRegexValue{ + DriverVersionKeyName, PlatformVersionKeyName, DeviceNameKeyName, + PlatformNameKeyName}; + + size_t KeyStart = 0, KeyEnd = 0, ValueStart = 0, ValueEnd = 0, + DeviceDescIndex = 0; + + const char DelimeterBtwKeyAndValue = ':'; + const char DelimeterBtwItemsInDeviceDesc = ','; + const char DelimeterBtwDeviceDescs = '|'; + + while ((KeyEnd = AllowListRaw.find(DelimeterBtwKeyAndValue, KeyStart)) != + std::string::npos) { + if ((ValueStart = AllowListRaw.find_first_not_of( + DelimeterBtwKeyAndValue, KeyEnd)) == std::string::npos) + break; + const std::string &Key = AllowListRaw.substr(KeyStart, KeyEnd - KeyStart); + + // check that provided key is supported + if (std::find(SupportedAllowListKeyNames.begin(), + SupportedAllowListKeyNames.end(), + Key) == SupportedAllowListKeyNames.end()) { + throw sycl::runtime_error( + "Unrecognized key in SYCL_DEVICE_ALLOWLIST. For details, please " + "refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md", + PI_INVALID_VALUE); + } + + bool ShouldAllocateNewDeviceDescMap = false; + + std::string Value; + + auto &DeviceDescMap = AllowListParsed[DeviceDescIndex]; + + // check if Key is not already defined in DeviceDescMap, e.g., caused by the + // following invalid syntax: Key1:Value1,Key2:Value2,Key1:Value3 + if (DeviceDescMap.find(Key) == DeviceDescMap.end()) { + // calculate and validate value which has fixed format + if (std::find(SupportedKeyNamesHaveFixedValue.begin(), + SupportedKeyNamesHaveFixedValue.end(), + Key) != SupportedKeyNamesHaveFixedValue.end()) { + ValueEnd = AllowListRaw.find(DelimeterBtwItemsInDeviceDesc, ValueStart); + // check if it is the last Key:Value pair in the device description, and + // correct end position of that value + if (size_t ValueEndCand = + AllowListRaw.find(DelimeterBtwDeviceDescs, ValueStart); + (ValueEndCand != std::string::npos) && (ValueEndCand < ValueEnd)) { + ValueEnd = ValueEndCand; + ShouldAllocateNewDeviceDescMap = true; + } + if (ValueEnd == std::string::npos) + ValueEnd = AllowListRaw.length(); + + Value = AllowListRaw.substr(ValueStart, ValueEnd - ValueStart); + + // post-processing checks for some values + + auto ValidateEnumValues = [&](std::string CheckingKeyName, + auto SourceOfSupportedValues) { + if (Key == CheckingKeyName) { + bool ValueIsValid = false; + for (const auto &Item : SourceOfSupportedValues) + if (Value == Item.first) { + ValueIsValid = true; + break; + } + if (!ValueIsValid) + throw sycl::runtime_error( + "Value " + Value + " for key " + Key + + " is not valid in " + "SYCL_DEVICE_ALLOWLIST. For details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md", + PI_INVALID_VALUE); + } + }; + + // check that values of keys, which should have some fixed format, are + // valid. E.g., for BackendName key, the allowed values are only ones + // described in SyclBeMap + ValidateEnumValues(BackendNameKeyName, SyclBeMap); + ValidateEnumValues(DeviceTypeKeyName, SyclDeviceTypeMap); + + if (Key == DeviceVendorIdKeyName) { + // DeviceVendorId should have hex format + if (!std::regex_match(Value, std::regex("0[xX][0-9a-fA-F]+"))) { + throw sycl::runtime_error( + "Value " + Value + " for key " + Key + + " is not valid in " + "SYCL_DEVICE_ALLOWLIST. It should have the hex format. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md", + PI_INVALID_VALUE); + } + } + } + // calculate and validate value which has regex format + else if (std::find(SupportedKeyNamesRequireRegexValue.begin(), + SupportedKeyNamesRequireRegexValue.end(), + Key) != SupportedKeyNamesRequireRegexValue.end()) { + const std::string Prefix("{{"); + // TODO: can be changed to string_view::starts_with after switching + // DPC++ RT to C++20 + if (Prefix != AllowListRaw.substr(ValueStart, Prefix.length())) { + throw sycl::runtime_error("Key " + Key + + " of SYCL_DEVICE_ALLOWLIST should have " + "value which starts with " + + Prefix, + PI_INVALID_VALUE); + } + // cut off prefix from the value + ValueStart += Prefix.length(); + + ValueEnd = ValueStart; + const std::string Postfix("}}"); + for (; ValueEnd < AllowListRaw.length() - Postfix.length() + 1; + ++ValueEnd) { + if (Postfix == AllowListRaw.substr(ValueEnd, Postfix.length())) + break; + // if it is the last iteration and next 2 symbols are not a postfix, + // throw exception + if (ValueEnd == AllowListRaw.length() - Postfix.length()) + throw sycl::runtime_error( + "Key " + Key + + " of SYCL_DEVICE_ALLOWLIST should have " + "value which ends with " + + Postfix, + PI_INVALID_VALUE); + } + size_t NextExpectedDelimeterPos = ValueEnd + Postfix.length(); + // if it is not the end of the string, check that symbol next to a + // postfix is a delimeter (, or ;) + if ((AllowListRaw.length() != NextExpectedDelimeterPos) && + (AllowListRaw[NextExpectedDelimeterPos] != + DelimeterBtwItemsInDeviceDesc) && + (AllowListRaw[NextExpectedDelimeterPos] != DelimeterBtwDeviceDescs)) + throw sycl::runtime_error( + "Unexpected symbol on position " + + std::to_string(NextExpectedDelimeterPos) + ": " + + AllowListRaw[NextExpectedDelimeterPos] + + ". Should be either " + DelimeterBtwItemsInDeviceDesc + + " or " + DelimeterBtwDeviceDescs, + PI_INVALID_VALUE); + + if (AllowListRaw[NextExpectedDelimeterPos] == DelimeterBtwDeviceDescs) + ShouldAllocateNewDeviceDescMap = true; + + Value = AllowListRaw.substr(ValueStart, ValueEnd - ValueStart); + + ValueEnd += Postfix.length(); + } else + assert(false && + "Key should be either in SupportedKeyNamesHaveFixedValue " + "or SupportedKeyNamesRequireRegexValue"); + + // add key and value to the map + DeviceDescMap.emplace(Key, Value); + } else + throw sycl::runtime_error("Re-definition of key " + Key + + " is not allowed in " + "SYCL_DEVICE_ALLOWLIST", + PI_INVALID_VALUE); + + KeyStart = ValueEnd; + if (KeyStart != std::string::npos) + ++KeyStart; + if (ShouldAllocateNewDeviceDescMap) { + ++DeviceDescIndex; + AllowListParsed.emplace_back(); + } + } + + return AllowListParsed; +} + +// Checking if we can allow device with device description DeviceDesc +bool deviceIsAllowed(const DeviceDescT &DeviceDesc, + const AllowListParsedT &AllowListParsed) { + for (const auto &SupportedKeyName : SupportedAllowListKeyNames) + assert((DeviceDesc.find(SupportedKeyName) != DeviceDesc.end()) && + "DeviceDesc map should have all supported keys for " + "SYCL_DEVICE_ALLOWLIST."); + auto EqualityComp = [&](const std::string &KeyName, + const DeviceDescT &AllowListDeviceDesc) { + // change to map::contains after switching DPC++ RT to C++20 + if (AllowListDeviceDesc.find(KeyName) != AllowListDeviceDesc.end()) + if (AllowListDeviceDesc.at(KeyName) != DeviceDesc.at(KeyName)) + return false; + return true; + }; + auto RegexComp = [&](const std::string &KeyName, + const DeviceDescT &AllowListDeviceDesc) { + if (AllowListDeviceDesc.find(KeyName) != AllowListDeviceDesc.end()) + if (!std::regex_match(DeviceDesc.at(KeyName), + std::regex(AllowListDeviceDesc.at(KeyName)))) + return false; + return true; + }; + + bool ShouldDeviceBeAllowed = false; + + for (const auto &AllowListDeviceDesc : AllowListParsed) { + if (!EqualityComp(BackendNameKeyName, AllowListDeviceDesc)) + continue; + if (!EqualityComp(DeviceTypeKeyName, AllowListDeviceDesc)) + continue; + if (!EqualityComp(DeviceVendorIdKeyName, AllowListDeviceDesc)) + continue; + if (!RegexComp(DriverVersionKeyName, AllowListDeviceDesc)) + continue; + if (!RegexComp(PlatformVersionKeyName, AllowListDeviceDesc)) + continue; + if (!RegexComp(DeviceNameKeyName, AllowListDeviceDesc)) + continue; + if (!RegexComp(PlatformNameKeyName, AllowListDeviceDesc)) + continue; + + // no any continue was called on this iteration, so all parameters matched + // successfully, so allow this device to use + ShouldDeviceBeAllowed = true; + break; + } + + return ShouldDeviceBeAllowed; +} + +void applyAllowList(std::vector &PiDevices, + RT::PiPlatform PiPlatform, const plugin &Plugin) { + AllowListParsedT AllowListParsed = + parseAllowList(SYCLConfig::get()); + if (AllowListParsed.empty()) + return; + + DeviceDescT DeviceDesc; + + // get BackendName value and put it to DeviceDesc + sycl::backend Backend = Plugin.getBackend(); + for (const auto &SyclBe : SyclBeMap) { + if (SyclBe.second == Backend) { + DeviceDesc.emplace(BackendNameKeyName, SyclBe.first); + break; + } + } + // get PlatformVersion value and put it to DeviceDesc + DeviceDesc.emplace( + PlatformVersionKeyName, + sycl::detail::get_platform_info::get(PiPlatform, + Plugin)); + // get PlatformName value and put it to DeviceDesc + DeviceDesc.emplace( + PlatformNameKeyName, + sycl::detail::get_platform_info::get( + PiPlatform, Plugin)); + + int InsertIDx = 0; + for (RT::PiDevice Device : PiDevices) { + // get DeviceType value and put it to DeviceDesc + RT::PiDeviceType PiDevType; + Plugin.call(Device, PI_DEVICE_INFO_TYPE, + sizeof(RT::PiDeviceType), + &PiDevType, nullptr); + sycl::info::device_type DeviceType = pi::cast(PiDevType); + for (const auto &SyclDeviceType : SyclDeviceTypeMap) { + if (SyclDeviceType.second == DeviceType) { + const auto &DeviceTypeValue = SyclDeviceType.first; + DeviceDesc[DeviceTypeKeyName] = DeviceTypeValue; + break; + } + } + // get DeviceVendorId value and put it to DeviceDesc + uint32_t DeviceVendorIdUInt = + sycl::detail::get_device_info::get( + Device, Plugin); + std::stringstream DeviceVendorIdHexStringStream; + DeviceVendorIdHexStringStream << "0x" << std::hex << DeviceVendorIdUInt; + const auto &DeviceVendorIdValue = DeviceVendorIdHexStringStream.str(); + DeviceDesc[DeviceVendorIdKeyName] = DeviceVendorIdValue; + // get DriverVersion value and put it to DeviceDesc + const auto &DriverVersionValue = sycl::detail::get_device_info< + std::string, info::device::driver_version>::get(Device, Plugin); + DeviceDesc[DriverVersionKeyName] = DriverVersionValue; + // get DeviceName value and put it to DeviceDesc + const auto &DeviceNameValue = + sycl::detail::get_device_info::get( + Device, Plugin); + DeviceDesc[DeviceNameKeyName] = DeviceNameValue; + + // check if we can allow device with such device description DeviceDesc + if (deviceIsAllowed(DeviceDesc, AllowListParsed)) { + PiDevices[InsertIDx++] = Device; + } + } + PiDevices.resize(InsertIDx); +} + +} // namespace detail +} // namespace sycl +} // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/source/detail/allowlist.hpp b/sycl/source/detail/allowlist.hpp new file mode 100644 index 0000000000000..b12f2eab5a3ac --- /dev/null +++ b/sycl/source/detail/allowlist.hpp @@ -0,0 +1,35 @@ +//==-------------- allowlist.hpp - SYCL_DEVICE_ALLOWLIST -------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include +#include +#include + +#include +#include + +__SYCL_INLINE_NAMESPACE(cl) { +namespace sycl { +namespace detail { + +using DeviceDescT = std::map; +using AllowListParsedT = std::vector; + +AllowListParsedT parseAllowList(const std::string &AllowListRaw); + +bool deviceIsAllowed(const DeviceDescT &DeviceDesc, + const AllowListParsedT &AllowListParsed); + +void applyAllowList(std::vector &PiDevices, + RT::PiPlatform PiPlatform, const plugin &Plugin); + +} // namespace detail +} // namespace sycl +} // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/source/detail/config.hpp b/sycl/source/detail/config.hpp index 8f54271e260f6..f32f1ea5b41b9 100644 --- a/sycl/source/detail/config.hpp +++ b/sycl/source/detail/config.hpp @@ -1,4 +1,4 @@ -//==---------------- config.hpp - SYCL context ------------------*- C++-*---==// +//==---------------- config.hpp - SYCL config -------------------*- C++-*---==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -166,6 +166,22 @@ template <> class SYCLConfig { } }; +// Array is used by SYCL_DEVICE_FILTER and SYCL_DEVICE_ALLOWLIST +static const std::array, 5> + SyclDeviceTypeMap = {{{"host", info::device_type::host}, + {"cpu", info::device_type::cpu}, + {"gpu", info::device_type::gpu}, + {"acc", info::device_type::accelerator}, + {"*", info::device_type::all}}}; + +// Array is used by SYCL_DEVICE_FILTER and SYCL_DEVICE_ALLOWLIST +static const std::array, 5> SyclBeMap = { + {{"host", backend::host}, + {"opencl", backend::opencl}, + {"level_zero", backend::level_zero}, + {"cuda", backend::cuda}, + {"*", backend::all}}}; + template <> class SYCLConfig { using BaseT = SYCLConfigBase; diff --git a/sycl/source/detail/device_filter.cpp b/sycl/source/detail/device_filter.cpp index 9b672d2371c44..8558d0d9e4f94 100644 --- a/sycl/source/detail/device_filter.cpp +++ b/sycl/source/detail/device_filter.cpp @@ -18,19 +18,6 @@ namespace sycl { namespace detail { device_filter::device_filter(const std::string &FilterString) { - const std::array, 5> - SyclDeviceTypeMap = {{{"host", info::device_type::host}, - {"cpu", info::device_type::cpu}, - {"gpu", info::device_type::gpu}, - {"acc", info::device_type::accelerator}, - {"*", info::device_type::all}}}; - const std::array, 5> SyclBeMap = { - {{"host", backend::host}, - {"opencl", backend::opencl}, - {"level_zero", backend::level_zero}, - {"cuda", backend::cuda}, - {"*", backend::all}}}; - size_t Cursor = 0; size_t ColonPos = 0; auto findElement = [&](auto Element) { diff --git a/sycl/source/detail/platform_impl.cpp b/sycl/source/detail/platform_impl.cpp index 1995990a06e89..b4b27df526953 100644 --- a/sycl/source/detail/platform_impl.cpp +++ b/sycl/source/detail/platform_impl.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include +#include #include #include #include @@ -16,7 +17,6 @@ #include #include -#include #include #include @@ -133,164 +133,6 @@ vector_class platform_impl::get_platforms() { return Platforms; } -std::string getValue(const std::string &AllowList, size_t &Pos, - unsigned long int Size) { - size_t Prev = Pos; - if ((Pos = AllowList.find("{{", Pos)) == std::string::npos) { - throw sycl::runtime_error("Malformed syntax in SYCL_DEVICE_ALLOWLIST", - PI_INVALID_VALUE); - } - if (Pos > Prev + Size) { - throw sycl::runtime_error("Malformed syntax in SYCL_DEVICE_ALLOWLIST", - PI_INVALID_VALUE); - } - - Pos = Pos + 2; - size_t Start = Pos; - if ((Pos = AllowList.find("}}", Pos)) == std::string::npos) { - throw sycl::runtime_error("Malformed syntax in SYCL_DEVICE_ALLOWLIST", - PI_INVALID_VALUE); - } - std::string Value = AllowList.substr(Start, Pos - Start); - Pos = Pos + 2; - return Value; -} - -struct DevDescT { - std::string DevName; - std::string DevDriverVer; - std::string PlatName; - std::string PlatVer; -}; - -static std::vector getAllowListDesc() { - std::string AllowList(SYCLConfig::get()); - if (AllowList.empty()) - return {}; - - std::string DeviceName("DeviceName:"); - std::string DriverVersion("DriverVersion:"); - std::string PlatformName("PlatformName:"); - std::string PlatformVersion("PlatformVersion:"); - std::vector DecDescs; - DecDescs.emplace_back(); - - size_t Pos = 0; - while (Pos < AllowList.size()) { - if ((AllowList.compare(Pos, DeviceName.size(), DeviceName)) == 0) { - DecDescs.back().DevName = getValue(AllowList, Pos, DeviceName.size()); - if (AllowList[Pos] == ',') { - Pos++; - } - } - - else if ((AllowList.compare(Pos, DriverVersion.size(), DriverVersion)) == - 0) { - DecDescs.back().DevDriverVer = - getValue(AllowList, Pos, DriverVersion.size()); - if (AllowList[Pos] == ',') { - Pos++; - } - } - - else if ((AllowList.compare(Pos, PlatformName.size(), PlatformName)) == 0) { - DecDescs.back().PlatName = getValue(AllowList, Pos, PlatformName.size()); - if (AllowList[Pos] == ',') { - Pos++; - } - } - - else if ((AllowList.compare(Pos, PlatformVersion.size(), - PlatformVersion)) == 0) { - DecDescs.back().PlatVer = - getValue(AllowList, Pos, PlatformVersion.size()); - } else if (AllowList.find('|', Pos) != std::string::npos) { - Pos = AllowList.find('|') + 1; - while (AllowList[Pos] == ' ') { - Pos++; - } - DecDescs.emplace_back(); - } - - else { - throw sycl::runtime_error("Unrecognized key in device allowlist", - PI_INVALID_VALUE); - } - } // while (Pos <= AllowList.size()) - return DecDescs; -} - -enum class FilterState { DENIED, ALLOWED }; - -static void filterAllowList(vector_class &PiDevices, - RT::PiPlatform PiPlatform, const plugin &Plugin) { - const std::vector AllowList(getAllowListDesc()); - if (AllowList.empty()) - return; - - FilterState DevNameState = FilterState::ALLOWED; - FilterState DevVerState = FilterState::ALLOWED; - FilterState PlatNameState = FilterState::ALLOWED; - FilterState PlatVerState = FilterState::ALLOWED; - - const string_class PlatformName = - sycl::detail::get_platform_info::get( - PiPlatform, Plugin); - - const string_class PlatformVer = - sycl::detail::get_platform_info::get(PiPlatform, - Plugin); - - int InsertIDx = 0; - for (RT::PiDevice Device : PiDevices) { - const string_class DeviceName = - sycl::detail::get_device_info::get( - Device, Plugin); - - const string_class DeviceDriverVer = sycl::detail::get_device_info< - string_class, info::device::driver_version>::get(Device, Plugin); - - for (const DevDescT &Desc : AllowList) { - if (!Desc.PlatName.empty()) { - if (!std::regex_match(PlatformName, std::regex(Desc.PlatName))) { - PlatNameState = FilterState::DENIED; - continue; - } - } - - if (!Desc.PlatVer.empty()) { - if (!std::regex_match(PlatformVer, std::regex(Desc.PlatVer))) { - PlatVerState = FilterState::DENIED; - continue; - } - } - - if (!Desc.DevName.empty()) { - if (!std::regex_match(DeviceName, std::regex(Desc.DevName))) { - DevNameState = FilterState::DENIED; - continue; - } - } - - if (!Desc.DevDriverVer.empty()) { - if (!std::regex_match(DeviceDriverVer, std::regex(Desc.DevDriverVer))) { - DevVerState = FilterState::DENIED; - continue; - } - } - - if (DevNameState == FilterState::ALLOWED && - DevVerState == FilterState::ALLOWED && - PlatNameState == FilterState::ALLOWED && - PlatVerState == FilterState::ALLOWED) - PiDevices[InsertIDx++] = Device; - break; - } - } - PiDevices.resize(InsertIDx); -} - // Filter out the devices that are not compatible with SYCL_DEVICE_FILTER. // All three entries (backend:device_type:device_num) are optional. // The missing entries are constructed using '*', which means 'any' | 'all' @@ -392,9 +234,9 @@ platform_impl::get_devices(info::device_type DeviceType) const { pi::cast(DeviceType), NumDevices, PiDevices.data(), nullptr); - // Filter out devices that are not present in the allowlist + // Filter out devices that are not present in the SYCL_DEVICE_ALLOWLIST if (SYCLConfig::get()) - filterAllowList(PiDevices, MPlatform, this->getPlugin()); + applyAllowList(PiDevices, MPlatform, this->getPlugin()); // Filter out devices that are not compatible with SYCL_DEVICE_FILTER filterDeviceFilter(PiDevices, Plugin); diff --git a/sycl/unittests/CMakeLists.txt b/sycl/unittests/CMakeLists.txt index 5da1955d9e5ff..03e604b194b93 100644 --- a/sycl/unittests/CMakeLists.txt +++ b/sycl/unittests/CMakeLists.txt @@ -9,6 +9,7 @@ endforeach() include(AddSYCLUnitTest) +add_subdirectory(allowlist) add_subdirectory(get_native_interop) add_subdirectory(misc) add_subdirectory(pi) diff --git a/sycl/unittests/allowlist/CMakeLists.txt b/sycl/unittests/allowlist/CMakeLists.txt new file mode 100644 index 0000000000000..c78efbf3068f1 --- /dev/null +++ b/sycl/unittests/allowlist/CMakeLists.txt @@ -0,0 +1,8 @@ +set(CMAKE_CXX_EXTENSIONS OFF) + +# Enable exception handling for these unit tests +set(LLVM_REQUIRES_EH 1) +add_sycl_unittest(AllowListTests OBJECT + ParseAllowList.cpp + DeviceIsAllowed.cpp +) diff --git a/sycl/unittests/allowlist/DeviceIsAllowed.cpp b/sycl/unittests/allowlist/DeviceIsAllowed.cpp new file mode 100644 index 0000000000000..a523d67dcba14 --- /dev/null +++ b/sycl/unittests/allowlist/DeviceIsAllowed.cpp @@ -0,0 +1,225 @@ +//==------- DeviceIsAllowed.cpp --- SYCL_DEVICE_ALLOWLIST unit test --------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include + +#include + +constexpr char SyclDeviceAllowList[] = + "BackendName:opencl,DeviceType:gpu,DeviceVendorId:0x8086,DriverVersion:{{(" + "19\\.(4[3-9]|[5-9]\\d)\\..*)|([2-9][0-9]\\.\\d+\\..*)|(\\d+\\.\\d+\\." + "100\\.(737[2-9]|73[8-9]\\d|7[4-9]\\d+|[8-9]\\d+)|\\.\\d+\\.\\d+\\.10[1-9]" + "\\.\\d+)}}|BackendName:opencl,DeviceType:cpu,DeviceVendorId:0x8086," + "DriverVersion:{{(2019\\.[^\\.]+\\.[1-9][1-9]\\..*)|(20[2-9][0-9]\\..*)}}|" + "BackendName:opencl,DeviceType:acc,DeviceVendorId:0x1172,DriverVersion:{{(" + "2019\\.[^\\.]+\\.[1-9][0-9]\\..*)|(20[2-9][0-9]\\..*)}}|BackendName:" + "opencl,DeviceType:acc,DeviceVendorId:0x1172,PlatformVersion:{{.*Version " + "(19\\.[3-9][0-9]*|2[0-9]\\.[0-9]+).*}}|BackendName:level_zero,DeviceType:" + "gpu,DeviceVendorId:0x8086,DriverVersion:{{.*}}"; +constexpr char SyclDeviceAllowListOldStyle[] = + "DeviceName:{{.*Intel.*Graphics.*}},DriverVersion:{{(19\\.(4[3-9]|[5-9]\\d)" + "\\..*)|([2-9][0-9]\\.\\d+\\..*)|(\\d+\\.\\d+\\.100\\.(737[2-9]|73[8-9]\\d|" + "7[4-9]\\d+|[8-9]\\d+)|\\.\\d+\\.\\d+\\.10[1-9]\\.\\d+)}}|DeviceName:{{.*" + "Intel.*(CPU|Processor).*}},DriverVersion:{{(2019\\.[^\\.]+\\.[1-9][1-9]\\." + ".*)|(20[2-9][0-9]\\..*)}}|DeviceName:{{.*Intel.*FPGA " + "Emulation.*}},DriverVersion:{{(2019\\.[^\\.]+\\.[1-9][0-9]\\..*)|(20[2-9][" + "0-9]\\..*)}}|PlatformName:{{.*Intel.*FPGA.*}},PlatformVersion:{{.*Version " + "(19\\.[3-9][0-9]*|2[0-9]\\.[0-9]+).*}}|PlatformName:{{.*Intel.*Level-Zero." + "*}},DeviceName:{{.*Intel.*Gen.*}},DriverVersion:{{.*}}"; + +sycl::detail::DeviceDescT OpenCLGPUDeviceDesc{ + {"BackendName", "opencl"}, + {"DeviceType", "gpu"}, + {"DeviceVendorId", "0x8086"}, + {"DriverVersion", "21.19.19792"}, + {"PlatformVersion", "OpenCL 3.0"}, + {"DeviceName", "Intel(R) HD Graphics 630 [0x5912]"}, + {"PlatformName", "Intel(R) OpenCL HD Graphics"}}; + +sycl::detail::DeviceDescT OpenCLCPUDeviceDesc{ + {"BackendName", "opencl"}, + {"DeviceType", "cpu"}, + {"DeviceVendorId", "0x8086"}, + {"DriverVersion", "2021.12.5.0.09"}, + {"PlatformVersion", "OpenCL 2.1 LINUX"}, + {"DeviceName", "Intel(R) Core(TM) i7-8700K Processor @ 4.60GHz"}, + {"PlatformName", "Intel(R) OpenCL"}}; + +sycl::detail::DeviceDescT OpenCLFPGAEmuDeviceDesc{ + {"BackendName", "opencl"}, + {"DeviceType", "acc"}, + {"DeviceVendorId", "0x1172"}, + {"DriverVersion", "2021.12.5.0.09"}, + {"PlatformVersion", + "OpenCL 1.2 Intel(R) FPGA SDK for OpenCL(TM), Version 20.3"}, + {"DeviceName", "Intel(R) FPGA Emulation Device"}, + {"PlatformName", "Intel(R) FPGA Emulation Platform for OpenCL(TM)"}}; + +sycl::detail::DeviceDescT OpenCLFPGABoardDeviceDesc{ + {"BackendName", "opencl"}, + {"DeviceType", "acc"}, + {"DeviceVendorId", "0x1172"}, + {"DriverVersion", "20.3.0.0.00"}, + {"PlatformVersion", + "OpenCL 1.0 Intel(R) FPGA SDK for OpenCL(TM), Version 20.3"}, + {"DeviceName", "Intel(R) Arria(R) 10 GX FPGA"}, + {"PlatformName", "Intel(R) FPGA SDK for OpenCL(TM)"}}; + +sycl::detail::DeviceDescT LevelZeroGPUDeviceDesc{ + {"BackendName", "level_zero"}, + {"DeviceType", "gpu"}, + {"DeviceVendorId", "0x8086"}, + {"DriverVersion", "1.1.19792"}, + {"PlatformVersion", "1.1"}, + {"DeviceName", "Intel(R) Gen9 HD Graphics 630"}, + {"PlatformName", "Intel(R) Level-Zero"}}; + +TEST(DeviceIsAllowedTests, CheckSupportedOpenCLGPUDeviceIsAllowed) { + bool Actual = sycl::detail::deviceIsAllowed( + OpenCLGPUDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, CheckSupportedOpenCLCPUDeviceIsAllowed) { + bool Actual = sycl::detail::deviceIsAllowed( + OpenCLCPUDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, CheckSupportedOpenCLFPGAEmuDeviceIsAllowed) { + bool Actual = sycl::detail::deviceIsAllowed( + OpenCLFPGAEmuDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, CheckSupportedOpenCLFPGABoardDeviceIsAllowed) { + bool Actual = sycl::detail::deviceIsAllowed( + OpenCLFPGABoardDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, CheckSupportedLevelZeroGPUDeviceIsAllowed) { + bool Actual = sycl::detail::deviceIsAllowed( + LevelZeroGPUDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, + CheckOpenCLGPUDeviceWithNotSupportedBackendNameIsNotAllowed) { + auto DeviceDesc = OpenCLGPUDeviceDesc; + DeviceDesc.at("BackendName") = "cuda"; + bool Actual = sycl::detail::deviceIsAllowed( + DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, false); +} + +TEST(DeviceIsAllowedTests, + CheckOpenCLGPUDeviceWithNotSupportedDeviceTypeIsNotAllowed) { + auto DeviceDesc = OpenCLGPUDeviceDesc; + DeviceDesc.at("DeviceType") = "cpu"; + bool Actual = sycl::detail::deviceIsAllowed( + DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, false); +} + +TEST(DeviceIsAllowedTests, + CheckOpenCLGPUDeviceWithNotSupportedDeviceVendorIdIsNotAllowed) { + auto DeviceDesc = OpenCLGPUDeviceDesc; + DeviceDesc.at("DeviceVendorId") = "0x0000"; + bool Actual = sycl::detail::deviceIsAllowed( + DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, false); +} + +TEST(DeviceIsAllowedTests, + CheckOpenCLGPUDeviceWithNotSupportedDriverVersionIsNotAllowed) { + auto DeviceDesc = OpenCLGPUDeviceDesc; + DeviceDesc.at("DriverVersion") = "0.0.0.0"; + bool Actual = sycl::detail::deviceIsAllowed( + DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, false); +} + +TEST(DeviceIsAllowedTests, + CheckOpenCLFPGABoardDeviceWithNotSupportedPlatformVersionIsNotAllowed) { + auto DeviceDesc = OpenCLFPGABoardDeviceDesc; + DeviceDesc.at("PlatformVersion") = "42"; + bool Actual = sycl::detail::deviceIsAllowed( + DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); + EXPECT_EQ(Actual, false); +} + +TEST(DeviceIsAllowedTests, + CheckAssertHappensIfIncompleteDeviceDescIsPassedToTheFunc) { + sycl::detail::DeviceDescT IncompleteDeviceDesc{{"BackendName", "level_zero"}}; + EXPECT_DEATH(sycl::detail::deviceIsAllowed( + IncompleteDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowList)), + ".*DeviceDesc map should have all supported keys for.*" + "SYCL_DEVICE_ALLOWLIST..*"); +} + +TEST(DeviceIsAllowedTests, CheckSupportedOpenCLGPUDeviceIsAllowedInOldStyle) { + bool Actual = sycl::detail::deviceIsAllowed( + OpenCLGPUDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, CheckSupportedOpenCLCPUDeviceIsAllowedInOldStyle) { + bool Actual = sycl::detail::deviceIsAllowed( + OpenCLCPUDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, + CheckSupportedOpenCLFPGAEmuDeviceIsAllowedInOldStyle) { + bool Actual = sycl::detail::deviceIsAllowed( + OpenCLFPGAEmuDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, + CheckSupportedOpenCLFPGABoardDeviceIsAllowedInOldStyle) { + bool Actual = sycl::detail::deviceIsAllowed( + OpenCLFPGABoardDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, + CheckSupportedLevelZeroGPUDeviceIsAllowedInOldStyle) { + bool Actual = sycl::detail::deviceIsAllowed( + LevelZeroGPUDeviceDesc, + sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); + EXPECT_EQ(Actual, true); +} + +TEST(DeviceIsAllowedTests, + CheckLevelZeroGPUDeviceWithNotSupportedDeviceNameIsNotAllowedInOldStyle) { + auto DeviceDesc = OpenCLGPUDeviceDesc; + DeviceDesc.at("DeviceName") = "ABCD"; + bool Actual = sycl::detail::deviceIsAllowed( + DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); + EXPECT_EQ(Actual, false); +} + +TEST( + DeviceIsAllowedTests, + CheckOpenCLFPGABoardDeviceWithNotSupportedPlatformNameIsNotAllowedInOldStyle) { + auto DeviceDesc = OpenCLFPGABoardDeviceDesc; + DeviceDesc.at("PlatformName") = "AABBCCDD"; + bool Actual = sycl::detail::deviceIsAllowed( + DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); + EXPECT_EQ(Actual, false); +} diff --git a/sycl/unittests/allowlist/ParseAllowList.cpp b/sycl/unittests/allowlist/ParseAllowList.cpp new file mode 100644 index 0000000000000..5ed854932b730 --- /dev/null +++ b/sycl/unittests/allowlist/ParseAllowList.cpp @@ -0,0 +1,254 @@ +//==------- ParseAllowList.cpp --- SYCL_DEVICE_ALLOWLIST unit test ---------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include +#include // for SyclBeMap and SyclDeviceTypeMap + +#include + +TEST(ParseAllowListTests, CheckAllowListIsEmpty) { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList(""); + sycl::detail::AllowListParsedT ExpectedValue{}; + EXPECT_EQ(ExpectedValue, ActualValue); +} + +TEST(ParseAllowListTests, CheckAllowListSingleDeviceDesc) { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "BackendName:level_zero,DeviceType:gpu,DeviceVendorId:0x0000"); + sycl::detail::AllowListParsedT ExpectedValue{{{"BackendName", "level_zero"}, + {"DeviceType", "gpu"}, + {"DeviceVendorId", "0x0000"}}}; + EXPECT_EQ(ExpectedValue, ActualValue); +} + +TEST(ParseAllowListTests, CheckAllowListMultipleDeviceDesc) { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "BackendName:level_zero,DeviceType:gpu,DeviceVendorId:0x0000|BackendName:" + "opencl,DeviceType:cpu,DeviceVendorId:0x1234|BackendName:opencl," + "DeviceType:acc,DeviceVendorId:0x4321"); + sycl::detail::AllowListParsedT ExpectedValue{{{"BackendName", "level_zero"}, + {"DeviceType", "gpu"}, + {"DeviceVendorId", "0x0000"}}, + {{"BackendName", "opencl"}, + {"DeviceType", "cpu"}, + {"DeviceVendorId", "0x1234"}}, + {{"BackendName", "opencl"}, + {"DeviceType", "acc"}, + {"DeviceVendorId", "0x4321"}}}; + EXPECT_EQ(ExpectedValue, ActualValue); +} + +TEST(ParseAllowListTests, CheckUnsupportedKeyNameIsHandledInSingleDeviceDesc) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "BackendName:level_zero,SomeUnsupportedKey:gpu"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(std::string("Unrecognized key in SYCL_DEVICE_ALLOWLIST. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST( + ParseAllowListTests, + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescsFirstContainingRegexValue) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "DriverVersion:{{value}}|SomeUnsupportedKey:gpu"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(std::string("Unrecognized key in SYCL_DEVICE_ALLOWLIST. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST( + ParseAllowListTests, + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescsFirstContainingFixedValue) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "BackendName:level_zero|SomeUnsupportedKey:gpu"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(std::string("Unrecognized key in SYCL_DEVICE_ALLOWLIST. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescsBothContainingRegexValue) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "DriverVersion:{{value1}}|SomeUnsupportedKey:{{value2}}"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(std::string("Unrecognized key in SYCL_DEVICE_ALLOWLIST. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckRegexIsProcessedCorrectly) { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "DeviceName:{{regex1}},DriverVersion:{{regex1|regex2}}|PlatformName:{{" + "regex3}},PlatformVersion:{{regex4|regex5|regex6}}"); + sycl::detail::AllowListParsedT ExpectedValue{ + {{"DeviceName", "regex1"}, {"DriverVersion", "regex1|regex2"}}, + {{"PlatformName", "regex3"}, + {"PlatformVersion", "regex4|regex5|regex6"}}}; + EXPECT_EQ(ExpectedValue, ActualValue); +} + +TEST(ParseAllowListTests, CheckMissingOpenDoubleCurlyBracesAreHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "DeviceName:regex1}},DriverVersion:{{regex1|regex2}}"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ( + std::string( + "Key DeviceName of SYCL_DEVICE_ALLOWLIST " + "should have value which starts with {{ -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckMissingClosedDoubleCurlyBracesAreHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "DeviceName:{{regex1}},DriverVersion:{{regex1|regex2"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ( + std::string( + "Key DriverVersion of SYCL_DEVICE_ALLOWLIST " + "should have value which ends with }} -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckAllValidBackendNameValuesAreProcessed) { + std::string AllowList; + for (const auto &SyclBe : sycl::detail::SyclBeMap) { + if (!AllowList.empty()) + AllowList += "|"; + AllowList += "BackendName:" + SyclBe.first; + } + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList(AllowList); + sycl::detail::AllowListParsedT ExpectedValue{{{"BackendName", "host"}}, + {{"BackendName", "opencl"}}, + {{"BackendName", "level_zero"}}, + {{"BackendName", "cuda"}}, + {{"BackendName", "*"}}}; + EXPECT_EQ(ExpectedValue, ActualValue); +} + +TEST(ParseAllowListTests, CheckAllValidDeviceTypeValuesAreProcessed) { + std::string AllowList; + for (const auto &SyclDeviceType : sycl::detail::SyclDeviceTypeMap) { + if (!AllowList.empty()) + AllowList += "|"; + AllowList += "DeviceType:" + SyclDeviceType.first; + } + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList(AllowList); + sycl::detail::AllowListParsedT ExpectedValue{{{"DeviceType", "host"}}, + {{"DeviceType", "cpu"}}, + {{"DeviceType", "gpu"}}, + {{"DeviceType", "acc"}}, + {{"DeviceType", "*"}}}; + EXPECT_EQ(ExpectedValue, ActualValue); +} + +TEST(ParseAllowListTests, CheckIncorrectBackendNameValueIsHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("BackendName:blablabla"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(std::string("Value blablabla for key BackendName is not valid in " + "SYCL_DEVICE_ALLOWLIST. For details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckIncorrectDeviceTypeValueIsHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("DeviceType:blablabla"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(std::string("Value blablabla for key DeviceType is not valid in " + "SYCL_DEVICE_ALLOWLIST. For details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckIncorrectDeviceVendorIdValueIsHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("DeviceVendorId:blablabla"); + throw std::logic_error("sycl::runtime_error didn't throw"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ( + std::string("Value blablabla for key DeviceVendorId is not valid in " + "SYCL_DEVICE_ALLOWLIST. It should have the hex format. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckTwoColonsBetweenKeyAndValue) { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("DeviceVendorId::0x1234"); + sycl::detail::AllowListParsedT ExpectedValue{{{"DeviceVendorId", "0x1234"}}}; + EXPECT_EQ(ExpectedValue, ActualValue); +} + +TEST(ParseAllowListTests, CheckMultipleColonsBetweenKeyAndValue) { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("DeviceVendorId:::::0x1234"); + sycl::detail::AllowListParsedT ExpectedValue{{{"DeviceVendorId", "0x1234"}}}; + EXPECT_EQ(ExpectedValue, ActualValue); +}