Repository navigation
Quadratic performance in TH1Merger::LabelMerge #23681
Copy link
Copy link
Open
Labels
Description
Check duplicate issues.
- Checked for duplicates
Description
Under certain conditions, TH1Merger::LabelMerge loops over all histogram bins and queries bin labels for each of them:
root/hist/hist/src/TH1Merger.cxx
Lines 1033 to 1035 in 2f99ebf
| const char * labelX = hist->GetXaxis()->GetBinLabel(binx); | |
| const char * labelY = (fH0->fDimension > 1) ? hist->GetYaxis()->GetBinLabel(biny) : nullptr; | |
| const char * labelZ = (fH0->fDimension > 2) ? hist->GetYaxis()->GetBinLabel(binz) : nullptr; |
Querying a bin label is linear in the axis length:
Line 450 in ab4c55b
| while ((obj=(TObjString*)next())) { |
Thus we get quadratic performance. This tremendously slows down hadd for histograms with labels.
For a minimally invasive fix, I would convert the THashList to std::vector before iterating over bins.
Reproducer
Use the following macro to generate a file:
void slowHaddFile() {
const int Nbins = 1000;
auto h = new TH2D("h", "h", Nbins, 0., 1., Nbins, 0., 1.);
for (int i = 1; i <= Nbins; ++i) h->GetXaxis()->SetBinLabel(i, Form("label%d", i));
for (int i = 1; i <= Nbins; ++i) h->GetYaxis()->SetBinLabel(i, Form("label%d", i));
for (int i = 1; i <= h->GetNcells(); ++i) h->SetBinContent(i, 1); // prevent shortcut at TH1Merger.cxx#L1027
auto f = new TFile("base.root", "RECREATE");
f->WriteObject(h, "h");
f->Close();
}Then,
$ time hadd out.root base.root base.root base.root base.root base.root
Info in <hadd>: target file: out.root
Info in <hadd>: compression setting for all output: 101
hadd Source file 1: base.root
hadd Source file 2: base.root
hadd Source file 3: base.root
hadd Source file 4: base.root
hadd Source file 5: base.root
hadd Target path: root://eoscms.cern.ch//eos/cms/store/group/phys_smp/ec/DAS/0071/tmp/out.root:/
real 1m27.908s
user 1m26.475s
sys 0m0.752s
The same histogram without bin labels adds 90 times faster:
$ time hadd out.root base.root base.root base.root base.root base.root
Info in <hadd>: target file: out.root
Info in <hadd>: compression setting for all output: 101
hadd Source file 1: base.root
hadd Source file 2: base.root
hadd Source file 3: base.root
hadd Source file 4: base.root
hadd Source file 5: base.root
hadd Target path: out.root:/
real 0m0.938s
user 0m0.399s
sys 0m0.170s
ROOT version
------------------------------------------------------------------
| Welcome to ROOT 6.40.04 https://root.cern |
| (c) 1995-2025, The ROOT Team; conception: R. Brun, F. Rademakers |
| Built for linuxx8664gcc on Aug 29 2026, 00:00:00 |
| From tags/6-40-04@6-40-04 |
| With g++ (GCC) 11.5.0 20240719 (Red Hat 11.5.0-14) std201703 |
| Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q' |
------------------------------------------------------------------
Installation method
lxplus
Operating system
lxplus9
Additional context
No response
Reactions are currently unavailable
Activity
dpiparo commentedon Oct 11, 2026
Thanks @lmoureaux .
@silverweed do you think something could be done and backported to 6.40, at least (if not to earlier releases)?
It looks ROOT was affected by this issue since a very long while.
dpiparo commentedon Oct 11, 2026
The PR above is an attempt to address the performance degradation. Admittedly, its a minimal intervention and would not be valid in all possible cases.
[hist] Optimize bin label search
[hist] Optimize bin label search
[hist] Cache axis labels before merging