|
22 | 22 | #include "Framework/SHA1.h" |
23 | 23 | #include "utils/timer.h" |
24 | 24 |
|
| 25 | +#include <algorithm> |
25 | 26 | #include <array> |
26 | 27 | #include <cstdio> |
27 | 28 | #include <cstring> |
@@ -148,26 +149,40 @@ static void compile(const GPUSettingsProcessing& proc, uint32_t nCompile, const |
148 | 149 | } |
149 | 150 | } |
150 | 151 |
|
151 | | -class Cache // RTC cache file (if rtc.cacheOutput), locked while the object exists. Usage: if (!cache.load(...)) { compile; cache.store(...); } |
| 152 | +class Cache // RTC cache file <cacheFolder>/rtc.<backend>.cache.<id> (no id with rtctech.ignoreCacheValid) (if rtc.cacheOutput), id from the SHAs of the inputs, locked per backend while the object exists. Usage: if (!cache.load(...)) { compile; cache.store(...); } |
152 | 153 | { |
153 | 154 | public: |
154 | 155 | static constexpr uint32_t N_SHA = 6; |
155 | 156 | using Inputs = std::array<std::string_view, N_SHA>; // source, param, command line, kernel definitions, launch bounds, compiler versions |
156 | 157 |
|
157 | | - Cache(const GPUSettingsProcessing& proc, const char* cacheName, const Inputs& inputs) : mProc(proc), mFile(proc.rtctech.cacheFolder + "/" + cacheName) |
| 158 | + Cache(const GPUSettingsProcessing& proc, const char* backend, const Inputs& inputs) : mProc(proc), mPrefix(std::string("rtc.") + backend + ".cache.") |
158 | 159 | { |
159 | 160 | if (!mProc.rtc.cacheOutput) { |
160 | 161 | return; |
161 | 162 | } |
| 163 | + char shaSettings[21]; // Only for the id, the settings are compared with operator== on load (the raw bytes include padding) |
162 | 164 | for (uint32_t i = 0; i < N_SHA; i++) { |
163 | 165 | o2::framework::internal::SHA1(mSHA[i], inputs[i].data(), inputs[i].size()); |
164 | 166 | } |
| 167 | + o2::framework::internal::SHA1(shaSettings, (const char*)&mProc.rtc, sizeof(mProc.rtc)); |
| 168 | + uint64_t id = 0; |
| 169 | + for (uint32_t i = 0; i <= N_SHA; i++) { |
| 170 | + for (uint32_t j = 0; j < 20; j += 5) { // XOR of all SHAs in 5-byte blocks |
| 171 | + uint64_t block = 0; |
| 172 | + memcpy(&block, (i < N_SHA ? mSHA[i] : shaSettings) + j, 5); |
| 173 | + id ^= block; |
| 174 | + } |
| 175 | + } |
| 176 | + char idStr[11]; |
| 177 | + snprintf(idStr, sizeof(idStr), "%010llX", (unsigned long long)id); |
| 178 | + mFileName = mProc.rtctech.ignoreCacheValid ? mPrefix.substr(0, mPrefix.size() - 1) : (mPrefix + idStr); // Without id for ignoreCacheValid, to find the cache file for any input |
| 179 | + mFile = mProc.rtctech.cacheFolder + "/" + mFileName; |
165 | 180 | if (mProc.rtctech.cacheFolder != ".") { |
166 | 181 | std::filesystem::create_directories(mProc.rtctech.cacheFolder); |
167 | 182 | } |
168 | 183 | if (mProc.rtctech.cacheMutex) { |
169 | 184 | mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; |
170 | | - mFd = open((mProc.rtctech.cacheFolder + "/cache.lock").c_str(), O_RDWR | O_CREAT | O_CLOEXEC, mask); |
| 185 | + mFd = open((mProc.rtctech.cacheFolder + "/cache_" + backend + ".lock").c_str(), O_RDWR | O_CREAT | O_CLOEXEC, mask); |
171 | 186 | if (mFd == -1) { |
172 | 187 | throw std::runtime_error("Error opening rtc cache mutex lock file"); |
173 | 188 | } |
@@ -204,6 +219,8 @@ class Cache // RTC cache file (if rtc.cacheOutput), locked while the object exis |
204 | 219 | fclose(fp); |
205 | 220 | if (retVal) { |
206 | 221 | GPUInfo("Using RTC cache file"); |
| 222 | + std::error_code ec; |
| 223 | + std::filesystem::last_write_time(mFile, std::filesystem::file_time_type::clock::now(), ec); // Mark as recently used for removeOldFiles() |
207 | 224 | } |
208 | 225 | return retVal; |
209 | 226 | } |
@@ -245,9 +262,32 @@ class Cache // RTC cache file (if rtc.cacheOutput), locked while the object exis |
245 | 262 | } |
246 | 263 | } |
247 | 264 | fclose(fp); |
| 265 | + removeOldFiles(); |
248 | 266 | } |
249 | 267 |
|
250 | 268 | private: |
| 269 | + void removeOldFiles() const // Keeps the rtctech.cacheSize most recent cache files of this backend, including the one just written |
| 270 | + { |
| 271 | + if (mProc.rtctech.cacheSize == 0 || mProc.rtctech.ignoreCacheValid) { |
| 272 | + return; |
| 273 | + } |
| 274 | + std::vector<std::pair<std::filesystem::file_time_type, std::filesystem::path>> files; |
| 275 | + std::error_code ec; |
| 276 | + for (const auto& entry : std::filesystem::directory_iterator(mProc.rtctech.cacheFolder)) { |
| 277 | + const std::string name = entry.path().filename().string(); |
| 278 | + if (name.starts_with(mPrefix) && name != mFileName && entry.is_regular_file(ec)) { |
| 279 | + files.emplace_back(entry.last_write_time(ec), entry.path()); |
| 280 | + } |
| 281 | + } |
| 282 | + if (files.size() < mProc.rtctech.cacheSize) { |
| 283 | + return; |
| 284 | + } |
| 285 | + std::sort(files.begin(), files.end(), std::greater<>()); // Most recent first |
| 286 | + for (uint32_t i = mProc.rtctech.cacheSize - 1; i < files.size(); i++) { |
| 287 | + std::filesystem::remove(files[i].second, ec); |
| 288 | + } |
| 289 | + } |
| 290 | + |
251 | 291 | bool read(FILE* fp, const std::string& filename, const char* binExtension, uint32_t nCompile) |
252 | 292 | { |
253 | 293 | static constexpr const char* names[N_SHA] = {"source", "param", "command line", "kernel definitions", "launch bounds", "compiler versions"}; |
@@ -301,7 +341,8 @@ class Cache // RTC cache file (if rtc.cacheOutput), locked while the object exis |
301 | 341 | } |
302 | 342 |
|
303 | 343 | const GPUSettingsProcessing& mProc; |
304 | | - const std::string mFile; |
| 344 | + const std::string mPrefix; |
| 345 | + std::string mFileName, mFile; |
305 | 346 | char mSHA[N_SHA][21]; |
306 | 347 | int32_t mFd = -1; |
307 | 348 | }; |
|
0 commit comments