Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
uditagarwal97 committed Dec 5, 2024
1 parent 051fa68 commit d04b01a
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 21 deletions.
2 changes: 2 additions & 0 deletions sycl/include/sycl/detail/os_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ class __SYCL_EXPORT OSUtil {
// Get list of all files in the directory along with its last access time.
static std::vector<std::pair<time_t, std::string>>
getFilesWithAccessTime(const std::string &Path);

static size_t DirSizeVar;
};

} // namespace detail
Expand Down
28 changes: 16 additions & 12 deletions sycl/source/detail/os_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <cstring>
#include <dlfcn.h>
#include <fstream>
#include <ftw.h> // for ftw - file tree walk
#include <libgen.h> // for dirname
#include <link.h>
#include <linux/limits.h> // for PATH_MAX
Expand Down Expand Up @@ -276,22 +277,25 @@ int OSUtil::makeDir(const char *Dir) {
return 0;
}

size_t OSUtil::DirSizeVar = 0;
// Get size of a directory in bytes.
size_t OSUtil::getDirectorySize(const std::string &Path) {

size_t Size = 0;
#if __GNUC__ && __GNUC__ < 8
// Should we worry about this case?
assert(false && "getDirectorySize is not implemented for GCC < 8");
#else
// Use C++17 filesystem API to get the size of the directory.
for (const auto &entry :
std::filesystem::recursive_directory_iterator(Path)) {
if (entry.is_regular_file())
Size += entry.file_size();
}
DirSizeVar = 0;
// Use ftw for Linux and darwin as they support posix.
#if defined(__SYCL_RT_OS_LINUX) || defined(__SYCL_RT_OS_DARWIN)
auto SumSize =
[](const char *Fpath, const struct stat *StatBuf, int TypeFlag) {
if (TypeFlag == FTW_F)
DirSizeVar += StatBuf->st_size;
return 0;
};

if (ftw(Path.c_str(),SumSize, 1) == -1)
std::cerr << "Failed to get directory size: " << Path << std::endl;
#endif
return Size;

return DirSizeVar;
}

