Skip to content

Quadratic performance in TH1Merger::LabelMerge #23681

Open

Description

@lmoureaux

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:

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:

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

Activity

  1. dpiparo commented on Oct 11, 2026

    @dpiparo
    Member

    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.

  2. dpiparo commented on Oct 11, 2026

    @dpiparo
    Member

    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.

  3. added a commit that references this issue on Oct 11, 2026
    dbb2422
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions