Skip to content

Commit d04b01a

Browse files
committed
Add unit tests
1 parent 051fa68 commit d04b01a

File tree

5 files changed

+155
-21
lines changed

5 files changed

+155
-21
lines changed

sycl/include/sycl/detail/os_util.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ class __SYCL_EXPORT OSUtil {
9999
// Get list of all files in the directory along with its last access time.
100100
static std::vector<std::pair<time_t, std::string>>
101101
getFilesWithAccessTime(const std::string &Path);
102+
103+
static size_t DirSizeVar;
102104
};
103105

104106
} // namespace detail

sycl/source/detail/os_util.cpp

+16-12
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <cstring>
2727
#include <dlfcn.h>
2828
#include <fstream>
29+
#include <ftw.h> // for ftw - file tree walk
2930
#include <libgen.h> // for dirname
3031
#include <link.h>
3132
#include <linux/limits.h> // for PATH_MAX
@@ -276,22 +277,25 @@ int OSUtil::makeDir(const char *Dir) {
276277
return 0;
277278
}
278279

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

282-
size_t Size = 0;
283-
#if __GNUC__ && __GNUC__ < 8
284-
// Should we worry about this case?
285-
assert(false && "getDirectorySize is not implemented for GCC < 8");
286-
#else
287-
// Use C++17 filesystem API to get the size of the directory.
288-
for (const auto &entry :
289-
std::filesystem::recursive_directory_iterator(Path)) {
290-
if (entry.is_regular_file())
291-
Size += entry.file_size();
292-
}
284+
DirSizeVar = 0;
285+
// Use ftw for Linux and darwin as they support posix.
286+
#if defined(__SYCL_RT_OS_LINUX) || defined(__SYCL_RT_OS_DARWIN)
287+
auto SumSize =
288+
[](const char *Fpath, const struct stat *StatBuf, int TypeFlag) {
289+
if (TypeFlag == FTW_F)
290+
DirSizeVar += StatBuf->st_size;
291+
return 0;
292+
};
293+
294+
if (ftw(Path.c_str(),SumSize, 1) == -1)
295+
std::cerr << "Failed to get directory size: " << Path << std::endl;
293296
#endif
294-
return Size;
297+
298+
return DirSizeVar;
295299
}
296300

297301
// Get size of file in bytes.

sycl/source/detail/persistent_device_code_cache.cpp

