TrimGalore --clumpify multi-data-type benchmark

Generated 2026-05-06. Branch clumping @ 3fd0454, --cores 6 --memory 1G (default) on a 16 GiB Apple M1 Pro. Three configurations per dataset (plus a pending fourth):

Note: the final scrnaseq_10x_clumpify_compress6 row is still running at the time this report was generated. Placeholder values are marked TBD; numbers will be filled in when the run completes (estimated finish 23:00–23:15).

Headline matrix

Dataset Mode Configuration Wall (s) User CPU (s) Max RSS Output (MB) Saving vs plain Wall vs plain
MiSeq amplicon (CRISPR)SE 4.4M plain 16.187.8114 MB 500—1.00×
--clumpify 16.489.31265 MB 418−16.3%1.02×
--compression 6 26.4144.6114 MB 374−25.1%1.64×
--clumpify --compression 6 24.2129.51274 MB 342−31.7%1.51×
ChIP-seqSE 28.6M plain 12.982.971 MB 1542—1.00×
--clumpify 18.1104.71495 MB 1543+0.08%1.40×
--compression 6 63.4378.372 MB 1325−14.1%4.91×
--clumpify --compression 6 61.6329.31230 MB 1308−15.2%4.77×
WESSE 105M plain 102.3637.188 MB 9166—1.00×
--clumpify 113.7777.91856 MB 8758−4.4%1.11×
--compression 6 652.23809.280 MB 7756−15.4%6.38×
--clumpify --compression 6 636.73552.81304 MB 7285−20.5%6.22×
Long-read (ONT/PacBio)SE ~100K plain 10.132.1867 MB 558—1.00×
--clumpify 10.836.1781 MB 558~0%1.07×
--compression 6 33.3157.2974 MB 510−8.6%3.30×
--clumpify --compression 6 31.4158.8972 MB 509−8.8%3.11×
ATAC-seqPE 31.5M plain 41.5260.7193 MB 2869—1.00×
--clumpify 47.1303.11654 MB 1870−34.8%1.13×
--compression 6 172.11023.8144 MB 2247−21.7%4.15×
--clumpify --compression 6 98.4616.31989 MB 1478−48.5%2.37×
Ribo-seqPE ~30M plain 50.2308.8304 MB 3987—1.00×
--clumpify 53.5345.31914 MB 3380−15.2%1.07×
--compression 6 264.51556.6279 MB 3239−18.8%5.27×
--clumpify --compression 6 192.51156.21858 MB 2710−32.0%3.84×
RNA-seqPE 93M plain 146.4938.1148 MB 17,034—1.00×
--clumpify 153.21046.02039 MB 14,455−15.1%1.05×
--compression 6 864.55184.0139 MB 14,658−14.0%5.90×
--clumpify --compression 6 1956.93981.81530 MB 12,400−27.2%13.36×
scRNA-seq 10x ChromiumPE 392M plain 383.12514.1578 MB 39,575—1.00×
--clumpify 471.13112.22099 MB 42,033+6.2%1.23×
--compression 6 2312.713,550.8146 MB 32,806−17.1%6.04×
--clumpify --compression 6 TBDTBDTBD TBDTBDTBD

Output (MB): sum of all *.fq.gz in the run's output dir (R1 + R2 for paired). Saving vs plain: percentage reduction relative to the plain row of the same dataset. Wall vs plain: ratio of the configuration's wall time to the plain wall time of the same dataset.

At-a-glance plots

Each plot has 8 dataset groups along the X axis, with 3 bars per group: --clumpify (default L1) · --compression 6 · --clumpify --compression 6. Plain (no flags) is the implicit baseline. The dashed bar with `?` is the still-pending scRNA-seq run.

Compression saving vs plain (%) positive = output smaller; negative = output grew 50% 40% 30% 20% 10% 0% −10% MiSeq ChIP-seq WES Long-read ATAC-seq Ribo-seq RNA-seq scRNA-seq 10x ? --clumpify (L1, default) --compression 6 --clumpify --compression 6 Wall time vs plain (×) how much longer than the plain run took 1× (plain wall) 0× 2× 4× 6× 8× 10× 12× 14× MiSeq ChIP-seq WES Long-read ATAC-seq Ribo-seq RNA-seq scRNA-seq 10x 13.4× ? --clumpify (L1, default) --compression 6 --clumpify --compression 6

