Skip to content

[SYCL] Do not use current directory for JIT cache #4047

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sycl/doc/EnvironmentVariables.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ subject to change. Do not rely on these variables in production code.
| `SYCL_DISABLE_PARALLEL_FOR_RANGE_ROUNDING` | Any(\*) | Disables automatic rounding-up of `parallel_for` invocation ranges. |
| `SYCL_ENABLE_PCI` | Integer | When set to 1, enables obtaining the GPU PCI address when using the Level Zero backend. The default is 0. |
| `SYCL_HOST_UNIFIED_MEMORY` | Integer | Enforce host unified memory support or lack of it for the execution graph builder. If set to 0, it is enforced as not supported by all devices. If set to 1, it is enforced as supported by all devices. |
| `SYCL_CACHE_DIR` | Path | Path to persistent cache root directory. Default values are `%AppData%\libsycl_cache` for Windows and `$XDG_CACHE_HOME/libsycl_cache` on Linux, if `XDG_CACHE_HOME` is not set then `$HOME/.cache/libsycl_cache`. |
| `SYCL_CACHE_DIR` | Path | Path to persistent cache root directory. Default values are `%AppData%\libsycl_cache` for Windows and `$XDG_CACHE_HOME/libsycl_cache` on Linux, if `XDG_CACHE_HOME` is not set then `$HOME/.cache/libsycl_cache`. When none of the environment variables are set SYCL persistent cache is disabled. |
| `SYCL_CACHE_TRACE` | Any(\*) | If the variable is set, messages are sent to std::cerr when caching events or non-blocking failures happen (e.g. unable to access cache item file). |
| `SYCL_CACHE_DISABLE_PERSISTENT (deprecated)` | Any(\*) | Has no effect. |
| `SYCL_CACHE_PERSISTENT` | Integer | Controls persistent device compiled code cache. Turns it on if set to '1' and turns it off if set to '0'. When cache is enabled SYCL runtime will try to cache and reuse JIT-compiled binaries. Default is off. |
Expand Down
4 changes: 3 additions & 1 deletion sycl/doc/KernelProgramCache.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,9 @@ The device code image are stored on file system using structure below:
<n>.bin
```

- `<cache_root>` - root directory storing cache files;
- `<cache_root>` - root directory storing cache files, that depends on
environment variables (see SYCL_CACHE_DIR description in the
[EnvironmentVariables.md](EnvironmentVariables.md));
- `<device_hash>` - hash out of device information used to identify target
device;
- `<device_image_hash>` - hash made out of device image used as input for the
Expand Down
29 changes: 17 additions & 12 deletions sycl/source/detail/persistent_device_code_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ void PersistentDeviceCodeCache::putItemToDisc(
const SerializedObj &SpecConsts, const std::string &BuildOptionsString,
const RT::PiProgram &NativePrg) {

if (!isImageCached(Img))
std::string DirName =
getCacheItemPath(Device, Img, SpecConsts, BuildOptionsString);

if (!isImageCached(Img) || DirName.empty())
return;

auto Plugin = detail::getSyclObjImpl(Device)->getPlugin();
std::string DirName =
getCacheItemPath(Device, Img, SpecConsts, BuildOptionsString);

size_t i = 0;
std::string FileName;
Expand Down Expand Up @@ -136,13 +137,10 @@ std::vector<std::vector<char>> PersistentDeviceCodeCache::getItemFromDisc(
const device &Device, const RTDeviceBinaryImage &Img,
const SerializedObj &SpecConsts, const std::string &BuildOptionsString) {

if (!isImageCached(Img))
return {};

std::string Path =
getCacheItemPath(Device, Img, SpecConsts, BuildOptionsString);

if (!OSUtil::isPathPresent(Path))
if (!isImageCached(Img) || Path.empty() || !OSUtil::isPathPresent(Path))
return {};

int i = 0;
Expand Down Expand Up @@ -315,6 +313,10 @@ std::string PersistentDeviceCodeCache::getCacheItemPath(
const device &Device, const RTDeviceBinaryImage &Img,
const SerializedObj &SpecConsts, const std::string &BuildOptionsString) {
static std::string cache_root{getRootDir()};
if (cache_root.empty()) {
trace("Disable persistent cache due to unconfigured cache root.");
return {};
}

std::string ImgString{(const char *)Img.getRawData().BinaryStart,
Img.getSize()};
Expand Down Expand Up @@ -379,6 +381,8 @@ bool PersistentDeviceCodeCache::isEnabled() {
}

/* Returns path for device code cache root directory
* If environment variables are not available return an empty string to identify
* that cache is not available.
*/
std::string PersistentDeviceCodeCache::getRootDir() {
static const char *RootDir = SYCLConfig<SYCL_CACHE_DIR>::get();
Expand All @@ -391,15 +395,16 @@ std::string PersistentDeviceCodeCache::getRootDir() {
#if defined(__SYCL_RT_OS_LINUX)
static const char *CacheDir = std::getenv("XDG_CACHE_HOME");
static const char *HomeDir = std::getenv("HOME");
if (!CacheDir && !HomeDir)
return {};
static std::string Res{
std::string(CacheDir
? CacheDir
: (HomeDir ? std::string(HomeDir) + "/.cache" : ".")) +
std::string(CacheDir ? CacheDir : (std::string(HomeDir) + "/.cache")) +
DeviceCodeCacheDir};
#else
static const char *AppDataDir = std::getenv("AppData");
static std::string Res{std::string(AppDataDir ? AppDataDir : ".") +
DeviceCodeCacheDir};
if (!AppDataDir)
return {};
static std::string Res{std::string(AppDataDir) + DeviceCodeCacheDir};
#endif
return Res;
}
Expand Down
2 changes: 2 additions & 0 deletions sycl/test/Unit/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,7 @@ def find_shlibpath_var():
lit_config.warning("unable to inject shared library path on '{}'"
.format(platform.system()))

config.environment['SYCL_CACHE_DIR'] = config.llvm_obj_root + "/sycl_cache"
config.environment['SYCL_DEVICE_FILTER'] = lit_config.params.get('SYCL_PLUGIN', "opencl") + ",host"
lit_config.note("Backend: {}".format(config.environment['SYCL_DEVICE_FILTER']))
lit_config.note("SYCL cache directory: {}".format(config.environment['SYCL_CACHE_DIR']))
68 changes: 40 additions & 28 deletions sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ class PersistenDeviceCodeCache : public ::testing::Test {
return _putenv_s(name, value);
}
#endif
virtual void SetUp() {
EXPECT_NE(getenv("SYCL_CACHE_DIR"), nullptr)
<< "Please set SYCL_CACHE_DIR environment variable pointing to cache "
"location.";
}

PersistenDeviceCodeCache() : Plt{default_selector()} {

Expand Down Expand Up @@ -134,8 +139,8 @@ class PersistenDeviceCodeCache : public ::testing::Test {
BuildOptions);
for (size_t i = 0; i < Res.size(); ++i) {
for (size_t j = 0; j < Res[i].size(); ++j) {
assert(Res[i][j] == static_cast<char>(i) &&
"Corrupted image loaded from persistent cache");
EXPECT_EQ(Res[i][j], static_cast<char>(i))
<< "Corrupted image loaded from persistent cache";
}
}
};
Expand Down Expand Up @@ -189,12 +194,13 @@ TEST_F(PersistenDeviceCodeCache, KeysWithNullTermSymbol) {
NativeProg);
auto Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img,
SpecConst, Key);
assert(Res.size() != 0 && "Failed to load cache item");
EXPECT_NE(Res.size(), static_cast<size_t>(0)) << "Failed to load cache item";
for (size_t i = 0; i < Res.size(); ++i) {
assert(Res[i].size() != 0 && "Failed to device image");
EXPECT_NE(Res[i].size(), static_cast<size_t>(0))
<< "Failed to load device image";
for (size_t j = 0; j < Res[i].size(); ++j) {
assert(Res[i][j] == static_cast<char>(i) &&
"Corrupted image loaded from persistent cache");
EXPECT_EQ(Res[i][j], static_cast<unsigned char>(i))
<< "Corrupted image loaded from persistent cache";
}
}

Expand Down Expand Up @@ -245,21 +251,23 @@ TEST_F(PersistenDeviceCodeCache, CorruptedCacheFiles) {
// Only source file is present
detail::PersistentDeviceCodeCache::putItemToDisc(Dev, Img, {}, BuildOptions,
NativeProg);
assert(!llvm::sys::fs::remove(ItemDir + "/0.bin") &&
"Failed to remove binary file");
EXPECT_FALSE(llvm::sys::fs::remove(ItemDir + "/0.bin"))
<< "Failed to remove binary file";
auto Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img, {},
BuildOptions);
assert(Res.size() == 0 && "Item with missed binary file was read");
EXPECT_EQ(Res.size(), static_cast<size_t>(0))
<< "Item with missed binary file was read";
llvm::sys::fs::remove_directories(ItemDir);

// Only binary file is present
detail::PersistentDeviceCodeCache::putItemToDisc(Dev, Img, {}, BuildOptions,
NativeProg);
assert(!llvm::sys::fs::remove(ItemDir + "/0.src") &&
"Failed to remove source file");
EXPECT_FALSE(llvm::sys::fs::remove(ItemDir + "/0.src"))
<< "Failed to remove source file";
Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img, {},
BuildOptions);
assert(Res.size() == 0 && "Item with missed source file was read");
EXPECT_EQ(Res.size(), static_cast<size_t>(0))
<< "Item with missed source file was read";
llvm::sys::fs::remove_directories(ItemDir);

// Binary file is corrupted
Expand All @@ -272,10 +280,11 @@ TEST_F(PersistenDeviceCodeCache, CorruptedCacheFiles) {
*/
FileStream << 2 << 12 << "123456789012" << 23 << "1234";
FileStream.close();
assert((!FileStream.fail()) && "Failed to create trancated binary file");
EXPECT_FALSE(FileStream.fail()) << "Failed to create trancated binary file";
Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img, {},
BuildOptions);
assert(Res.size() == 0 && "Item with corrupted binary file was read");
EXPECT_EQ(Res.size(), static_cast<size_t>(0))
<< "Item with corrupted binary file was read";

llvm::sys::fs::remove_directories(ItemDir);

Expand All @@ -288,7 +297,8 @@ TEST_F(PersistenDeviceCodeCache, CorruptedCacheFiles) {
}
Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img, {},
BuildOptions);
assert(Res.size() == 0 && "Item with corrupted binary file was read");
EXPECT_EQ(Res.size(), static_cast<size_t>(0))
<< "Item with corrupted binary file was read";
llvm::sys::fs::remove_directories(ItemDir);
}

Expand All @@ -312,37 +322,38 @@ TEST_F(PersistenDeviceCodeCache, LockFile) {
// Create 1st cahe item
detail::PersistentDeviceCodeCache::putItemToDisc(Dev, Img, {}, BuildOptions,
NativeProg);
assert(llvm::sys::fs::exists(ItemDir + "/0.bin") && "No file created");
EXPECT_TRUE(llvm::sys::fs::exists(ItemDir + "/0.bin")) << "No file created";
std::string LockFile = ItemDir + "/0.lock";
assert(!llvm::sys::fs::exists(LockFile) && "Cache item locked");
EXPECT_FALSE(llvm::sys::fs::exists(LockFile)) << "Cache item locked";

// Create lock file for the 1st cache item
{ std::ofstream File{LockFile}; }

// Cache item is locked, cache miss happens on read
auto Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img, {},
BuildOptions);
assert(Res.size() == 0 && "Locked item was read");
EXPECT_EQ(Res.size(), static_cast<size_t>(0)) << "Locked item was read";

// Cache item is locked - new cache item to be created
detail::PersistentDeviceCodeCache::putItemToDisc(Dev, Img, {}, BuildOptions,
NativeProg);
assert(llvm::sys::fs::exists(ItemDir + "/1.bin") && "No file created");
EXPECT_TRUE(llvm::sys::fs::exists(ItemDir + "/1.bin")) << "No file created";

// Second cache item is locked, cache miss happens on read
{ std::ofstream File{ItemDir + "/1.lock"}; }
Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img, {},
BuildOptions);
assert(Res.size() == 0 && "Locked item was read");

EXPECT_EQ(Res.size(), static_cast<size_t>(0)) << "Locked item was read";

// First cache item was unlocked and successfully read
std::remove(LockFile.c_str());
Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img, {},
BuildOptions);
for (size_t i = 0; i < Res.size(); ++i) {
for (size_t j = 0; j < Res[i].size(); ++j) {
assert(Res[i][j] == static_cast<char>(i) &&
"Corrupted image loaded from persistent cache");
EXPECT_EQ(Res[i][j], static_cast<unsigned char>(i))
<< "Corrupted image loaded from persistent cache";
}
}
llvm::sys::fs::remove_directories(ItemDir);
Expand All @@ -366,19 +377,20 @@ TEST_F(PersistenDeviceCodeCache, AccessDeniedForCacheDir) {
llvm::sys::fs::remove_directories(ItemDir);
detail::PersistentDeviceCodeCache::putItemToDisc(Dev, Img, {}, BuildOptions,
NativeProg);
assert(llvm::sys::fs::exists(ItemDir + "/0.bin") && "No file created");
EXPECT_TRUE(llvm::sys::fs::exists(ItemDir + "/0.bin")) << "No file created";
llvm::sys::fs::setPermissions(ItemDir + "/0.bin", llvm::sys::fs::no_perms);
// No access to binary file new cache item to be created
detail::PersistentDeviceCodeCache::putItemToDisc(Dev, Img, {}, BuildOptions,
NativeProg);
assert(llvm::sys::fs::exists(ItemDir + "/1.bin") && "No file created");
EXPECT_TRUE(llvm::sys::fs::exists(ItemDir + "/1.bin")) << "No file created";

llvm::sys::fs::setPermissions(ItemDir + "/1.bin", llvm::sys::fs::no_perms);
auto Res = detail::PersistentDeviceCodeCache::getItemFromDisc(Dev, Img, {},
BuildOptions);

// No image to be read due to lack of permissions fro source file
assert(Res.size() == 0);
// No image to be read due to lack of permissions from source file
EXPECT_EQ(Res.size(), static_cast<size_t>(0))
<< "Read from the file without permissions.";

llvm::sys::fs::setPermissions(ItemDir + "/0.bin", llvm::sys::fs::all_perms);
llvm::sys::fs::setPermissions(ItemDir + "/1.bin", llvm::sys::fs::all_perms);
Expand All @@ -388,8 +400,8 @@ TEST_F(PersistenDeviceCodeCache, AccessDeniedForCacheDir) {
// Image should be successfully read
for (size_t i = 0; i < Res.size(); ++i) {
for (size_t j = 0; j < Res[i].size(); ++j) {
assert(Res[i][j] == static_cast<char>(i) &&
"Corrupted image loaded from persistent cache");
EXPECT_EQ(Res[i][j], static_cast<unsigned char>(i))
<< "Corrupted image loaded from persistent cache";
}
}
llvm::sys::fs::remove_directories(ItemDir);
Expand Down