+9-6
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ getProgramBinaryData(const ur_program_handle_t &NativePrg,
182182
// If not, create it and populate it with the size of the cache directory.
183183
void PersistentDeviceCodeCache::repopulateCacheSizeFile(
184184
const std::string &CacheRoot) {
185+
186+
// No need to store cache size if eviction is disabled.
187+
if (!isEvictionEnabled())
188+
return;
189+
185190
const std::string CacheSizeFileName = "cache_size.txt";
186191
const std::string CacheSizeFile = CacheRoot + "/" + CacheSizeFileName;
187192

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

196-
std::cerr << "Cache size: " << CacheSize << std::endl;
197-
198201
// Take the lock to write the cache size to the file.
199202
{
200203
LockCacheItem Lock{CacheSizeFile};
@@ -311,6 +314,10 @@ void PersistentDeviceCodeCache::evictItemsFromCache(
311314
void PersistentDeviceCodeCache::updateCacheFileSizeAndTriggerEviction(
312315
const std::string &CacheRoot, size_t ItemSize) {
313316

317+
// No need to store cache size if eviction is disabled.
318+
if (!isEvictionEnabled())
319+
return;
320+
314321
const std::string CacheSizeFileName = "cache_size.txt";
315322
const std::string CacheSizeFile = CacheRoot + "/" + CacheSizeFileName;
316323
size_t CurrentCacheSize = 0;
@@ -336,7 +343,6 @@ void PersistentDeviceCodeCache::updateCacheFileSizeAndTriggerEviction(
336343

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

346352
// Check if the cache size exceeds the threshold and trigger cache eviction if
347353
// needed.
348-
if (!SYCLConfig<SYCL_CACHE_MAX_SIZE>::isPersistentCacheEvictionEnabled())
349-
return;
350-
351354
size_t MaxCacheSize = SYCLConfig<SYCL_CACHE_MAX_SIZE>::getProgramCacheSize();
352355
if (CurrentCacheSize > MaxCacheSize) {
353356
// Trigger cache eviction.

sycl/source/detail/persistent_device_code_cache.hpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,6 @@ class PersistentDeviceCodeCache {
118118
const std::vector<const RTDeviceBinaryImage *> &SortedImgs,
119119
const SerializedObj &SpecConsts, const std::string &BuildOptionsString);
120120

121-
/* Returns the path to directory storing persistent device code cache.*/
122-
static std::string getRootDir();
123-
124121
/* Form string representing device version */
125122
static std::string getDeviceIDString(const device &Device);
126123

@@ -152,6 +149,9 @@ class PersistentDeviceCodeCache {
152149
1024 * 1024 * 1024;
153150

154151
public:
152+
/* Returns the path to directory storing persistent device code cache.*/
153+
static std::string getRootDir();
154+
155155
/* Check if on-disk cache enabled.
156156
*/
157157
static bool isEnabled();
@@ -228,6 +228,11 @@ class PersistentDeviceCodeCache {
228228
// Evict LRU items from the cache to make space for new items.
229229
static void evictItemsFromCache(const std::string &CacheRoot,
230230
size_t CacheSize, size_t MaxCacheSize);
231+
232+
// Check if eviction is enabled.
233+
static bool isEvictionEnabled() {
234+
return SYCLConfig<SYCL_CACHE_MAX_SIZE>::isPersistentCacheEvictionEnabled();
235+
}
231236
};
232237
} // namespace detail
233238
} // namespace _V1

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

+120
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ class PersistentDeviceCodeCache
135135
SYCLCachePersistentChanged = true;
136136
}
137137

138+
// Set SYCL_CACHE_MAX_SIZE.
139+
void SetDiskCacheEvictionEnv(const char *NewValue) {
140+
set_env("SYCL_CACHE_MAX_SIZE", NewValue);
141+
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_MAX_SIZE>::reset();
142+
}
143+
138144
void AppendToSYCLCacheDirEnv(const char *SubDir) {
139145
std::string NewSYCLCacheDirPath{RootSYCLCacheDir};
140146
if (NewSYCLCacheDirPath.back() != '\\' && NewSYCLCacheDirPath.back() != '/')
@@ -144,6 +150,24 @@ class PersistentDeviceCodeCache
144150
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_DIR>::reset();
145151
}
146152

153+
// Get the list of binary files in the cache directory.
154+
std::vector<std::string> getBinaryFileNames(std::string CachePath) {
155+
156+
std::vector<std::string> FileNames;
157+
std::error_code EC;
158+
for (llvm::sys::fs::directory_iterator DirIt(CachePath, EC);
159+
DirIt != llvm::sys::fs::directory_iterator(); DirIt.increment(EC)) {
160+
// Check if the file is a binary file.
161+
std::string filename = DirIt->path();
162+
if (filename.find(".bin") != std::string::npos) {
163+
// Just return the file name without the path.
164+
FileNames.push_back(filename.substr(filename.find_last_of("/\\") + 1));
165+
}
166+
}
167+
168+
return FileNames;
169+
}
170+
147171
void ResetSYCLCacheDirEnv() {
148172
set_env("SYCL_CACHE_DIR", RootSYCLCacheDir.c_str());
149173
sycl::detail::SYCLConfig<sycl::detail::SYCL_CACHE_DIR>::reset();
@@ -169,6 +193,9 @@ class PersistentDeviceCodeCache
169193
SetSYCLCachePersistentEnv(SYCLCachePersistentBefore
170194
? SYCLCachePersistentBefore->c_str()
171195
: nullptr);
196+
197+
// Reset SYCL_CACHE_MAX_SIZE.
198+
SetDiskCacheEvictionEnv(nullptr);
172199
ResetSYCLCacheDirEnv();
173200
}
174201

@@ -519,6 +546,99 @@ TEST_P(PersistentDeviceCodeCache, AccessDeniedForCacheDir) {
519546
}
520547
#endif //_WIN32
521548

549+
// Unit tests for testing eviction in persistent cache.
550+
TEST_P(PersistentDeviceCodeCache, BasicEviction) {
551+
552+
// Cleanup the cache directory.
553+
std::string CacheRoot = detail::PersistentDeviceCodeCache::getRootDir();
554+
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(CacheRoot));
555+
ASSERT_NO_ERROR(llvm::sys::fs::create_directories(CacheRoot));
556+
557+
// Disable eviction for the time being.
558+
SetDiskCacheEvictionEnv("0");
559+
560+
std::string BuildOptions{"--eviction"};
561+
// Put 3 items to the cache.
562+
// Sleeping for 1 second between each put to ensure that the items are
563+
// written to the cache with different timestamps. After that, we will
564+
// have three binary files in the cache with different timestamps. This is
565+
// required to keep this unit test deterministic.
566+
detail::PersistentDeviceCodeCache::putItemToDisc({Dev}, {&Img}, {},
567+
BuildOptions, NativeProg);
568+
std::this_thread::sleep_for(std::chrono::seconds(1));
569+
570+
detail::PersistentDeviceCodeCache::putItemToDisc({Dev}, {&Img}, {},
571+
BuildOptions, NativeProg);
572+
std::this_thread::sleep_for(std::chrono::seconds(1));
573+
574+
detail::PersistentDeviceCodeCache::putItemToDisc({Dev}, {&Img}, {},
575+
BuildOptions, NativeProg);
576+
std::this_thread::sleep_for(std::chrono::seconds(1));
577+
578+
// Retrieve 0.bin from the cache.
579+
auto Res = detail::PersistentDeviceCodeCache::getItemFromDisc(
580+
{Dev}, {&Img}, {}, BuildOptions);
581+
582+
// Get the number of binary files in the cached item folder.
583+
std::string ItemDir = detail::PersistentDeviceCodeCache::getCacheItemPath(
584+
Dev, {&Img}, {}, BuildOptions);
585+
auto BinFiles = getBinaryFileNames(ItemDir);
586+
587+
EXPECT_EQ(BinFiles.size(), static_cast<size_t>(3))
588+
<< "Missing binary files. Eviction should not have happened.";
589+
590+
// Get Cache size and size of each entry. Set eviction threshold so that
591+
// just one item is evicted.
592+
size_t CurrentCacheSize = 0;
593+
size_t SizeOfOneEntry =
594+
(size_t)(detail::OSUtil::getDirectorySize(CacheRoot)) + 10;
595+
596+
// Set SYCL_CACHE_MAX_SIZE.
597+
SetDiskCacheEvictionEnv(std::to_string(SizeOfOneEntry).c_str());
598+
599+
// Put 4th item to the cache. This should trigger eviction. Only the first
600+
// item should be evicted.
601+
detail::PersistentDeviceCodeCache::putItemToDisc({Dev}, {&Img}, {},
602+
BuildOptions, NativeProg);
603+
604+
// We should have three binary files: 0.bin, 2.bin, 3.bin.
605+
BinFiles = getBinaryFileNames(ItemDir);
606+
EXPECT_EQ(BinFiles.size(), static_cast<size_t>(3))
607+
<< "Eviction failed. Wrong number of binary files in the cache.";
608+
609+
// Check that 1.bin was evicted.
610+
for (const auto &File : BinFiles) {
611+
EXPECT_NE(File, "1.bin")
612+
<< "Eviction failed. 1.bin should have been evicted.";
613+
}
614+
615+
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(ItemDir));
616+
}
617+
618+
// Unit test for testing size file creation and update, concurrently.
619+
TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteCacheFileSize) {
620+
// Cleanup the cache directory.
621+
std::string CacheRoot = detail::PersistentDeviceCodeCache::getRootDir();
622+
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(CacheRoot));
623+
ASSERT_NO_ERROR(llvm::sys::fs::create_directories(CacheRoot));
624+
625+
// Insanely large value to not trigger eviction. This test just checks
626+
// for deadlocks/crashes when updating the size file concurrently.
627+
SetDiskCacheEvictionEnv("10000000");
628+
ConcurentReadWriteCache(1, 50);
629+
}
630+
631+
// Unit test for adding and evicting cache, concurrently.
632+
TEST_P(PersistentDeviceCodeCache, ConcurentReadWriteCacheEviction) {
633+
// Cleanup the cache directory.
634+
std::string CacheRoot = detail::PersistentDeviceCodeCache::getRootDir();
635+
ASSERT_NO_ERROR(llvm::sys::fs::remove_directories(CacheRoot));
636+
ASSERT_NO_ERROR(llvm::sys::fs::create_directories(CacheRoot));
637+
638+
SetDiskCacheEvictionEnv("1000");
639+
ConcurentReadWriteCache(2, 40);
640+
}
641+
522642
INSTANTIATE_TEST_SUITE_P(PersistentDeviceCodeCacheImpl,
523643
PersistentDeviceCodeCache,
524644
::testing::Values(SYCL_DEVICE_BINARY_TYPE_SPIRV,

0 commit comments

Comments
 (0)