Skip to content

Commit cb46557

Browse files
committed
[SYCL] Add SYCLConfig helper
SYCLConfig helper provides an access to configs that is defined in config.hpp. Such configs can be set at compile time, using environment variable and configuration file. SYCLConfig checks all the sources and return value which was set using an option which has highest priority. Current priorities are: 1. Environment variable 2. Configuration file 3. Compiler time If a value is not set nullptr is returned. Signed-off-by: Vlad Romanov <[email protected]>
1 parent 0c717f8 commit cb46557

File tree

6 files changed

+261
-1
lines changed

6 files changed

+261
-1
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Singnature:
2+
// CONFIG(CONFIG_NAME, VALUE_MAX_SIZE_IN_BYTES, COMPILE_TIME_CONFIG_NAME)
3+
//
4+
// CONFIG_NAME is used as a specifier to access specific config using
5+
// SYCLConfig class. It is also used in order to determine a config key when
6+
// reading the configuration file.
7+
// VALUE_MAX_SIZE_IN_BYTES is used as a maximum size of a storage when reading
8+
// configs from the configuration file.
9+
// COMPILE_TIME_CONFIG_NAME is a name of compile time macro which can be used
10+
// to set a value of a config. COMPILE_TIME_CONFIG_NAME must start with double
11+
// underscore(__).
12+
13+
CONFIG(SYCL_PRINT_EXECUTION_GRAPH, 32, __SYCL_PRINT_EXECUTION_GRAPH)
14+
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//==---------------- config.hpp - SYCL context ------------------*- C++-*---==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#pragma once
10+
11+
#include <cstdlib>
12+
13+
namespace cl {
14+
namespace sycl {
15+
namespace detail {
16+
17+
#ifdef DISABLE_CONFIG_FROM_ENV
18+
constexpr bool ConfigFromEnvEnabled = false;
19+
#else
20+
constexpr bool ConfigFromEnvEnabled = true;
21+
#endif // DISABLE_CONFIG_FROM_ENV
22+
23+
#ifdef DISABLE_CONFIG_FROM_CONFIG_FILE
24+
constexpr bool ConfigFromFileEnabled = false;
25+
#else
26+
constexpr bool ConfigFromFileEnabled = true;
27+
#endif // DISABLE_CONFIG_FROM_CONFIG_FILE
28+
29+
#ifdef DISABLE_CONFIG_FROM_COMPILE_TIME
30+
constexpr bool ConfigFromCompileDefEnabled = false;
31+
#else
32+
constexpr bool ConfigFromCompileDefEnabled = true;
33+
#endif // DISABLE_CONFIG_FROM_COMPILE_TIME
34+
35+
// Enum of config IDs for accessing other arrays
36+
enum ConfigID {
37+
START = 0,
38+
#define CONFIG(name, ...) name,
39+
#include "config.def"
40+
#undef CONFIG
41+
END
42+
};
43+
44+
// Consider strings starting with __ as unset
45+
constexpr const char *getStrOrNullptr(const char *Str) {
46+
return (Str[0] == '_' && Str[1] == '_') ? nullptr : Str;
47+
}
48+
49+
template <ConfigID Config> class SYCLConfigBase;
50+
51+
#define CONFIG(Name, MaxSize, CompileTimeDef) \
52+
template <> class SYCLConfigBase<Name> { \
53+
public: \
54+
/*Preallocated storage for config value which is extracted from a config \
55+
* file*/ \
56+
static char MStorage[MaxSize]; \
57+
/*Points to the storage if config is set in the file, nullptr otherwise*/ \
58+
static const char *MValueFromFile; \
59+
/*The name of the config*/ \
60+
static const char *const MConfigName; \
61+
/*Points to the value which is set during compilation, nullptr otherwise. \
62+
* Detection of whether a value is set or not is based on checking the \
63+
* beginning of the string, if it starts with double underscore(__) the \
64+
* value is not set.*/ \
65+
static const char *const MCompileTimeDef; \
66+
};
67+
#include "config.def"
68+
#undef CONFIG
69+
70+
// Intializes configs from the configuration file
71+
void readConfig();
72+
73+
template <ConfigID Config> class SYCLConfig {
74+
using BaseT = SYCLConfigBase<Config>;
75+
76+
public:
77+
static const char *get() {
78+
const char *ValStr = getRawValue();
79+
return ValStr;
80+
}
81+
82+
private:
83+
static const char *getRawValue() {
84+
if (ConfigFromEnvEnabled)
85+
if (const char *ValStr = getenv(BaseT::MConfigName))
86+
return ValStr;
87+
88+
if (ConfigFromFileEnabled) {
89+
readConfig();
90+
if (BaseT::MValueFromFile)
91+
return BaseT::MValueFromFile;
92+
}
93+
94+
if (ConfigFromCompileDefEnabled && BaseT::MCompileTimeDef)
95+
return BaseT::MCompileTimeDef;
96+
97+
return nullptr;
98+
}
99+
};
100+
101+
} // namespace cl
102+
} // namespace sycl
103+
} // namespace detail

