From c77b57049baac80302eb02e88bdd054c0a987ecd Mon Sep 17 00:00:00 2001 From: Felix Weiglhofer <weiglhofer@fias.uni-frankfurt.de> Date: Tue, 16 Apr 2024 10:27:17 +0000 Subject: [PATCH] algo: Add MemoryLogger to log memory usage of process. --- algo/CMakeLists.txt | 3 +++ algo/base/System.cxx | 46 ++++++++++++++++++++++++++++++++ algo/base/System.h | 31 ++++++++++++++++++++++ algo/base/util/MemoryLogger.cxx | 32 ++++++++++++++++++++++ algo/base/util/MemoryLogger.h | 47 +++++++++++++++++++++++++++++++++ reco/app/cbmreco/main.cxx | 8 ++++++ 6 files changed, 167 insertions(+) create mode 100644 algo/base/System.cxx create mode 100644 algo/base/System.h create mode 100644 algo/base/util/MemoryLogger.cxx create mode 100644 algo/base/util/MemoryLogger.h diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 85b74016e4..7cbf4a011a 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -74,6 +74,8 @@ set(SRCS base/Options.cxx base/MainConfig.cxx base/RecoParams.cxx + base/System.cxx + base/util/MemoryLogger.cxx base/util/StlUtils.cxx base/util/EnumDict.cxx base/util/TimingsFormat.cxx @@ -248,6 +250,7 @@ install( base/Options.h base/RecoParams.h base/SubChain.h + base/System.h base/PartitionedVector.h base/PartitionedSpan.h global/Reco.h diff --git a/algo/base/System.cxx b/algo/base/System.cxx new file mode 100644 index 0000000000..88bf1ac516 --- /dev/null +++ b/algo/base/System.cxx @@ -0,0 +1,46 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#include "System.h" + +#include <cstdio> + +#ifdef __linux__ +#include <sys/resource.h> +#include <unistd.h> +#endif + + +size_t cbm::algo::GetCurrentRSS() +{ + // Implementation copied from https://stackoverflow.com/a/14927379 +#ifndef __linux__ + return 0; +#else + unsigned long rss = 0L; + FILE* fp = nullptr; + if ((fp = fopen("/proc/self/statm", "r")) == nullptr) { + return size_t(0L); /* Can't open? */ + } + if (fscanf(fp, "%*s%lu", &rss) != 1) { + fclose(fp); + return size_t(0L); /* Can't read? */ + } + fclose(fp); + return size_t(rss) * size_t(sysconf(_SC_PAGESIZE)); +#endif +} + +size_t cbm::algo::GetPeakRSS() +{ + // Implementation copied from https://stackoverflow.com/a/14927379 +#ifndef __linux__ + return 0; +#else + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); + + return size_t(rusage.ru_maxrss * 1024L); +#endif +} diff --git a/algo/base/System.h b/algo/base/System.h new file mode 100644 index 0000000000..3c415ba131 --- /dev/null +++ b/algo/base/System.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#pragma once + +#include <cstddef> + +/** + * @file System.h + * @brief System functions +**/ + +namespace cbm::algo +{ + + /** + * @brief Get the current resident set size (pyhysical memory usage) of the process + * @return The current resident set size in bytes + * @note Returns zero if the value cannot be determined + **/ + size_t GetCurrentRSS(); + + /** + * @brief Get the peak resident set size (pyhysical memory usage) of the process + * @return The peak resident set size in bytes + * @note Returns zero if the value cannot be determined + **/ + size_t GetPeakRSS(); + +} // namespace cbm::algo diff --git a/algo/base/util/MemoryLogger.cxx b/algo/base/util/MemoryLogger.cxx new file mode 100644 index 0000000000..61c4777219 --- /dev/null +++ b/algo/base/util/MemoryLogger.cxx @@ -0,0 +1,32 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#include "MemoryLogger.h" + +#include "System.h" + +#include <log.hpp> + +using namespace cbm::algo; + +template<typename T> +T MemoryLogger::BytesToMB(T bytes) const +{ + return bytes / (1024 * 1024); +} + +void MemoryLogger::Log() +{ + size_t currentRSS = GetCurrentRSS(); + size_t peakRSS = GetPeakRSS(); + + ptrdiff_t deltaRSS = currentRSS - mLastRSS; + float deltaPercent = 100.0f * deltaRSS / currentRSS; + + L_(debug) << "Current memory usage: " << BytesToMB(currentRSS) << "MB (delta " << BytesToMB(deltaRSS) << "MB / " + << deltaPercent << "%)" + << ", peak: " << BytesToMB(peakRSS) << "MB"; + + mLastRSS = currentRSS; +} diff --git a/algo/base/util/MemoryLogger.h b/algo/base/util/MemoryLogger.h new file mode 100644 index 0000000000..5b732ccd96 --- /dev/null +++ b/algo/base/util/MemoryLogger.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#pragma once + +#include <cstddef> + +/** + * @file MemoryLogger.h + * @brief Memory logging +**/ + +namespace cbm::algo +{ + + /** + * @brief Track the memory usage of the process and write it to the log + **/ + class MemoryLogger { + + public: + /** + * @brief Constructor + **/ + MemoryLogger() = default; + + /** + * @brief Destructor + **/ + ~MemoryLogger() = default; + + /** + * @brief Log the current memory usage + **/ + void Log(); + + private: + size_t mLastRSS = 0; + + // Convert bytes to MB + // Template to allow for different integer types + template<typename T> + T BytesToMB(T bytes) const; + }; + +} // namespace cbm::algo diff --git a/reco/app/cbmreco/main.cxx b/reco/app/cbmreco/main.cxx index 21ef274235..b078661f1a 100644 --- a/reco/app/cbmreco/main.cxx +++ b/reco/app/cbmreco/main.cxx @@ -8,8 +8,10 @@ #include "Reco.h" #include "RecoResultsInputArchive.h" #include "RecoResultsOutputArchive.h" +#include "System.h" #include "compat/OpenMP.h" #include "gpu/DeviceImage.h" +#include "util/MemoryLogger.h" #include <TimesliceAutoSource.hpp> @@ -160,6 +162,7 @@ int main(int argc, char** argv) if (dumpArchive(opts)) return 0; Reco reco; + MemoryLogger memoryLogger; auto startProcessing = std::chrono::high_resolution_clock::now(); reco.Init(opts); @@ -198,6 +201,11 @@ int main(int argc, char** argv) L_(error) << "Caught ProcessingError while processing timeslice " << tsIdx << ": " << e.what(); } + // Release memory after each timeslice and log memory usage + // This is useful to detect memory leaks as the memory usage should be constant between timeslices + ts.reset(); + memoryLogger.Log(); + tsIdx++; if (num_ts > 0 && tsIdx >= num_ts) break; -- GitLab