Skip to content

Commit 1abad42

Browse files
[SYCL] Separate cache dir for tests and move cache config logic (#6286)
This commit makes the following changes: Makes each persistent device code cache test use a unique cache directory to prevent possible overlap. Move the logic and caching of SYCL_CACHE_PERSISTENT and SYCL_CACHE_DIR to their own specializations of SYCLConfig. This removes the need for PersistentDeviceCodeCache::reparseConfig as the SYCLConfig specializations offer their own reset functionality.
1 parent f0df89a commit 1abad42

File tree

4 files changed

+138
-127
lines changed

4 files changed

+138
-127
lines changed

sycl/source/detail/config.hpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,95 @@ template <> class SYCLConfig<SYCL_QUEUE_THREAD_POOL_SIZE> {
378378
}
379379
};
380380

381+
template <> class SYCLConfig<SYCL_CACHE_PERSISTENT> {
382+
using BaseT = SYCLConfigBase<SYCL_CACHE_PERSISTENT>;
383+
384+
public:
385+
static constexpr bool Default = false; // default is disabled
386+
387+
static bool get() { return getCachedValue(); }
388+
389+
static void reset() { (void)getCachedValue(/*ResetCache=*/true); }
390+
391+
static const char *getName() { return BaseT::MConfigName; }
392+
393+
private:
394+
static bool parseValue() {
395+
// Check if deprecated opt-out env var is used, then warn.
396+
if (SYCLConfig<SYCL_CACHE_DISABLE_PERSISTENT>::get()) {
397+
std::cerr
398+
<< "WARNING: " << SYCLConfig<SYCL_CACHE_DISABLE_PERSISTENT>::getName()
399+
<< " environment variable is deprecated "
400+
<< "and has no effect. By default, persistent device code caching is "
401+
<< (Default ? "enabled." : "disabled.") << " Use " << getName()
402+
<< "=1/0 to enable/disable.\n";
403+
}
404+
405+
const char *ValStr = BaseT::getRawValue();
406+
if (!ValStr)
407+
return Default;
408+
if (strlen(ValStr) != 1 || (ValStr[0] != '0' && ValStr[0] != '1')) {
409+
std::string Msg =
410+
std::string{"Invalid value for bool configuration variable "} +
411+
getName() + std::string{": "} + ValStr;
412+
throw runtime_error(Msg, PI_ERROR_INVALID_OPERATION);
413+
}
414+
return ValStr[0] == '1';
415+
}
416+
417+
static bool getCachedValue(bool ResetCache = false) {
418+
static bool Val = parseValue();
419+
if (ResetCache)
420+
Val = parseValue();
421+
return Val;
422+
}
423+
};
424+
425+
template <> class SYCLConfig<SYCL_CACHE_DIR> {
426+
using BaseT = SYCLConfigBase<SYCL_CACHE_DIR>;
427+
428+
public:
429+
static std::string get() { return getCachedValue(); }
430+
431+
static void reset() { (void)getCachedValue(/*ResetCache=*/true); }
432+
433+
static const char *getName() { return BaseT::MConfigName; }
434+
435+
private:
436+
// If environment variables are not available return an empty string to
437+
// identify that cache is not available.
438+
static std::string parseValue() {
439+
const char *RootDir = BaseT::getRawValue();
440+
if (RootDir)
441+
return RootDir;
442+
443+
constexpr char DeviceCodeCacheDir[] = "/libsycl_cache";
444+
445+
#if defined(__SYCL_RT_OS_LINUX)
446+
const char *CacheDir = std::getenv("XDG_CACHE_HOME");
447+
const char *HomeDir = std::getenv("HOME");
448+
if (!CacheDir && !HomeDir)
449+
return {};
450+
std::string Res{
451+
std::string(CacheDir ? CacheDir : (std::string(HomeDir) + "/.cache")) +
452+
DeviceCodeCacheDir};
453+
#else
454+
const char *AppDataDir = std::getenv("AppData");
455+
if (!AppDataDir)
456+
return {};
457+
std::string Res{std::string(AppDataDir) + DeviceCodeCacheDir};
458+
#endif
459+
return Res;
460+
}
461+
462+
static std::string getCachedValue(bool ResetCache = false) {
463+
static std::string Val = parseValue();
464+
if (ResetCache)
465+
Val = parseValue();
466+
return Val;
467+
}
468+
};
469+
381470
} // namespace detail
382471
} // namespace sycl
383472
} // __SYCL_INLINE_NAMESPACE(cl)