sycl/source/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ set(SYCL_SOURCES
4343
"detail/builtins_relational.cpp"
4444
"detail/pi.cpp"
4545
"detail/common.cpp"
46+
"detail/config.cpp"
4647
"detail/context_impl.cpp"
4748
"detail/device_impl.cpp"
4849
"detail/device_info.cpp"

sycl/source/detail/config.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//==---------------- config.cpp ---------------------------------*- C++-*---==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <CL/sycl/detail/config.hpp>
10+
11+
#include <cstring>
12+
#include <fstream>
13+
#include <iostream>
14+
#include <limits>
15+
16+
#define STRINGIFY_LINE_HELP(s) #s
17+
#define STRINGIFY_LINE(s) STRINGIFY_LINE_HELP(s)
18+
19+
namespace cl {
20+
namespace sycl {
21+
namespace detail {
22+
23+
#ifndef SYCL_CONFIG_NAME
24+
#define SYCL_CONFIG_NAME sycl.cfg
25+
#endif // SYCL_CONFIG_NAME
26+
27+
#define CONFIG(Name, MaxSize, CompileTimeDef) \
28+
const char *SYCLConfigBase<Name>::MValueFromFile = nullptr; \
29+
char SYCLConfigBase<Name>::MStorage[MaxSize]; \
30+
const char *const SYCLConfigBase<Name>::MCompileTimeDef = \
31+
getStrOrNullptr(STRINGIFY_LINE(CompileTimeDef)); \
32+
const char *const SYCLConfigBase<Name>::MConfigName = STRINGIFY_LINE(Name);
33+
#include <CL/sycl/detail/config.def>
34+
#undef CONFIG
35+
36+
#define MAX_CONFIG_NAME 256
37+
38+
static void initValue(const char *Key, const char *Value) {
39+
#define CONFIG(Name, MaxSize, CompileTimeDef) \
40+
if (0 == strncmp(Key, SYCLConfigBase<Name>::MConfigName, MAX_CONFIG_NAME)) { \
41+
strcpy(SYCLConfigBase<Name>::MStorage, Value); \
42+
SYCLConfigBase<Name>::MValueFromFile = SYCLConfigBase<Name>::MStorage; \
43+
return; \
44+
}
45+
#include <CL/sycl/detail/config.def>
46+
#undef CONFIG
47+
}
48+
49+
void readConfig() {
50+
static bool Initialized = false;
51+
if (Initialized)
52+
return;
53+
std::fstream File;
54+
// TODO: Find libsycl.so location.
55+
static const char *ConfigFile = getenv("SYCL_CONFIG_FILE");
56+
const char *FileToLoad =
57+
ConfigFile ? ConfigFile : STRINGIFY_LINE(SYCL_CONFIG_NAME);
58+
File.open(FileToLoad, std::ios::in);
59+
if (File.is_open()) {
60+
// TODO: Use max size from macro instead of 256
61+
char Key[MAX_CONFIG_NAME] = {0}, Value[256] = {0};
62+
while (!File.eof()) {
63+
// Expected fromat:
64+
// ConfigName=Value
65+
// ConfigName=Value
66+
// TODO: Skip spaces before and after '='
67+
File.getline(Key, sizeof(Key), '=');
68+
if (File.fail()) {
69+
// Fail to process the line. Skip it completely and try next one.
70+
// Do we want to restore here? Or just throw an exception?
71+
File.clear(File.rdstate() & ~std::ios_base::failbit);
72+
File.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
73+
continue;
74+
}
75+
File.getline(Value, sizeof(Value), '\n');
76+
if (File.fail()) {
77+
// Fail to process the value while config name is OK. It's likely that
78+
// value is too long. Currently just deal what we have got and ignore
79+
// remaining characters on the line.
80+
// Do we want to restore here? Or just throw an exception?
81+
File.clear(File.rdstate() & ~std::ios_base::failbit);
82+
File.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
83+
}
84+
initValue(Key, Value);
85+
}
86+
}
87+
Initialized = true;
88+
}
89+
90+
// Prints configs name with their value
91+
void dumpConfig() {
92+
#define CONFIG(Name, MaxSize, CompileTimeDef) \
93+
const char *Val = SYCLConfig<Name>::get(); \
94+
std::cerr << SYCLConfigBase<Name>::MConfigName << " : " \
95+
<< (Val ? Val : "unset") << std::endl;
96+
#include <CL/sycl/detail/config.def>
97+
#undef CONFIG
98+
}
99+
100+
} // namespace cl
101+
} // namespace sycl
102+
} // namespace detail
103+
104+
#undef STRINGIFY_LINE_HELP
105+
#undef STRINGIFY_LINE

sycl/source/detail/scheduler/graph_builder.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include <CL/sycl/access/access.hpp>
10+
#include <CL/sycl/detail/config.hpp>
1011
#include <CL/sycl/detail/event_impl.hpp>
1112
#include <CL/sycl/detail/memory_manager.hpp>
1213
#include <CL/sycl/detail/queue_impl.hpp>
@@ -46,7 +47,7 @@ static bool IsSuitableSubReq(const Requirement *Req) {
4647
}
4748

4849
Scheduler::GraphBuilder::GraphBuilder() {
49-
if (const char *EnvVarCStr = std::getenv("SYCL_PRINT_EXECUTION_GRAPH")) {
50+
if (const char *EnvVarCStr = SYCLConfig<SYCL_PRINT_EXECUTION_GRAPH>::get()) {
5051
std::string GraphPrintOpts(EnvVarCStr);
5152
bool EnableAlways = GraphPrintOpts.find("always") != std::string::npos;
5253

sycl/test/config/config.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//==---- config.cpp --------------------------------------------------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// RUN: %clangxx -g -O0 -fsycl %s -o %t1.out
9+
// RUN: %clangxx -g -O0 -fsycl %s -o %t2.out
10+
// RUN: echo "SYCL_PRINT_EXECUTION_GRAPH=ValueFromConfigFile" > %t3.cfg
11+
// RUN: env SYCL_CONFIG_FILE=%t3.cfg env SYCL_PRINT_EXECUTION_GRAPH=VlaueFromEnvVar %t1.out
12+
// RUN: env SYCL_CONFIG_FILE=%t3.cfg %t1.out
13+
// RUN: %t2.out
14+
15+
#include <CL/sycl/detail/config.hpp>
16+
17+
#include <cstring>
18+
19+
int main() {
20+
const char *Val = cl::sycl::detail::SYCLConfig<
21+
cl::sycl::detail::SYCL_PRINT_EXECUTION_GRAPH>::get();
22+
23+
if (getenv("SYCL_PRINT_EXECUTION_GRAPH")) {
24+
if (!Val)
25+
return 1;
26+
return strcmp(Val, "VlaueFromEnvVar");
27+
}
28+
29+
if (getenv("SYCL_CONFIG_FILE")) {
30+
if(!Val)
31+
return 1;
32+
return strcmp(Val, "ValueFromConfigFile");
33+
}
34+
35+
return nullptr != Val;
36+
}

0 commit comments

Comments
 (0)