Skip to content

[SYCL] Additional support for SYCL_DEVICE_ALLOWLIST #2483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sycl/doc/EnvironmentVariables.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,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 minimum 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. |
| 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 "|".|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| 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: 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 "\|".|

escape required for pipe to visualize properly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks for catching this.

| 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_LEVEL0_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. |
Expand Down
225 changes: 125 additions & 100 deletions sycl/source/detail/platform_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <algorithm>
#include <cstring>
#include <regex>
#include <string>

__SYCL_INLINE_NAMESPACE(cl) {
namespace sycl {
Expand Down Expand Up @@ -120,104 +121,106 @@ vector_class<platform> platform_impl::get_platforms() {
return Platforms;
}

struct DevDescT {
const char *devName = nullptr;
int devNameSize = 0;
const char *devDriverVer = nullptr;
int devDriverVerSize = 0;
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);
}

const char *platformName = nullptr;
int platformNameSize = 0;
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;
}

const char *platformVer = nullptr;
int platformVerSize = 0;
struct DevDescT {
std::string DevName;
std::string DevDriverVer;
std::string PlatName;
std::string PlatVer;
};

static std::vector<DevDescT> getAllowListDesc() {
const char *str = SYCLConfig<SYCL_DEVICE_ALLOWLIST>::get();
if (!str)
std::string AllowList(SYCLConfig<SYCL_DEVICE_ALLOWLIST>::get());
if (AllowList.empty())
return {};

std::vector<DevDescT> decDescs;
const char devNameStr[] = "DeviceName";
const char driverVerStr[] = "DriverVersion";
const char platformNameStr[] = "PlatformName";
const char platformVerStr[] = "PlatformVersion";
decDescs.emplace_back();
while ('\0' != *str) {
const char **valuePtr = nullptr;
int *size = nullptr;

// -1 to avoid comparing null terminator
if (0 == strncmp(devNameStr, str, sizeof(devNameStr) - 1)) {
valuePtr = &decDescs.back().devName;
size = &decDescs.back().devNameSize;
str += sizeof(devNameStr) - 1;
} else if (0 ==
strncmp(platformNameStr, str, sizeof(platformNameStr) - 1)) {
valuePtr = &decDescs.back().platformName;
size = &decDescs.back().platformNameSize;
str += sizeof(platformNameStr) - 1;
} else if (0 == strncmp(platformVerStr, str, sizeof(platformVerStr) - 1)) {
valuePtr = &decDescs.back().platformVer;
size = &decDescs.back().platformVerSize;
str += sizeof(platformVerStr) - 1;
} else if (0 == strncmp(driverVerStr, str, sizeof(driverVerStr) - 1)) {
valuePtr = &decDescs.back().devDriverVer;
size = &decDescs.back().devDriverVerSize;
str += sizeof(driverVerStr) - 1;
} else {
throw sycl::runtime_error("Unrecognized key in device allowlist",
PI_INVALID_VALUE);
std::string DeviceName("DeviceName:");
std::string DriverVersion("DriverVersion:");
std::string PlatformName("PlatformName:");
std::string PlatformVersion("PlatformVersion:");
std::vector<DevDescT> 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++;
}
}

if (':' != *str)
throw sycl::runtime_error("Malformed device allowlist", PI_INVALID_VALUE);

// Skip ':'
str += 1;

if ('{' != *str || '{' != *(str + 1))
throw sycl::runtime_error("Malformed device allowlist", PI_INVALID_VALUE);

// Skip opening sequence "{{"
str += 2;

*valuePtr = str;

// Increment until closing sequence is encountered
while (('\0' != *str) && ('}' != *str || '}' != *(str + 1)))
++str;

if ('\0' == *str)
throw sycl::runtime_error("Malformed device allowlist", PI_INVALID_VALUE);

*size = str - *valuePtr;

// Skip closing sequence "}}"
str += 2;

if ('\0' == *str)
break;
else if ((AllowList.compare(Pos, DriverVersion.size(), DriverVersion)) ==
0) {
DecDescs.back().DevDriverVer =
getValue(AllowList, Pos, DriverVersion.size());
if (AllowList[Pos] == ',') {
Pos++;
}
}

// '|' means that the is another filter
if ('|' == *str)
decDescs.emplace_back();
else if (',' != *str)
throw sycl::runtime_error("Malformed device allowlist", PI_INVALID_VALUE);
else if ((AllowList.compare(Pos, PlatformName.size(), PlatformName)) == 0) {
DecDescs.back().PlatName = getValue(AllowList, Pos, PlatformName.size());
if (AllowList[Pos] == ',') {
Pos++;
}
}

++str;
}
else if ((AllowList.compare(Pos, PlatformVersion.size(),
PlatformVersion)) == 0) {
DecDescs.back().PlatVer =
getValue(AllowList, Pos, PlatformVersion.size());
} else if (AllowList.find('|', Pos) != std::string::npos) {
Pos = AllowList.find('|') + 1;
while (AllowList[Pos] == ' ') {
Pos++;
}
DecDescs.emplace_back();
}