// Get size of file in bytes.
Expand Down
15 changes: 9 additions & 6 deletions sycl/source/detail/persistent_device_code_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ getProgramBinaryData(const ur_program_handle_t &NativePrg,
// If not, create it and populate it with the size of the cache directory.
void PersistentDeviceCodeCache::repopulateCacheSizeFile(
const std::string &CacheRoot) {

// No need to store cache size if eviction is disabled.
if (!isEvictionEnabled())
return;

const std::string CacheSizeFileName = "cache_size.txt";
const std::string CacheSizeFile = CacheRoot + "/" + CacheSizeFileName;

Expand All @@ -193,8 +198,6 @@ void PersistentDeviceCodeCache::repopulateCacheSizeFile(
// Calculate the size of the cache directory.
size_t CacheSize = OSUtil::getDirectorySize(CacheRoot);

std::cerr << "Cache size: " << CacheSize << std::endl;

// Take the lock to write the cache size to the file.
{
LockCacheItem Lock{CacheSizeFile};
Expand Down Expand Up @@ -311,6 +314,10 @@ void PersistentDeviceCodeCache::evictItemsFromCache(
void PersistentDeviceCodeCache::updateCacheFileSizeAndTriggerEviction(
const std::string &CacheRoot, size_t ItemSize) {

// No need to store cache size if eviction is disabled.
if (!isEvictionEnabled())
return;

const std::string CacheSizeFileName = "cache_size.txt";
const std::string CacheSizeFile = CacheRoot + "/" + CacheSizeFileName;
size_t CurrentCacheSize = 0;
Expand All @@ -336,7 +343,6 @@ void PersistentDeviceCodeCache::updateCacheFileSizeAndTriggerEviction(

// Write the updated cache size to the file.
FileStream.open(CacheSizeFile, std::ios::out | std::ios::trunc);
std::cerr << "Current cache size: " << CurrentCacheSize << std::endl;
FileStream << CurrentCacheSize;
FileStream.close();
break;
Expand All @@ -345,9 +351,6 @@ void PersistentDeviceCodeCache::updateCacheFileSizeAndTriggerEviction(

// Check if the cache size exceeds the threshold and trigger cache eviction if
// needed.
if (!SYCLConfig<SYCL_CACHE_MAX_SIZE>::isPersistentCacheEvictionEnabled())
return;

size_t MaxCacheSize = SYCLConfig<SYCL_CACHE_MAX_SIZE>::getProgramCacheSize();
if (CurrentCacheSize > MaxCacheSize) {
// Trigger cache eviction.
Expand Down
11 changes: 8 additions & 3 deletions sycl/source/detail/persistent_device_code_cache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@ class PersistentDeviceCodeCache {
const std::vector<const RTDeviceBinaryImage *> &SortedImgs,
const SerializedObj &SpecConsts, const std::string &BuildOptionsString);

/* Returns the path to directory storing persistent device code cache.*/
static std::string getRootDir();

/* Form string representing device version */
static std::string getDeviceIDString(const device &Device);

Expand Down Expand Up @@ -152,6 +149,9 @@ class PersistentDeviceCodeCache {
1024 * 1024 * 1024;

public:
/* Returns the path to directory storing persistent device code cache.*/
static std::string getRootDir();

/* Check if on-disk cache enabled.
*/
static bool isEnabled();
Expand Down Expand Up @@ -228,6 +228,11 @@ class PersistentDeviceCodeCache {
// Evict LRU items from the cache to make space for new items.
static void evictItemsFromCache(const std::string &CacheRoot,
size_t CacheSize, size_t MaxCacheSize);

// Check if eviction is enabled.
static bool isEvictionEnabled() {
return SYCLConfig<SYCL_CACHE_MAX_SIZE>::isPersistentCacheEvictionEnabled();
}
};
} // namespace detail
} // namespace _V1
Expand Down
120 changes: 120 additions & 0 deletions sycl/unittests/kernel-and-program/PersistentDeviceCodeCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ class PersistentDeviceCodeCache
SYCLCachePersistentChanged = true;
}

// Set SYCL_CACHE_MAX_SIZE.
void SetDiskCacheEvictionEnv(const char *NewValue) {
set_env("SYCL_CACHE_MAX_SIZE", NewValue);
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_MAX_SIZE>::reset();
}

void AppendToSYCLCacheDirEnv(const char *SubDir) {
std::string NewSYCLCacheDirPath{RootSYCLCacheDir};
if (NewSYCLCacheDirPath.back() != '\\' && NewSYCLCacheDirPath.back() != '/')
Expand All @@ -144,6 +150,24 @@ class PersistentDeviceCodeCache
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_DIR>::reset();
}

// Get the list of binary files in the cache directory.
std::vector<std::string> getBinaryFileNames(std::string CachePath) {

std::vector<std::string> FileNames;
std::error_code EC;
for (llvm::sys::fs::directory_iterator DirIt(CachePath, EC);
DirIt != llvm::sys::fs::directory_iterator(); DirIt.increment(EC)) {
// Check if the file is a binary file.
std::string filename = DirIt->path();
if (filename.find(".bin") != std::string::npos) {
// Just return the file name without the path.
FileNames.push_back(filename.substr(filename.find_last_of("/\\") + 1));
}
}

return FileNames;
}

void ResetSYCLCacheDirEnv() {
set_env("SYCL_CACHE_DIR", RootSYCLCacheDir.c_str());
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_DIR>::reset();
Expand All @@ -169,6 +193,9 @@ class PersistentDeviceCodeCache
SetSYCLCachePersistentEnv(SYCLCachePersistentBefore
? SYCLCachePersistentBefore->c_str()
: nullptr);

// Reset SYCL_CACHE_MAX_SIZE.
SetDiskCacheEvictionEnv(nullptr);
ResetSYCLCacheDirEnv();
}

Expand Down Expand Up @@ -519,6 +546,99 @@ TEST_P(PersistentDeviceCodeCache, AccessDeniedForCacheDir) {
}
#endif //_WIN32

// Unit tests for testing eviction in persistent cache.
TEST_P(PersistentDeviceCodeCache, BasicEviction) {

// Cleanup the cache directory.
std::string CacheRoot = detail::PersistentDeviceCodeCache::getRootDir();
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(CacheRoot));
ASSERT_NO_ERROR(llvm::sys::fs::create_directories(CacheRoot));

// Disable eviction for the time being.
SetDiskCacheEvictionEnv("0");

std::string BuildOptions{"--eviction"};
// Put 3 items to the cache.
// Sleeping for 1 second between each put to ensure that the items are
// written to the cache with different timestamps. After that, we will
// have three binary files in the cache with different timestamps. This is
// required to keep this unit test deterministic.
detail::PersistentDeviceCodeCache::putItemToDisc({Dev}, {&Img}, {},
BuildOptions, NativeProg);
std::this_thread::sleep_for(std::chrono::seconds(1));

detail::PersistentDeviceCodeCache::putItemToDisc({Dev}, {&Img}, {},
BuildOptions, NativeProg);
std::this_thread::sleep_for(std::chrono::seconds(1));

detail::PersistentDeviceCodeCache::putItemToDisc({Dev}, {&Img}, {},
BuildOptions, NativeProg);
std::this_thread::sleep_for(std::chrono::seconds(1));

// Retrieve 0.bin from the cache.
auto Res = detail::PersistentDeviceCodeCache::getItemFromDisc(
{Dev}, {&Img}, {}, BuildOptions);

// Get the number of binary files in the cached item folder.
std::string ItemDir = detail::PersistentDeviceCodeCache::getCacheItemPath(
Dev, {&Img}, {}, BuildOptions);
auto BinFiles = getBinaryFileNames(ItemDir);

EXPECT_EQ(BinFiles.size(), static_cast<size_t>(3))
<< "Missing binary files. Eviction should not have happened.";

// Get Cache size and size of each entry. Set eviction threshold so that
// just one item is evicted.
size_t CurrentCacheSize = 0;
size_t SizeOfOneEntry =
(size_t)(detail::OSUtil::getDirectorySize(CacheRoot)) + 10;

// Set SYCL_CACHE_MAX_SIZE.
SetDiskCacheEvictionEnv(std::to_string(SizeOfOneEntry).c_str());

// Put 4th item to the cache. This should trigger eviction. Only the first
// item should be evicted.
detail::PersistentDeviceCodeCache::putItemToDisc({Dev}, {&Img}, {},
BuildOptions, NativeProg);

// We should have three binary files: 0.bin, 2.bin, 3.bin.
BinFiles = getBinaryFileNames(ItemDir);
EXPECT_EQ(BinFiles.size(), static_cast<size_t>(3))
<< "Eviction failed. Wrong number of binary files in the cache.";

// Check that 1.bin was evicted.
for (const auto &File : BinFiles) {
EXPECT_NE(File, "1.bin")
<< "Eviction failed. 1.bin should have been evicted.";
}

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

// Unit test for testing size file creation and update, concurrently.
TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteCacheFileSize) {
// Cleanup the cache directory.
std::string CacheRoot = detail::PersistentDeviceCodeCache::getRootDir();
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(CacheRoot));
ASSERT_NO_ERROR(llvm::sys::fs::create_directories(CacheRoot));

// Insanely large value to not trigger eviction. This test just checks
// for deadlocks/crashes when updating the size file concurrently.
SetDiskCacheEvictionEnv("10000000");
ConcurentReadWriteCache(1, 50);
}

// Unit test for adding and evicting cache, concurrently.
TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteCacheEviction) {
// Cleanup the cache directory.
std::string CacheRoot = detail::PersistentDeviceCodeCache::getRootDir();
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(CacheRoot));
ASSERT_NO_ERROR(llvm::sys::fs::create_directories(CacheRoot));

SetDiskCacheEvictionEnv("1000");
ConcurentReadWriteCache(2, 40);
}

INSTANTIATE_TEST_SUITE_P(PersistentDeviceCodeCacheImpl,
PersistentDeviceCodeCache,
::testing::Values(SYCL_DEVICE_BINARY_TYPE_SPIRV,
Expand Down

0 comments on commit d04b01a

Please sign in to comment.