perf(mapping): pipe minimap2 straight into samtools sort (removes ~1.3 GiB of disk traffic per mapping) - #3
Open
sanjaynagi-eit wants to merge 1 commit into
Open
Conversation
sanjaynagi-eit
force-pushed
the
perf/pipe-minimap-to-sort
branch
2 times, most recently
from
August 13, 2026 21:54
8249fb0 to
bdc474e
Compare
Every depth calculation wrote minimap2's full uncompressed SAM to disk and then had samtools sort read it straight back. The SAM had exactly one consumer; it existed only as a pipe buffer. For one real ONT isolate that is 0.64 GiB written and re-read per mapping, and `plassembler run` does this twice (long and short). Nextflow traces of a 90-isolate plate show plassembler doing ~2.2-2.7 GB of writes per sample, a large part of which is this. Add ExternalTool.run_piped, which runs a chain of tools connected by pipes without a shell: it closes the parent's copy of each upstream read end, waits on every stage downstream-first, and raises CalledProcessError for the earliest failing stage. Then add minimap_long_reads_to_sorted_bam / minimap_short_reads_to_sorted_bam on top of it and use them at the six map-then-sort sites in plass_class. The resulting bam is identical: alignment records compare byte-for-byte and `samtools depth` output has the same md5. Only the @pg header line differs, because it records the command line that produced the file. On a fast local NVMe with a warm page cache the wall-clock difference is small (20.4s -> 20.0s); the win is the 1.27 GiB of avoided disk traffic per mapping, which matters when many isolates run concurrently and the page cache is contended. minimap_long_reads / minimap_short_reads are kept: the hybrid path's long_read.sam has two consumers and is handled separately. If a stage fails to start partway through building the chain - a missing binary, a fork failure - the stages already started are killed and reaped rather than left blocked on a pipe nobody will read.
sanjaynagi-eit
force-pushed
the
perf/pipe-minimap-to-sort
branch
from
August 13, 2026 22:18
bdc474e to
d76ab2c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every depth calculation does:
The SAM has exactly one consumer. It is written to disk in full, uncompressed, purely so that the next process can read it straight back.
On one real ONT isolate that is 0.64 GiB written and 0.64 GiB re-read per mapping, and
plassembler rundoes it twice (long and short reads). Nextflow traces from a 90-isolate plate showPLASSEMBLER_LONGdoing 2.2-2.7 GB of writes and 3.4-4.2 GB of reads per sample; a large part of that is this pattern.Change
Add
ExternalTool.run_piped, a shell-free pipeline runner that:CalledProcessErrorfor the earliest failing stage, which is the informative one;samtools sort -o) as well as one whose stdout is captured.On top of it,
minimap_long_reads_to_sorted_bam/minimap_short_reads_to_sorted_bam, used at the six map-then-sort sites inplass_class.py.Also factors the duplicated
--pacbio_model-> minimap2 preset mapping intominimap2_model_for().Equivalence
Comparing the old two-step and the new piped form on the same reads and reference:
samtools viewalignment records: byte-for-byte identicalsamtools depthoutput: same md5@PGheader line, which records the command line that produced the fileWall clock
On a fast local NVMe with a warm page cache, 20.4 s -> 20.0 s. The change is about I/O volume and peak disk footprint rather than CPU: the benefit shows up when many isolates run concurrently (as in a Nextflow plate) and the page cache is contended, or on network-backed storage.
Scope
minimap_long_reads/minimap_short_readsandsam_to_sorted_bamare unchanged and still used: the hybrid path'slong_read.samhas two consumers, so it needs a different treatment and is out of scope here.Tests
New
tests/test_piped_tools.pycovers stdout capture, a last stage writing its own file, failure propagation, and that the earliest failing stage is the one reported. All existing tests pass.