From 7619bce552d5a379c06dde0e2cbdaa0ace712ebe Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:09:12 +0200 Subject: [PATCH] DPL Analysis: out-of-line HistogramSpec related construction The price we pay in compile time is not worth the speedup in registering the histograms, so we move the related methods out of line. --- .../Core/include/Framework/HistogramSpec.h | 53 +++++-------------- Framework/Core/src/HistogramSpec.cxx | 43 +++++++++++++++ 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/Framework/Core/include/Framework/HistogramSpec.h b/Framework/Core/include/Framework/HistogramSpec.h index bfd9ba702496d..365b2255eeb99 100644 --- a/Framework/Core/include/Framework/HistogramSpec.h +++ b/Framework/Core/include/Framework/HistogramSpec.h @@ -84,41 +84,20 @@ using HistPtr = std::variant, std::shared_ptr, s constexpr double VARIABLE_WIDTH = 0.; struct AxisSpec { - AxisSpec(std::vector binEdges_, std::optional title_ = std::nullopt, std::optional name_ = std::nullopt) - : nBins(std::nullopt), - binEdges(std::move(binEdges_)), - title(std::move(title_)), - name(std::move(name_)) - { - } - - AxisSpec(int nBins_, double binMin_, double binMax_, std::optional title_ = std::nullopt, std::optional name_ = std::nullopt) - : nBins(nBins_), - binEdges({binMin_, binMax_}), - title(std::move(title_)), - name(std::move(name_)) - { - if (binMin_ > binMax_) { - LOG(fatal) << "Defined ill-defined axis"; - } - } + // Defined out of line in HistogramSpec.cxx on purpose. These run once per + // histogram at init() time, so inlining them buys nothing at runtime, while + // a task that books a few hundred histograms in one init() pays for every + // expansion: each one materialises a std::vector and two + // std::optional at the call site, with the matching destructor + // and exception-unwind paths. Under -g that also means a debug record per + // temporary, which is what makes the register allocator's rewrite pass go + // superlinear on such functions. + AxisSpec(std::vector binEdges_, std::optional title_ = std::nullopt, std::optional name_ = std::nullopt); + + AxisSpec(int nBins_, double binMin_, double binMax_, std::optional title_ = std::nullopt, std::optional name_ = std::nullopt); // first entry is assumed to be the number of bins; in case of variable size binning it must be set to zero - AxisSpec(ConfigurableAxis binEdges_, std::optional title_ = std::nullopt, std::optional name_ = std::nullopt) - : nBins(std::nullopt), - binEdges(std::vector(binEdges_)), - title(std::move(title_)), - name(std::move(name_)) - { - if (binEdges.empty()) { - return; - } - if (binEdges[0] != VARIABLE_WIDTH) { - nBins = static_cast(binEdges[0]); - binEdges.resize(3); // nBins, lowerBound, upperBound, disregard whatever else is stored in vecotr - } - binEdges.erase(binEdges.begin()); // remove first entry that we assume to be number of bins - } + AxisSpec(ConfigurableAxis binEdges_, std::optional title_ = std::nullopt, std::optional name_ = std::nullopt); [[nodiscard]] long getNbins() const; @@ -138,12 +117,8 @@ struct AxisSpec { */ //************************************************************************************************** struct HistogramConfigSpec { - HistogramConfigSpec(HistType type_, std::vector axes_, uint8_t nSteps_ = 1) - : type(type_), - axes(std::move(axes_)), - nSteps(nSteps_) - { - } + // Out of line for the same reason as the AxisSpec constructors above. + HistogramConfigSpec(HistType type_, std::vector axes_, uint8_t nSteps_ = 1); HistogramConfigSpec() = default; HistogramConfigSpec(HistogramConfigSpec const& other) = default; HistogramConfigSpec(HistogramConfigSpec&& other) = default; diff --git a/Framework/Core/src/HistogramSpec.cxx b/Framework/Core/src/HistogramSpec.cxx index ef23a29c828f7..496a07a6dcba4 100644 --- a/Framework/Core/src/HistogramSpec.cxx +++ b/Framework/Core/src/HistogramSpec.cxx @@ -15,6 +15,49 @@ namespace o2::framework { +// Out of line: see the comment on the declarations in HistogramSpec.h. +AxisSpec::AxisSpec(std::vector binEdges_, std::optional title_, std::optional name_) + : nBins(std::nullopt), + binEdges(std::move(binEdges_)), + title(std::move(title_)), + name(std::move(name_)) +{ +} + +AxisSpec::AxisSpec(int nBins_, double binMin_, double binMax_, std::optional title_, std::optional name_) + : nBins(nBins_), + binEdges({binMin_, binMax_}), + title(std::move(title_)), + name(std::move(name_)) +{ + if (binMin_ > binMax_) { + LOG(fatal) << "Defined ill-defined axis"; + } +} + +AxisSpec::AxisSpec(ConfigurableAxis binEdges_, std::optional title_, std::optional name_) + : nBins(std::nullopt), + binEdges(std::vector(binEdges_)), + title(std::move(title_)), + name(std::move(name_)) +{ + if (binEdges.empty()) { + return; + } + if (binEdges[0] != VARIABLE_WIDTH) { + nBins = static_cast(binEdges[0]); + binEdges.resize(3); // nBins, lowerBound, upperBound, disregard whatever else is stored in vecotr + } + binEdges.erase(binEdges.begin()); // remove first entry that we assume to be number of bins +} + +HistogramConfigSpec::HistogramConfigSpec(HistType type_, std::vector axes_, uint8_t nSteps_) + : type(type_), + axes(std::move(axes_)), + nSteps(nSteps_) +{ +} + void AxisSpec::makeLogarithmic() { if (binEdges.size() > 2) {