refactor: linux cl_cache eviction mechanism

Refactored eviction mechanism works as follows:
- eviction is needed only if
total size of cache binaries + size of the new binary exceed cache limit
- single evition call removes files with a summed size of 1/3 of the cache limit
- if new binary can not fit in the cache size limit
even after eviction, it will not be saved
- cache limit applies only to
files in cache directory with .cl_cache/.l0_cache extension.
Only these files are counted and only these files are removed

Minor:
- rename variables for better readability
- add `const` where possible

Related-To: NEO-4262
Signed-off-by: Fabian Zwolinski <fabian.zwolinski@intel.com>
This commit is contained in:
Fabian Zwolinski
2023-11-27 15:47:03 +00:00
committed by Compute-Runtime-Automation
parent 88cccaf328
commit a02ac1c140
2 changed files with 239 additions and 43 deletions

View File

@@ -428,9 +428,189 @@ TEST(CompilerCacheTests, GivenCompilerCacheWhenLockConfigFileThenFdIsSetProperSi
EXPECT_EQ(directory, LockConfigFileAndConfigFileIsCreatedInMeantime::configSize);
}
class CompilerCacheFailingLokcConfigFileAndReadSizeLinux : public CompilerCache {
TEST(CompilerCacheTests, GivenCacheBinaryWhenBinarySizeIsOverCacheLimitThenEarlyReturnFalse) {
const size_t cacheSize = MemoryConstants::megaByte;
CompilerCacheMockLinux cache({true, ".cl_cache", "/home/cl_cache/", cacheSize});
auto result = cache.cacheBinary("fileHash", "123456", cacheSize * 2);
EXPECT_FALSE(result);
}
namespace PWriteCallsCountedAndDirSizeWritten {
size_t pWriteCalled = 0u;
size_t dirSize = 0u;
decltype(NEO::SysCalls::sysCallsPwrite) mockPwrite = [](int fd, const void *buf, size_t count, off_t offset) -> ssize_t {
pWriteCalled++;
memcpy(&dirSize, buf, sizeof(dirSize));
return 0;
};
} // namespace PWriteCallsCountedAndDirSizeWritten
class CompilerCacheEvictionTestsMockLinux : public CompilerCache {
public:
CompilerCacheFailingLokcConfigFileAndReadSizeLinux(const CompilerCacheConfig &config) : CompilerCache(config) {}
CompilerCacheEvictionTestsMockLinux(const CompilerCacheConfig &config) : CompilerCache(config) {}
using CompilerCache::createUniqueTempFileAndWriteData;
using CompilerCache::evictCache;
using CompilerCache::lockConfigFileAndReadSize;
using CompilerCache::renameTempFileBinaryToProperName;
bool createUniqueTempFileAndWriteData(char *tmpFilePathTemplate, const char *pBinary, size_t binarySize) override {
createUniqueTempFileAndWriteDataCalled++;
return createUniqueTempFileAndWriteDataResult;
}
size_t createUniqueTempFileAndWriteDataCalled = 0u;
bool createUniqueTempFileAndWriteDataResult = true;
bool renameTempFileBinaryToProperName(const std::string &oldName, const std::string &kernelFileHash) override {
renameTempFileBinaryToProperNameCalled++;
return renameTempFileBinaryToProperNameResult;
}
size_t renameTempFileBinaryToProperNameCalled = 0u;
bool renameTempFileBinaryToProperNameResult = true;
bool evictCache(uint64_t &bytesEvicted) override {
bytesEvicted = evictCacheBytesEvicted;
return evictCacheResult;
}
uint64_t evictCacheBytesEvicted = 0u;
bool evictCacheResult = true;
void lockConfigFileAndReadSize(const std::string &configFilePath, UnifiedHandle &fd, size_t &directorySize) override {
lockConfigFileAndReadSizeCalled++;
std::get<int>(fd) = lockConfigFileAndReadSizeFd;
directorySize = lockConfigFileAndReadSizeDirSize;
return;
}
size_t lockConfigFileAndReadSizeCalled = 0u;
int lockConfigFileAndReadSizeFd = -1;
size_t lockConfigFileAndReadSizeDirSize = 0u;
};
TEST(CompilerCacheTests, GivenCacheDirectoryFilledToTheLimitWhenNewBinaryFitsAfterEvictionThenWriteCacheAndUpdateConfigAndReturnTrue) {
const size_t cacheSize = 10;
CompilerCacheEvictionTestsMockLinux cache({true, ".cl_cache", "/home/cl_cache/", cacheSize});
cache.lockConfigFileAndReadSizeFd = 1;
cache.lockConfigFileAndReadSizeDirSize = 6;
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> statBackup(&NEO::SysCalls::sysCallsStat, [](const std::string &filePath, struct stat *statbuf) -> int { return -1; });
cache.evictCacheResult = true;
cache.evictCacheBytesEvicted = cacheSize / 3;
cache.createUniqueTempFileAndWriteDataResult = true;
cache.renameTempFileBinaryToProperNameResult = true;
VariableBackup<decltype(NEO::SysCalls::sysCallsPwrite)> pWriteBackup(&NEO::SysCalls::sysCallsPwrite, PWriteCallsCountedAndDirSizeWritten::mockPwrite);
VariableBackup<decltype(PWriteCallsCountedAndDirSizeWritten::pWriteCalled)> pWriteCalledBackup(&PWriteCallsCountedAndDirSizeWritten::pWriteCalled, 0);
VariableBackup<decltype(PWriteCallsCountedAndDirSizeWritten::dirSize)> dirSizeBackup(&PWriteCallsCountedAndDirSizeWritten::dirSize, 0);
const std::string kernelFileHash = "7e3291364d8df42";
const char *binary = "123456";
const size_t binarySize = strlen(binary);
auto result = cache.cacheBinary(kernelFileHash, binary, binarySize);
const size_t expectedDirectorySize = 6 - (cacheSize / 3) + binarySize;
EXPECT_TRUE(result);
EXPECT_EQ(1u, cache.lockConfigFileAndReadSizeCalled);
EXPECT_EQ(1u, cache.createUniqueTempFileAndWriteDataCalled);
EXPECT_EQ(1u, cache.renameTempFileBinaryToProperNameCalled);
EXPECT_EQ(1u, PWriteCallsCountedAndDirSizeWritten::pWriteCalled);
EXPECT_EQ(expectedDirectorySize, PWriteCallsCountedAndDirSizeWritten::dirSize);
}
TEST(CompilerCacheTests, GivenCacheBinaryWhenBinaryDoesntFitAfterEvictionThenWriteToConfigAndReturnFalse) {
const size_t cacheSize = 10;
CompilerCacheEvictionTestsMockLinux cache({true, ".cl_cache", "/home/cl_cache/", cacheSize});
cache.lockConfigFileAndReadSizeFd = 1;
cache.lockConfigFileAndReadSizeDirSize = 9;
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> statBackup(&NEO::SysCalls::sysCallsStat, [](const std::string &filePath, struct stat *statbuf) -> int { return -1; });
cache.evictCacheResult = true;
cache.evictCacheBytesEvicted = cacheSize / 3;
VariableBackup<decltype(NEO::SysCalls::sysCallsPwrite)> pWriteBackup(&NEO::SysCalls::sysCallsPwrite, PWriteCallsCountedAndDirSizeWritten::mockPwrite);
VariableBackup<decltype(PWriteCallsCountedAndDirSizeWritten::pWriteCalled)> pWriteCalledBackup(&PWriteCallsCountedAndDirSizeWritten::pWriteCalled, 0);
VariableBackup<decltype(PWriteCallsCountedAndDirSizeWritten::dirSize)> dirSizeBackup(&PWriteCallsCountedAndDirSizeWritten::dirSize, 0);
const std::string kernelFileHash = "7e3291364d8df42";
const char *binary = "123456";
const size_t binarySize = strlen(binary);
auto result = cache.cacheBinary(kernelFileHash, binary, binarySize);
const size_t expectedDirectorySize = 9 - (cacheSize / 3);
EXPECT_FALSE(result);
EXPECT_EQ(1u, cache.lockConfigFileAndReadSizeCalled);
EXPECT_EQ(1u, PWriteCallsCountedAndDirSizeWritten::pWriteCalled);
EXPECT_EQ(0u, cache.createUniqueTempFileAndWriteDataCalled);
EXPECT_EQ(0u, cache.renameTempFileBinaryToProperNameCalled);
EXPECT_EQ(expectedDirectorySize, PWriteCallsCountedAndDirSizeWritten::dirSize);
}
TEST(CompilerCacheTests, GivenCacheDirectoryFilledToTheLimitWhenNoBytesHaveBeenEvictedAndNewBinaryDoesntFitAfterEvictionThenDontWriteToConfigAndReturnFalse) {
const size_t cacheSize = 10;
CompilerCacheEvictionTestsMockLinux cache({true, ".cl_cache", "/home/cl_cache/", cacheSize});
cache.lockConfigFileAndReadSizeFd = 1;
cache.lockConfigFileAndReadSizeDirSize = 9;
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> statBackup(&NEO::SysCalls::sysCallsStat, [](const std::string &filePath, struct stat *statbuf) -> int { return -1; });
cache.evictCacheResult = true;
cache.evictCacheBytesEvicted = 0;
VariableBackup<decltype(NEO::SysCalls::sysCallsPwrite)> pWriteBackup(&NEO::SysCalls::sysCallsPwrite, PWriteCallsCountedAndDirSizeWritten::mockPwrite);
VariableBackup<decltype(PWriteCallsCountedAndDirSizeWritten::pWriteCalled)> pWriteCalledBackup(&PWriteCallsCountedAndDirSizeWritten::pWriteCalled, 0);
VariableBackup<decltype(PWriteCallsCountedAndDirSizeWritten::dirSize)> dirSizeBackup(&PWriteCallsCountedAndDirSizeWritten::dirSize, 0);
const std::string kernelFileHash = "7e3291364d8df42";
const char *binary = "123456";
const size_t binarySize = strlen(binary);
auto result = cache.cacheBinary(kernelFileHash, binary, binarySize);
EXPECT_FALSE(result);
EXPECT_EQ(1u, cache.lockConfigFileAndReadSizeCalled);
EXPECT_EQ(0u, PWriteCallsCountedAndDirSizeWritten::pWriteCalled);
EXPECT_EQ(0u, cache.createUniqueTempFileAndWriteDataCalled);
EXPECT_EQ(0u, cache.renameTempFileBinaryToProperNameCalled);
}
TEST(CompilerCacheTests, GivenCacheBinaryWhenEvictCacheFailsThenReturnFalse) {
const size_t cacheSize = 10;
CompilerCacheEvictionTestsMockLinux cache({true, ".cl_cache", "/home/cl_cache/", cacheSize});
cache.lockConfigFileAndReadSizeFd = 1;
cache.lockConfigFileAndReadSizeDirSize = 5;
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> statBackup(&NEO::SysCalls::sysCallsStat, [](const std::string &filePath, struct stat *statbuf) -> int { return -1; });
cache.evictCacheResult = false;
VariableBackup<decltype(NEO::SysCalls::sysCallsPwrite)> pWriteBackup(&NEO::SysCalls::sysCallsPwrite, PWriteCallsCountedAndDirSizeWritten::mockPwrite);
VariableBackup<decltype(PWriteCallsCountedAndDirSizeWritten::pWriteCalled)> pWriteCalledBackup(&PWriteCallsCountedAndDirSizeWritten::pWriteCalled, 0);
VariableBackup<decltype(PWriteCallsCountedAndDirSizeWritten::dirSize)> dirSizeBackup(&PWriteCallsCountedAndDirSizeWritten::dirSize, 0);
const std::string kernelFileHash = "7e3291364d8df42";
const char *binary = "123456";
const size_t binarySize = strlen(binary);
auto result = cache.cacheBinary(kernelFileHash, binary, binarySize);
EXPECT_FALSE(result);
EXPECT_EQ(1u, cache.lockConfigFileAndReadSizeCalled);
EXPECT_EQ(0u, PWriteCallsCountedAndDirSizeWritten::pWriteCalled);
EXPECT_EQ(0u, cache.createUniqueTempFileAndWriteDataCalled);
EXPECT_EQ(0u, cache.renameTempFileBinaryToProperNameCalled);
}
class CompilerCacheFailingLockConfigFileAndReadSizeLinux : public CompilerCache {
public:
CompilerCacheFailingLockConfigFileAndReadSizeLinux(const CompilerCacheConfig &config) : CompilerCache(config) {}
using CompilerCache::createUniqueTempFileAndWriteData;
using CompilerCache::evictCache;
using CompilerCache::lockConfigFileAndReadSize;
@@ -443,7 +623,7 @@ class CompilerCacheFailingLokcConfigFileAndReadSizeLinux : public CompilerCache
};
TEST(CompilerCacheTests, GivenCompilerCacheWhenLockConfigFileFailThenCacheBinaryReturnsFalse) {
CompilerCacheFailingLokcConfigFileAndReadSizeLinux cache({true, ".cl_cache", "/home/cl_cache/", MemoryConstants::megaByte});
CompilerCacheFailingLockConfigFileAndReadSizeLinux cache({true, ".cl_cache", "/home/cl_cache/", MemoryConstants::megaByte});
EXPECT_FALSE(cache.cacheBinary("config.file", "1", 1));
}