Skip to content

Commit 2a35df0

Browse files
[SYCL] Fix SYCL config processing for DPC++ RT (#4366)
Fix SYCL configuration file processing for DPCPP runtime. The reason for this change is that the config for SYCL broke from the simplest changes, for example, from a comment in the config. Without these changes, it was a dangerous code that may fail and even don't send an error. What's new: 1. Rewritten line processing; 2. Supported format: 3. ConfigName=Value #comment; 4. Skip lines which do not contain variables; 5. Throw error message if variable is incorrect; 6. Several tests for new functionality.
1 parent 6e02880 commit 2a35df0

File tree

6 files changed

+346
-26
lines changed

6 files changed

+346
-26
lines changed

sycl/source/detail/config.cpp

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ namespace detail {
3333
#include "detail/config.def"
3434
#undef CONFIG
3535

36-
#define MAX_CONFIG_NAME 256
37-
3836
static void initValue(const char *Key, const char *Value) {
3937
#define CONFIG(Name, MaxSize, CompileTimeDef) \
4038
if (0 == strncmp(Key, SYCLConfigBase<Name>::MConfigName, MAX_CONFIG_NAME)) { \
@@ -47,10 +45,11 @@ static void initValue(const char *Key, const char *Value) {
4745
#undef CONFIG
4846
}
4947

50-
void readConfig() {
48+
void readConfig(bool ForceInitialization) {
5149
static bool Initialized = false;
52-
if (Initialized)
50+
if (!ForceInitialization && Initialized) {
5351
return;
52+
}
5453

5554
std::fstream File;
5655
if (const char *ConfigFile = getenv("SYCL_CONFIG_FILE_NAME"))
@@ -62,39 +61,85 @@ void readConfig() {
6261
}
6362

6463
if (File.is_open()) {
65-
// TODO: Use max size from macro instead of 256
66-
char Key[MAX_CONFIG_NAME] = {0}, Value[256] = {0};
64+
char Key[MAX_CONFIG_NAME] = {0}, Value[MAX_CONFIG_VALUE] = {0};
65+
std::string BufString;
66+
std::size_t Position = std::string::npos;
6767
while (!File.eof()) {
68-
// Expected fromat:
68+
// Expected format:
6969
// ConfigName=Value\r
70+
// ConfigName=Value #comment
7071
// ConfigName=Value
7172
// TODO: Skip spaces before and after '='
72-
File.getline(Key, sizeof(Key), '=');
73-
if (File.fail()) {
74-
// Fail to process the line. Skip it completely and try next one.
75-
// Do we want to restore here? Or just throw an exception?
73+
std::getline(File, BufString);
74+
if (File.fail() && !File.eof()) {
75+
// Fail to process the line.
7676
File.clear(File.rdstate() & ~std::ios_base::failbit);
7777
File.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
78+
throw sycl::exception(
79+
make_error_code(errc::runtime),
80+
"An error occurred while attempting to read a line");
81+
}
82+
// Handle '\r'
83+
if ((BufString.length() > 0) &&
84+
(BufString[BufString.length() - 1] == '\r')) {
85+
BufString.pop_back();
86+
}
87+
// Handle comments
88+
if (BufString.find("#") != std::string::npos) {
89+
BufString.erase(BufString.find("#"));
90+
while ((BufString.length() > 0) &&
91+
(BufString[BufString.length() - 1] == ' ')) {
92+
BufString.pop_back();
93+
}
94+
}
95+
// Skip lines with a length = 0 or which don't have "="
96+
if ((BufString.length() == 0) ||
97+
(BufString.find("=") == std::string::npos)) {
7898
continue;
7999
}
80-
File.getline(Value, sizeof(Value), '\n');
81-
82-
if (File.fail()) {
83-
// Fail to process the value while config name is OK. It's likely that
84-
// value is too long. Currently just deal what we have got and ignore
85-
// remaining characters on the line.
86-
// Do we want to restore here? Or just throw an exception?
87-
File.clear(File.rdstate() & ~std::ios_base::failbit);
88-
File.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
100+
// Finding the position of '='
101+
Position = BufString.find("=");
102+
// Checking that the variable name is less than MAX_CONFIG_NAME and more
103+
// than zero character
104+
if ((Position <= MAX_CONFIG_NAME) && (Position > 0)) {
105+
// Checking that the value is less than MAX_CONFIG_VALUE and
106+
// more than zero character
107+
if ((BufString.length() - (Position + 1) <= MAX_CONFIG_VALUE) &&
108+
(BufString.length() != Position + 1)) {
109+
// Checking for spaces at the beginning and end of the line,
110+
// before and after '='
111+
if ((BufString[0] == ' ') ||
112+
(BufString[BufString.length() - 1] == ' ') ||
113+
(BufString[Position - 1] == ' ') ||
114+
(BufString[Position + 1] == ' ')) {
115+
throw sycl::exception(
116+
make_error_code(errc::runtime),
117+
"SPACE found at the beginning/end of the line "
118+
"or before/after '='");
119+
}
120+
// Creating pairs of (key, value)
121+
BufString.copy(Key, Position, 0);
122+
Key[Position] = '\0';
123+
BufString.copy(Value, BufString.length() - (Position + 1),
124+
Position + 1);
125+
Value[BufString.length() - (Position + 1)] = '\0';
126+
} else {
127+
throw sycl::exception(
128+
make_error_code(errc::runtime),
129+
"The value contains more than " +
130+
std::to_string(MAX_CONFIG_VALUE) +
131+
" characters or does not contain them at all");
132+
}
133+
} else {
134+
throw sycl::exception(make_error_code(errc::runtime),
135+
"Variable name is more than " +
136+
std::to_string(MAX_CONFIG_NAME) +
137+
" or less than one character");
89138
}
90139

91-
// Handle '\r' by nullifying it
92-
const std::streamsize ReadSybmols = File.gcount();
93-
if (ReadSybmols > 1 && '\r' == Value[ReadSybmols - 2])
94-
Value[ReadSybmols - 2] = '\0';
95-
96140
initValue(Key, Value);
97141
}
142+
File.close();
98143
}
99144
Initialized = true;
100145
}

sycl/source/detail/config.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ constexpr bool ConfigFromCompileDefEnabled = false;
4343
constexpr bool ConfigFromCompileDefEnabled = true;
4444
#endif // DISABLE_CONFIG_FROM_COMPILE_TIME
4545

46+
constexpr int MAX_CONFIG_NAME = 256;
47+
constexpr int MAX_CONFIG_VALUE = 256;
48+
4649
// Enum of config IDs for accessing other arrays
4750
enum ConfigID {
4851
START = 0,
@@ -58,7 +61,7 @@ constexpr const char *getStrOrNullptr(const char *Str) {
5861
}
5962

6063
// Intializes configs from the configuration file
61-
void readConfig();
64+
void readConfig(bool ForceInitialization = false);
6265

6366
template <ConfigID Config> class SYCLConfigBase;
6467

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clangxx -fsycl %s -o %t.out
2+
//
3+
// RUN: env TEST=SET_CORRECT_ENVIRONMENT %t.out > %t.conf
4+
// RUN: env TEST=CORRECT_CONFIG_FILE env SYCL_CONFIG_FILE_NAME=%t.conf %t.out
5+
// RUN: ls *.dot
6+
// RUN: rm *.dot
7+
8+
#include <CL/sycl.hpp>
9+
#include <iostream>
10+
#include <regex>
11+
12+
int main() {
13+
std::string testEnvVarValue = getenv("TEST");
14+
15+
// Сonfig creation
16+
if (testEnvVarValue == "SET_CORRECT_ENVIRONMENT") {
17+
std::cout << "#\n"
18+
<< "#abc\n"
19+
<< "# abc = cba \r\n"
20+
<< "\r\n"
21+
<< "SYCL_PRINT_EXECUTION_GRAPH=always\r\n"
22+
<< std::endl;
23+
return 0;
24+
}
25+
26+
// Config check
27+
if (testEnvVarValue == "CORRECT_CONFIG_FILE") {
28+
sycl::buffer<int, 1> Buf(sycl::range<1>{1});
29+
auto Acc = Buf.get_access<sycl::access::mode::read>();
30+
return 0;
31+
}
32+
throw std::logic_error("Environment is incorrect");
33+
}

sycl/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ string(TOLOWER "${CMAKE_BUILD_TYPE}" build_type_lower)
1212
include(AddSYCLUnitTest)
1313

1414
add_subdirectory(allowlist)
15+
add_subdirectory(config)
1516
add_subdirectory(misc)
1617
add_subdirectory(pi)
1718
add_subdirectory(kernel-and-program)

sycl/unittests/config/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
set(CMAKE_CXX_EXTENSIONS OFF)
2+
3+
# Enable exception handling for these unit tests
4+
set(LLVM_REQUIRES_EH 1)
5+
add_sycl_unittest(ConfigTests OBJECT
6+
ConfigTests.cpp
7+
)

0 commit comments

Comments
 (0)