DPC++ Runtime
Runtime libraries for oneAPI DPC++
config.hpp
Go to the documentation of this file.
1 //==---------------- config.hpp - SYCL config -------------------*- 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 
12 #include <sycl/backend_types.hpp>
13 #include <sycl/detail/defines.hpp>
15 #include <sycl/detail/pi.hpp>
16 #include <sycl/info/info_desc.hpp>
17 
18 #include <algorithm>
19 #include <array>
20 #include <cstdlib>
21 #include <mutex>
22 #include <string>
23 #include <utility>
24 
25 namespace sycl {
27 namespace detail {
28 
29 #ifdef DISABLE_CONFIG_FROM_ENV
30 constexpr bool ConfigFromEnvEnabled = false;
31 #else
32 constexpr bool ConfigFromEnvEnabled = true;
33 #endif // DISABLE_CONFIG_FROM_ENV
34 
35 #ifdef DISABLE_CONFIG_FROM_CONFIG_FILE
36 constexpr bool ConfigFromFileEnabled = false;
37 #else
38 constexpr bool ConfigFromFileEnabled = true;
39 #endif // DISABLE_CONFIG_FROM_CONFIG_FILE
40 
41 #ifdef DISABLE_CONFIG_FROM_COMPILE_TIME
42 constexpr bool ConfigFromCompileDefEnabled = false;
43 #else
44 constexpr bool ConfigFromCompileDefEnabled = true;
45 #endif // DISABLE_CONFIG_FROM_COMPILE_TIME
46 
47 constexpr int MAX_CONFIG_NAME = 256;
48 constexpr int MAX_CONFIG_VALUE = 1024;
49 
50 // Enum of config IDs for accessing other arrays
51 enum ConfigID {
52  START = 0,
53 #define CONFIG(name, ...) name,
54 #include "config.def"
55 #undef CONFIG
56  END
57 };
58 
59 // Consider strings starting with __ as unset
60 constexpr const char *getStrOrNullptr(const char *Str) {
61  return (Str[0] == '_' && Str[1] == '_') ? nullptr : Str;
62 }
63 
64 // Intializes configs from the configuration file
65 void readConfig(bool ForceInitialization = false);
66 
67 template <ConfigID Config> class SYCLConfigBase;
68 
69 #define CONFIG(Name, MaxSize, CompileTimeDef) \
70  template <> class SYCLConfigBase<Name> { \
71  public: \
72  /*Preallocated storage for config value which is extracted from a config \
73  * file*/ \
74  static char MStorage[MaxSize + 1]; \
75  /*Points to the storage if config is set in the file, nullptr otherwise*/ \
76  static const char *MValueFromFile; \
77  /*The name of the config*/ \
78  static const char *const MConfigName; \
79  /*Points to the value which is set during compilation, nullptr otherwise. \
80  * Detection of whether a value is set or not is based on checking the \
81  * beginning of the string, if it starts with double underscore(__) the \
82  * value is not set.*/ \
83  static const char *const MCompileTimeDef; \
84  \
85  static const char *getRawValue() { \
86  if (ConfigFromEnvEnabled) \
87  if (const char *ValStr = getenv(MConfigName)) \
88  return ValStr; \
89  \
90  if (ConfigFromFileEnabled) { \
91  readConfig(); \
92  if (MValueFromFile) \
93  return MValueFromFile; \
94  } \
95  \
96  if (ConfigFromCompileDefEnabled && MCompileTimeDef) \
97  return MCompileTimeDef; \
98  \
99  return nullptr; \
100  } \
101  };
102 #include "config.def"
103 #undef CONFIG
104 
105 #define INVALID_CONFIG_EXCEPTION(BASE, MSG) \
106  sycl::exception(sycl::make_error_code(sycl::errc::invalid), \
107  "Invalid value for " + std::string{BASE::MConfigName} + \
108  " environment variable: " + MSG)
109 
110 template <ConfigID Config> class SYCLConfig {
112 
113 public:
114  static const char *get() { return getCachedValue(); }
115 
116  static void reset() { (void)getCachedValue(/*ResetCache=*/true); }
117 
118  static const char *getName() { return BaseT::MConfigName; }
119 
120 private:
121  static const char *getCachedValue(bool ResetCache = false) {
122  static const char *ValStr = BaseT::getRawValue();
123  if (ResetCache)
124  ValStr = BaseT::getRawValue();
125  return ValStr;
126  }
127 };
128 
129 template <> class SYCLConfig<SYCL_PI_TRACE> {
131 
132 public:
133  static int get() {
134  static bool Initialized = false;
135  // We don't use TraceLevel enum here because user can provide any bitmask
136  // which can correspond to several enum values.
137  static int Level = 0; // No tracing by default
138 
139  // Configuration parameters are processed only once, like reading a string
140  // from environment and converting it into a typed object.
141  if (Initialized)
142  return Level;
143 
144  const char *ValStr = BaseT::getRawValue();
145  Level = (ValStr ? std::atoi(ValStr) : 0);
146  Initialized = true;
147  return Level;
148  }
149 };
150 
151 template <> class SYCLConfig<SYCL_RT_WARNING_LEVEL> {
153 
154 public:
155  static unsigned int get() { return getCachedValue(); }
156 
157  static void reset() { (void)getCachedValue(true); }
158 
159 private:
160  static unsigned int getCachedValue(bool ResetCache = false) {
161  const auto Parser = []() {
162  const char *ValStr = BaseT::getRawValue();
163  int SignedLevel = ValStr ? std::atoi(ValStr) : 0;
164  return SignedLevel >= 0 ? SignedLevel : 0;
165  };
166 
167  static unsigned int Level = Parser();
168  if (ResetCache)
169  Level = Parser();
170 
171  return Level;
172  }
173 };
174 
175 template <> class SYCLConfig<SYCL_PARALLEL_FOR_RANGE_ROUNDING_TRACE> {
177 
178 public:
179  static bool get() {
180  static const char *ValStr = BaseT::getRawValue();
181  return ValStr != nullptr;
182  }
183 };
184 
185 template <> class SYCLConfig<SYCL_DISABLE_PARALLEL_FOR_RANGE_ROUNDING> {
187 
188 public:
189  static bool get() {
190  static const char *ValStr = BaseT::getRawValue();
191  return ValStr != nullptr;
192  }
193 };
194 
195 template <> class SYCLConfig<SYCL_PARALLEL_FOR_RANGE_ROUNDING_PARAMS> {
197 
198 private:
199 public:
200  static void GetSettings(size_t &MinFactor, size_t &GoodFactor,
201  size_t &MinRange) {
202  static const char *RoundParams = BaseT::getRawValue();
203  if (RoundParams == nullptr)
204  return;
205 
206  static bool ProcessedFactors = false;
207  static size_t MF;
208  static size_t GF;
209  static size_t MR;
210  if (!ProcessedFactors) {
211  // Parse optional parameters of this form (all values required):
212  // MinRound:PreferredRound:MinRange
213  std::string Params(RoundParams);
214  size_t Pos = Params.find(':');
215  if (Pos != std::string::npos) {
216  MF = std::stoi(Params.substr(0, Pos));
217  Params.erase(0, Pos + 1);
218  Pos = Params.find(':');
219  if (Pos != std::string::npos) {
220  GF = std::stoi(Params.substr(0, Pos));
221  Params.erase(0, Pos + 1);
222  MR = std::stoi(Params);
223  }
224  }
225  ProcessedFactors = true;
226  }
227  MinFactor = MF;
228  GoodFactor = GF;
229  MinRange = MR;
230  }
231 };
232 
233 // Array is used by SYCL_DEVICE_FILTER and SYCL_DEVICE_ALLOWLIST and
234 // ONEAPI_DEVICE_SELECTOR
235 const std::array<std::pair<std::string, info::device_type>, 6> &
237 
238 // Array is used by SYCL_DEVICE_FILTER and SYCL_DEVICE_ALLOWLIST and
239 // ONEAPI_DEVICE_SELECTOR
240 const std::array<std::pair<std::string, backend>, 7> &getSyclBeMap();
241 
242 // ---------------------------------------
243 // ONEAPI_DEVICE_SELECTOR support
244 template <> class SYCLConfig<ONEAPI_DEVICE_SELECTOR> {
246 
247 public:
248  static ods_target_list *get() {
249  // Configuration parameters are processed only once, like reading a string
250  // from environment and converting it into a typed object.
251  static bool Initialized = false;
252  static ods_target_list *DeviceTargets = nullptr;
253 
254  if (Initialized) {
255  return DeviceTargets;
256  }
257  const char *ValStr = BaseT::getRawValue();
258  if (ValStr) {
259  DeviceTargets =
260  &GlobalHandler::instance().getOneapiDeviceSelectorTargets(ValStr);
261  }
262  Initialized = true;
263  return DeviceTargets;
264  }
265 };
266 
267 // ---------------------------------------
268 // SYCL_DEVICE_FILTER support
269 
270 template <>
271 class __SYCL2020_DEPRECATED("Use SYCLConfig<ONEAPI_DEVICE_SELECTOR> instead")
272  SYCLConfig<SYCL_DEVICE_FILTER> {
273  using BaseT = SYCLConfigBase<SYCL_DEVICE_FILTER>;
274 
275 public:
276  static device_filter_list *get() {
277  static bool Initialized = false;
278  static device_filter_list *FilterList = nullptr;
279 
280  // Configuration parameters are processed only once, like reading a string
281  // from environment and converting it into a typed object.
282  if (Initialized) {
283  return FilterList;
284  }
285 
286  const char *ValStr = BaseT::getRawValue();
287  if (ValStr) {
288 
289  std::cerr
290  << "\nWARNING: The enviroment variable SYCL_DEVICE_FILTER"
291  " is deprecated. Please use ONEAPI_DEVICE_SELECTOR instead.\n"
292  "For more details, please refer to:\n"
293  "https://github.com/intel/llvm/blob/sycl/sycl/doc/"
294  "EnvironmentVariables.md#oneapi_device_selector\n\n";
295 
296  FilterList = &GlobalHandler::instance().getDeviceFilterList(ValStr);
297  }
298 
299  // As mentioned above, configuration parameters are processed only once.
300  // If multiple threads are checking this env var at the same time,
301  // they will end up setting the configration to the same value.
302  // If other threads check after one thread already set configration,
303  // the threads will get the same value as the first thread.
304  Initialized = true;
305  return FilterList;
306  }
307 };
308 
309 template <> class SYCLConfig<SYCL_ENABLE_DEFAULT_CONTEXTS> {
311 
312 public:
313  static bool get() {
314 #ifdef WIN32
315  constexpr bool DefaultValue = false;
316 #else
317  constexpr bool DefaultValue = true;
318 #endif
319 
320  const char *ValStr = getCachedValue();
321 
322  if (!ValStr)
323  return DefaultValue;
324 
325  return ValStr[0] == '1';
326  }
327 
328  static void reset() { (void)getCachedValue(/*ResetCache=*/true); }
329 
330  static const char *getName() { return BaseT::MConfigName; }
331 
332 private:
333  static const char *getCachedValue(bool ResetCache = false) {
334  static const char *ValStr = BaseT::getRawValue();
335  if (ResetCache)
336  ValStr = BaseT::getRawValue();
337  return ValStr;
338  }
339 };
340 
341 template <> class SYCLConfig<SYCL_QUEUE_THREAD_POOL_SIZE> {
343 
344 public:
345  static int get() {
346  static int Value = [] {
347  const char *ValueStr = BaseT::getRawValue();
348 
349  int Result = 1;
350 
351  if (ValueStr)
352  try {
353  Result = std::stoi(ValueStr);
354  } catch (...) {
355  throw invalid_parameter_error(
356  "Invalid value for SYCL_QUEUE_THREAD_POOL_SIZE environment "
357  "variable: value should be a number",
358  PI_ERROR_INVALID_VALUE);
359  }
360 
361  if (Result < 1)
362  throw invalid_parameter_error(
363  "Invalid value for SYCL_QUEUE_THREAD_POOL_SIZE environment "
364  "variable: value should be larger than zero",
365  PI_ERROR_INVALID_VALUE);
366 
367  return Result;
368  }();
369 
370  return Value;
371  }
372 };
373 
374 template <> class SYCLConfig<SYCL_CACHE_PERSISTENT> {
376 
377 public:
378  static constexpr bool Default = false; // default is disabled
379 
380  static bool get() { return getCachedValue(); }
381 
382  static void reset() { (void)getCachedValue(/*ResetCache=*/true); }
383 
384  static const char *getName() { return BaseT::MConfigName; }
385 
386 private:
387  static bool parseValue() {
388  // Check if deprecated opt-out env var is used, then warn.
390  std::cerr
392  << " environment variable is deprecated "
393  << "and has no effect. By default, persistent device code caching is "
394  << (Default ? "enabled." : "disabled.") << " Use " << getName()
395  << "=1/0 to enable/disable.\n";
396  }
397 
398  const char *ValStr = BaseT::getRawValue();
399  if (!ValStr)
400  return Default;
401  if (strlen(ValStr) != 1 || (ValStr[0] != '0' && ValStr[0] != '1')) {
402  std::string Msg =
403  std::string{"Invalid value for bool configuration variable "} +
404  getName() + std::string{": "} + ValStr;
405  throw runtime_error(Msg, PI_ERROR_INVALID_OPERATION);
406  }
407  return ValStr[0] == '1';
408  }
409 
410  static bool getCachedValue(bool ResetCache = false) {
411  static bool Val = parseValue();
412  if (ResetCache)
413  Val = parseValue();
414  return Val;
415  }
416 };
417 
418 template <> class SYCLConfig<SYCL_CACHE_DIR> {
420 
421 public:
422  static std::string get() { return getCachedValue(); }
423 
424  static void reset() { (void)getCachedValue(/*ResetCache=*/true); }
425 
426  static const char *getName() { return BaseT::MConfigName; }
427 
428 private:
429  // If environment variables are not available return an empty string to
430  // identify that cache is not available.
431  static std::string parseValue() {
432  const char *RootDir = BaseT::getRawValue();
433  if (RootDir)
434  return RootDir;
435 
436  constexpr char DeviceCodeCacheDir[] = "/libsycl_cache";
437 
438 #if defined(__SYCL_RT_OS_LINUX)
439  const char *CacheDir = std::getenv("XDG_CACHE_HOME");
440  const char *HomeDir = std::getenv("HOME");
441  if (!CacheDir && !HomeDir)
442  return {};
443  std::string Res{
444  std::string(CacheDir ? CacheDir : (std::string(HomeDir) + "/.cache")) +
445  DeviceCodeCacheDir};
446 #else
447  const char *AppDataDir = std::getenv("AppData");
448  if (!AppDataDir)
449  return {};
450  std::string Res{std::string(AppDataDir) + DeviceCodeCacheDir};
451 #endif
452  return Res;
453  }
454 
455  static std::string getCachedValue(bool ResetCache = false) {
456  static std::string Val = parseValue();
457  if (ResetCache)
458  Val = parseValue();
459  return Val;
460  }
461 };
462 
463 template <> class SYCLConfig<SYCL_REDUCTION_PREFERRED_WORKGROUP_SIZE> {
465 
466  struct ParsedValue {
467  size_t CPU = 0;
468  size_t GPU = 0;
469  size_t Accelerator = 0;
470  };
471 
472 public:
473  static size_t get(info::device_type DeviceType) {
474  ParsedValue Value = getCachedValue();
475  return getRefByDeviceType(Value, DeviceType);
476  }
477 
478  static void reset() { (void)getCachedValue(/*ResetCache=*/true); }
479 
480  static const char *getName() { return BaseT::MConfigName; }
481 
482 private:
483  static size_t &getRefByDeviceType(ParsedValue &Value,
484  info::device_type DeviceType) {
485  switch (DeviceType) {
486  case info::device_type::cpu:
487  return Value.CPU;
488  case info::device_type::gpu:
489  return Value.GPU;
490  case info::device_type::accelerator:
491  return Value.Accelerator;
492  default:
493  // Expect to get here if user used wrong device type. Include wildcard
494  // in the message even though it's handled in the caller.
496  BaseT, "Device types must be \"cpu\", \"gpu\", \"acc\", or \"*\".");
497  }
498  }
499 
500  static ParsedValue parseValue() {
501  const char *ValueRaw = BaseT::getRawValue();
502  ParsedValue Result{};
503 
504  // Default to 0 to signify an unset value.
505  if (!ValueRaw)
506  return Result;
507 
508  std::string ValueStr{ValueRaw};
509  auto DeviceTypeMap = getSyclDeviceTypeMap();
510 
511  // Iterate over all configurations.
512  size_t Start = 0, End = 0;
513  do {
514  End = ValueStr.find(',', Start);
515  if (End == std::string::npos)
516  End = ValueStr.size();
517 
518  // Get a substring of the current configuration pair.
519  std::string DeviceConfigStr = ValueStr.substr(Start, End - Start);
520 
521  // Find the delimiter in the configuration pair.
522  size_t ConfigDelimLoc = DeviceConfigStr.find(':');
523  if (ConfigDelimLoc == std::string::npos)
525  BaseT, "Device-value pair \"" + DeviceConfigStr +
526  "\" does not contain the ':' delimiter.");
527 
528  // Split configuration pair into its constituents.
529  std::string DeviceConfigTypeStr =
530  DeviceConfigStr.substr(0, ConfigDelimLoc);
531  std::string DeviceConfigValueStr = DeviceConfigStr.substr(
532  ConfigDelimLoc + 1, DeviceConfigStr.size() - ConfigDelimLoc - 1);
533 
534  // Find the device type in the "device type map".
535  auto DeviceTypeIter = std::find_if(
536  std::begin(DeviceTypeMap), std::end(DeviceTypeMap),
537  [&](auto Element) { return DeviceConfigTypeStr == Element.first; });
538  if (DeviceTypeIter == DeviceTypeMap.end())
540  BaseT,
541  "\"" + DeviceConfigTypeStr + "\" is not a recognized device type.");
542 
543  // Parse the configuration value.
544  int DeviceConfigValue = 1;
545  try {
546  DeviceConfigValue = std::stoi(DeviceConfigValueStr);
547  } catch (...) {
549  BaseT, "Value \"" + DeviceConfigValueStr + "\" must be a number");
550  }
551 
552  if (DeviceConfigValue < 1)
553  throw INVALID_CONFIG_EXCEPTION(BaseT,
554  "Value \"" + DeviceConfigValueStr +
555  "\" must be larger than zero");
556 
557  if (DeviceTypeIter->second == info::device_type::all) {
558  // Set all configuration values if we got the device-type wildcard.
559  Result.GPU = DeviceConfigValue;
560  Result.CPU = DeviceConfigValue;
561  Result.Accelerator = DeviceConfigValue;
562  } else {
563  // Try setting the corresponding configuration.
564  getRefByDeviceType(Result, DeviceTypeIter->second) = DeviceConfigValue;
565  }
566 
567  // Move to the start of the next configuration. If the start is outside
568  // the full value string we are done.
569  Start = End + 1;
570  } while (Start < ValueStr.size());
571  return Result;
572  }
573 
574  static ParsedValue getCachedValue(bool ResetCache = false) {
575  static ParsedValue Val = parseValue();
576  if (ResetCache)
577  Val = parseValue();
578  return Val;
579  }
580 };
581 
582 #undef INVALID_CONFIG_EXCEPTION
583 
584 } // namespace detail
585 } // __SYCL_INLINE_VER_NAMESPACE(_V1)
586 } // namespace sycl
static void GetSettings(size_t &MinFactor, size_t &GoodFactor, size_t &MinRange)
Definition: config.hpp:200
static const char * getName()
Definition: config.hpp:118
static const char * get()
Definition: config.hpp:114
#define INVALID_CONFIG_EXCEPTION(BASE, MSG)
Definition: config.hpp:105
#define __SYCL_INLINE_VER_NAMESPACE(X)
#define __SYCL2020_DEPRECATED(message)
constexpr tuple_element< I, tuple< Types... > >::type & get(sycl::detail::tuple< Types... > &Arg) noexcept
Definition: tuple.hpp:199
__SYCL_EXTERN_STREAM_ATTRS ostream cerr
Linked to standard error (unbuffered)
constexpr bool ConfigFromEnvEnabled
Definition: config.hpp:32
void readConfig(bool ForceInitialization)
Definition: config.cpp:48
constexpr int MAX_CONFIG_VALUE
Definition: config.hpp:48
const std::array< std::pair< std::string, info::device_type >, 6 > & getSyclDeviceTypeMap()
Definition: config.cpp:162
constexpr const char * getStrOrNullptr(const char *Str)
Definition: config.hpp:60
constexpr bool ConfigFromFileEnabled
Definition: config.hpp:38
const std::array< std::pair< std::string, backend >, 7 > & getSyclBeMap()
Definition: config.cpp:175
constexpr bool ConfigFromCompileDefEnabled
Definition: config.hpp:44
constexpr int MAX_CONFIG_NAME
Definition: config.hpp:47
detail::enable_if_t< detail::is_sigeninteger< T >::value, detail::anyall_ret_t > all(T x) __NOEXC
Definition: builtins.hpp:1243
std::uint8_t instead
Definition: aliases.hpp:69
---— Error handling, matching OpenCL plugin semantics.
Definition: access.hpp:14
C++ wrapper of extern "C" PI interfaces.