diff --git a/GPU/GPUTracking/Base/GPUReconstructionRTCHelpers.inc b/GPU/GPUTracking/Base/GPUReconstructionRTCHelpers.inc new file mode 100644 index 0000000000000..f6f794315a783 --- /dev/null +++ b/GPU/GPUTracking/Base/GPUReconstructionRTCHelpers.inc @@ -0,0 +1,350 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUReconstructionRTCHelpers.inc +/// \author David Rohr + +// Backend-independent helpers for the genRTC functions of the RTC backends, include only once per backend source file + +#include "GPUSettings.h" +#include "GPUParamRTC.h" +#include "GPUDefParametersLoad.inc" +#include "GPUNoFastMathKernels.h" +#include "GPULogging.h" +#include "Framework/SHA1.h" +#include "utils/timer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace o2::gpu::internal::rtc +{ + +static std::string paramCode(const GPUSettingsProcessing& proc, const GPUParam& param) // RTC defines and parameters, common to all compilations +{ + return std::string("#define GPUCA_RTC_CODE\n") + + (proc.rtc.optSpecialCode ? "#define GPUCA_RTC_SPECIAL_CODE(...) __VA_ARGS__\n" : "#define GPUCA_RTC_SPECIAL_CODE(...)\n") + + (proc.rtc.optConstexpr ? "#define GPUCA_RTC_CONSTEXPR constexpr\n" : "#define GPUCA_RTC_CONSTEXPR\n") + + GPUParamRTC::generateRTCCode(param, proc.rtc.optConstexpr); +} + +static void tmpFilename(std::string& filename, const char* defaultPrefix) +{ + filename = (filename == "" ? defaultPrefix : filename) + std::to_string(getpid()) + "_" + std::to_string(rand()); +} + +static std::string joinKernels(const std::vector& kernels) +{ + std::string retVal; + for (const auto& kernel : kernels) { + retVal += kernel + "\n"; + } + return retVal; +} + +static std::string baseCommand(const GPUSettingsProcessing& proc, std::string_view embeddedCommand) // Prepended command + compiler command (embedded or from O2_GPU_RTC_OVERRIDE_CMD) +{ + const char* overrideCmd = getenv("O2_GPU_RTC_OVERRIDE_CMD"); + return (proc.rtctech.prependCommand != "" ? (proc.rtctech.prependCommand + " ") : "") + (overrideCmd ? std::string(overrideCmd) : std::string(embeddedCommand)); +} + +static void loadLaunchBounds(const GPUSettingsProcessing& proc, GPUDefParameters& par) +{ + if (proc.rtctech.loadLaunchBoundsFromFile.size() == 0) { + return; + } + FILE* fp = fopen(proc.rtctech.loadLaunchBoundsFromFile.c_str(), "rb"); + if (fp == nullptr) { + throw std::runtime_error("Cannot open launch bounds parameter module file"); + } + fseek(fp, 0, SEEK_END); + size_t size = ftell(fp); + if (size != sizeof(par)) { + throw std::runtime_error("launch bounds parameter file has incorrect size"); + } + fseek(fp, 0, SEEK_SET); + if (fread(&par, 1, size, fp) != size) { + throw std::runtime_error("Error reading launch bounds parameter file"); + } + fclose(fp); +} + +static std::string launchBoundsCode(const GPUSettingsProcessing& proc, const GPUDefParameters& par, int32_t minBlockFactor, uint32_t warpSize) // Prints the launch bounds if requested +{ + std::string retVal = GPUDefParametersExport(par, true, minBlockFactor) + "#define GPUCA_WARP_SIZE " + std::to_string(warpSize) + "\n"; + if (proc.rtctech.printLaunchBounds || proc.debugLevel >= 3) { + GPUInfo("RTC Launch Bounds:\n%s", retVal.c_str()); + } + return retVal; +} + +static bool deterministic(const GPUSettingsProcessing& proc, const std::string& kernelName) // Whether compilation of kernel (or of all kernels with !compilePerKernel) uses deterministic code and no fast math +{ + return proc.rtc.deterministic || (proc.rtc.compilePerKernel && noFastMathKernels.find(kernelName) != noFastMathKernels.end()); +} + +static void writeSource(const std::string& file, bool deterministic, const std::string& param, const std::string& launchBounds, std::string_view source, const std::string& kernel) +{ + const std::string deterministicStr = deterministic ? "#define GPUCA_DETERMINISTIC_CODE(det, indet) det\n" : "#define GPUCA_DETERMINISTIC_CODE(det, indet) indet\n"; + FILE* fp = fopen(file.c_str(), "w+b"); + if (fp == nullptr) { + throw std::runtime_error("Error opening file"); + } + for (std::string_view part : {std::string_view(deterministicStr), std::string_view(param), std::string_view(launchBounds), source, std::string_view(kernel)}) { + if (fwrite(part.data(), 1, part.size(), fp) != part.size()) { + throw std::runtime_error("Error writing file"); + } + } + fclose(fp); +} + +static void runCommand(const GPUSettingsProcessing& proc, std::string command, const std::string& sourceFile, const char* errorMessage) // Runs the compiler command, output suppressed depending on the debug level +{ + if (proc.debugLevel < 0) { + command += " &> /dev/null"; + } else if (proc.debugLevel < 2) { + command += " > /dev/null"; + } + if (proc.debugLevel >= 3) { + printf("Running command %s\n", command.c_str()); + } + if (system(command.c_str())) { + if (proc.debugLevel >= 3) { + printf("Source code file: %s", sourceFile.c_str()); + } + throw std::runtime_error(errorMessage); + } +} + +template +static void compile(const GPUSettingsProcessing& proc, uint32_t nCompile, const char* backend, T&& compileOne) // Runs compileOne(i) for all compilations in parallel +{ + if (proc.debugLevel >= 0) { + GPUInfo("Starting %s RTC Compilation", backend); + } + HighResTimer rtcTimer; + rtcTimer.ResetStart(); + tbb::parallel_for(0, nCompile, compileOne, tbb::simple_partitioner()); + if (proc.debugLevel >= 0) { + GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); + } +} + +class Cache // RTC cache file /rtc..cache. (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(...); } +{ + public: + static constexpr uint32_t N_SHA = 6; + using Inputs = std::array; // source, param, command line, kernel definitions, launch bounds, compiler versions + + Cache(const GPUSettingsProcessing& proc, const char* backend, const Inputs& inputs) : mProc(proc), mPrefix(std::string("rtc.") + backend + ".cache.") + { + if (!mProc.rtc.cacheOutput) { + return; + } + char shaSettings[21]; // Only for the id, the settings are compared with operator== on load (the raw bytes include padding) + for (uint32_t i = 0; i < N_SHA; i++) { + o2::framework::internal::SHA1(mSHA[i], inputs[i].data(), inputs[i].size()); + } + o2::framework::internal::SHA1(shaSettings, (const char*)&mProc.rtc, sizeof(mProc.rtc)); + uint64_t id = 0; + for (uint32_t i = 0; i <= N_SHA; i++) { + for (uint32_t j = 0; j < 20; j += 5) { // XOR of all SHAs in 5-byte blocks + uint64_t block = 0; + memcpy(&block, (i < N_SHA ? mSHA[i] : shaSettings) + j, 5); + id ^= block; + } + } + char idStr[11]; + snprintf(idStr, sizeof(idStr), "%010llX", (unsigned long long)id); + mFileName = mProc.rtctech.ignoreCacheValid ? mPrefix.substr(0, mPrefix.size() - 1) : (mPrefix + idStr); // Without id for ignoreCacheValid, to find the cache file for any input + mFile = mProc.rtctech.cacheFolder + "/" + mFileName; + if (mProc.rtctech.cacheFolder != ".") { + std::filesystem::create_directories(mProc.rtctech.cacheFolder); + } + if (mProc.rtctech.cacheMutex) { + mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + mFd = open((mProc.rtctech.cacheFolder + "/cache_" + backend + ".lock").c_str(), O_RDWR | O_CREAT | O_CLOEXEC, mask); + if (mFd == -1) { + throw std::runtime_error("Error opening rtc cache mutex lock file"); + } + fchmod(mFd, mask); + if (lockf(mFd, F_LOCK, 0)) { + close(mFd); + mFd = -1; + throw std::runtime_error("Error locking rtc cache mutex file"); + } + } + } + ~Cache() + { + if (mFd != -1) { + if (lockf(mFd, F_ULOCK, 0)) { + GPUError("Error unlocking RTC cache mutex file"); + } + close(mFd); + } + } + Cache(const Cache&) = delete; + Cache& operator=(const Cache&) = delete; + + bool load(const std::string& filename, const char* binExtension, uint32_t nCompile) // Writes the cached binaries to filename_, false if no valid cache + { + if (!mProc.rtc.cacheOutput) { + return false; + } + FILE* fp = fopen(mFile.c_str(), "rb"); + if (fp == nullptr) { + return false; + } + bool retVal = read(fp, filename, binExtension, nCompile); + fclose(fp); + if (retVal) { + GPUInfo("Using RTC cache file"); + std::error_code ec; + std::filesystem::last_write_time(mFile, std::filesystem::file_time_type::clock::now(), ec); // Mark as recently used for removeOldFiles() + } + return retVal; + } + + void store(const std::string& filename, const char* binExtension, uint32_t nCompile) + { + if (!mProc.rtc.cacheOutput) { + return; + } + FILE* fp = fopen(mFile.c_str(), "w+b"); + if (fp == nullptr) { + throw std::runtime_error("Cannot open cache file for writing"); + } + GPUInfo("Storing RTC compilation result in cache file"); + for (uint32_t i = 0; i < N_SHA; i++) { + if (fwrite(mSHA[i], 1, 20, fp) != 20) { + throw std::runtime_error("Error writing cache file"); + } + } + if (fwrite(&mProc.rtc, sizeof(mProc.rtc), 1, fp) != 1) { + throw std::runtime_error("Error writing cache file"); + } + std::vector buffer; + for (uint32_t i = 0; i < nCompile; i++) { + FILE* fp2 = fopen((filename + "_" + std::to_string(i) + binExtension).c_str(), "rb"); + if (fp2 == nullptr) { + throw std::runtime_error("Cannot open RTC binary file"); + } + fseek(fp2, 0, SEEK_END); + size_t size = ftell(fp2); + buffer.resize(size); + fseek(fp2, 0, SEEK_SET); + if (fread(buffer.data(), 1, size, fp2) != size) { + throw std::runtime_error("Error reading RTC binary file"); + } + fclose(fp2); + if (fwrite(&size, sizeof(size), 1, fp) != 1 || fwrite(buffer.data(), 1, size, fp) != size) { + throw std::runtime_error("Error writing cache file"); + } + } + fclose(fp); + removeOldFiles(); + } + + private: + void removeOldFiles() const // Keeps the rtctech.cacheSize most recent cache files of this backend, including the one just written + { + if (mProc.rtctech.cacheSize == 0 || mProc.rtctech.ignoreCacheValid) { + return; + } + std::vector> files; + std::error_code ec; + for (const auto& entry : std::filesystem::directory_iterator(mProc.rtctech.cacheFolder)) { + const std::string name = entry.path().filename().string(); + if (name.starts_with(mPrefix) && name != mFileName && entry.is_regular_file(ec)) { + files.emplace_back(entry.last_write_time(ec), entry.path()); + } + } + if (files.size() < mProc.rtctech.cacheSize) { + return; + } + std::sort(files.begin(), files.end(), std::greater<>()); // Most recent first + for (uint32_t i = mProc.rtctech.cacheSize - 1; i < files.size(); i++) { + std::filesystem::remove(files[i].second, ec); + } + } + + bool read(FILE* fp, const std::string& filename, const char* binExtension, uint32_t nCompile) + { + static constexpr const char* names[N_SHA] = {"source", "param", "command line", "kernel definitions", "launch bounds", "compiler versions"}; + for (uint32_t i = 0; i < N_SHA; i++) { + char sharead[20]; + if (fread(sharead, 1, 20, fp) != 20) { + throw std::runtime_error("Cache file corrupt"); + } + if (mProc.debugLevel >= 3) { + char shaprint1[41], shaprint2[41]; + for (uint32_t j = 0; j < 20; j++) { + snprintf(shaprint1 + 2 * j, 3, "%02X", (uint8_t)mSHA[i][j]); + snprintf(shaprint2 + 2 * j, 3, "%02X", (uint8_t)sharead[j]); + } + GPUInfo("SHA for %s: expected %s, read %s", names[i], shaprint1, shaprint2); + } + if (!mProc.rtctech.ignoreCacheValid && memcmp(sharead, mSHA[i], 20)) { + GPUInfo("Cache file content outdated (%s)", names[i]); + return false; + } + } + GPUSettingsProcessingRTC cachedSettings; + static_assert(std::is_trivially_copyable_v == true, "GPUSettingsProcessingRTC must be POD"); + if (fread(&cachedSettings, sizeof(cachedSettings), 1, fp) != 1) { + throw std::runtime_error("Cache file corrupt"); + } + if (!mProc.rtctech.ignoreCacheValid && !(cachedSettings == mProc.rtc)) { + GPUInfo("Cache file content outdated (rtc parameters)"); + return false; + } + std::vector buffer; + for (uint32_t i = 0; i < nCompile; i++) { + size_t len; + if (fread(&len, sizeof(len), 1, fp) != 1) { + throw std::runtime_error("Cache file corrupt"); + } + buffer.resize(len); + if (fread(buffer.data(), 1, len, fp) != len) { + throw std::runtime_error("Cache file corrupt"); + } + FILE* fp2 = fopen((filename + "_" + std::to_string(i) + binExtension).c_str(), "w+b"); + if (fp2 == nullptr) { + throw std::runtime_error("Cannot open tmp file"); + } + if (fwrite(buffer.data(), 1, len, fp2) != len) { + throw std::runtime_error("Error writing file"); + } + fclose(fp2); + } + return true; + } + + const GPUSettingsProcessing& mProc; + const std::string mPrefix; + std::string mFileName, mFile; + char mSHA[N_SHA][21]; + int32_t mFd = -1; +}; + +} // namespace o2::gpu::internal::rtc diff --git a/GPU/GPUTracking/Base/cpudevice/GPUReconstructionCPUDeviceGenRTC.cxx b/GPU/GPUTracking/Base/cpudevice/GPUReconstructionCPUDeviceGenRTC.cxx index 14501ffc9da6b..90a765b85cba3 100644 --- a/GPU/GPUTracking/Base/cpudevice/GPUReconstructionCPUDeviceGenRTC.cxx +++ b/GPU/GPUTracking/Base/cpudevice/GPUReconstructionCPUDeviceGenRTC.cxx @@ -23,28 +23,17 @@ #include "GPUReconstructionCPUDeviceInternals.h" #include "GPUReconstructionKernelIncludes.h" #include "GPUReconstructionKernelMacros.h" -#include "GPUParamRTC.h" -#include "GPUDefParametersLoad.inc" -#include "GPUNoFastMathKernels.h" -#include "Framework/SHA1.h" +#include "GPUReconstructionRTCHelpers.inc" #include "utils/qGetLdBinarySymbols.h" -#include "utils/timer.h" -#include -#include -#include -#include -#include #include -#include -#include -#include QGET_LD_BINARY_SYMBOLS(GPUReconstructionCPUDevicertc_src); QGET_LD_BINARY_SYMBOLS(GPUReconstructionCPUDevicertc_command); QGET_LD_BINARY_SYMBOLS(GPUReconstructionCPUDevicertc_command_no_fast_math); using namespace o2::gpu; +namespace rtc = o2::gpu::internal::rtc; static constexpr const char* RTC_SRC_EXTENSION = ".cxx"; static constexpr const char* RTC_BIN_EXTENSION = ".so"; @@ -54,17 +43,10 @@ static bool kernelWithoutRTC(const std::string& name) { return name == "GPUTPCCF int32_t GPUReconstructionCPUDevice::genRTC(std::string& filename, uint32_t& nCompile) { + const auto& proc = GetProcessingSettings(); const std::string_view rtcSource(_binary_GPUReconstructionCPUDevicertc_src_start, _binary_GPUReconstructionCPUDevicertc_src_len); - const std::string rtcparam = std::string("#define GPUCA_RTC_CODE\n") + - std::string(GetProcessingSettings().rtc.optSpecialCode ? "#define GPUCA_RTC_SPECIAL_CODE(...) __VA_ARGS__\n" : "#define GPUCA_RTC_SPECIAL_CODE(...)\n") + - std::string(GetProcessingSettings().rtc.optConstexpr ? "#define GPUCA_RTC_CONSTEXPR constexpr\n" : "#define GPUCA_RTC_CONSTEXPR\n") + - GPUParamRTC::generateRTCCode(param(), GetProcessingSettings().rtc.optConstexpr); - if (filename == "") { - filename = "/tmp/o2cagpu_rtc_cpudevice_"; - } - filename += std::to_string(getpid()); - filename += "_"; - filename += std::to_string(rand()); + const std::string rtcparam = rtc::paramCode(proc, param()); + rtc::tmpFilename(filename, "/tmp/o2cagpu_rtc_cpudevice_"); std::vector kernels; getRTCKernelCalls(kernels); @@ -73,235 +55,41 @@ int32_t GPUReconstructionCPUDevice::genRTC(std::string& filename, uint32_t& nCom kernels[i].clear(); } } - std::string kernelsall; - for (uint32_t i = 0; i < kernels.size(); i++) { - kernelsall += kernels[i] + "\n"; - } + const std::string kernelsall = rtc::joinKernels(kernels); - std::string baseCommand = (GetProcessingSettings().rtctech.prependCommand != "" ? (GetProcessingSettings().rtctech.prependCommand + " ") : ""); - baseCommand += (getenv("O2_GPU_RTC_OVERRIDE_CMD") ? std::string(getenv("O2_GPU_RTC_OVERRIDE_CMD")) : std::string(_binary_GPUReconstructionCPUDevicertc_command_start, _binary_GPUReconstructionCPUDevicertc_command_len)); - baseCommand += std::string(" ") + GetProcessingSettings().rtctech.overrideArchitecture; + const std::string baseCommand = rtc::baseCommand(proc, std::string_view(_binary_GPUReconstructionCPUDevicertc_command_start, _binary_GPUReconstructionCPUDevicertc_command_len)) + " " + proc.rtctech.overrideArchitecture; + const std::string noFastMath(_binary_GPUReconstructionCPUDevicertc_command_no_fast_math_start, _binary_GPUReconstructionCPUDevicertc_command_no_fast_math_len); - if (GetProcessingSettings().rtctech.loadLaunchBoundsFromFile.size()) { - FILE* fp = fopen(GetProcessingSettings().rtctech.loadLaunchBoundsFromFile.c_str(), "rb"); - if (fp == nullptr) { - throw std::runtime_error("Cannot open launch bounds parameter module file"); - } - fseek(fp, 0, SEEK_END); - size_t size = ftell(fp); - if (size != sizeof(*mParDevice)) { - throw std::runtime_error("launch bounds parameter file has incorrect size"); - } - fseek(fp, 0, SEEK_SET); - if (fread(mParDevice, 1, size, fp) != size) { - throw std::runtime_error("Error reading launch bounds parameter file"); - } - fclose(fp); - } - const std::string launchBounds = o2::gpu::internal::GPUDefParametersExport(*mParDevice, true, 0) + "#define GPUCA_WARP_SIZE " + std::to_string(mWarpSize) + "\n"; - if (GetProcessingSettings().rtctech.printLaunchBounds || GetProcessingSettings().debugLevel >= 3) { - GPUInfo("RTC Launch Bounds:\n%s", launchBounds.c_str()); - if (GetProcessingSettings().rtctech.printLaunchBounds >= 2) { - return 1; - } + rtc::loadLaunchBounds(proc, *mParDevice); + const std::string launchBounds = rtc::launchBoundsCode(proc, *mParDevice, 0, mWarpSize); + if (proc.rtctech.printLaunchBounds >= 2) { + return 1; } + nCompile = proc.rtc.compilePerKernel ? kernels.size() : 1; const std::string compilerVersions = getBackendVersions(); - - char shasource[21], shaparam[21], shacmd[21], shakernels[21], shabounds[21], shaversion[21]; - if (GetProcessingSettings().rtc.cacheOutput) { - o2::framework::internal::SHA1(shasource, rtcSource.data(), rtcSource.size()); - o2::framework::internal::SHA1(shaparam, rtcparam.c_str(), rtcparam.size()); - o2::framework::internal::SHA1(shacmd, baseCommand.c_str(), baseCommand.size()); - o2::framework::internal::SHA1(shakernels, kernelsall.c_str(), kernelsall.size()); - o2::framework::internal::SHA1(shabounds, launchBounds.c_str(), launchBounds.size()); - o2::framework::internal::SHA1(shaversion, compilerVersions.c_str(), compilerVersions.size()); - } - - nCompile = GetProcessingSettings().rtc.compilePerKernel ? kernels.size() : 1; - bool cacheLoaded = false; - int32_t fd = 0; - const std::string cacheFile = GetProcessingSettings().rtctech.cacheFolder + "/rtc.cpudevice.cache"; - if (GetProcessingSettings().rtc.cacheOutput) { - if (GetProcessingSettings().rtctech.cacheFolder != ".") { - std::filesystem::create_directories(GetProcessingSettings().rtctech.cacheFolder); - } - if (GetProcessingSettings().rtctech.cacheMutex) { - mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - fd = open((GetProcessingSettings().rtctech.cacheFolder + "/cache.lock").c_str(), O_RDWR | O_CREAT | O_CLOEXEC, mask); - if (fd == -1) { - throw std::runtime_error("Error opening rtc cache mutex lock file"); - } - fchmod(fd, mask); - if (lockf(fd, F_LOCK, 0)) { - throw std::runtime_error("Error locking rtc cache mutex file"); - } - } - - FILE* fp = fopen(cacheFile.c_str(), "rb"); - char sharead[20]; - if (fp) { - size_t len; - while (true) { - auto checkSHA = [&](const char* shacmp, const char* name) { - if (fread(sharead, 1, 20, fp) != 20) { - throw std::runtime_error("Cache file corrupt"); - } - if (!GetProcessingSettings().rtctech.ignoreCacheValid && memcmp(sharead, shacmp, 20)) { - GPUInfo("Cache file content outdated (%s)", name); - return 1; - } - return 0; - }; - if (checkSHA(shasource, "source") || - checkSHA(shaparam, "param") || - checkSHA(shacmd, "command line") || - checkSHA(shakernels, "kernel definitions") || - checkSHA(shabounds, "launch bounds") || - checkSHA(shaversion, "compiler versions")) { - break; - } - GPUSettingsProcessingRTC cachedSettings; - static_assert(std::is_trivially_copyable_v == true, "GPUSettingsProcessingRTC must be POD"); - if (fread(&cachedSettings, sizeof(cachedSettings), 1, fp) != 1) { - throw std::runtime_error("Cache file corrupt"); - } - if (!GetProcessingSettings().rtctech.ignoreCacheValid && !(cachedSettings == GetProcessingSettings().rtc)) { - GPUInfo("Cache file content outdated (rtc parameters)"); - break; - } - std::vector buffer; - for (uint32_t i = 0; i < nCompile; i++) { - if (fread(&len, sizeof(len), 1, fp) != 1) { - throw std::runtime_error("Cache file corrupt"); - } - buffer.resize(len); - if (fread(buffer.data(), 1, len, fp) != len) { - throw std::runtime_error("Cache file corrupt"); - } - FILE* fp2 = fopen((filename + "_" + std::to_string(i) + RTC_BIN_EXTENSION).c_str(), "w+b"); - if (fp2 == nullptr) { - throw std::runtime_error("Cannot open tmp file"); - } - if (fwrite(buffer.data(), 1, len, fp2) != len) { - throw std::runtime_error("Error writing file"); - } - fclose(fp2); - } - GPUInfo("Using RTC cache file"); - cacheLoaded = true; - break; - }; - fclose(fp); - } - } - if (!cacheLoaded) { - if (GetProcessingSettings().debugLevel >= 0) { - GPUInfo("Starting CPUDevice RTC Compilation"); - } - HighResTimer rtcTimer; - rtcTimer.ResetStart(); - tbb::parallel_for(0, nCompile, [&](auto i) { + rtc::Cache cache(proc, "cpudevice", {rtcSource, rtcparam, baseCommand, kernelsall, launchBounds, compilerVersions}); + if (!cache.load(filename, RTC_BIN_EXTENSION, nCompile)) { + rtc::compile(proc, nCompile, "CPUDevice", [&](uint32_t i) { const std::string fileBase = filename + "_" + std::to_string(i); - if (GetProcessingSettings().debugLevel >= 3) { + if (proc.debugLevel >= 3) { printf("Compiling %s\n", (fileBase + RTC_SRC_EXTENSION).c_str()); } - FILE* fp = fopen((fileBase + RTC_SRC_EXTENSION).c_str(), "w+b"); - if (fp == nullptr) { - throw std::runtime_error("Error opening file"); - } - - const std::string& kernel = GetProcessingSettings().rtc.compilePerKernel ? kernels[i] : kernelsall; - - bool deterministic = GetProcessingSettings().rtc.deterministic || (GetProcessingSettings().rtc.compilePerKernel && o2::gpu::internal::noFastMathKernels.find(GetKernelName(i)) != o2::gpu::internal::noFastMathKernels.end()); - const std::string deterministicStr = std::string(deterministic ? "#define GPUCA_DETERMINISTIC_CODE(det, indet) det\n" : "#define GPUCA_DETERMINISTIC_CODE(det, indet) indet\n"); - - if (fwrite(deterministicStr.c_str(), 1, deterministicStr.size(), fp) != deterministicStr.size() || - fwrite(rtcparam.c_str(), 1, rtcparam.size(), fp) != rtcparam.size() || - fwrite(launchBounds.c_str(), 1, launchBounds.size(), fp) != launchBounds.size() || - fwrite(rtcSource.data(), 1, rtcSource.size(), fp) != rtcSource.size() || - fwrite(kernel.c_str(), 1, kernel.size(), fp) != kernel.size()) { - throw std::runtime_error("Error writing file"); - } - fclose(fp); + const bool deterministic = rtc::deterministic(proc, GetKernelName(i)); + rtc::writeSource(fileBase + RTC_SRC_EXTENSION, deterministic, rtcparam, launchBounds, rtcSource, proc.rtc.compilePerKernel ? kernels[i] : kernelsall); // Export only the kernel entry points, everything else stays local to the RTC library to avoid symbol collisions - fp = fopen((fileBase + RTC_MAP_EXTENSION).c_str(), "w+b"); + FILE* fp = fopen((fileBase + RTC_MAP_EXTENSION).c_str(), "w+b"); if (fp == nullptr || fprintf(fp, "{ global: krnl_*; local: *; };\n") < 0) { throw std::runtime_error("Error writing version script"); } fclose(fp); - std::string command = baseCommand; - if (deterministic) { - command += std::string(" ") + std::string(_binary_GPUReconstructionCPUDevicertc_command_no_fast_math_start, _binary_GPUReconstructionCPUDevicertc_command_no_fast_math_len); - } - command += " -Wl,--version-script=" + fileBase + RTC_MAP_EXTENSION + " -x c++ " + fileBase + RTC_SRC_EXTENSION + " -o " + fileBase + RTC_BIN_EXTENSION; - if (GetProcessingSettings().debugLevel < 0) { - command += " &> /dev/null"; - } else if (GetProcessingSettings().debugLevel < 2) { - command += " > /dev/null"; - } - if (GetProcessingSettings().debugLevel >= 3) { - printf("Running command %s\n", command.c_str()); - } - if (system(command.c_str())) { - if (GetProcessingSettings().debugLevel >= 3) { - printf("Source code file: %s", (fileBase + RTC_SRC_EXTENSION).c_str()); - } - throw std::runtime_error("Error during CPUDevice RTC compilation"); - } // clang-format off - }, tbb::simple_partitioner()); // clang-format on - if (GetProcessingSettings().debugLevel >= 0) { - GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); - } - if (GetProcessingSettings().rtc.cacheOutput) { - FILE* fp = fopen(cacheFile.c_str(), "w+b"); - if (fp == nullptr) { - throw std::runtime_error("Cannot open cache file for writing"); - } - GPUInfo("Storing RTC compilation result in cache file"); - - if (fwrite(shasource, 1, 20, fp) != 20 || - fwrite(shaparam, 1, 20, fp) != 20 || - fwrite(shacmd, 1, 20, fp) != 20 || - fwrite(shakernels, 1, 20, fp) != 20 || - fwrite(shabounds, 1, 20, fp) != 20 || - fwrite(shaversion, 1, 20, fp) != 20 || - fwrite(&GetProcessingSettings().rtc, sizeof(GetProcessingSettings().rtc), 1, fp) != 1) { - throw std::runtime_error("Error writing cache file"); - } - - std::vector buffer; - for (uint32_t i = 0; i < nCompile; i++) { - FILE* fp2 = fopen((filename + "_" + std::to_string(i) + RTC_BIN_EXTENSION).c_str(), "rb"); - if (fp2 == nullptr) { - throw std::runtime_error("Cannot open RTC library file"); - } - fseek(fp2, 0, SEEK_END); - size_t size = ftell(fp2); - buffer.resize(size); - fseek(fp2, 0, SEEK_SET); - if (fread(buffer.data(), 1, size, fp2) != size) { - throw std::runtime_error("Error reading RTC library file"); - } - fclose(fp2); - - if (fwrite(&size, sizeof(size), 1, fp) != 1 || - fwrite(buffer.data(), 1, size, fp) != size) { - throw std::runtime_error("Error writing cache file"); - } - } - fclose(fp); - } + const std::string command = baseCommand + (deterministic ? " " + noFastMath : "") + " -Wl,--version-script=" + fileBase + RTC_MAP_EXTENSION + " -x c++ " + fileBase + RTC_SRC_EXTENSION + " -o " + fileBase + RTC_BIN_EXTENSION; + rtc::runCommand(proc, command, fileBase + RTC_SRC_EXTENSION, "Error during CPUDevice RTC compilation"); + }); + cache.store(filename, RTC_BIN_EXTENSION, nCompile); } - if (GetProcessingSettings().rtc.cacheOutput && GetProcessingSettings().rtctech.cacheMutex) { - if (lockf(fd, F_ULOCK, 0)) { - throw std::runtime_error("Error unlocking RTC cache mutex file"); - } - close(fd); - } - return 0; } diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cxx b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cxx index 2081570f8cdb9..c16bbae598e72 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cxx +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cxx @@ -15,18 +15,12 @@ #define GPUCA_GPUCODE_HOSTONLY #include "GPUReconstructionCUDA.h" -#include "GPUParamRTC.h" -#include "GPUDefParametersLoad.inc" +#include "GPUReconstructionRTCHelpers.inc" #include "GPUKernelsWith1Warp.inc" -#include -#include "Framework/SHA1.h" -#include -#include -#include #include -#include using namespace o2::gpu; +namespace rtc = o2::gpu::internal::rtc; #include "utils/qGetLdBinarySymbols.h" QGET_LD_BINARY_SYMBOLS(GPUReconstructionCUDArtc_src); @@ -34,51 +28,25 @@ QGET_LD_BINARY_SYMBOLS(GPUReconstructionCUDArtc_command); QGET_LD_BINARY_SYMBOLS(GPUReconstructionCUDArtc_command_arch); QGET_LD_BINARY_SYMBOLS(GPUReconstructionCUDArtc_command_no_fast_math); -#include "GPUNoFastMathKernels.h" - int32_t GPUReconstructionCUDA::genRTC(std::string& filename, uint32_t& nCompile) { - std::string rtcparam = std::string("#define GPUCA_RTC_CODE\n") + - std::string(GetProcessingSettings().rtc.optSpecialCode ? "#define GPUCA_RTC_SPECIAL_CODE(...) __VA_ARGS__\n" : "#define GPUCA_RTC_SPECIAL_CODE(...)\n") + - std::string(GetProcessingSettings().rtc.optConstexpr ? "#define GPUCA_RTC_CONSTEXPR constexpr\n" : "#define GPUCA_RTC_CONSTEXPR\n") + - GPUParamRTC::generateRTCCode(param(), GetProcessingSettings().rtc.optConstexpr); - if (filename == "") { - filename = "/tmp/o2cagpu_rtc_"; - } - filename += std::to_string(getpid()); - filename += "_"; - filename += std::to_string(rand()); + const auto& proc = GetProcessingSettings(); + const std::string_view rtcSource(_binary_GPUReconstructionCUDArtc_src_start, _binary_GPUReconstructionCUDArtc_src_len); + const std::string rtcparam = rtc::paramCode(proc, param()); + rtc::tmpFilename(filename, "/tmp/o2cagpu_rtc_"); std::vector kernels; getRTCKernelCalls(kernels); - std::string kernelsall; - for (uint32_t i = 0; i < kernels.size(); i++) { - kernelsall += kernels[i] + "\n"; - } + const std::string kernelsall = rtc::joinKernels(kernels); - std::string baseCommand = (GetProcessingSettings().rtctech.prependCommand != "" ? (GetProcessingSettings().rtctech.prependCommand + " ") : ""); - baseCommand += (getenv("O2_GPU_RTC_OVERRIDE_CMD") ? std::string(getenv("O2_GPU_RTC_OVERRIDE_CMD")) : std::string(_binary_GPUReconstructionCUDArtc_command_start, _binary_GPUReconstructionCUDArtc_command_len)); - baseCommand += std::string(" ") + (GetProcessingSettings().rtctech.overrideArchitecture != "" ? GetProcessingSettings().rtctech.overrideArchitecture : std::string(_binary_GPUReconstructionCUDArtc_command_arch_start, _binary_GPUReconstructionCUDArtc_command_arch_len)); + const std::string baseCommand = rtc::baseCommand(proc, std::string_view(_binary_GPUReconstructionCUDArtc_command_start, _binary_GPUReconstructionCUDArtc_command_len)) + " " + + (proc.rtctech.overrideArchitecture != "" ? proc.rtctech.overrideArchitecture : std::string(_binary_GPUReconstructionCUDArtc_command_arch_start, _binary_GPUReconstructionCUDArtc_command_arch_len)); + const std::string noFastMath(_binary_GPUReconstructionCUDArtc_command_no_fast_math_start, _binary_GPUReconstructionCUDArtc_command_no_fast_math_len); - if (GetProcessingSettings().rtctech.loadLaunchBoundsFromFile.size()) { - FILE* fp = fopen(GetProcessingSettings().rtctech.loadLaunchBoundsFromFile.c_str(), "rb"); - if (fp == nullptr) { - throw std::runtime_error("Cannot open launch bounds parameter module file"); - } - fseek(fp, 0, SEEK_END); - size_t size = ftell(fp); - if (size != sizeof(*mParDevice)) { - throw std::runtime_error("launch bounds parameter file has incorrect size"); - } - fseek(fp, 0, SEEK_SET); - if (fread(mParDevice, 1, size, fp) != size) { - throw std::runtime_error("Error reading launch bounds parameter file"); - } - fclose(fp); - } + rtc::loadLaunchBounds(proc, *mParDevice); if constexpr (std::string_view("CUDA") == "HIP") { // Check if we are RTC-compiling for HIP - if (GetProcessingSettings().hipOverrideAMDEUSperCU > 0) { - mParDevice->par_AMD_EUS_PER_CU = GetProcessingSettings().hipOverrideAMDEUSperCU; + if (proc.hipOverrideAMDEUSperCU > 0) { + mParDevice->par_AMD_EUS_PER_CU = proc.hipOverrideAMDEUSperCU; } else if (mParDevice->par_AMD_EUS_PER_CU <= 0) { GPUFatal("AMD_EUS_PER_CU not set in the parameters provided for the AMD GPU, you can override this via --PROChipOverrideAMDEUSperCU [n]"); } @@ -88,210 +56,27 @@ int32_t GPUReconstructionCUDA::genRTC(std::string& filename, uint32_t& nCompile) mParDevice->par_LB_maxThreads[i] = mWarpSize; } } - const std::string launchBounds = o2::gpu::internal::GPUDefParametersExport(*mParDevice, true, mParDevice->par_AMD_EUS_PER_CU ? (mParDevice->par_AMD_EUS_PER_CU * mWarpSize) : 0) + - "#define GPUCA_WARP_SIZE " + std::to_string(mWarpSize) + "\n"; - if (GetProcessingSettings().rtctech.printLaunchBounds || GetProcessingSettings().debugLevel >= 3) { - GPUInfo("RTC Launch Bounds:\n%s", launchBounds.c_str()); - if (GetProcessingSettings().rtctech.printLaunchBounds >= 2) { - return 1; - } + const std::string launchBounds = rtc::launchBoundsCode(proc, *mParDevice, mParDevice->par_AMD_EUS_PER_CU ? (mParDevice->par_AMD_EUS_PER_CU * mWarpSize) : 0, mWarpSize); + if (proc.rtctech.printLaunchBounds >= 2) { + return 1; } + nCompile = proc.rtc.compilePerKernel ? kernels.size() : 1; const std::string compilerVersions = getBackendVersions(); - - char shasource[21], shaparam[21], shacmd[21], shakernels[21], shabounds[21], shaversion[21]; - if (GetProcessingSettings().rtc.cacheOutput) { - o2::framework::internal::SHA1(shasource, _binary_GPUReconstructionCUDArtc_src_start, _binary_GPUReconstructionCUDArtc_src_len); - o2::framework::internal::SHA1(shaparam, rtcparam.c_str(), rtcparam.size()); - o2::framework::internal::SHA1(shacmd, baseCommand.c_str(), baseCommand.size()); - o2::framework::internal::SHA1(shakernels, kernelsall.c_str(), kernelsall.size()); - o2::framework::internal::SHA1(shabounds, launchBounds.c_str(), launchBounds.size()); - o2::framework::internal::SHA1(shaversion, compilerVersions.c_str(), compilerVersions.size()); - } - - nCompile = GetProcessingSettings().rtc.compilePerKernel ? kernels.size() : 1; - bool cacheLoaded = false; - int32_t fd = 0; - if (GetProcessingSettings().rtc.cacheOutput) { - if (GetProcessingSettings().rtctech.cacheFolder != ".") { - std::filesystem::create_directories(GetProcessingSettings().rtctech.cacheFolder); - } - if (GetProcessingSettings().rtctech.cacheMutex) { - mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - fd = open((GetProcessingSettings().rtctech.cacheFolder + "/cache.lock").c_str(), O_RDWR | O_CREAT | O_CLOEXEC, mask); - if (fd == -1) { - throw std::runtime_error("Error opening rtc cache mutex lock file"); - } - fchmod(fd, mask); - if (lockf(fd, F_LOCK, 0)) { - throw std::runtime_error("Error locking rtc cache mutex file"); - } - } - - FILE* fp = fopen((GetProcessingSettings().rtctech.cacheFolder + "/rtc.cuda.cache").c_str(), "rb"); - char sharead[20]; - if (fp) { - size_t len; - while (true) { - auto checkSHA = [&](const char* shacmp, const char* name) { - if (fread(sharead, 1, 20, fp) != 20) { - throw std::runtime_error("Cache file corrupt"); - } - if (GetProcessingSettings().debugLevel >= 3) { - char shaprint1[41], shaprint2[41]; - for (uint32_t i = 0; i < 20; i++) { - sprintf(shaprint1 + 2 * i, "%02X ", shacmp[i]); - sprintf(shaprint2 + 2 * i, "%02X ", sharead[i]); - } - GPUInfo("SHA for %s: expected %s, read %s", name, shaprint1, shaprint2); - } - if (!GetProcessingSettings().rtctech.ignoreCacheValid && memcmp(sharead, shacmp, 20)) { - GPUInfo("Cache file content outdated (%s)", name); - return 1; - } - return 0; - }; - if (checkSHA(shasource, "source") || - checkSHA(shaparam, "param") || - checkSHA(shacmd, "command line") || - checkSHA(shakernels, "kernel definitions") || - checkSHA(shabounds, "launch bounds") || - checkSHA(shaversion, "compiler versions")) { - break; - } - GPUSettingsProcessingRTC cachedSettings; - static_assert(std::is_trivially_copyable_v == true, "GPUSettingsProcessingRTC must be POD"); - if (fread(&cachedSettings, sizeof(cachedSettings), 1, fp) != 1) { - throw std::runtime_error("Cache file corrupt"); - } - if (!GetProcessingSettings().rtctech.ignoreCacheValid && !(cachedSettings == GetProcessingSettings().rtc)) { - GPUInfo("Cache file content outdated (rtc parameters)"); - break; - } - std::vector buffer; - for (uint32_t i = 0; i < nCompile; i++) { - if (fread(&len, sizeof(len), 1, fp) != 1) { - throw std::runtime_error("Cache file corrupt"); - } - buffer.resize(len); - if (fread(buffer.data(), 1, len, fp) != len) { - throw std::runtime_error("Cache file corrupt"); - } - FILE* fp2 = fopen((filename + "_" + std::to_string(i) + mRtcBinExtension).c_str(), "w+b"); - if (fp2 == nullptr) { - throw std::runtime_error("Cannot open tmp file"); - } - if (fwrite(buffer.data(), 1, len, fp2) != len) { - throw std::runtime_error("Error writing file"); - } - fclose(fp2); - } - GPUInfo("Using RTC cache file"); - cacheLoaded = true; - break; - }; - fclose(fp); - } - } - if (!cacheLoaded) { - if (GetProcessingSettings().debugLevel >= 0) { - GPUInfo("Starting CUDA RTC Compilation"); - } - HighResTimer rtcTimer; - rtcTimer.ResetStart(); - tbb::parallel_for(0, nCompile, [&](auto i) { - if (GetProcessingSettings().debugLevel >= 3) { - printf("Compiling %s\n", (filename + "_" + std::to_string(i) + mRtcSrcExtension).c_str()); + rtc::Cache cache(proc, "cuda", {rtcSource, rtcparam, baseCommand, kernelsall, launchBounds, compilerVersions}); + if (!cache.load(filename, mRtcBinExtension, nCompile)) { + rtc::compile(proc, nCompile, "CUDA", [&](uint32_t i) { + const std::string fileBase = filename + "_" + std::to_string(i); + if (proc.debugLevel >= 3) { + printf("Compiling %s\n", (fileBase + mRtcSrcExtension).c_str()); } - FILE* fp = fopen((filename + "_" + std::to_string(i) + mRtcSrcExtension).c_str(), "w+b"); - if (fp == nullptr) { - throw std::runtime_error("Error opening file"); - } - - std::string kernel = "extern \"C\" {"; - kernel += GetProcessingSettings().rtc.compilePerKernel ? kernels[i] : kernelsall; - kernel += "}"; - - bool deterministic = GetProcessingSettings().rtc.deterministic || (GetProcessingSettings().rtc.compilePerKernel && o2::gpu::internal::noFastMathKernels.find(GetKernelName(i)) != o2::gpu::internal::noFastMathKernels.end()); - const std::string deterministicStr = std::string(deterministic ? "#define GPUCA_DETERMINISTIC_CODE(det, indet) det\n" : "#define GPUCA_DETERMINISTIC_CODE(det, indet) indet\n"); - - if (fwrite(deterministicStr.c_str(), 1, deterministicStr.size(), fp) != deterministicStr.size() || - fwrite(rtcparam.c_str(), 1, rtcparam.size(), fp) != rtcparam.size() || - fwrite(launchBounds.c_str(), 1, launchBounds.size(), fp) != launchBounds.size() || - fwrite(_binary_GPUReconstructionCUDArtc_src_start, 1, _binary_GPUReconstructionCUDArtc_src_len, fp) != _binary_GPUReconstructionCUDArtc_src_len || - fwrite(kernel.c_str(), 1, kernel.size(), fp) != kernel.size()) { - throw std::runtime_error("Error writing file"); - } - fclose(fp); - std::string command = baseCommand; - if (deterministic) { - command += std::string(" ") + std::string(_binary_GPUReconstructionCUDArtc_command_no_fast_math_start, _binary_GPUReconstructionCUDArtc_command_no_fast_math_len); - } - command += " -c " + filename + "_" + std::to_string(i) + mRtcSrcExtension + " -o " + filename + "_" + std::to_string(i) + mRtcBinExtension; - if (GetProcessingSettings().debugLevel < 0) { - command += " &> /dev/null"; - } else if (GetProcessingSettings().debugLevel < 2) { - command += " > /dev/null"; - } - if (GetProcessingSettings().debugLevel >= 3) { - printf("Running command %s\n", command.c_str()); - } - if (system(command.c_str())) { - if (GetProcessingSettings().debugLevel >= 3) { - printf("Source code file: %s", filename.c_str()); - } - throw std::runtime_error("Error during CUDA compilation"); - } // clang-format off - }, tbb::simple_partitioner()); // clang-format on - if (GetProcessingSettings().debugLevel >= 0) { - GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); - } - if (GetProcessingSettings().rtc.cacheOutput) { - FILE* fp = fopen((GetProcessingSettings().rtctech.cacheFolder + "/rtc.cuda.cache").c_str(), "w+b"); - if (fp == nullptr) { - throw std::runtime_error("Cannot open cache file for writing"); - } - GPUInfo("Storing RTC compilation result in cache file"); - - if (fwrite(shasource, 1, 20, fp) != 20 || - fwrite(shaparam, 1, 20, fp) != 20 || - fwrite(shacmd, 1, 20, fp) != 20 || - fwrite(shakernels, 1, 20, fp) != 20 || - fwrite(shabounds, 1, 20, fp) != 20 || - fwrite(shaversion, 1, 20, fp) != 20 || - fwrite(&GetProcessingSettings().rtc, sizeof(GetProcessingSettings().rtc), 1, fp) != 1) { - throw std::runtime_error("Error writing cache file"); - } - - std::vector buffer; - for (uint32_t i = 0; i < nCompile; i++) { - FILE* fp2 = fopen((filename + "_" + std::to_string(i) + mRtcBinExtension).c_str(), "rb"); - if (fp2 == nullptr) { - throw std::runtime_error("Cannot open cuda module file"); - } - fseek(fp2, 0, SEEK_END); - size_t size = ftell(fp2); - buffer.resize(size); - fseek(fp2, 0, SEEK_SET); - if (fread(buffer.data(), 1, size, fp2) != size) { - throw std::runtime_error("Error reading cuda module file"); - } - fclose(fp2); - - if (fwrite(&size, sizeof(size), 1, fp) != 1 || - fwrite(buffer.data(), 1, size, fp) != size) { - throw std::runtime_error("Error writing cache file"); - } - } - fclose(fp); - } - } - if (GetProcessingSettings().rtc.cacheOutput && GetProcessingSettings().rtctech.cacheMutex) { - if (lockf(fd, F_ULOCK, 0)) { - throw std::runtime_error("Error unlocking RTC cache mutex file"); - } - close(fd); + const bool deterministic = rtc::deterministic(proc, GetKernelName(i)); + const std::string kernel = std::string("extern \"C\" {") + (proc.rtc.compilePerKernel ? kernels[i] : kernelsall) + "}"; + rtc::writeSource(fileBase + mRtcSrcExtension, deterministic, rtcparam, launchBounds, rtcSource, kernel); + const std::string command = baseCommand + (deterministic ? " " + noFastMath : "") + " -c " + fileBase + mRtcSrcExtension + " -o " + fileBase + mRtcBinExtension; + rtc::runCommand(proc, command, fileBase + mRtcSrcExtension, "Error during CUDA compilation"); + }); + cache.store(filename, mRtcBinExtension, nCompile); } - return 0; } diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index f2a7927f9c1d2..ba51ce47a1cba 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -238,10 +238,11 @@ EndConfig() BeginSubConfig(GPUSettingsProcessingRTCtechnical, rtctech, configStandalone.proc, "RTCTECH", 0, "Processing settings", proc_rtctech) AddOption(runTest, int32_t, 0, "", 0, "Do not run the actual benchmark, but just test RTC compilation (1 full test, 2 test only compilation)") AddOption(cacheMutex, bool, true, "", 0, "Use a file lock to serialize access to the cache folder") -AddOption(ignoreCacheValid, bool, false, "", 0, "If set, allows to use RTC cached code files even if they are not valid for the current source code / parameters") +AddOption(ignoreCacheValid, bool, false, "", 0, "If set, allows to use RTC cached code files even if they are not valid for the current source code / parameters (loads cache files without hash suffix)") AddOption(printLaunchBounds, int32_t, false, "", 0, "Print launch bounds used for RTC code as debugging option, 2 for exit after printing", def(1)) AddOption(allowOptimizedSlaveReconstruction, bool, false, "", 0, "Allow RTC with slave GPUReconstruction instances with optConstexpr and optSpecialcode") AddOption(cacheFolder, std::string, "./rtccache/", "", 0, "Folder in which the cache file is stored") +AddOption(cacheSize, uint32_t, 10, "", 0, "Maximum number of RTC cache files per backend in the cache folder, the oldest are removed (0 = no limit)") AddOption(prependCommand, std::string, "", "", 0, "Prepend RTC compilation commands by this string") AddOption(overrideArchitecture, std::string, "", "", 0, "Override arhcitecture part of RTC compilation command line") // Part of cmdLine, so checked against the cache AddOption(loadLaunchBoundsFromFile, std::string, "", "", 0, "Load a parameter object containing the launch bounds from a file") diff --git a/GPU/documentation/run-time-compilation.md b/GPU/documentation/run-time-compilation.md index accfceb47b870..f819b744e095c 100644 --- a/GPU/documentation/run-time-compilation.md +++ b/GPU/documentation/run-time-compilation.md @@ -10,7 +10,7 @@ Generally, RTC is enabled via the `--RTCenable` flag for the standalone benchmar For a list of RTC options, please see [GPUSettingsList.h](https://github.com/AliceO2Group/AliceO2/blob/80a80a17f5a1d9cb77743e2a39b15b653fe1a4f9/GPU/GPUTracking/Definitions/GPUSettingsList.h#L215). Caching the output: -- The RTC output can be cached and reused, so that when running multiple times, compilation is not repeated. This is enabled via the `--RTCcacheOutput` setting. The folder to store the cache files can be selected via `--RTCTECHcacheFolder` and with `--RTCTECHcacheMutex` (default: enabled), a file-lock mutex can be used to synchronize access to the cache folder. The cached code is checked against the to-be-compiled source code with SHA1 hashes, and only if the code is not change the cache is used, otherwise the code is recompiled and the cache updated. It is possible to force using outdated cache files via the `--RTCTECHignoreCacheValid` option. +- The RTC output can be cached and reused, so that when running multiple times, compilation is not repeated. This is enabled via the `--RTCcacheOutput` setting. The folder to store the cache files can be selected via `--RTCTECHcacheFolder` and with `--RTCTECHcacheMutex` (default: enabled), a file-lock mutex (`cache_.lock`, one per backend) can be used to synchronize access to the cache folder. Each backend can have multiple cache files `rtc..cache.`, where the id is derived from the SHA1 hashes below, so that switching between configurations does not require recompilation; when a new cache file is written, only the `--RTCTECHcacheSize` (default 10, 0 = no limit) most recent files of the backend are kept. The cached code is checked against the to-be-compiled source code with SHA1 hashes, and only if the code is not change the cache is used, otherwise the code is recompiled and the cache updated. It is possible to force using outdated cache files via the `--RTCTECHignoreCacheValid` option; in this case the cache file is `rtc..cache` without id, and old cache files are not removed. For chaning the launch bounds and other parameters, please consider `--RTCTECHloadLaunchBoundsFromFile` (and `--RTCTECHprintLaunchBounds`), which can launch a parameter set which can be created via [dumpGPUDefParam.C](https://github.com/AliceO2Group/AliceO2/blob/dev/GPU/GPUTracking/Standalone/tools/dumpGPUDefParam.C). A set of default parameters is stored in `[INSTALL_FOLDER]/share/GPU`.