How to read these together: a configuration is a good trade if its blue/orange/green bar is tall in the saving plot AND short in the wall plot. The L1 default (blue) is short in both — minimal cost, modest saving. --compression 6 alone (orange) trades wall time for saving. The combined config (green) is the only one that's tall in saving while often being shorter than orange in wall time — see ATAC-seq, Ribo-seq.

Why is --clumpify --compression 6 often faster than --compression 6 alone? Counter-intuitive but real: gzip's deflate is data-dependent in CPU cost, not just in output size. When clumpify groups reads sharing a 16-mer minimizer, adjacent records share long substrings; deflate's LZ77 hash chain finds a long match on the first probe and exits the search early (the L6 tuning is `nice_match=128, max_chain=128` — sorted data trips `nice_match` instantly). On unsorted data deflate scans the full chain trying to find any decent match, settles for a short one, and emits more literal bytes. Net effect: with sorted input, gzip does less CPU work per byte AND writes a smaller output (less I/O). Both bonuses come from the same property — the minimizer sort effectively pre-does the dictionary search work that deflate would otherwise do less effectively.

Verifying on the data: user CPU drops too, not just wall:
Dataset--compression 6 user CPU--clumpify --compression 6 user CPUCPU saved
ATAC-seq1024 s616 s−40%
Ribo-seq1557 s1156 s−26%
MiSeq amplicon145 s130 s−10%
WES3809 s3553 s−7%

The effect is strongest on data with high R1 redundancy (ATAC-seq Tn5 footprints, Ribo-seq, amplicons). Diverse data (WES, ChIP-seq) shows a smaller speedup because the minimizer sort produces shorter runs of similar reads.

Trade-off space (scatter)

Same data, plotted as one point per (dataset × config). Up-and-left is best (high saving, low wall cost). Each dataset has 3 dots — one per config — connected with a thin grey line to make it easy to track the same dataset across configs. Hover for tooltips.

Saving vs wall — trade-off space each point = one (dataset × config); thin lines connect the 3 configs of one dataset 0% saving 1× wall 50% 40% 30% 20% 10% 0% −10% saving vs plain (%) 0× 2× 4× 6× 8× 10× 12× 14× wall time vs plain (×) ↖ better MiSeq, --clumpify: 16.3% saving, 1.02× wall MiSeq, --compression 6: 25.1% saving, 1.64× wall MiSeq, --clumpify --compression 6: 31.7% saving, 1.51× wall MiSeq ChIP-seq, --clumpify: −0.08% saving, 1.40× wall ChIP-seq, --compression 6: 14.1% saving, 4.91× wall ChIP-seq, --clumpify --compression 6: 15.2% saving, 4.77× wall ChIP-seq WES, --clumpify: 4.4% saving, 1.11× wall WES, --compression 6: 15.4% saving, 6.38× wall WES, --clumpify --compression 6: 20.5% saving, 6.22× wall WES Long-read, --clumpify: 0.0% saving, 1.07× wall Long-read, --compression 6: 8.6% saving, 3.30× wall Long-read, --clumpify --compression 6: 8.8% saving, 3.11× wall Long-read ATAC-seq, --clumpify: 34.8% saving, 1.13× wall ATAC-seq, --compression 6: 21.7% saving, 4.15× wall ATAC-seq, --clumpify --compression 6: 48.5% saving, 2.37× wall ATAC-seq ⭐ Ribo-seq, --clumpify: 15.2% saving, 1.07× wall Ribo-seq, --compression 6: 18.8% saving, 5.27× wall Ribo-seq, --clumpify --compression 6: 32.0% saving, 3.84× wall Ribo-seq RNA-seq, --clumpify: 15.1% saving, 1.05× wall RNA-seq, --compression 6: 14.0% saving, 5.90× wall RNA-seq, --clumpify --compression 6: 27.2% saving, 13.36× wall (single-run outlier) RNA-seq scRNA-seq 10x, --clumpify: −6.2% saving, 1.23× wall (got bigger) scRNA-seq 10x, --compression 6: 17.1% saving, 6.04× wall scRNA-seq 10x scRNA-seq 10x, --clumpify --compression 6: pending ? pending L1 cluster (low cost) --clumpify (L1, default) --compression 6 --clumpify --compression 6

What jumps out:

Pattern observations

