perf(collect): reuse per-read SMEM/reseed buffers via CollectScratch - #46
Conversation
`collect_smems` allocated and freed two Vecs per read — the emitted SMEM buffer and the pass-2 reseed work-list. bwa-mem3 runs the collector once per read over millions of reads, so those two allocate/free pairs recur on the compute-bound seeding path. Add a reusable `CollectScratch` and a `collect_smems_into` entry point that clears and reuses those buffers instead of allocating fresh ones. The walk moves into `collect_smems_unsorted_into`, which clears the caller-held buffers on entry and drains (rather than consumes) the reseed list so its capacity is retained between reads. `collect_smems` stays a thin wrapper that allocates a throwaway scratch, so every existing caller, the FFI slice contract, and the output are unchanged. The C entry point `prmi_collect_smems` now holds a thread-local `CollectScratch`, so the amortization reaches the consumer without any ABI change while preserving per-thread isolation. This is byte-identical by construction (the buffers are cleared before use). Verified by a new proptest that runs a reused, pre-dirtied scratch against the fresh-allocating path across the full opts sweep, by the existing oracle/ISA byte-identity proptests, and by an end-to-end collect_gate SMEM-dump comparison vs main (0 differences across a 24-point k/split_len/split_width/max_mem_intv grid on a 1 Mbp reference). A new `wall_gate` example measures the seeding wall (single-thread, warm, load-excluded); the scratch path is a small, consistent win over the allocating path (min/median/mean ns/read all lower) with identical output.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughIntroduces ChangesCollectScratch reuse for SMEM collection
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
Action performedReview triggered.
|
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
LearnedIndex::collect_smemsallocated and freed twoVecs on every read — the emitted SMEM buffer and the pass-2 reseed work-list. bwa-mem3 runs the collector once per read over millions of reads, so those two allocate/free pairs recur on the compute-bound seeding path.This adds a reusable
CollectScratchand acollect_smems_intoentry point that clears and reuses those buffers instead of allocating fresh ones:collect_smems_unsorted_into, which clears the caller-held buffers on entry anddrains (rather than consumes) the reseed list so its capacity is retained between reads.collect_smemsstays a thin wrapper that allocates a throwawayCollectScratch, so every existing caller, the FFI slice contract, and the output are unchanged.prmi_collect_smemsnow holds a thread-localCollectScratch, so the amortization reaches the consumer without any ABI change while preserving per-thread isolation.Byte-identical by construction — the buffers are cleared before use. Verified by:
collect_smems_into_equals_collect_smemsproptest that runs a reused, pre-dirtied scratch against the fresh-allocating path across the full opts sweep (long-then-short reads, to catch stale-tail bugs).collect_gateSMEM-dump comparison vsmain: 0 differences across a 24-pointk/split_len/split_width/max_mem_intvgrid on a 1 Mbp reference.cargo clippy --all-features --all-targets -D warningsandcargo +nightly fmt --checkclean; fullcargo testworkspace suite passes.Performance (secondary): a new
wall_gateexample measures the seeding wall (single-thread, warm, load-excluded). The scratch path is a small, consistent win over the allocating path — min/median/mean ns/read all lower (paired runs ~0.5–3%) — with identical output. This is a hygiene / allocation-pressure win, not a large speedup.Summary by CodeRabbit
CollectScratchAPI for SMEM collection operations.collect_smems_intomethod onLearnedIndexfor configurable collection workflows.