Skip to content

Commit edb985a

Browse files
authored
[WIP] [SYCL] Add SYCLConfig helper (#859)
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. Currently SYCLConfig can be used from the source directory only. Signed-off-by: Vlad Romanov <[email protected]>
1 parent a7336c2 commit edb985a

File tree

7 files changed

+264
-1
lines changed

7 files changed

+264
-1
lines changed

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: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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/os_util.hpp>
10+
#include <detail/config.hpp>
11+
12+
#include <cstring>
13+
#include <fstream>
14+
#include <iostream>
15+
#include <limits>
16+
17+
#define STRINGIFY_LINE_HELP(s) #s
18+
#define STRINGIFY_LINE(s) STRINGIFY_LINE_HELP(s)
19+
20+
namespace cl {
21+
namespace sycl {
22+
namespace detail {
23+
24+
#ifndef SYCL_CONFIG_FILE_NAME
25+
#define SYCL_CONFIG_FILE_NAME "sycl.conf"
26+
#endif // SYCL_CONFIG_FILE_NAME
27+
28+
#define CONFIG(Name, MaxSize, CompileTimeDef) \
29+
const char *SYCLConfigBase<Name>::MValueFromFile = nullptr; \
30+
char SYCLConfigBase<Name>::MStorage[MaxSize]; \
31+
const char *const SYCLConfigBase<Name>::MCompileTimeDef = \
32+
getStrOrNullptr(STRINGIFY_LINE(CompileTimeDef)); \
33+
const char *const SYCLConfigBase<Name>::MConfigName = STRINGIFY_LINE(Name);
34+
#include "detail/config.def"
35+
#undef CONFIG
36+
37+
#define MAX_CONFIG_NAME 256
38+
39+
static void initValue(const char *Key, const char *Value) {
40+
#define CONFIG(Name, MaxSize, CompileTimeDef) \
41+
if (0 == strncmp(Key, SYCLConfigBase<Name>::MConfigName, MAX_CONFIG_NAME)) { \
42+
strncpy(SYCLConfigBase<Name>::MStorage, Value, MaxSize); \
43+
SYCLConfigBase<Name>::MValueFromFile = SYCLConfigBase<Name>::MStorage; \
44+
return; \
45+
}
46+
#include "detail/config.def"
47+
#undef CONFIG
48+
}
49+
50+
void readConfig() {
51+
static bool Initialized = false;
52+
if (Initialized)
53+
return;
54+
55+
std::fstream File;
56+
if (const char *ConfigFile = getenv("SYCL_CONFIG_FILE_NAME"))
57+
File.open(ConfigFile, std::ios::in);
58+
else {
59+
const std::string LibSYCLDir = sycl::detail::OSUtil::getCurrentDSODir();
60+
File.open(LibSYCLDir + sycl::detail::OSUtil::DirSep + SYCL_CONFIG_FILE_NAME,
61+
std::ios::in);
62+
}
63+
64+
if (File.is_open()) {
65+
// TODO: Use max size from macro instead of 256
66+
char Key[MAX_CONFIG_NAME] = {0}, Value[256] = {0};
67+
while (!File.eof()) {
68+
// Expected fromat:
69+
// ConfigName=Value\r
70+
// ConfigName=Value
71+
// 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?
76+
File.clear(File.rdstate() & ~std::ios_base::failbit);
77+
File.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
78+
continue;
79+
}
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');
89+
}
90+
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+
96+
initValue(Key, Value);
97+
}
98+
}
99+
Initialized = true;
100+
}
101+
102+
// Prints configs name with their value
103+
void dumpConfig() {
104+
#define CONFIG(Name, MaxSize, CompileTimeDef) \
105+
const char *Val = SYCLConfig<Name>::get(); \
106+
std::cerr << SYCLConfigBase<Name>::MConfigName << " : " \
107+
<< (Val ? Val : "unset") << std::endl;
108+
#include "detail/config.def"
109+
#undef CONFIG
110+
}
111+
112+
} // namespace cl
113+
} // namespace sycl
114+
} // namespace detail
115+
116+
#undef STRINGIFY_LINE_HELP
117+
#undef STRINGIFY_LINE

sycl/source/detail/config.def

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Syntax:
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+

sycl/source/detail/config.hpp

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/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 "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/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ configure_lit_site_cfg(
2929
list(APPEND SYCL_TEST_DEPS
3030
sycl-toolchain
3131
FileCheck
32+
not
3233
get_device_count_by_type
3334
llvm-config
3435
)

sycl/test/config/config.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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 %t.out
9+
// RUN: echo "SYCL_PRINT_EXECUTION_GRAPH=always" > %t.cfg
10+
// RUN: env SYCL_CONFIG_FILE_NAME=%t.cfg %t.out
11+
// RUN: ls | grep dot
12+
// RUN: rm *.dot
13+
// RUN: env SYCL_PRINT_EXECUTION_GRAPH=always %t.out
14+
// RUN: ls | grep dot
15+
// RUN: rm *.dot
16+
// RUN: %t.out
17+
// RUN: ls | not grep dot
18+
19+
#include <CL/sycl.hpp>
20+
21+
using namespace cl;
22+
23+
int main() {
24+
sycl::buffer<int, 1> Buf(sycl::range<1>{1});
25+
auto Acc = Buf.get_access<sycl::access::mode::read>();
26+
}

0 commit comments

Comments
 (0)