Default --clumpify (L1) is mostly free but mostly modest. Wall ratios are 1.02–1.40× plain across 7 of 8 datasets (only scRNA-seq is meaningfully slower at 1.23×). Savings range from ~0% (ChIP-seq, long-read, scRNA-seq) up to 35% (ATAC-seq). The L1 sweet spots are datasets where R1 has strong intrinsic redundancy: ATAC-seq Tn5 footprints, MiSeq amplicons, RNA-seq highly-expressed transcripts, Ribo-seq ribosome footprints.
scRNA-seq 10x at default L1 gets bigger by 6.2%. Cell-barcode R1 is highly redundant and reorders cleanly; R2 (cDNA) follows R1's order to preserve pair lockstep, ending up effectively scrambled vs the natural flowcell-cluster order of the input. At L1 the R2 disruption outweighs the R1 win. At L6 with reordering on top (still pending) we'd expect the loss to flip to a win — gzip's larger dictionary at L6 catches the R2 fragmentation.
--clumpify --compression 6 is the headline configuration. On every dataset where it has finished, it's the best on both saving (largest reduction) and — surprisingly — often on wall time vs plain L6: ATAC-seq L6 alone is 4.15× plain at 22% saving; --clumpify --compression 6 is only 2.37× plain at 49% saving. The reorder pays for itself by giving gzip cleaner runs to compress, which finishes faster than gzip slogging through unsorted data at L6.
RNA-seq L6 + clumpify took 13× plain (1957 s vs 146 s). Outlier in the table — the other PE datasets were 2–4× plain at this configuration. User CPU was 3982 s vs wall 1957 s = 2.0× CPU/wall ratio, meaning workers averaged just 2 of 6 cores busy. Likely transient memory pressure from another process during this specific run; max RSS hit 1.53 GB vs the 1023 MiB predicted peak. Treat as a single-data-point caveat.

Per-dataset commentary

MiSeq amplicon (CRISPR), SE 4.4M

Cleanest result: every step adds value. --clumpify alone saves 16% with no wall penalty; --compression 6 alone saves 25% at 1.64× wall; combining both saves 32% at 1.51× wall — actually slightly faster than gzip-L6 alone, because the sorted bins compress more efficiently. CRISPR-PCR amplicons are nearly identical reads, so this is the best-case scenario.

ChIP-seq, SE 28.6M

L1 reorder gains nothing (peaks aren't dense enough at 28 M reads to fill the small L1 dictionary window). L6 alone saves 14%; clumpify on top of L6 adds only 1 ppt. Largest L1-clumpify wall penalty in the matrix (1.40× plain) for zero benefit — at L1 specifically, ChIP-seq is a bad fit.

WES, SE 105M

Diverse whole-exome coverage gives modest savings across the board: 4% L1-clumpify, 15% L6 alone, 21% combined. Wall penalty is significant at L6 (~6× plain, ~10 minutes wall) — proportional to data volume, not algorithmic. Reorder stacks cleanly with L6 (+5 ppt over L6 alone).

Long-read (ONT/PacBio), SE ~100K

Reorder is essentially a no-op (long reads are unique fragments). L6 alone saves 9%; clumpify on top adds nothing. Useful negative result: --clumpify isn't actively harmful on long-read data, but there's no benefit either.

ATAC-seq, PE 31.5M

Strongest reorder beneficiary by a wide margin. L1-clumpify saves 35%; L6 alone saves 22%; combining gets 49%. Counter-intuitively, clumpify+L6 runs faster than L6 alone (98 s vs 172 s) because the bin-sorted gzip members compress so efficiently that less data is written.

Ribo-seq, PE ~30M

Mid-tier beneficiary. L1-clumpify saves 15%; L6 alone saves 19%; combining gets 32%. Same wall-time anomaly as ATAC-seq: clumpify+L6 (193 s) beats L6 alone (264 s).

RNA-seq, PE 93M

L1-clumpify saves 15% at almost no wall cost (1.05× plain) — a clear recommendation. L6 alone saves 14% at 5.9× plain wall. Combining gets 27% but the wall-time outlier (13× plain) noted above clouds the picture for this single run.

scRNA-seq 10x Chromium, PE 392M

The interesting case. L1-clumpify is actively harmful (+6%). L6 alone saves 17% at 6× plain wall (~38 minutes). The --clumpify --compression 6 result is still pending; if it lands above L6-alone's 17% saving, it validates the hypothesis that R2 fragmentation at L1 is recoverable at L6's larger dictionary window.

Reproducibility

Driver scripts:

Logs and outputs: /Volumes/T7 Shield/clumpy-bench/data_types_v2/*.log and corresponding /Volumes/T7 Shield/clumpy-bench/data_types_v2/*/ output directories.

All runs sequential, --cores 6 --paired (where applicable), on Apple M1 Pro / 16 GiB RAM / macOS Darwin 25.4.