From 3a584328452bbd2e50fc01f1b4e0753143213a0c Mon Sep 17 00:00:00 2001 From: Dmitry Vodopyanov Date: Wed, 26 May 2021 21:22:19 +0300 Subject: [PATCH 1/7] [SYCL] Improve SYCL_DEVICE_ALLOWLIST This patch adds more stability to SYCL_DEVICE_ALLOWLIST: 1. Introduce 3 new keys `BackendName`, `DeviceType` and `DeviceVendorId` which should be used instead of `DeviceName` and `PlatformName`. These 3 new keys are more stable. 2. Refactor the implementation of SYCL_DEVICE_ALLOWLIST to make it more stable, to fix std::bad_alloc crash, and to make the code testable 3. Add unit tests for parsing SYCL_DEVICE_ALLOWLIST value and for functionality which allows device to use or reject it. --- sycl/doc/EnvironmentVariables.md | 2 +- sycl/source/detail/config.hpp | 18 +- sycl/source/detail/device_filter.cpp | 13 - sycl/source/detail/platform_impl.cpp | 465 +++++++++++++------ sycl/source/detail/platform_impl.hpp | 10 + sycl/unittests/CMakeLists.txt | 1 + sycl/unittests/allowlist/CMakeLists.txt | 8 + sycl/unittests/allowlist/DeviceIsAllowed.cpp | 225 +++++++++ sycl/unittests/allowlist/ParseAllowList.cpp | 167 +++++++ 9 files changed, 764 insertions(+), 145 deletions(-) create mode 100644 sycl/unittests/allowlist/CMakeLists.txt create mode 100644 sycl/unittests/allowlist/DeviceIsAllowed.cpp create mode 100644 sycl/unittests/allowlist/ParseAllowList.cpp diff --git a/sycl/doc/EnvironmentVariables.md b/sycl/doc/EnvironmentVariables.md index 369618b82f243..66ede087c6d9a 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: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 "\|".| | 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/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..c90776cd306a0 100644 --- a/sycl/source/detail/platform_impl.cpp +++ b/sycl/source/detail/platform_impl.cpp @@ -133,159 +133,364 @@ 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); - } +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"; + +// change to constexpr std::vector after switching DPC++ RT to C++20 +const std::vector 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 {}; - 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; -} + AllowListParsedT AllowListParsed; + AllowListParsed.emplace_back(); -struct DevDescT { - std::string DevName; - std::string DevDriverVer; - std::string PlatName; - std::string PlatVer; -}; + const std::vector SupportedKeyNamesHaveFixedValue{ + BackendNameKeyName, DeviceTypeKeyName, DeviceVendorIdKeyName}; + const std::vector SupportedKeyNamesRequireRegexValue{ + DriverVersionKeyName, PlatformVersionKeyName, DeviceNameKeyName, + PlatformNameKeyName}; -static std::vector getAllowListDesc() { - std::string AllowList(SYCLConfig::get()); - if (AllowList.empty()) - return {}; + const std::string &DeprecatedKeyNameDeviceName = DeviceNameKeyName; + const std::string &DeprecatedKeyNamePlatformName = PlatformNameKeyName; - 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++; - } - } + size_t KeyStart = 0, KeyEnd = 0, ValueStart = 0, ValueEnd = 0, + DeviceDescIndex = 0; - else if ((AllowList.compare(Pos, DriverVersion.size(), DriverVersion)) == - 0) { - DecDescs.back().DevDriverVer = - getValue(AllowList, Pos, DriverVersion.size()); - if (AllowList[Pos] == ',') { - Pos++; - } - } + bool IsDeprecatedKeyNameDeviceNameWasUsed = false; + bool IsDeprecatedKeyNamePlatformNameWasUsed = false; - else if ((AllowList.compare(Pos, PlatformName.size(), PlatformName)) == 0) { - DecDescs.back().PlatName = getValue(AllowList, Pos, PlatformName.size()); - if (AllowList[Pos] == ',') { - Pos++; - } + while ((KeyEnd = AllowListRaw.find(':', KeyStart)) != std::string::npos) { + if ((ValueStart = AllowListRaw.find_first_not_of(":", 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", + PI_INVALID_VALUE); + } + if (Key == DeprecatedKeyNameDeviceName) { + IsDeprecatedKeyNameDeviceNameWasUsed = true; + } + if (Key == DeprecatedKeyNamePlatformName) { + IsDeprecatedKeyNamePlatformNameWasUsed = true; } - 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++; + bool ShouldAllocateNewDeviceDescMap = false; + + ValueEnd = AllowListRaw.find(',', ValueStart); + if (ValueEnd == std::string::npos) { + ValueEnd = AllowListRaw.length(); + } + for (const auto &SupportedKeyName : SupportedAllowListKeyNames) { + // 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("|" + SupportedKeyName, ValueStart); + (ValueEndCand != std::string::npos) && (ValueEndCand < ValueEnd)) { + ValueEnd = ValueEndCand; + ShouldAllocateNewDeviceDescMap = true; } - DecDescs.emplace_back(); } + 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()) { + // check that regex values have double curly braces at the beginning and + // at the end + size_t CurlyBracesStartSize = 0, CurlyBracesEndSize = 0; + if (std::find(SupportedKeyNamesRequireRegexValue.begin(), + SupportedKeyNamesRequireRegexValue.end(), + Key) != SupportedKeyNamesRequireRegexValue.end()) { + const std::string &ValueRaw = + AllowListRaw.substr(ValueStart, ValueEnd - ValueStart); + std::string Prefix("{{"); + // can be changed to string_view::starts_with after switching DPC++ RT + // to C++20 + if (Prefix != ValueRaw.substr(0, Prefix.length())) { + throw sycl::runtime_error("Key " + Key + + " of SYCL_DEVICE_ALLOWLIST should have " + "value which starts with {{", + PI_INVALID_VALUE); + } + std::string Postfix("}}"); + // can be changed to string_view::ends_with after switching DPC++ RT to + // C++20 + if (Postfix != ValueRaw.substr(ValueRaw.length() - Postfix.length(), + ValueRaw.length())) { + throw sycl::runtime_error("Key " + Key + + " of SYCL_DEVICE_ALLOWLIST should have " + "value which ends with }}", + PI_INVALID_VALUE); + } + CurlyBracesStartSize = Prefix.length(); + CurlyBracesEndSize = Postfix.length(); + } + // if value has curly braces {{ and }} at the beginning and at the end, + // CurlyBracesStartSize and CurlyBracesEndSize != 0, so we move boundaries + // to remove these braces + const std::string &Value = + AllowListRaw.substr(ValueStart + CurlyBracesStartSize, + (ValueEnd - CurlyBracesEndSize) - + (ValueStart + CurlyBracesStartSize)); + // 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 + if (std::find(SupportedKeyNamesHaveFixedValue.begin(), + SupportedKeyNamesHaveFixedValue.end(), + Key) != SupportedKeyNamesHaveFixedValue.end()) { + if (Key == BackendNameKeyName) { + bool ValueForBackendNameIsValid = false; + for (const auto &SyclBe : SyclBeMap) { + if (Value == SyclBe.first) { + ValueForBackendNameIsValid = true; + break; + } + } + if (!ValueForBackendNameIsValid) { + 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); + } + } + if (Key == DeviceTypeKeyName) { + bool ValueForDeviceTypeIsValid = false; + for (const auto &SyclDeviceType : SyclDeviceTypeMap) { + if (Value == SyclDeviceType.first) { + ValueForDeviceTypeIsValid = true; + break; + } + } + if (!ValueForDeviceTypeIsValid) { + 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); + } + } + 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 hex format. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md", + PI_INVALID_VALUE); + } + } + } - else { - throw sycl::runtime_error("Unrecognized key in device allowlist", + // 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); } - } // while (Pos <= AllowList.size()) - return DecDescs; -} -enum class FilterState { DENIED, ALLOWED }; + KeyStart = ValueEnd; + if (KeyStart != std::string::npos) + ++KeyStart; + if (ShouldAllocateNewDeviceDescMap) { + ++DeviceDescIndex; + AllowListParsed.emplace_back(); + } + } -static void filterAllowList(vector_class &PiDevices, - RT::PiPlatform PiPlatform, const plugin &Plugin) { - const std::vector AllowList(getAllowListDesc()); - if (AllowList.empty()) - return; + if (IsDeprecatedKeyNameDeviceNameWasUsed && + IsDeprecatedKeyNamePlatformNameWasUsed) { + std::cerr << "\nWARNING: DeviceName and PlatformName in " + "SYCL_DEVICE_ALLOWLIST are deprecated. "; + } else if (IsDeprecatedKeyNameDeviceNameWasUsed) { + std::cerr + << "\nWARNING: DeviceName in SYCL_DEVICE_ALLOWLIST is deprecated. "; + } else if (IsDeprecatedKeyNamePlatformNameWasUsed) { + std::cerr + << "\nWARNING: PlatformName in SYCL_DEVICE_ALLOWLIST is deprecated. "; + } + if (IsDeprecatedKeyNameDeviceNameWasUsed || + IsDeprecatedKeyNamePlatformNameWasUsed) { + std::cerr << "Please use BackendName, DeviceType and DeviceVendorId " + "instead. For details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md\n\n"; + } + + return AllowListParsed; +} - FilterState DevNameState = FilterState::ALLOWED; - FilterState DevVerState = FilterState::ALLOWED; - FilterState PlatNameState = FilterState::ALLOWED; - FilterState PlatVerState = FilterState::ALLOWED; +// 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; + }; - const string_class PlatformName = - sycl::detail::get_platform_info::get( - PiPlatform, Plugin); + bool ShouldDeviceBeAllowed = false; - const string_class PlatformVer = - sycl::detail::get_platform_info::get(PiPlatform, - Plugin); + 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; - int InsertIDx = 0; - for (RT::PiDevice Device : PiDevices) { - const string_class DeviceName = - sycl::detail::get_device_info::get( - Device, Plugin); + // no any continue was called on this iteration, so all parameters matched + // successfully, so allow this device to use + ShouldDeviceBeAllowed = true; + break; + } - const string_class DeviceDriverVer = sycl::detail::get_device_info< - string_class, info::device::driver_version>::get(Device, Plugin); + return ShouldDeviceBeAllowed; +} - for (const DevDescT &Desc : AllowList) { - if (!Desc.PlatName.empty()) { - if (!std::regex_match(PlatformName, std::regex(Desc.PlatName))) { - PlatNameState = FilterState::DENIED; - continue; - } - } +static void applyAllowList(std::vector &PiDevices, + RT::PiPlatform PiPlatform, const plugin &Plugin) { + AllowListParsedT AllowListParsed = + parseAllowList(SYCLConfig::get()); + if (AllowListParsed.empty()) + return; - if (!Desc.PlatVer.empty()) { - if (!std::regex_match(PlatformVer, std::regex(Desc.PlatVer))) { - PlatVerState = FilterState::DENIED; - continue; - } - } + DeviceDescT DeviceDesc; - if (!Desc.DevName.empty()) { - if (!std::regex_match(DeviceName, std::regex(Desc.DevName))) { - DevNameState = FilterState::DENIED; - continue; - } - } + // 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); + } + } + // 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)); - if (!Desc.DevDriverVer.empty()) { - if (!std::regex_match(DeviceDriverVer, std::regex(Desc.DevDriverVer))) { - DevVerState = FilterState::DENIED; - continue; - } + int InsertIDx = 0; + for (RT::PiDevice Device : PiDevices) { + bool IsInserted = false; + // 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; + std::tie(std::ignore, IsInserted) = + DeviceDesc.emplace(DeviceTypeKeyName, DeviceTypeValue); + if (!IsInserted) + DeviceDesc.at(DeviceTypeKeyName) = DeviceTypeValue; + break; } - - if (DevNameState == FilterState::ALLOWED && - DevVerState == FilterState::ALLOWED && - PlatNameState == FilterState::ALLOWED && - PlatVerState == FilterState::ALLOWED) - PiDevices[InsertIDx++] = Device; - 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(); + std::tie(std::ignore, IsInserted) = DeviceDesc.emplace( + DeviceVendorIdKeyName, DeviceVendorIdHexStringStream.str()); + if (!IsInserted) + DeviceDesc.at(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); + std::tie(std::ignore, IsInserted) = + DeviceDesc.emplace(DriverVersionKeyName, DriverVersionValue); + if (!IsInserted) + DeviceDesc.at(DriverVersionKeyName) = DriverVersionValue; + // get DeviceName value and put it to DeviceDesc + const auto &DeviceNameValue = + sycl::detail::get_device_info::get( + Device, Plugin); + std::tie(std::ignore, IsInserted) = + DeviceDesc.emplace(DeviceNameKeyName, DeviceNameValue); + if (!IsInserted) + DeviceDesc.at(DeviceNameKeyName) = DeviceNameValue; + + // check if we can allow device with such device description DeviceDesc + if (DeviceIsAllowed(DeviceDesc, AllowListParsed)) { + PiDevices[InsertIDx++] = Device; } } PiDevices.resize(InsertIDx); @@ -392,9 +597,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/source/detail/platform_impl.hpp b/sycl/source/detail/platform_impl.hpp index 8af8874413a94..59c8f89e8da31 100644 --- a/sycl/source/detail/platform_impl.hpp +++ b/sycl/source/detail/platform_impl.hpp @@ -14,6 +14,8 @@ #include #include +#include + __SYCL_INLINE_NAMESPACE(cl) { namespace sycl { @@ -188,6 +190,14 @@ class platform_impl { std::mutex MDeviceMapMutex; }; +using DeviceDescT = std::map; +using AllowListParsedT = std::vector; + +AllowListParsedT parseAllowList(const std::string &AllowListRaw); + +bool DeviceIsAllowed(const DeviceDescT &DeviceDesc, + const AllowListParsedT &AllowListParsed); + } // namespace detail } // namespace sycl } // __SYCL_INLINE_NAMESPACE(cl) 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..deb5c2de14c8e --- /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 +) \ No newline at end of file diff --git a/sycl/unittests/allowlist/DeviceIsAllowed.cpp b/sycl/unittests/allowlist/DeviceIsAllowed.cpp new file mode 100644 index 0000000000000..a1c0c2cff6a75 --- /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..f80b6d1c03493 --- /dev/null +++ b/sycl/unittests/allowlist/ParseAllowList.cpp @@ -0,0 +1,167 @@ +//==------- 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 + +TEST(ParseAllowListTests, CheckAllowListIsEmpty) { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList(""); + sycl::detail::AllowListParsedT ExpectedValue{}; + EXPECT_EQ(ActualValue, ExpectedValue); +} + +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(ActualValue, ExpectedValue); +} + +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(ActualValue, ExpectedValue); +} + +TEST(ParseAllowListTests, CheckUnsupportedKeyNameIsHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "BackendName:level_zero,SomeUnsupportedKey:gpu"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(e.what(), std::string("Unrecognized key in SYCL_DEVICE_ALLOWLIST " + "-30 (CL_INVALID_VALUE)")); + } 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(ActualValue, ExpectedValue); +} + +TEST(ParseAllowListTests, CheckMissingOpenDoubleCurlyBracesAreHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "DeviceName:regex1}},DriverVersion:{{regex1|regex2}}"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ( + e.what(), + std::string( + "Key DeviceName of SYCL_DEVICE_ALLOWLIST " + "should have value which starts with {{ -30 (CL_INVALID_VALUE)")); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckMissingClosedDoubleCurlyBracesAreHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "DeviceName:{{regex1}},DriverVersion:{{regex1|regex2"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ( + e.what(), + std::string( + "Key DriverVersion of SYCL_DEVICE_ALLOWLIST " + "should have value which ends with }} -30 (CL_INVALID_VALUE)")); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckAllValidBackendNameValuesAreProcessed) { + sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( + "BackendName:host|BackendName:opencl|BackendName:level_zero|BackendName:" + "cuda|BackendName:*"); + sycl::detail::AllowListParsedT ExpectedValue{{{"BackendName", "host"}}, + {{"BackendName", "opencl"}}, + {{"BackendName", "level_zero"}}, + {{"BackendName", "cuda"}}, + {{"BackendName", "*"}}}; + EXPECT_EQ(ActualValue, ExpectedValue); +} + +TEST(ParseAllowListTests, CheckAllValidDeviceTypeValuesAreProcessed) { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("DeviceType:host|DeviceType:cpu|DeviceType:" + "gpu|DeviceType:acc|DeviceType:*"); + sycl::detail::AllowListParsedT ExpectedValue{{{"DeviceType", "host"}}, + {{"DeviceType", "cpu"}}, + {{"DeviceType", "gpu"}}, + {{"DeviceType", "acc"}}, + {{"DeviceType", "*"}}}; + EXPECT_EQ(ActualValue, ExpectedValue); +} + +TEST(ParseAllowListTests, CheckIncorrectBackendNameValueIsHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("BackendName:blablabla"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(e.what(), + 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)")); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckIncorrectDeviceTypeValueIsHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("DeviceType:blablabla"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ(e.what(), + 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)")); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} + +TEST(ParseAllowListTests, CheckIncorrectDeviceVendorIdValueIsHandled) { + try { + sycl::detail::AllowListParsedT ActualValue = + sycl::detail::parseAllowList("DeviceVendorId:blablabla"); + } catch (sycl::runtime_error const &e) { + EXPECT_EQ( + e.what(), + std::string("Value blablabla for key DeviceVendorId is not valid in " + "SYCL_DEVICE_ALLOWLIST. It should have hex format. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)")); + } catch (...) { + FAIL() << "Expected sycl::runtime_error"; + } +} From 18949a71233c3cd3f1d2489d904b016c833ca16e Mon Sep 17 00:00:00 2001 From: Dmitry Vodopyanov Date: Wed, 26 May 2021 21:30:15 +0300 Subject: [PATCH 2/7] Remove early depracation of some parameters --- sycl/source/detail/platform_impl.cpp | 31 ---------------------------- 1 file changed, 31 deletions(-) diff --git a/sycl/source/detail/platform_impl.cpp b/sycl/source/detail/platform_impl.cpp index c90776cd306a0..d42114439f040 100644 --- a/sycl/source/detail/platform_impl.cpp +++ b/sycl/source/detail/platform_impl.cpp @@ -179,15 +179,9 @@ AllowListParsedT parseAllowList(const std::string &AllowListRaw) { DriverVersionKeyName, PlatformVersionKeyName, DeviceNameKeyName, PlatformNameKeyName}; - const std::string &DeprecatedKeyNameDeviceName = DeviceNameKeyName; - const std::string &DeprecatedKeyNamePlatformName = PlatformNameKeyName; - size_t KeyStart = 0, KeyEnd = 0, ValueStart = 0, ValueEnd = 0, DeviceDescIndex = 0; - bool IsDeprecatedKeyNameDeviceNameWasUsed = false; - bool IsDeprecatedKeyNamePlatformNameWasUsed = false; - while ((KeyEnd = AllowListRaw.find(':', KeyStart)) != std::string::npos) { if ((ValueStart = AllowListRaw.find_first_not_of(":", KeyEnd)) == std::string::npos) @@ -201,12 +195,6 @@ AllowListParsedT parseAllowList(const std::string &AllowListRaw) { throw sycl::runtime_error("Unrecognized key in SYCL_DEVICE_ALLOWLIST", PI_INVALID_VALUE); } - if (Key == DeprecatedKeyNameDeviceName) { - IsDeprecatedKeyNameDeviceNameWasUsed = true; - } - if (Key == DeprecatedKeyNamePlatformName) { - IsDeprecatedKeyNamePlatformNameWasUsed = true; - } bool ShouldAllocateNewDeviceDescMap = false; @@ -341,25 +329,6 @@ AllowListParsedT parseAllowList(const std::string &AllowListRaw) { } } - if (IsDeprecatedKeyNameDeviceNameWasUsed && - IsDeprecatedKeyNamePlatformNameWasUsed) { - std::cerr << "\nWARNING: DeviceName and PlatformName in " - "SYCL_DEVICE_ALLOWLIST are deprecated. "; - } else if (IsDeprecatedKeyNameDeviceNameWasUsed) { - std::cerr - << "\nWARNING: DeviceName in SYCL_DEVICE_ALLOWLIST is deprecated. "; - } else if (IsDeprecatedKeyNamePlatformNameWasUsed) { - std::cerr - << "\nWARNING: PlatformName in SYCL_DEVICE_ALLOWLIST is deprecated. "; - } - if (IsDeprecatedKeyNameDeviceNameWasUsed || - IsDeprecatedKeyNamePlatformNameWasUsed) { - std::cerr << "Please use BackendName, DeviceType and DeviceVendorId " - "instead. For details, please refer to " - "https://github.com/intel/llvm/blob/sycl/sycl/doc/" - "EnvironmentVariables.md\n\n"; - } - return AllowListParsed; } From 215f5165fb18a09fabdb859f8905f99ab65fd2d4 Mon Sep 17 00:00:00 2001 From: Dmitry Vodopyanov Date: Tue, 1 Jun 2021 14:17:42 +0300 Subject: [PATCH 3/7] Apply CR comments --- sycl/doc/EnvironmentVariables.md | 2 +- sycl/source/CMakeLists.txt | 1 + sycl/source/detail/allowlist.cpp | 354 +++++++++++++++++++ sycl/source/detail/allowlist.hpp | 35 ++ sycl/source/detail/platform_impl.cpp | 334 +---------------- sycl/source/detail/platform_impl.hpp | 10 - sycl/unittests/allowlist/CMakeLists.txt | 2 +- sycl/unittests/allowlist/DeviceIsAllowed.cpp | 38 +- sycl/unittests/allowlist/ParseAllowList.cpp | 2 +- 9 files changed, 413 insertions(+), 365 deletions(-) create mode 100644 sycl/source/detail/allowlist.cpp create mode 100644 sycl/source/detail/allowlist.hpp diff --git a/sycl/doc/EnvironmentVariables.md b/sycl/doc/EnvironmentVariables.md index 66ede087c6d9a..d27ec2dfae2bf 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: 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 "\|".| +| 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 7da8d346e8d3b..6bd95e678c6c3 100644 --- a/sycl/source/CMakeLists.txt +++ b/sycl/source/CMakeLists.txt @@ -106,6 +106,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..0f7a3605ecd74 --- /dev/null +++ b/sycl/source/detail/allowlist.cpp @@ -0,0 +1,354 @@ +//==-------------- 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; + + while ((KeyEnd = AllowListRaw.find(':', KeyStart)) != std::string::npos) { + if ((ValueStart = AllowListRaw.find_first_not_of(":", 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", + PI_INVALID_VALUE); + } + + bool ShouldAllocateNewDeviceDescMap = false; + + ValueEnd = AllowListRaw.find(',', ValueStart); + if (ValueEnd == std::string::npos) { + ValueEnd = AllowListRaw.length(); + } + for (const auto &SupportedKeyName : SupportedAllowListKeyNames) { + // 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( + "|" + std::string(SupportedKeyName), ValueStart); + (ValueEndCand != std::string::npos) && (ValueEndCand < ValueEnd)) { + ValueEnd = ValueEndCand; + ShouldAllocateNewDeviceDescMap = true; + } + } + + 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()) { + // check that regex values have double curly braces at the beginning and + // at the end + size_t CurlyBracesStartSize = 0, CurlyBracesEndSize = 0; + if (std::find(SupportedKeyNamesRequireRegexValue.begin(), + SupportedKeyNamesRequireRegexValue.end(), + Key) != SupportedKeyNamesRequireRegexValue.end()) { + const std::string &ValueRaw = + AllowListRaw.substr(ValueStart, ValueEnd - ValueStart); + std::string Prefix("{{"); + // can be changed to string_view::starts_with after switching DPC++ RT + // to C++20 + if (Prefix != ValueRaw.substr(0, Prefix.length())) { + throw sycl::runtime_error("Key " + Key + + " of SYCL_DEVICE_ALLOWLIST should have " + "value which starts with {{", + PI_INVALID_VALUE); + } + std::string Postfix("}}"); + // can be changed to string_view::ends_with after switching DPC++ RT to + // C++20 + if (Postfix != ValueRaw.substr(ValueRaw.length() - Postfix.length(), + ValueRaw.length())) { + throw sycl::runtime_error("Key " + Key + + " of SYCL_DEVICE_ALLOWLIST should have " + "value which ends with }}", + PI_INVALID_VALUE); + } + CurlyBracesStartSize = Prefix.length(); + CurlyBracesEndSize = Postfix.length(); + } + // if value has curly braces {{ and }} at the beginning and at the end, + // CurlyBracesStartSize and CurlyBracesEndSize != 0, so we move boundaries + // to remove these braces + const std::string &Value = + AllowListRaw.substr(ValueStart + CurlyBracesStartSize, + (ValueEnd - CurlyBracesEndSize) - + (ValueStart + CurlyBracesStartSize)); + // 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 + if (std::find(SupportedKeyNamesHaveFixedValue.begin(), + SupportedKeyNamesHaveFixedValue.end(), + Key) != SupportedKeyNamesHaveFixedValue.end()) { + if (Key == BackendNameKeyName) { + bool ValueForBackendNameIsValid = false; + for (const auto &SyclBe : SyclBeMap) { + if (Value == SyclBe.first) { + ValueForBackendNameIsValid = true; + break; + } + } + if (!ValueForBackendNameIsValid) { + 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); + } + } + if (Key == DeviceTypeKeyName) { + bool ValueForDeviceTypeIsValid = false; + for (const auto &SyclDeviceType : SyclDeviceTypeMap) { + if (Value == SyclDeviceType.first) { + ValueForDeviceTypeIsValid = true; + break; + } + } + if (!ValueForDeviceTypeIsValid) { + 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); + } + } + 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 hex format. For " + "details, please refer to " + "https://github.com/intel/llvm/blob/sycl/sycl/doc/" + "EnvironmentVariables.md", + PI_INVALID_VALUE); + } + } + } + + // 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); + } + } + // 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) { + bool IsInserted = false; + // 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; + std::tie(std::ignore, IsInserted) = + DeviceDesc.emplace(DeviceTypeKeyName, DeviceTypeValue); + if (!IsInserted) + DeviceDesc.at(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(); + std::tie(std::ignore, IsInserted) = DeviceDesc.emplace( + DeviceVendorIdKeyName, DeviceVendorIdHexStringStream.str()); + if (!IsInserted) + DeviceDesc.at(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); + std::tie(std::ignore, IsInserted) = + DeviceDesc.emplace(DriverVersionKeyName, DriverVersionValue); + if (!IsInserted) + DeviceDesc.at(DriverVersionKeyName) = DriverVersionValue; + // get DeviceName value and put it to DeviceDesc + const auto &DeviceNameValue = + sycl::detail::get_device_info::get( + Device, Plugin); + std::tie(std::ignore, IsInserted) = + DeviceDesc.emplace(DeviceNameKeyName, DeviceNameValue); + if (!IsInserted) + DeviceDesc.at(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/platform_impl.cpp b/sycl/source/detail/platform_impl.cpp index d42114439f040..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,338 +133,6 @@ vector_class platform_impl::get_platforms() { return Platforms; } -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"; - -// change to constexpr std::vector after switching DPC++ RT to C++20 -const std::vector 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(); - - const std::vector SupportedKeyNamesHaveFixedValue{ - BackendNameKeyName, DeviceTypeKeyName, DeviceVendorIdKeyName}; - const std::vector SupportedKeyNamesRequireRegexValue{ - DriverVersionKeyName, PlatformVersionKeyName, DeviceNameKeyName, - PlatformNameKeyName}; - - size_t KeyStart = 0, KeyEnd = 0, ValueStart = 0, ValueEnd = 0, - DeviceDescIndex = 0; - - while ((KeyEnd = AllowListRaw.find(':', KeyStart)) != std::string::npos) { - if ((ValueStart = AllowListRaw.find_first_not_of(":", 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", - PI_INVALID_VALUE); - } - - bool ShouldAllocateNewDeviceDescMap = false; - - ValueEnd = AllowListRaw.find(',', ValueStart); - if (ValueEnd == std::string::npos) { - ValueEnd = AllowListRaw.length(); - } - for (const auto &SupportedKeyName : SupportedAllowListKeyNames) { - // 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("|" + SupportedKeyName, ValueStart); - (ValueEndCand != std::string::npos) && (ValueEndCand < ValueEnd)) { - ValueEnd = ValueEndCand; - ShouldAllocateNewDeviceDescMap = true; - } - } - 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()) { - // check that regex values have double curly braces at the beginning and - // at the end - size_t CurlyBracesStartSize = 0, CurlyBracesEndSize = 0; - if (std::find(SupportedKeyNamesRequireRegexValue.begin(), - SupportedKeyNamesRequireRegexValue.end(), - Key) != SupportedKeyNamesRequireRegexValue.end()) { - const std::string &ValueRaw = - AllowListRaw.substr(ValueStart, ValueEnd - ValueStart); - std::string Prefix("{{"); - // can be changed to string_view::starts_with after switching DPC++ RT - // to C++20 - if (Prefix != ValueRaw.substr(0, Prefix.length())) { - throw sycl::runtime_error("Key " + Key + - " of SYCL_DEVICE_ALLOWLIST should have " - "value which starts with {{", - PI_INVALID_VALUE); - } - std::string Postfix("}}"); - // can be changed to string_view::ends_with after switching DPC++ RT to - // C++20 - if (Postfix != ValueRaw.substr(ValueRaw.length() - Postfix.length(), - ValueRaw.length())) { - throw sycl::runtime_error("Key " + Key + - " of SYCL_DEVICE_ALLOWLIST should have " - "value which ends with }}", - PI_INVALID_VALUE); - } - CurlyBracesStartSize = Prefix.length(); - CurlyBracesEndSize = Postfix.length(); - } - // if value has curly braces {{ and }} at the beginning and at the end, - // CurlyBracesStartSize and CurlyBracesEndSize != 0, so we move boundaries - // to remove these braces - const std::string &Value = - AllowListRaw.substr(ValueStart + CurlyBracesStartSize, - (ValueEnd - CurlyBracesEndSize) - - (ValueStart + CurlyBracesStartSize)); - // 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 - if (std::find(SupportedKeyNamesHaveFixedValue.begin(), - SupportedKeyNamesHaveFixedValue.end(), - Key) != SupportedKeyNamesHaveFixedValue.end()) { - if (Key == BackendNameKeyName) { - bool ValueForBackendNameIsValid = false; - for (const auto &SyclBe : SyclBeMap) { - if (Value == SyclBe.first) { - ValueForBackendNameIsValid = true; - break; - } - } - if (!ValueForBackendNameIsValid) { - 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); - } - } - if (Key == DeviceTypeKeyName) { - bool ValueForDeviceTypeIsValid = false; - for (const auto &SyclDeviceType : SyclDeviceTypeMap) { - if (Value == SyclDeviceType.first) { - ValueForDeviceTypeIsValid = true; - break; - } - } - if (!ValueForDeviceTypeIsValid) { - 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); - } - } - 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 hex format. For " - "details, please refer to " - "https://github.com/intel/llvm/blob/sycl/sycl/doc/" - "EnvironmentVariables.md", - PI_INVALID_VALUE); - } - } - } - - // 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; -} - -static 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); - } - } - // 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) { - bool IsInserted = false; - // 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; - std::tie(std::ignore, IsInserted) = - DeviceDesc.emplace(DeviceTypeKeyName, DeviceTypeValue); - if (!IsInserted) - DeviceDesc.at(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(); - std::tie(std::ignore, IsInserted) = DeviceDesc.emplace( - DeviceVendorIdKeyName, DeviceVendorIdHexStringStream.str()); - if (!IsInserted) - DeviceDesc.at(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); - std::tie(std::ignore, IsInserted) = - DeviceDesc.emplace(DriverVersionKeyName, DriverVersionValue); - if (!IsInserted) - DeviceDesc.at(DriverVersionKeyName) = DriverVersionValue; - // get DeviceName value and put it to DeviceDesc - const auto &DeviceNameValue = - sycl::detail::get_device_info::get( - Device, Plugin); - std::tie(std::ignore, IsInserted) = - DeviceDesc.emplace(DeviceNameKeyName, DeviceNameValue); - if (!IsInserted) - DeviceDesc.at(DeviceNameKeyName) = DeviceNameValue; - - // check if we can allow device with such device description DeviceDesc - if (DeviceIsAllowed(DeviceDesc, AllowListParsed)) { - PiDevices[InsertIDx++] = Device; - } - } - 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' diff --git a/sycl/source/detail/platform_impl.hpp b/sycl/source/detail/platform_impl.hpp index 59c8f89e8da31..8af8874413a94 100644 --- a/sycl/source/detail/platform_impl.hpp +++ b/sycl/source/detail/platform_impl.hpp @@ -14,8 +14,6 @@ #include #include -#include - __SYCL_INLINE_NAMESPACE(cl) { namespace sycl { @@ -190,14 +188,6 @@ class platform_impl { std::mutex MDeviceMapMutex; }; -using DeviceDescT = std::map; -using AllowListParsedT = std::vector; - -AllowListParsedT parseAllowList(const std::string &AllowListRaw); - -bool DeviceIsAllowed(const DeviceDescT &DeviceDesc, - const AllowListParsedT &AllowListParsed); - } // namespace detail } // namespace sycl } // __SYCL_INLINE_NAMESPACE(cl) diff --git a/sycl/unittests/allowlist/CMakeLists.txt b/sycl/unittests/allowlist/CMakeLists.txt index deb5c2de14c8e..c78efbf3068f1 100644 --- a/sycl/unittests/allowlist/CMakeLists.txt +++ b/sycl/unittests/allowlist/CMakeLists.txt @@ -5,4 +5,4 @@ set(LLVM_REQUIRES_EH 1) add_sycl_unittest(AllowListTests OBJECT ParseAllowList.cpp DeviceIsAllowed.cpp -) \ No newline at end of file +) diff --git a/sycl/unittests/allowlist/DeviceIsAllowed.cpp b/sycl/unittests/allowlist/DeviceIsAllowed.cpp index a1c0c2cff6a75..a523d67dcba14 100644 --- a/sycl/unittests/allowlist/DeviceIsAllowed.cpp +++ b/sycl/unittests/allowlist/DeviceIsAllowed.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include @@ -80,33 +80,33 @@ sycl::detail::DeviceDescT LevelZeroGPUDeviceDesc{ {"PlatformName", "Intel(R) Level-Zero"}}; TEST(DeviceIsAllowedTests, CheckSupportedOpenCLGPUDeviceIsAllowed) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( OpenCLGPUDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, true); } TEST(DeviceIsAllowedTests, CheckSupportedOpenCLCPUDeviceIsAllowed) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( OpenCLCPUDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, true); } TEST(DeviceIsAllowedTests, CheckSupportedOpenCLFPGAEmuDeviceIsAllowed) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( OpenCLFPGAEmuDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, true); } TEST(DeviceIsAllowedTests, CheckSupportedOpenCLFPGABoardDeviceIsAllowed) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( OpenCLFPGABoardDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, true); } TEST(DeviceIsAllowedTests, CheckSupportedLevelZeroGPUDeviceIsAllowed) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( LevelZeroGPUDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, true); @@ -116,7 +116,7 @@ TEST(DeviceIsAllowedTests, CheckOpenCLGPUDeviceWithNotSupportedBackendNameIsNotAllowed) { auto DeviceDesc = OpenCLGPUDeviceDesc; DeviceDesc.at("BackendName") = "cuda"; - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, false); } @@ -125,7 +125,7 @@ TEST(DeviceIsAllowedTests, CheckOpenCLGPUDeviceWithNotSupportedDeviceTypeIsNotAllowed) { auto DeviceDesc = OpenCLGPUDeviceDesc; DeviceDesc.at("DeviceType") = "cpu"; - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, false); } @@ -134,7 +134,7 @@ TEST(DeviceIsAllowedTests, CheckOpenCLGPUDeviceWithNotSupportedDeviceVendorIdIsNotAllowed) { auto DeviceDesc = OpenCLGPUDeviceDesc; DeviceDesc.at("DeviceVendorId") = "0x0000"; - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, false); } @@ -143,7 +143,7 @@ TEST(DeviceIsAllowedTests, CheckOpenCLGPUDeviceWithNotSupportedDriverVersionIsNotAllowed) { auto DeviceDesc = OpenCLGPUDeviceDesc; DeviceDesc.at("DriverVersion") = "0.0.0.0"; - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, false); } @@ -152,7 +152,7 @@ TEST(DeviceIsAllowedTests, CheckOpenCLFPGABoardDeviceWithNotSupportedPlatformVersionIsNotAllowed) { auto DeviceDesc = OpenCLFPGABoardDeviceDesc; DeviceDesc.at("PlatformVersion") = "42"; - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)); EXPECT_EQ(Actual, false); } @@ -160,7 +160,7 @@ TEST(DeviceIsAllowedTests, TEST(DeviceIsAllowedTests, CheckAssertHappensIfIncompleteDeviceDescIsPassedToTheFunc) { sycl::detail::DeviceDescT IncompleteDeviceDesc{{"BackendName", "level_zero"}}; - EXPECT_DEATH(sycl::detail::DeviceIsAllowed( + EXPECT_DEATH(sycl::detail::deviceIsAllowed( IncompleteDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowList)), ".*DeviceDesc map should have all supported keys for.*" @@ -168,14 +168,14 @@ TEST(DeviceIsAllowedTests, } TEST(DeviceIsAllowedTests, CheckSupportedOpenCLGPUDeviceIsAllowedInOldStyle) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( OpenCLGPUDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); EXPECT_EQ(Actual, true); } TEST(DeviceIsAllowedTests, CheckSupportedOpenCLCPUDeviceIsAllowedInOldStyle) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( OpenCLCPUDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); EXPECT_EQ(Actual, true); @@ -183,7 +183,7 @@ TEST(DeviceIsAllowedTests, CheckSupportedOpenCLCPUDeviceIsAllowedInOldStyle) { TEST(DeviceIsAllowedTests, CheckSupportedOpenCLFPGAEmuDeviceIsAllowedInOldStyle) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( OpenCLFPGAEmuDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); EXPECT_EQ(Actual, true); @@ -191,7 +191,7 @@ TEST(DeviceIsAllowedTests, TEST(DeviceIsAllowedTests, CheckSupportedOpenCLFPGABoardDeviceIsAllowedInOldStyle) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( OpenCLFPGABoardDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); EXPECT_EQ(Actual, true); @@ -199,7 +199,7 @@ TEST(DeviceIsAllowedTests, TEST(DeviceIsAllowedTests, CheckSupportedLevelZeroGPUDeviceIsAllowedInOldStyle) { - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( LevelZeroGPUDeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); EXPECT_EQ(Actual, true); @@ -209,7 +209,7 @@ TEST(DeviceIsAllowedTests, CheckLevelZeroGPUDeviceWithNotSupportedDeviceNameIsNotAllowedInOldStyle) { auto DeviceDesc = OpenCLGPUDeviceDesc; DeviceDesc.at("DeviceName") = "ABCD"; - bool Actual = sycl::detail::DeviceIsAllowed( + bool Actual = sycl::detail::deviceIsAllowed( DeviceDesc, sycl::detail::parseAllowList(SyclDeviceAllowListOldStyle)); EXPECT_EQ(Actual, false); } @@ -219,7 +219,7 @@ TEST( CheckOpenCLFPGABoardDeviceWithNotSupportedPlatformNameIsNotAllowedInOldStyle) { auto DeviceDesc = OpenCLFPGABoardDeviceDesc; DeviceDesc.at("PlatformName") = "AABBCCDD"; - bool Actual = sycl::detail::DeviceIsAllowed( + 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 index f80b6d1c03493..27ec71f1d4a85 100644 --- a/sycl/unittests/allowlist/ParseAllowList.cpp +++ b/sycl/unittests/allowlist/ParseAllowList.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include From c20fe51d55f9b9b4b697cdf6174bc47261f279dd Mon Sep 17 00:00:00 2001 From: Dmitry Vodopyanov Date: Tue, 1 Jun 2021 14:22:35 +0300 Subject: [PATCH 4/7] Fix clang-format --- sycl/source/detail/allowlist.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sycl/source/detail/allowlist.cpp b/sycl/source/detail/allowlist.cpp index 0f7a3605ecd74..7b259e233dad6 100644 --- a/sycl/source/detail/allowlist.cpp +++ b/sycl/source/detail/allowlist.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#include #include +#include #include #include @@ -25,7 +25,7 @@ constexpr char PlatformVersionKeyName[] = "PlatformVersion"; constexpr char DeviceNameKeyName[] = "DeviceName"; constexpr char PlatformNameKeyName[] = "PlatformName"; -constexpr std::array SupportedAllowListKeyNames{ +constexpr std::array SupportedAllowListKeyNames{ BackendNameKeyName, DeviceTypeKeyName, DeviceVendorIdKeyName, DriverVersionKeyName, PlatformVersionKeyName, DeviceNameKeyName, PlatformNameKeyName}; @@ -268,7 +268,7 @@ bool deviceIsAllowed(const DeviceDescT &DeviceDesc, } void applyAllowList(std::vector &PiDevices, - RT::PiPlatform PiPlatform, const plugin &Plugin) { + RT::PiPlatform PiPlatform, const plugin &Plugin) { AllowListParsedT AllowListParsed = parseAllowList(SYCLConfig::get()); if (AllowListParsed.empty()) From 4c26d6c2ffad1b221fc33baada8b66ceff7c61fd Mon Sep 17 00:00:00 2001 From: Dmitry Vodopyanov Date: Wed, 2 Jun 2021 23:07:52 +0300 Subject: [PATCH 5/7] Fix CR comments --- sycl/doc/EnvironmentVariables.md | 2 +- sycl/source/detail/allowlist.cpp | 234 ++++++++++---------- sycl/unittests/allowlist/ParseAllowList.cpp | 142 +++++++++--- 3 files changed, 237 insertions(+), 141 deletions(-) diff --git a/sycl/doc/EnvironmentVariables.md b/sycl/doc/EnvironmentVariables.md index abb2b7fa84052..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: 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_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/detail/allowlist.cpp b/sycl/source/detail/allowlist.cpp index 7b259e233dad6..a684e905194ef 100644 --- a/sycl/source/detail/allowlist.cpp +++ b/sycl/source/detail/allowlist.cpp @@ -65,9 +65,14 @@ AllowListParsedT parseAllowList(const std::string &AllowListRaw) { size_t KeyStart = 0, KeyEnd = 0, ValueStart = 0, ValueEnd = 0, DeviceDescIndex = 0; - while ((KeyEnd = AllowListRaw.find(':', KeyStart)) != std::string::npos) { - if ((ValueStart = AllowListRaw.find_first_not_of(":", KeyEnd)) == - std::string::npos) + 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); @@ -75,118 +80,76 @@ AllowListParsedT parseAllowList(const std::string &AllowListRaw) { if (std::find(SupportedAllowListKeyNames.begin(), SupportedAllowListKeyNames.end(), Key) == SupportedAllowListKeyNames.end()) { - throw sycl::runtime_error("Unrecognized key in SYCL_DEVICE_ALLOWLIST", - PI_INVALID_VALUE); + 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; - ValueEnd = AllowListRaw.find(',', ValueStart); - if (ValueEnd == std::string::npos) { - ValueEnd = AllowListRaw.length(); - } - for (const auto &SupportedKeyName : SupportedAllowListKeyNames) { - // 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( - "|" + std::string(SupportedKeyName), ValueStart); - (ValueEndCand != std::string::npos) && (ValueEndCand < ValueEnd)) { - ValueEnd = ValueEndCand; - ShouldAllocateNewDeviceDescMap = true; - } - } + 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()) { - // check that regex values have double curly braces at the beginning and - // at the end - size_t CurlyBracesStartSize = 0, CurlyBracesEndSize = 0; - if (std::find(SupportedKeyNamesRequireRegexValue.begin(), - SupportedKeyNamesRequireRegexValue.end(), - Key) != SupportedKeyNamesRequireRegexValue.end()) { - const std::string &ValueRaw = - AllowListRaw.substr(ValueStart, ValueEnd - ValueStart); - std::string Prefix("{{"); - // can be changed to string_view::starts_with after switching DPC++ RT - // to C++20 - if (Prefix != ValueRaw.substr(0, Prefix.length())) { - throw sycl::runtime_error("Key " + Key + - " of SYCL_DEVICE_ALLOWLIST should have " - "value which starts with {{", - PI_INVALID_VALUE); - } - std::string Postfix("}}"); - // can be changed to string_view::ends_with after switching DPC++ RT to - // C++20 - if (Postfix != ValueRaw.substr(ValueRaw.length() - Postfix.length(), - ValueRaw.length())) { - throw sycl::runtime_error("Key " + Key + - " of SYCL_DEVICE_ALLOWLIST should have " - "value which ends with }}", - PI_INVALID_VALUE); - } - CurlyBracesStartSize = Prefix.length(); - CurlyBracesEndSize = Postfix.length(); - } - // if value has curly braces {{ and }} at the beginning and at the end, - // CurlyBracesStartSize and CurlyBracesEndSize != 0, so we move boundaries - // to remove these braces - const std::string &Value = - AllowListRaw.substr(ValueStart + CurlyBracesStartSize, - (ValueEnd - CurlyBracesEndSize) - - (ValueStart + CurlyBracesStartSize)); - // 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 + // calculate and validate value which has fixed format if (std::find(SupportedKeyNamesHaveFixedValue.begin(), SupportedKeyNamesHaveFixedValue.end(), Key) != SupportedKeyNamesHaveFixedValue.end()) { - if (Key == BackendNameKeyName) { - bool ValueForBackendNameIsValid = false; - for (const auto &SyclBe : SyclBeMap) { - if (Value == SyclBe.first) { - ValueForBackendNameIsValid = true; - break; - } - } - if (!ValueForBackendNameIsValid) { - 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); - } + 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 (Key == DeviceTypeKeyName) { - bool ValueForDeviceTypeIsValid = false; - for (const auto &SyclDeviceType : SyclDeviceTypeMap) { - if (Value == SyclDeviceType.first) { - ValueForDeviceTypeIsValid = true; - break; - } - } - if (!ValueForDeviceTypeIsValid) { - 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); + 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 hex format. For " + "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", @@ -194,15 +157,72 @@ AllowListParsedT parseAllowList(const std::string &AllowListRaw) { } } } + // 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 { + } 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) @@ -281,6 +301,7 @@ void applyAllowList(std::vector &PiDevices, for (const auto &SyclBe : SyclBeMap) { if (SyclBe.second == Backend) { DeviceDesc.emplace(BackendNameKeyName, SyclBe.first); + break; } } // get PlatformVersion value and put it to DeviceDesc @@ -297,7 +318,6 @@ void applyAllowList(std::vector &PiDevices, int InsertIDx = 0; for (RT::PiDevice Device : PiDevices) { - bool IsInserted = false; // get DeviceType value and put it to DeviceDesc RT::PiDeviceType PiDevType; Plugin.call(Device, PI_DEVICE_INFO_TYPE, @@ -307,10 +327,7 @@ void applyAllowList(std::vector &PiDevices, for (const auto &SyclDeviceType : SyclDeviceTypeMap) { if (SyclDeviceType.second == DeviceType) { const auto &DeviceTypeValue = SyclDeviceType.first; - std::tie(std::ignore, IsInserted) = - DeviceDesc.emplace(DeviceTypeKeyName, DeviceTypeValue); - if (!IsInserted) - DeviceDesc.at(DeviceTypeKeyName) = DeviceTypeValue; + DeviceDesc[DeviceTypeKeyName] = DeviceTypeValue; break; } } @@ -321,25 +338,16 @@ void applyAllowList(std::vector &PiDevices, std::stringstream DeviceVendorIdHexStringStream; DeviceVendorIdHexStringStream << "0x" << std::hex << DeviceVendorIdUInt; const auto &DeviceVendorIdValue = DeviceVendorIdHexStringStream.str(); - std::tie(std::ignore, IsInserted) = DeviceDesc.emplace( - DeviceVendorIdKeyName, DeviceVendorIdHexStringStream.str()); - if (!IsInserted) - DeviceDesc.at(DeviceVendorIdKeyName) = DeviceVendorIdValue; + 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); - std::tie(std::ignore, IsInserted) = - DeviceDesc.emplace(DriverVersionKeyName, DriverVersionValue); - if (!IsInserted) - DeviceDesc.at(DriverVersionKeyName) = DriverVersionValue; + DeviceDesc[DriverVersionKeyName] = DriverVersionValue; // get DeviceName value and put it to DeviceDesc const auto &DeviceNameValue = sycl::detail::get_device_info::get( Device, Plugin); - std::tie(std::ignore, IsInserted) = - DeviceDesc.emplace(DeviceNameKeyName, DeviceNameValue); - if (!IsInserted) - DeviceDesc.at(DeviceNameKeyName) = DeviceNameValue; + DeviceDesc[DeviceNameKeyName] = DeviceNameValue; // check if we can allow device with such device description DeviceDesc if (deviceIsAllowed(DeviceDesc, AllowListParsed)) { diff --git a/sycl/unittests/allowlist/ParseAllowList.cpp b/sycl/unittests/allowlist/ParseAllowList.cpp index 27ec71f1d4a85..67265972b1508 100644 --- a/sycl/unittests/allowlist/ParseAllowList.cpp +++ b/sycl/unittests/allowlist/ParseAllowList.cpp @@ -7,13 +7,14 @@ //===----------------------------------------------------------------------===// #include +#include // for SyclBeMap and SyclDeviceTypeMap #include TEST(ParseAllowListTests, CheckAllowListIsEmpty) { sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList(""); sycl::detail::AllowListParsedT ExpectedValue{}; - EXPECT_EQ(ActualValue, ExpectedValue); + EXPECT_EQ(ExpectedValue, ActualValue); } TEST(ParseAllowListTests, CheckAllowListSingleDeviceDesc) { @@ -22,7 +23,7 @@ TEST(ParseAllowListTests, CheckAllowListSingleDeviceDesc) { sycl::detail::AllowListParsedT ExpectedValue{{{"BackendName", "level_zero"}, {"DeviceType", "gpu"}, {"DeviceVendorId", "0x0000"}}}; - EXPECT_EQ(ActualValue, ExpectedValue); + EXPECT_EQ(ExpectedValue, ActualValue); } TEST(ParseAllowListTests, CheckAllowListMultipleDeviceDesc) { @@ -39,16 +40,74 @@ TEST(ParseAllowListTests, CheckAllowListMultipleDeviceDesc) { {{"BackendName", "opencl"}, {"DeviceType", "acc"}, {"DeviceVendorId", "0x4321"}}}; - EXPECT_EQ(ActualValue, ExpectedValue); + EXPECT_EQ(ExpectedValue, ActualValue); } -TEST(ParseAllowListTests, CheckUnsupportedKeyNameIsHandled) { +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(e.what(), std::string("Unrecognized key in SYCL_DEVICE_ALLOWLIST " - "-30 (CL_INVALID_VALUE)")); + 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, + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescWithFirstContainingRegexValue) { + 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, + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescWithFirstContainingFixedValue) { + 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, + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescWithFirstAndSecondContainingRegexValue) { + 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"; } @@ -62,19 +121,20 @@ TEST(ParseAllowListTests, CheckRegexIsProcessedCorrectly) { {{"DeviceName", "regex1"}, {"DriverVersion", "regex1|regex2"}}, {{"PlatformName", "regex3"}, {"PlatformVersion", "regex4|regex5|regex6"}}}; - EXPECT_EQ(ActualValue, ExpectedValue); + 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( - e.what(), std::string( "Key DeviceName of SYCL_DEVICE_ALLOWLIST " - "should have value which starts with {{ -30 (CL_INVALID_VALUE)")); + "should have value which starts with {{ -30 (CL_INVALID_VALUE)"), + e.what()); } catch (...) { FAIL() << "Expected sycl::runtime_error"; } @@ -84,51 +144,63 @@ 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( - e.what(), std::string( "Key DriverVersion of SYCL_DEVICE_ALLOWLIST " - "should have value which ends with }} -30 (CL_INVALID_VALUE)")); + "should have value which ends with }} -30 (CL_INVALID_VALUE)"), + e.what()); } catch (...) { FAIL() << "Expected sycl::runtime_error"; } } TEST(ParseAllowListTests, CheckAllValidBackendNameValuesAreProcessed) { - sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( - "BackendName:host|BackendName:opencl|BackendName:level_zero|BackendName:" - "cuda|BackendName:*"); + 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(ActualValue, ExpectedValue); + 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("DeviceType:host|DeviceType:cpu|DeviceType:" - "gpu|DeviceType:acc|DeviceType:*"); + sycl::detail::parseAllowList(AllowList); sycl::detail::AllowListParsedT ExpectedValue{{{"DeviceType", "host"}}, {{"DeviceType", "cpu"}}, {{"DeviceType", "gpu"}}, {{"DeviceType", "acc"}}, {{"DeviceType", "*"}}}; - EXPECT_EQ(ActualValue, ExpectedValue); + 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(e.what(), - std::string("Value blablabla for key BackendName is not valid in " + 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)")); + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); } catch (...) { FAIL() << "Expected sycl::runtime_error"; } @@ -138,12 +210,13 @@ 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(e.what(), - std::string("Value blablabla for key DeviceType is not valid in " + 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)")); + "EnvironmentVariables.md -30 (CL_INVALID_VALUE)"), + e.what()); } catch (...) { FAIL() << "Expected sycl::runtime_error"; } @@ -153,15 +226,30 @@ 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( - e.what(), std::string("Value blablabla for key DeviceVendorId is not valid in " - "SYCL_DEVICE_ALLOWLIST. It should have hex format. For " + "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)")); + "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); +} From 34535a6c9c34c674c0838c939f4bb9937385270f Mon Sep 17 00:00:00 2001 From: Dmitry Vodopyanov Date: Thu, 3 Jun 2021 11:15:51 +0300 Subject: [PATCH 6/7] Apply CR comments --- sycl/unittests/allowlist/ParseAllowList.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sycl/unittests/allowlist/ParseAllowList.cpp b/sycl/unittests/allowlist/ParseAllowList.cpp index 67265972b1508..adc36121aa6ad 100644 --- a/sycl/unittests/allowlist/ParseAllowList.cpp +++ b/sycl/unittests/allowlist/ParseAllowList.cpp @@ -61,7 +61,7 @@ TEST(ParseAllowListTests, CheckUnsupportedKeyNameIsHandledInSingleDeviceDesc) { TEST( ParseAllowListTests, - CheckUnsupportedKeyNameIsHandledInTwoDeviceDescWithFirstContainingRegexValue) { + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescsFirstContainingRegexValue) { try { sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( "DriverVersion:{{value}}|SomeUnsupportedKey:gpu"); @@ -79,7 +79,7 @@ TEST( TEST( ParseAllowListTests, - CheckUnsupportedKeyNameIsHandledInTwoDeviceDescWithFirstContainingFixedValue) { + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescsFirstContainingFixedValue) { try { sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( "BackendName:level_zero|SomeUnsupportedKey:gpu"); @@ -97,7 +97,7 @@ TEST( TEST( ParseAllowListTests, - CheckUnsupportedKeyNameIsHandledInTwoDeviceDescWithFirstAndSecondContainingRegexValue) { + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescsBothContainingRegexValue) { try { sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( "DriverVersion:{{value1}}|SomeUnsupportedKey:{{value2}}"); From ca7c12cb61465b90488acdd7a0b3eafbd9e4560f Mon Sep 17 00:00:00 2001 From: Dmitry Vodopyanov Date: Thu, 3 Jun 2021 11:39:13 +0300 Subject: [PATCH 7/7] Fix clang-format --- sycl/unittests/allowlist/ParseAllowList.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sycl/unittests/allowlist/ParseAllowList.cpp b/sycl/unittests/allowlist/ParseAllowList.cpp index adc36121aa6ad..5ed854932b730 100644 --- a/sycl/unittests/allowlist/ParseAllowList.cpp +++ b/sycl/unittests/allowlist/ParseAllowList.cpp @@ -95,9 +95,8 @@ TEST( } } -TEST( - ParseAllowListTests, - CheckUnsupportedKeyNameIsHandledInTwoDeviceDescsBothContainingRegexValue) { +TEST(ParseAllowListTests, + CheckUnsupportedKeyNameIsHandledInTwoDeviceDescsBothContainingRegexValue) { try { sycl::detail::AllowListParsedT ActualValue = sycl::detail::parseAllowList( "DriverVersion:{{value1}}|SomeUnsupportedKey:{{value2}}");