sycl/source/detail/persistent_device_code_cache.cpp

Lines changed: 10 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ bool PersistentDeviceCodeCache::isImageCached(const RTDeviceBinaryImage &Img) {
6565
return false;
6666
}
6767

68+
// TODO: Move parsing logic and caching to specializations of SYCLConfig.
6869
static auto MaxImgSize = getNumParam<SYCL_CACHE_MAX_DEVICE_IMAGE_SIZE>(
6970
DEFAULT_MAX_DEVICE_IMAGE_SIZE);
7071
static auto MinImgSize = getNumParam<SYCL_CACHE_MIN_DEVICE_IMAGE_SIZE>(
@@ -326,7 +327,7 @@ bool PersistentDeviceCodeCache::isCacheItemSrcEqual(
326327
std::string PersistentDeviceCodeCache::getCacheItemPath(
327328
const device &Device, const RTDeviceBinaryImage &Img,
328329
const SerializedObj &SpecConsts, const std::string &BuildOptionsString) {
329-
static std::string cache_root{getRootDir()};
330+
std::string cache_root{getRootDir()};
330331
if (cache_root.empty()) {
331332
trace("Disable persistent cache due to unconfigured cache root.");
332333
return {};
@@ -345,99 +346,22 @@ std::string PersistentDeviceCodeCache::getCacheItemPath(
345346
std::to_string(StringHasher(BuildOptionsString));
346347
}
347348

348-
// TODO Currently parsing configuration variables and error reporting is not
349-
// centralized, and is basically re-implemented (with different level of
350-
// reliability) for each particular variable. As a variant, this can go into
351-
// the SYCLConfigBase class, which can be templated by value type, default value
352-
// and value parser (combined with error checker). It can also have typed get()
353-
// function returning one-time parsed and error-checked value.
354-
355-
// Parses persistent cache configuration and checks it for errors.
356-
// Returns true if it is enabled, false otherwise.
357-
static bool parsePersistentCacheConfig() {
358-
constexpr bool Default = false; // default is disabled
359-
360-
// Check if deprecated opt-out env var is used, then warn.
361-
if (SYCLConfig<SYCL_CACHE_DISABLE_PERSISTENT>::get()) {
362-
std::cerr
363-
<< "WARNING: " << SYCLConfig<SYCL_CACHE_DISABLE_PERSISTENT>::getName()
364-
<< " environment variable is deprecated "
365-
<< "and has no effect. By default, persistent device code caching is "
366-
<< (Default ? "enabled." : "disabled.") << " Use "
367-
<< SYCLConfig<SYCL_CACHE_PERSISTENT>::getName()
368-
<< "=1/0 to enable/disable.\n";
369-
}
370-
bool Ret = Default;
371-
const char *RawVal = SYCLConfig<SYCL_CACHE_PERSISTENT>::get();
372-
373-
if (RawVal) {
374-
if (!std::strcmp(RawVal, "0")) {
375-
Ret = false;
376-
} else if (!std::strcmp(RawVal, "1")) {
377-
Ret = true;
378-
} else {
379-
std::string Msg =
380-
std::string{"Invalid value for bool configuration variable "} +
381-
SYCLConfig<SYCL_CACHE_PERSISTENT>::getName() + std::string{": "} +
382-
RawVal;
383-
throw runtime_error(Msg, PI_ERROR_INVALID_OPERATION);
384-
}
385-
}
386-
PersistentDeviceCodeCache::trace(Ret ? "enabled" : "disabled");
387-
return Ret;
388-
}
389-
390-
/* Cached static variable signalling if the persistent cache is enabled.
391-
* The variable can have three values:
392-
* - None : The configuration has not been parsed.
393-
* - true : The persistent cache is enabled.
394-
* - false : The persistent cache is disabled.
395-
*/
396-
static std::optional<bool> CacheIsEnabled;
397-
398-
/* Forces a reparsing of the information used to determine if the persistent
399-
* cache is enabled. This is primarily used for unit-testing where the
400-
* corresponding configuration variable is set by the individual tests.
401-
*/
402-
void PersistentDeviceCodeCache::reparseConfig() {
403-
CacheIsEnabled = parsePersistentCacheConfig();
404-
}
405-
406349
/* Returns true if persistent cache is enabled.
407350
*/
408351
bool PersistentDeviceCodeCache::isEnabled() {
409-
if (!CacheIsEnabled)
410-
reparseConfig();
411-
return *CacheIsEnabled;
352+
bool CacheIsEnabled = SYCLConfig<SYCL_CACHE_PERSISTENT>::get();
353+
static bool FirstCheck = true;
354+
if (FirstCheck) {
355+
PersistentDeviceCodeCache::trace(CacheIsEnabled ? "enabled" : "disabled");
356+
FirstCheck = false;
357+
}
358+
return CacheIsEnabled;
412359
}
413360

414361
/* Returns path for device code cache root directory
415-
* If environment variables are not available return an empty string to identify
416-
* that cache is not available.
417362
*/
418363
std::string PersistentDeviceCodeCache::getRootDir() {
419-
static const char *RootDir = SYCLConfig<SYCL_CACHE_DIR>::get();
420-
if (RootDir)
421-
return RootDir;
422-
423-
constexpr char DeviceCodeCacheDir[] = "/libsycl_cache";
424-
425-
// Use static to calculate directory only once per program run
426-
#if defined(__SYCL_RT_OS_LINUX)
427-
static const char *CacheDir = std::getenv("XDG_CACHE_HOME");
428-
static const char *HomeDir = std::getenv("HOME");
429-
if (!CacheDir && !HomeDir)
430-
return {};
431-
static std::string Res{
432-
std::string(CacheDir ? CacheDir : (std::string(HomeDir) + "/.cache")) +
433-
DeviceCodeCacheDir};
434-
#else
435-
static const char *AppDataDir = std::getenv("AppData");
436-
if (!AppDataDir)
437-
return {};
438-
static std::string Res{std::string(AppDataDir) + DeviceCodeCacheDir};
439-
#endif
440-
return Res;
364+
return SYCLConfig<SYCL_CACHE_DIR>::get();
441365
}
442366

443367
} // namespace detail

sycl/source/detail/persistent_device_code_cache.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,6 @@ class PersistentDeviceCodeCache {
184184
const std::string &BuildOptionsString,
185185
const RT::PiProgram &NativePrg);
186186

187-
/* Forces a reparsing of the information used to determine if the persistent
188-
* cache is enabled. This is primarily used for unit-testing where the
189-
* corresponding configuration variable is set by the individual tests.
190-
*/
191-
static void reparseConfig();
192-
193187
/* Sends message to std:cerr stream when SYCL_CACHE_TRACE environemnt is set*/
194188
static void trace(const std::string &msg) {
195189
static const char *TraceEnabled = SYCLConfig<SYCL_CACHE_TRACE>::get();

sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ class PersistentDeviceCodeCache
9797
std::optional<std::string> SYCLCachePersistentBefore;
9898
bool SYCLCachePersistentChanged = false;
9999

100+
std::string RootSYCLCacheDir;
101+
100102
// Caches the initial value of the SYCL_CACHE_PERSISTENT environment variable
101103
// before overwriting it with the new value.
102104
// Tear-down will reset the environment variable.
@@ -116,14 +118,38 @@ class PersistentDeviceCodeCache
116118
// persistent cache.
117119
set_env("SYCL_CACHE_PERSISTENT", NewValue);
118120
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_PERSISTENT>::reset();
119-
detail::PersistentDeviceCodeCache::reparseConfig();
120121
SYCLCachePersistentChanged = true;
121122
}
122123

124+
void AppendToSYCLCacheDirEnv(const char *SubDir) {
125+
std::string NewSYCLCacheDirPath{RootSYCLCacheDir};
126+
if (NewSYCLCacheDirPath.back() != '\\' && NewSYCLCacheDirPath.back() != '/')
127+
NewSYCLCacheDirPath += '/';
128+
NewSYCLCacheDirPath += SubDir;
129+
set_env("SYCL_CACHE_DIR", NewSYCLCacheDirPath.c_str());
130+
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_DIR>::reset();
131+
}
132+
133+
void ResetSYCLCacheDirEnv() {
134+
set_env("SYCL_CACHE_DIR", RootSYCLCacheDir.c_str());
135+
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_DIR>::reset();
136+
}
137+
123138
void SetUp() override {
124-
EXPECT_NE(getenv("SYCL_CACHE_DIR"), nullptr)
125-
<< "Please set SYCL_CACHE_DIR environment variable pointing to cache "
126-
"location.";
139+
if (Plt.is_host() || Plt.get_backend() != backend::opencl)
140+
GTEST_SKIP();
141+
142+
if (RootSYCLCacheDir == "")
143+
FAIL() << "Please set SYCL_CACHE_DIR environment variable pointing to "
144+
"cache location.";
145+
146+
// Append the test name to the cache dir to prevent conflicts with other
147+
// tests running in parallel.
148+
AppendToSYCLCacheDirEnv(
149+
::testing::UnitTest::GetInstance()->current_test_info()->name());
150+
151+
// Enable persistent cache
152+
SetSYCLCachePersistentEnv("1");
127153
}
128154

129155
void TearDown() override {
@@ -132,17 +158,25 @@ class PersistentDeviceCodeCache
132158
SetSYCLCachePersistentEnv(SYCLCachePersistentBefore
133159
? SYCLCachePersistentBefore->c_str()
134160
: nullptr);
161+
ResetSYCLCacheDirEnv();
135162
}
136163

137164
PersistentDeviceCodeCache() : Plt{default_selector()} {
138-
139165
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
140166
std::clog << "This test is only supported on OpenCL devices\n";
141167
std::clog << "Current platform is "
142168
<< Plt.get_info<info::platform::name>();
143169
return;
144170
}
145171

172+
char *SYCLCacheDir = getenv("SYCL_CACHE_DIR");
173+
if (!SYCLCacheDir) {
174+
std::clog << "This test requires the SYCL_CACHE_DIR environment variable "
175+
"to be set.";
176+
return;
177+
}
178+
RootSYCLCacheDir = SYCLCacheDir;
179+
146180
Mock = std::make_unique<unittest::PiMock>(Plt);
147181
Dev = Plt.get_devices()[0];
148182
Mock->redefine<detail::PiApiKind::piProgramGetInfo>(
@@ -155,12 +189,6 @@ class PersistentDeviceCodeCache
155189
* vector above.
156190
* ThreadCount - number of parallel executors used for the test*/
157191
void ConcurentReadWriteCache(unsigned char ProgramID, size_t ThreadCount) {
158-
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
159-
return;
160-
}
161-
162-
SetSYCLCachePersistentEnv("1");
163-
164192
std::string BuildOptions{"--concurrent-access=" +
165193
std::to_string(ThreadCount)};
166194
DeviceCodeID = ProgramID;
@@ -223,12 +251,6 @@ class PersistentDeviceCodeCache
223251
/* Checks that key values with \0 symbols are processed correctly
224252
*/
225253
TEST_P(PersistentDeviceCodeCache, KeysWithNullTermSymbol) {
226-
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
227-
return;
228-
}
229-
230-
SetSYCLCachePersistentEnv("1");
231-
232254
std::string Key{'1', '\0', '3', '4', '\0'};
233255
std::vector<unsigned char> SpecConst(Key.begin(), Key.end());
234256
std::string ItemDir = detail::PersistentDeviceCodeCache::getCacheItemPath(
@@ -281,12 +303,6 @@ TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteCacheBigItem) {
281303
* - binary file is corrupted.
282304
*/
283305
TEST_P(PersistentDeviceCodeCache, CorruptedCacheFiles) {
284-
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
285-
return;
286-
}
287-
288-
SetSYCLCachePersistentEnv("1");
289-
290306
std::string BuildOptions{"--corrupted-file"};
291307
std::string ItemDir = detail::PersistentDeviceCodeCache::getCacheItemPath(
292308
Dev, Img, {}, BuildOptions);
@@ -351,12 +367,6 @@ TEST_P(PersistentDeviceCodeCache, CorruptedCacheFiles) {
351367
* - cache miss happens on read operation.
352368
*/
353369
TEST_P(PersistentDeviceCodeCache, LockFile) {
354-
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
355-
return;
356-
}
357-
358-
SetSYCLCachePersistentEnv("1");
359-
360370
std::string BuildOptions{"--obsolete-lock"};
361371
std::string ItemDir = detail::PersistentDeviceCodeCache::getCacheItemPath(
362372
Dev, Img, {}, BuildOptions);
@@ -407,12 +417,6 @@ TEST_P(PersistentDeviceCodeCache, LockFile) {
407417
/* Checks cache behavior when filesystem read/write operations fail
408418
*/
409419
TEST_P(PersistentDeviceCodeCache, AccessDeniedForCacheDir) {
410-
if (Plt.is_host() || Plt.get_backend() != backend::opencl) {
411-
return;
412-
}
413-
414-
SetSYCLCachePersistentEnv("1");
415-
416420
std::string BuildOptions{"--build-options"};
417421
std::string ItemDir = detail::PersistentDeviceCodeCache::getCacheItemPath(
418422
Dev, Img, {}, BuildOptions);

0 commit comments

Comments
 (0)