Skip to content

Commit a02ac1c

Browse files
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 <[email protected]>
1 parent 88cccaf commit a02ac1c

File tree

2 files changed

+239
-43
lines changed

2 files changed

+239
-43
lines changed

shared/source/compiler_interface/linux/compiler_cache_linux.cpp

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
namespace NEO {
3232
int filterFunction(const struct dirent *file) {
3333
std::string_view fileName = file->d_name;
34-
if (fileName.find(".cl_cache") != fileName.npos || fileName.find(".l0_cache") != fileName.npos) {
34+
if (fileName.find(".cl_cache") != fileName.npos ||
35+
fileName.find(".l0_cache") != fileName.npos) {
3536
return 1;
3637
}
3738

@@ -50,38 +51,39 @@ bool compareByLastAccessTime(const ElementsStruct &a, ElementsStruct &b) {
5051
bool CompilerCache::evictCache(uint64_t &bytesEvicted) {
5152
struct dirent **files = 0;
5253

53-
int filesCount = NEO::SysCalls::scandir(config.cacheDir.c_str(), &files, filterFunction, NULL);
54+
const int filesCount = NEO::SysCalls::scandir(config.cacheDir.c_str(), &files, filterFunction, NULL);
5455

5556
if (filesCount == -1) {
5657
NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stderr, "PID %d [Cache failure]: Scandir failed! errno: %d\n", NEO::SysCalls::getProcessId(), errno);
5758
return false;
5859
}
5960

60-
std::vector<ElementsStruct> vec;
61-
vec.reserve(static_cast<size_t>(filesCount));
61+
std::vector<ElementsStruct> cacheFiles;
62+
cacheFiles.reserve(static_cast<size_t>(filesCount));
6263
for (int i = 0; i < filesCount; ++i) {
6364
ElementsStruct fileElement = {};
6465
fileElement.path = joinPath(config.cacheDir, files[i]->d_name);
6566
if (NEO::SysCalls::stat(fileElement.path.c_str(), &fileElement.statEl) == 0) {
66-
vec.push_back(std::move(fileElement));
67+
cacheFiles.push_back(std::move(fileElement));
6768
}
68-
}
69-
70-
for (int i = 0; i < filesCount; ++i) {
7169
free(files[i]);
7270
}
71+
7372
free(files);
7473

75-
std::sort(vec.begin(), vec.end(), compareByLastAccessTime);
74+
std::sort(cacheFiles.begin(), cacheFiles.end(), compareByLastAccessTime);
7675

77-
size_t evictionLimit = config.cacheSize / 3;
76+
bytesEvicted = 0;
77+
const auto evictionLimit = config.cacheSize / 3;
7878

79-
size_t evictionSizeCount = 0;
80-
for (size_t i = 0; i < vec.size(); ++i) {
81-
NEO::SysCalls::unlink(vec[i].path);
82-
evictionSizeCount += vec[i].statEl.st_size;
79+
for (const auto &file : cacheFiles) {
80+
auto res = NEO::SysCalls::unlink(file.path);
81+
if (res == -1) {
82+
continue;
83+
}
8384

84-
if (evictionSizeCount > evictionLimit) {
85+
bytesEvicted += file.statEl.st_size;
86+
if (bytesEvicted > evictionLimit) {
8587
return true;
8688
}
8789
}
@@ -146,7 +148,7 @@ void CompilerCache::lockConfigFileAndReadSize(const std::string &configFilePath,
146148
}
147149
}
148150

149-
int lockErr = NEO::SysCalls::flock(std::get<int>(fd), LOCK_EX);
151+
const int lockErr = NEO::SysCalls::flock(std::get<int>(fd), LOCK_EX);
150152

151153
if (lockErr < 0) {
152154
NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stderr, "PID %d [Cache failure]: Lock config file failed! errno: %d\n", NEO::SysCalls::getProcessId(), errno);
@@ -159,7 +161,7 @@ void CompilerCache::lockConfigFileAndReadSize(const std::string &configFilePath,
159161
if (countDirectorySize) {
160162
struct dirent **files = {};
161163

162-
int filesCount = NEO::SysCalls::scandir(config.cacheDir.c_str(), &files, filterFunction, NULL);
164+
const int filesCount = NEO::SysCalls::scandir(config.cacheDir.c_str(), &files, filterFunction, NULL);
163165

164166
if (filesCount == -1) {
165167
unlockFileAndClose(std::get<int>(fd));
@@ -168,30 +170,28 @@ void CompilerCache::lockConfigFileAndReadSize(const std::string &configFilePath,
168170
return;
169171
}
170172

171-
std::vector<ElementsStruct> vec;
172-
vec.reserve(static_cast<size_t>(filesCount));
173+
std::vector<ElementsStruct> cacheFiles;
174+
cacheFiles.reserve(static_cast<size_t>(filesCount));
173175
for (int i = 0; i < filesCount; ++i) {
174176
std::string_view fileName = files[i]->d_name;
175177
if (fileName.find(config.cacheFileExtension) != fileName.npos) {
176178
ElementsStruct fileElement = {};
177179
fileElement.path = joinPath(config.cacheDir, files[i]->d_name);
178180
if (NEO::SysCalls::stat(fileElement.path.c_str(), &fileElement.statEl) == 0) {
179-
vec.push_back(std::move(fileElement));
181+
cacheFiles.push_back(std::move(fileElement));
180182
}
181183
}
182-
}
183-
184-
for (int i = 0; i < filesCount; ++i) {
185184
free(files[i]);
186185
}
186+
187187
free(files);
188188

189-
for (auto &element : vec) {
189+
for (const auto &element : cacheFiles) {
190190
directorySize += element.statEl.st_size;
191191
}
192192

193193
} else {
194-
ssize_t readErr = NEO::SysCalls::pread(std::get<int>(fd), &directorySize, sizeof(directorySize), 0);
194+
const ssize_t readErr = NEO::SysCalls::pread(std::get<int>(fd), &directorySize, sizeof(directorySize), 0);
195195

196196
if (readErr < 0) {
197197
directorySize = 0;
@@ -202,16 +202,30 @@ void CompilerCache::lockConfigFileAndReadSize(const std::string &configFilePath,
202202
}
203203
}
204204

205+
class HandleGuard {
206+
public:
207+
HandleGuard() = delete;
208+
explicit HandleGuard(int &fileDescriptor) : fd(fileDescriptor) {}
209+
~HandleGuard() {
210+
if (fd != -1) {
211+
unlockFileAndClose(fd);
212+
}
213+
}
214+
215+
private:
216+
int fd = -1;
217+
};
218+
205219
bool CompilerCache::cacheBinary(const std::string &kernelFileHash, const char *pBinary, size_t binarySize) {
206-
if (pBinary == nullptr || binarySize == 0) {
220+
if (pBinary == nullptr || binarySize == 0 || binarySize > config.cacheSize) {
207221
return false;
208222
}
209223

210224
std::unique_lock<std::mutex> lock(cacheAccessMtx);
211225
constexpr std::string_view configFileName = "config.file";
212226

213227
std::string configFilePath = joinPath(config.cacheDir, configFileName.data());
214-
std::string filePath = joinPath(config.cacheDir, kernelFileHash + config.cacheFileExtension);
228+
std::string cacheFilePath = joinPath(config.cacheDir, kernelFileHash + config.cacheFileExtension);
215229

216230
UnifiedHandle fd{-1};
217231
size_t directorySize = 0u;
@@ -222,42 +236,44 @@ bool CompilerCache::cacheBinary(const std::string &kernelFileHash, const char *p
222236
return false;
223237
}
224238

239+
HandleGuard configGuard(std::get<int>(fd));
240+
225241
struct stat statbuf = {};
226-
if (NEO::SysCalls::stat(filePath, &statbuf) == 0) {
227-
unlockFileAndClose(std::get<int>(fd));
242+
if (NEO::SysCalls::stat(cacheFilePath, &statbuf) == 0) {
228243
return true;
229244
}
230245

231-
size_t maxSize = config.cacheSize;
232-
233-
if (maxSize < directorySize + binarySize) {
246+
const size_t maxSize = config.cacheSize;
247+
if (maxSize < (directorySize + binarySize)) {
234248
uint64_t bytesEvicted{0u};
235-
if (!evictCache(bytesEvicted)) {
236-
unlockFileAndClose(std::get<int>(fd));
249+
const auto evictSuccess = evictCache(bytesEvicted);
250+
const auto availableSpace = maxSize - directorySize + bytesEvicted;
251+
252+
directorySize = std::max<size_t>(0, directorySize - bytesEvicted);
253+
254+
if (!evictSuccess || binarySize > availableSpace) {
255+
if (bytesEvicted > 0) {
256+
NEO::SysCalls::pwrite(std::get<int>(fd), &directorySize, sizeof(directorySize), 0);
257+
}
237258
return false;
238259
}
239260
}
240261

241262
std::string tmpFileName = "cl_cache.XXXXXX";
242-
243263
std::string tmpFilePath = joinPath(config.cacheDir, tmpFileName);
244264

245265
if (!createUniqueTempFileAndWriteData(tmpFilePath.data(), pBinary, binarySize)) {
246-
unlockFileAndClose(std::get<int>(fd));
247266
return false;
248267
}
249268

250-
if (!renameTempFileBinaryToProperName(tmpFilePath, filePath)) {
251-
unlockFileAndClose(std::get<int>(fd));
269+
if (!renameTempFileBinaryToProperName(tmpFilePath, cacheFilePath)) {
252270
return false;
253271
}
254272

255273
directorySize += binarySize;
256274

257275
NEO::SysCalls::pwrite(std::get<int>(fd), &directorySize, sizeof(directorySize), 0);
258276

259-
unlockFileAndClose(std::get<int>(fd));
260-
261277
return true;
262278
}
263279

0 commit comments

Comments
 (0)