From 522c856341924ea1674f170eb740ffc99effa68f Mon Sep 17 00:00:00 2001 From: Felix Weiglhofer Date: Wed, 7 Oct 2026 15:27:52 +0200 Subject: [PATCH 1/2] 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/Definitions/GPUSettingsList.h | 1 + GPU/GPUTracking/Global/GPUChainTracking.cxx | 21 +++- GPU/GPUTracking/Global/GPUChainTracking.h | 5 +- GPU/GPUTracking/utils/HashStreamBuf.h | 115 ++++++++++++++++++ 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 GPU/GPUTracking/utils/HashStreamBuf.h diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 81949f0b8ed2a..3c479646bf844 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, "When using --debug 6, log only the checksum instead of writing the full dump to a file") 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..e54110e53aac3 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: %s", mDebugFileStream.hash().c_str()); + } } 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/utils/HashStreamBuf.h b/GPU/GPUTracking/utils/HashStreamBuf.h new file mode 100644 index 0000000000000..77db064e512ee --- /dev/null +++ b/GPU/GPUTracking/utils/HashStreamBuf.h @@ -0,0 +1,115 @@ +// 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 "Framework/SHA1.h" + +#include +#include +#include + + +class HashStreamBuf : public std::streambuf +{ + public: + HashStreamBuf() = default; + + HashStreamBuf(bool doHash, + std::streambuf* backing = nullptr) + : mBacking(backing), + mDoHash(doHash) + { + o2::framework::internal::SHA1Init(&mSHA1); + } + + // Returns the hash without modifying the current hashing state. + std::string hash() const + { + auto copy = mSHA1; + unsigned char digest[20]; + o2::framework::internal::SHA1Final(digest, ©); + + static constexpr char hex[] = "0123456789ABCDEF"; + std::string result; + result.reserve(40); + + for (unsigned char byte : digest) { + result += hex[byte >> 4]; + result += hex[byte & 0x0f]; + } + + return 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); + } + + updateHash(data, size_t(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(); + } + } + + updateHash(&c, 1); + + return ch; + } + + int sync() override + { + int s = 0; + if (mBacking) { + s = mBacking->pubsync(); + } + return s; + } + + private: + std::streambuf* mBacking = nullptr; + o2::framework::internal::SHA1_CTX mSHA1; + bool mDoHash = false; + + void updateHash(const char *data, size_t size) + { + if (mDoHash) { + o2::framework::internal::SHA1Update(&mSHA1, reinterpret_cast(data), size); + } + } +}; From 268f57aa04d8adbca7aa07728af89c728e13ae23 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Fri, 9 Oct 2026 14:21:43 +0000 Subject: [PATCH 2/2] Please consider the following formatting changes --- GPU/GPUTracking/utils/HashStreamBuf.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/GPU/GPUTracking/utils/HashStreamBuf.h b/GPU/GPUTracking/utils/HashStreamBuf.h index 77db064e512ee..5a3fe0768c47e 100644 --- a/GPU/GPUTracking/utils/HashStreamBuf.h +++ b/GPU/GPUTracking/utils/HashStreamBuf.h @@ -20,7 +20,6 @@ #include #include - class HashStreamBuf : public std::streambuf { public: @@ -46,8 +45,8 @@ class HashStreamBuf : public std::streambuf result.reserve(40); for (unsigned char byte : digest) { - result += hex[byte >> 4]; - result += hex[byte & 0x0f]; + result += hex[byte >> 4]; + result += hex[byte & 0x0f]; } return result; @@ -106,10 +105,10 @@ class HashStreamBuf : public std::streambuf o2::framework::internal::SHA1_CTX mSHA1; bool mDoHash = false; - void updateHash(const char *data, size_t size) + void updateHash(const char* data, size_t size) { if (mDoHash) { - o2::framework::internal::SHA1Update(&mSHA1, reinterpret_cast(data), size); + o2::framework::internal::SHA1Update(&mSHA1, reinterpret_cast(data), size); } } };