bismark/align: intra-instance -p threading (replace --multicore fork model for Bowtie 2 + HISAT2)#12385
bismark/align: intra-instance -p threading (replace --multicore fork model for Bowtie 2 + HISAT2)#12385FelixKrueger wants to merge 6 commits into
Conversation
Replace the --multicore fork resource model with an intra-instance -p divisor (-p = task.cpus / n_instances; n = 2 directional/pbat, 4 non-directional, 1 combined-index, 2 combined_index_parallel+non_dir) for Bowtie 2 and HISAT2. minimap2/rammap keep the legacy --multicore auto-compute unchanged. Lower peak RAM (one index load per strand instance instead of M forks each re-loading the index), fuller CPU use, and byte-identical Bowtie 2 output (-p N --reorder is thread-invariant). Emits -p only when task.cpus/n >= 2, else omits it (faithful single-thread-per-instance). Adds 4 nf-tests asserting -p is emitted (bowtie2 dir/non-dir, hisat2, combined-index) via a dedicated cpus=8 config; existing tests unchanged (cpus=2 emits no -p -> byte-identical, snapshots unchanged).
The -p-threading tests requested cpus=8 to force the divisor to emit -p, but nf-core CI runners have 4 cpus and nextflow.enable.strict=true rejects a request exceeding available cores (req 8 > avail 4) before the process runs. Drop to cpus=4 (the runner ceiling): directional -> -p 2, HISAT2 directional -> -p 2, combined (n=1) -> -p 4. The non-directional case at 4/4=1 now asserts -p is OMITTED, exercising the omit-below-2 boundary. Verified 9/9 nf-test pass on native amd64 with the 3.1.0 container.
nf-core/modules#12385 review (mashehu) asks for the long-name flag. bismark's -p was short-only (unlike bowtie2, which accepts -p/--threads); add the --threads alias so downstream (nf-core module) can use the long name once a bismark release with it ships. Behaviour-neutral: -p stays valid, no output change (existing tests + perl-oracle unaffected).
|
Thanks @mashehu! Two notes on these:
|
… 2) (#1075) * aligner: route -p to minimap2/rammap -t; kill 5-Base -t mangling (#1074) minimap2_options renders -t from cli.bowtie_threads (Bismark -p), defaulting to the faithful -t 2 when -p is absent — spike-confirmed minimap2 -t is thread- invariant (byte-identical + order-preserving), so a bare --minimap2 stays byte-identical to Perl. rammap-subprocess shares this clean-slate path; the rammap in-process pool (inprocess_rammap_threads) now honors -p too (precedence: -p > --multicore > capped available_parallelism). The 5-Base path's fragile `.replace("-t 2", …)` — a SUBSTRING replace that mangled `-t 20`→`-t 200` once the base carried a resolved `-t {p}` — is replaced by a token-safe rewrite of the value after `-t`. Closes #1074. Tests: 1427 lib tests pass incl. new -p-lift + C2 token-safe guard + rammap-pool -p cases; cargo fmt + clippy clean. * aligner: add --threads long alias for -p (nf-core long-name convention) nf-core/modules#12385 review (mashehu) asks for the long-name flag. bismark's -p was short-only (unlike bowtie2, which accepts -p/--threads); add the --threads alias so downstream (nf-core module) can use the long name once a bismark release with it ships. Behaviour-neutral: -p stays valid, no output change (existing tests + perl-oracle unaffected).
What & why
bismark/aligncurrently auto-computes--multicore ccore(ccore = task.cpus / 3directional // 5non-directional). For Bowtie 2,--multicore Nforks N file-level workers, and each worker runs the 2 (directional/pbat) or 4 (non-directional) concurrent per-strand Bowtie 2 instances — so the job holds N × (2 or 4) copies of the converted index in RAM and re-decodes the input per fork. It also under-subscribes the reservation (the/3,/5divisor leaves cores idle).This replaces that with intra-instance threading:
-p = task.cpus / n_instances, wheren_instances= 2 (directional/pbat), 4 (non-directional), 1 (--combined_index; 2 for--combined_index_parallel --non_directional). The job then holds only 2/4 index copies total and uses alltask.cpus.-p N --reorderis thread-invariant.-ptoo, so it gets the divisor. HISAT2 is not strictly thread-invariant, but the effect is negligible (see evidence) and HISAT2 was alreadytask.cpus-dependent under--multicore.-t 2and auto-scales rammap, so the module can't route threads to them; they keep the existing--multicoreauto-compute verbatim. (Unifying their threading is tracked separately, upstream in Bismark.)--multicore/--parallel/-pinext.argsshort-circuits the auto-compute.-pis emitted only whentask.cpus / n_instances >= 2, else omitted (faithful single-thread-per-instance).Evidence (benchmark)
GRCh38, 2 M paired-end reads, bismark 3.0.0/3.1.0 (resource model is byte-identical across the two), process-tree peak-RSS sampler, records-only 3-way byte-identity. Median of ≥3 reps; OLD =
--multicore ccore, NEW =-p (cpus/n):Bowtie 2 records byte-identical OLD vs NEW vs single-core oracle (both file-order and order-normalised md5), directional + non-directional. HISAT2 (separate spot-check): no RAM change (it never forked), wall −8 to −41 %, output re-baseline negligible (~2–4 records differ per 3.245 M, 99.9999 % identical).
Testing
nf-test9/9 pass on native amd64 with the bismark 3.1.0 container:cpus=2,task.cpus / n < 2so no-pis emitted for any path → commands byte-identical → no snapshots regenerated.-pvia the alignment report's options echo (-p N --reorder), atcpus=8(dedicated config): Bowtie 2 directional (-p 4), Bowtie 2 non-directional (-p 2), HISAT2 directional (-p 4), and--combined_index(-p 8, n=1).Notes for reviewers
-pbehaviour is verified by report-echo assertions, not snapshots, because the alignment BAM is thread-invariant (Bowtie 2) or near-invariant (HISAT2), so a snapshot wouldn't distinguish it.cpus-dependent). MultiQC parses metric counts (not the settings-echo line), so its output is unaffected for Bowtie 2.--multicorebut not its alias--parallel;--minimap2 --parallel Nat high cpu would crash on duplicate args. This predates this PR (the old single--multicoreblock had the same gap) and is left untouched here to keep minimap2/rammap byte-identical; it's folded into the upstream Bismark aligner-threading unification work.Checklist
nf-core modules lint bismark/align(CI)nf-test testgreen in CI (native amd64)modules.jsonunaffected (no version bump)