return decDescs;
else {
throw sycl::runtime_error("Unrecognized key in device allowlist",
PI_INVALID_VALUE);
}
} // while (Pos <= AllowList.size())
return DecDescs;
}

enum MatchState { UNKNOWN, MATCH, NOMATCH };

static void filterAllowList(vector_class<RT::PiDevice> &PiDevices,
RT::PiPlatform PiPlatform, const plugin &Plugin) {
const std::vector<DevDescT> AllowList(getAllowListDesc());
if (AllowList.empty())
return;

MatchState DevNameState = UNKNOWN;
MatchState DevVerState = UNKNOWN;
MatchState PlatNameState = UNKNOWN;
MatchState PlatVerState = UNKNOWN;

const string_class PlatformName =
sycl::detail::get_platform_info<string_class, info::platform::name>::get(
PiPlatform, Plugin);
Expand All @@ -237,33 +240,55 @@ static void filterAllowList(vector_class<RT::PiDevice> &PiDevices,
string_class, info::device::driver_version>::get(Device, Plugin);

for (const DevDescT &Desc : AllowList) {
if (nullptr != Desc.platformName &&
!std::regex_match(PlatformName,
std::regex(std::string(Desc.platformName,
Desc.platformNameSize))))
continue;

if (nullptr != Desc.platformVer &&
!std::regex_match(
PlatformVer,
std::regex(std::string(Desc.platformVer, Desc.platformVerSize))))
continue;

if (nullptr != Desc.devName &&
!std::regex_match(DeviceName, std::regex(std::string(
Desc.devName, Desc.devNameSize))))
continue;

if (nullptr != Desc.devDriverVer &&
!std::regex_match(DeviceDriverVer,
std::regex(std::string(Desc.devDriverVer,
Desc.devDriverVerSize))))
continue;
if (!Desc.PlatName.empty()) {
if (!std::regex_match(PlatformName, std::regex(Desc.PlatName))) {
PlatNameState = MatchState::NOMATCH;
continue;
} else {
PlatNameState = MatchState::MATCH;
}
}

if (!Desc.PlatVer.empty()) {
if (!std::regex_match(PlatformVer, std::regex(Desc.PlatVer))) {
PlatVerState = MatchState::NOMATCH;
continue;
} else {
PlatVerState = MatchState::MATCH;
}
}

if (!Desc.DevName.empty()) {
if (!std::regex_match(DeviceName, std::regex(Desc.DevName))) {
DevNameState = MatchState::NOMATCH;
continue;
} else {
DevNameState = MatchState::MATCH;
}
}

if (!Desc.DevDriverVer.empty()) {
if (!std::regex_match(DeviceDriverVer, std::regex(Desc.DevDriverVer))) {
DevVerState = MatchState::NOMATCH;
continue;
} else {
DevVerState = MatchState::MATCH;
}
}

PiDevices[InsertIDx++] = Device;
break;
}
}
if (DevNameState == MatchState::MATCH && DevVerState == MatchState::NOMATCH) {
throw sycl::runtime_error("Requested SYCL device not found",
PI_DEVICE_NOT_FOUND);
}
if (PlatNameState == MatchState::MATCH &&
PlatVerState == MatchState::NOMATCH) {
throw sycl::runtime_error("Requested SYCL platform not found",
PI_DEVICE_NOT_FOUND);
}
PiDevices.resize(InsertIDx);
}

Expand Down
Loading