From 484365c548424d65bae517d5817422e8b9c66a26 Mon Sep 17 00:00:00 2001 From: Felix Weiglhofer Date: Wed, 7 Oct 2026 15:27:52 +0200 Subject: [PATCH] GPU/Standalone: Compute checksum of dumped data Add an option to compute the checksum of dumped data on the fly when using --debug 6. Only prints the checksum instead of writing dumped data to file when this option is used. --- GPU/GPUTracking/CMakeLists.txt | 1 + GPU/GPUTracking/Definitions/GPUSettingsList.h | 1 + GPU/GPUTracking/Global/GPUChainTracking.cxx | 21 +++- GPU/GPUTracking/Global/GPUChainTracking.h | 5 +- GPU/GPUTracking/Standalone/CMakeLists.txt | 1 + GPU/GPUTracking/utils/HashStreamBuf.h | 98 +++++++++++++++++++ 6 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 GPU/GPUTracking/utils/HashStreamBuf.h diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index cc44b2003a01d..1a0c673dfed5b 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -454,6 +454,7 @@ if(GPUCA_QA) endif() target_link_libraries(${targetName} PRIVATE TBB::tbb) +target_link_libraries(${targetName} PUBLIC Boost::headers) target_compile_options(${targetName} PRIVATE -Wno-instantiation-after-specialization) diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 81949f0b8ed2a..02c50325f6d39 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -339,6 +339,7 @@ AddOption(debugLevel, int32_t, -1, "debug", 'd', "Set debug level (-2 = silent, AddOption(allocDebugLevel, int32_t, 0, "allocDebug", 0, "Some debug output for memory allocations (without messing with normal debug level)") AddOption(debugMask, uint32_t, (1 << 18) - 1, "debugMask", 0, "Mask for debug output dumps to file") AddOption(debugLogSuffix, std::string, "", "debugSuffix", 0, "Suffix for debug log files with --debug 6") +AddOption(debugDumpChecksum, bool, false, "", 0, "Dump the only the checkusm instead of the full file with --debug 6") AddOption(debugFileHexFloat, int32_t, -1, "", 0, "Use hex format to print floats to debug dump file") AddOption(debugCSV, std::string, "", "", 0, "CSV filename to append the benchmark results. Verbosity determined by parameter --debug.") AddOption(debugMarkdown, bool, false, "", 0, "Print the results of standlaone benchmarks in markdown format") diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index eb6d880398eec..673391544ecce 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -61,7 +61,7 @@ using namespace o2::gpu; using namespace o2::tpc; using namespace o2::trd; -GPUChainTracking::GPUChainTracking(GPUReconstruction* rec, uint32_t maxTPCHits, uint32_t maxTRDTracklets) : GPUChain(rec), mIOPtrs(processors()->ioPtrs), mInputsHost(new GPUTrackingInputProvider), mInputsShadow(new GPUTrackingInputProvider), mClusterNativeAccess(new ClusterNativeAccess), mTriggerBuffer(new GPUTriggerOutputs), mMaxTPCHits(maxTPCHits), mMaxTRDTracklets(maxTRDTracklets), mDebugFile(new std::ofstream) +GPUChainTracking::GPUChainTracking(GPUReconstruction* rec, uint32_t maxTPCHits, uint32_t maxTRDTracklets) : GPUChain(rec), mIOPtrs(processors()->ioPtrs), mInputsHost(new GPUTrackingInputProvider), mInputsShadow(new GPUTrackingInputProvider), mClusterNativeAccess(new ClusterNativeAccess), mTriggerBuffer(new GPUTriggerOutputs), mMaxTPCHits(maxTPCHits), mMaxTRDTracklets(maxTRDTracklets), mDebugFile(new std::ostream(nullptr)) { ClearIOPointers(); mFlatObjectsShadow.mChainTracking = this; @@ -386,7 +386,17 @@ int32_t GPUChainTracking::Init() if (GetProcessingSettings().debugLevel >= 6) { std::string filename = std::string(mRec->IsGPU() ? "GPU" : "CPU") + (mRec->slaveId() != -1 ? (std::string("_slave") + std::to_string(mRec->slaveId())) : std::string(mRec->slavesExist() ? "_master" : "")) + GetProcessingSettings().debugLogSuffix + ".out"; - mDebugFile->open(filename.c_str()); + + bool hashOnly = GetProcessingSettings().debugDumpChecksum; + + std::streambuf* backing = nullptr; + if (!hashOnly) { + mDebugFileBuffer.open(filename.c_str(), std::ios::out); + backing = &mDebugFileBuffer; + } + + mDebugFileStream = HashStreamBuf(hashOnly, backing); + mDebugFile->rdbuf(&mDebugFileStream); if (GetProcessingSettings().debugFileHexFloat >= 1 || (GetProcessingSettings().debugFileHexFloat == -1 && GetProcessingSettings().deterministicGPUReconstruction)) { *mDebugFile << std::hexfloat; } @@ -475,7 +485,12 @@ int32_t GPUChainTracking::Finalize() GetQA()->DrawQAHistograms(); } if (GetProcessingSettings().debugLevel >= 6) { - mDebugFile->close(); + mDebugFile->flush(); + mDebugFileBuffer.close(); + + if (GetProcessingSettings().debugDumpChecksum) { + GPUInfo("Debug hash: %lX", mDebugFileStream.hash()); + } } if (mCompressionStatistics) { mCompressionStatistics->Finish(); diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 759aaf818028e..4b235ef911aed 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -19,6 +19,7 @@ #include "GPUDataTypesIO.h" #include "GPUDataTypesConfig.h" #include "GPUCommonAlignedAlloc.h" +#include "utils/HashStreamBuf.h" #include #include #include @@ -286,7 +287,9 @@ class GPUChainTracking : public GPUChain uint32_t mMaxTRDTracklets = 0; // Debug - std::unique_ptr mDebugFile; + std::filebuf mDebugFileBuffer; + HashStreamBuf mDebugFileStream; + std::unique_ptr mDebugFile; // Synchronization and Locks eventStruct* mEvents = nullptr; diff --git a/GPU/GPUTracking/Standalone/CMakeLists.txt b/GPU/GPUTracking/Standalone/CMakeLists.txt index a4c5817d1f7f9..e4b7795c5738e 100644 --- a/GPU/GPUTracking/Standalone/CMakeLists.txt +++ b/GPU/GPUTracking/Standalone/CMakeLists.txt @@ -119,6 +119,7 @@ elseif(GPUCA_BUILD_EVENT_DISPLAY) message(FATAL_ERROR "Cannot build event display without ROOT") endif() find_package(Microsoft.GSL REQUIRED HINTS "$ENV{MS_GSL_ROOT}/share/cmake") +find_package(Boost 1.88 REQUIRED) # boost/hash2 (HashStreamBuf.h) if(GPUCA_CONFIG_FMT) find_package(fmt REQUIRED HINTS $ENV{FMT_ROOT}) diff --git a/GPU/GPUTracking/utils/HashStreamBuf.h b/GPU/GPUTracking/utils/HashStreamBuf.h new file mode 100644 index 0000000000000..587a293cf9f60 --- /dev/null +++ b/GPU/GPUTracking/utils/HashStreamBuf.h @@ -0,0 +1,98 @@ +// 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 HashStreamBuf.h +/// \author Felix Weiglhofer +/// \brief Stream buffer that supports on the fly hashing with an optional backing file buffer, +// if we want to access the hash and file contents at the same time. + +#include + +#include +#include +#include + +class HashStreamBuf : public std::streambuf +{ + public: + HashStreamBuf() = default; + + HashStreamBuf(bool doHash, + std::streambuf* backing = nullptr, + uint64_t seed = 0) + : mBacking(backing), + mHash(seed), + mDoHash(doHash) + { + } + + // Returns the hash without modifying the current hashing state. + uint64_t hash() const + { + auto copy = mHash; + return copy.result(); + } + + protected: + std::streamsize xsputn(const char* data, + std::streamsize size) override + { + if (size <= 0) { + size = 0; + } + + if (mBacking) { + // Only hash bytes that were successfully written + // to the backing stream. + size = mBacking->sputn(data, size); + } + + if (mDoHash) { + mHash.update(data, static_cast(size)); + } + return size; + } + + int_type overflow(int_type ch) override + { + if (traits_type::eq_int_type(ch, traits_type::eof())) + return traits_type::not_eof(ch); + + const char c = traits_type::to_char_type(ch); + + if (mBacking) { + const auto result = mBacking->sputc(c); + + if (traits_type::eq_int_type(result, + traits_type::eof())) { + return traits_type::eof(); + } + } + + mHash.update(&c, 1); + + return ch; + } + + int sync() override + { + int s = 0; + if (mBacking) { + s = mBacking->pubsync(); + } + return s; + } + + private: + std::streambuf* mBacking = nullptr; + boost::hash2::xxhash_64 mHash; + bool mDoHash = false; +};