Skip to main content

CI

Parallel HAdd (phadd)

A small, dependency-free CLI that merges ROOT files in parallel using hadd from ROOT. Instead of adding all files in a single pass, files are merged in chunks across multiple worker processes, then the chunks are merged again until one file remains — a tree reduction. This keeps memory usage low and makes use of all your CPU cores.

Requirements

  • Python 3.10+
  • ROOT's hadd available on your PATH

Development and CI run on Linux and macOS; Windows is untested.

Installation

From PyPI:

pip install parallel-hadd

With an optional rich progress bar and colored logs:

pip install "parallel-hadd[rich]"

From source:

git clone https://github.com/MohamedElashri/hadd-parallel
cd hadd-parallel
pip install .

Usage

phadd out.root *.root

where out.root is the merged output file containing all input files.

For more options see the help page:

phadd -h

Help page

usage: phadd [-h] [-j NUM_JOBS] [-n NUM_FILES] [-t TMPDIR] [-f] [-s] [--no-progress]
             [--hadd-args ARGS] [-l {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [-V]
             output_file input_file [input_file ...]

Merge ROOT files in parallel using hadd.

positional arguments:
  output_file           path of the merged output file
  input_file            two or more input files (wildcards are expanded)

options:
  -h, --help            show this help message and exit
  -j, --jobs NUM_JOBS   number of parallel hadd processes [default: number of CPUs]
  -n, --num-files NUM_FILES
                        number of files to merge per chunk, minimum 2 [default: auto
                        (~cuberoot of input count, minimum 10)]
  -t, --tmpdir TMPDIR   base directory for intermediate files [default: system temp]
  -f, --force-overwrite
                        overwrite the output file if it exists
  -s, --save-tmp        keep intermediate files instead of deleting them
  --no-progress         disable the progress bar (automatic when not attached to a
                        terminal)
  --hadd-args ARGS      extra flags forwarded verbatim to each inner hadd call; use "="
                        when they start with a dash, e.g. --hadd-args="-k -v"
  -l, --log {DEBUG,INFO,WARNING,ERROR,CRITICAL}
                        log level [default: WARNING]
  -V, --version         show program's version number and exit

Tip: place intermediates on fast local disk with --tmpdir when /tmp is RAM-backed or
slow. See the README for tuning guidance.

Inner hadd invocations always run with -f (never interactive) and are quieted; their output is shown with --log DEBUG or when a merge step fails.

How it works

Given N input files and a chunk size of -n:

  1. Files are grouped into chunks of at most n files.
  2. Each chunk is merged by its own hadd process; up to -j processes run concurrently.
  3. The resulting chunk outputs become the inputs of the next round.
  4. Rounds repeat until a single file remains, which is moved to the output path.

Intermediate files live in a temporary directory (configurable with -t) and are deleted afterwards unless -s is given.

The final output is written atomically (staged next to the destination, then renamed into place), so an interrupted run can never leave a half-written output file behind. If the output path is picked up by shell globbing (e.g. re-running phadd out.root *.root after out.root already exists), it is excluded from the input list automatically.

Tuning & performance

Understanding the trade-offs helps you pick the right flags:

I/O amplification. A tree reduction rewrites the surviving data every round: roughly log_n(N) full passes over the dataset for N files at chunk size n. Sequential merging writes the data once but cannot be parallelized — phadd trades extra I/O for wall-clock speed.

Chunk size (-n). By default phadd picks it automatically — roughly the cube root of the input count (minimum 10) — which holds the merge at about three rounds no matter the scale. Override it when your storage calls for something different:

  • Fast local SSD / NVMe: defaults are fine; extra passes cost little.
  • Network storage (NFS/Lustre/dCache): increase -n (e.g. -n 50) to cut the number of rounds and reduce metadata churn; parallelism then comes from fewer but larger workers.
  • Many small files: each inner hadd process pays ~0.5–2 s of ROOT startup, which dominates when chunks merge in milliseconds. Raise -n to amortize it.

Memory. Peak usage scales with jobs × chunk size: every concurrent hadd holds its chunk's objects in memory. Lower -j or -n if you hit RAM limits.

Temporary directory. On many systems /tmp is tmpfs (RAM-backed) or slow. For large merges place intermediates on fast local disk with -t /scratch.

Tail effect. The last rounds have few chunks (the final round is a single task), so some cores idle near the end. This is inherent to tree reduction; larger -n shortens that tail.

Exit codes. 0 success, 1 error, 127 hadd not found on PATH, 128+N terminated by signal N (intermediate files are cleaned up either way).

phadd vs native hadd -j

Since ROOT 6.24, plain hadd -j J merges with multiple threads. For modern ROOT installations, try it first — it avoids phadd's multi-pass I/O entirely.

phadd is still useful when you:

  • run ROOT older than 6.24, where hadd is single-threaded;
  • want process isolation: a corrupted input file crashes one chunk worker, not the whole merge;
  • need to scale past thread contention observed by single-process threaded merging on very high-core machines or shared/login nodes;
  • prefer explicit control over parallelism, temporary storage placement, and resumable-by-inspection intermediate trees (-s).

Known limitations

  • Input file lists are validated up front; inputs added mid-run will not be seen.
  • On Linux/macOS, interrupted merges clean up completely: workers and their hadd children run in dedicated process groups that are killed on interruption. On other platforms (e.g. Windows, untested) orphaned child processes may be left behind.
  • Windows is untested.

Development

git clone https://github.com/MohamedElashri/hadd-parallel
cd hadd-parallel
pip install -e '.[dev]'
pytest
ruff check . && ruff format --check .

Tests use a stub hadd executable, so no ROOT installation is required.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

parallel_hadd-2.0.0.tar.gz (16.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

parallel_hadd-2.0.0-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

Details for the file parallel_hadd-2.0.0.tar.gz.

File metadata

  • Download URL: parallel_hadd-2.0.0.tar.gz
  • Upload date:
  • Size: 16.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for parallel_hadd-2.0.0.tar.gz
Algorithm Hash digest
SHA256 747506c2ebfd6dd6d7d493c3caee2eb10b5f980247a7edde075abd1413e04693
MD5 d375b1cac6a5a75ca9c69ff3639a5e18
BLAKE2b-256 59e958ba52d79b8141c23077d1f93b9cc2140c5c61bf4a63f8d94b2ffc0fe9b4

See more details on using hashes here.

Provenance

The following attestation bundles were made for parallel_hadd-2.0.0.tar.gz:

Publisher: publish.yml on MohamedElashri/hadd-parallel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file parallel_hadd-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: parallel_hadd-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 13.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for parallel_hadd-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2f197213ccdd3d9630f573bb76e08f15eb19139f6e734a8028b244e399b3fbf1
MD5 ce6771ee47ed2ca5f1a945aa2e6701df
BLAKE2b-256 786ca20484123a970b1bb22d2a1d8a7b02a69b15eae3dc8b3a5d3180095f92f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for parallel_hadd-2.0.0-py3-none-any.whl:

Publisher: publish.yml on MohamedElashri/hadd-parallel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 files

1.2

2 files

1.1

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page