Skip to content

perf(raw-bam): follow-up speedups + SIMD nibble2base - #282

Merged
nh13 merged 1 commit into
mainfrom
nh/raw-bam-api-5-perf
Apr 17, 2026
Merged

nh13 merged 1 commit into
mainfrom
nh/raw-bam-api-5-perf

Conversation

@nh13

@nh13 nh13 commented Apr 15, 2026

Copy link
Copy Markdown
Member

Summary

Part 5 of 5 in the stacked series closing #272. Stacks on #281.

Six perf optimizations on top of the core API, grouped into three commits:

  1. f0b8b32 — small tag-lookup/header-decode wins

    • tag_value_size marked #[inline(always)] (hot inside find_tag_position)
    • find_tag_position compares tags as u16 instead of byte slices
    • aux_data_offset_from_record does a single u64 load over offsets 12..20
  2. bea6016 — set_sequence_and_qualities splices in place

    • Vec::copy_within + pack_sequence_into_slice replace intermediate Vec allocation
    • Impact: set_sequence_and_qualities_grow 300 ns → 125 ns (−58%); vs-RecordBuf speedup 6× → 13.8×
  3. df1089c + dd8b4fb — SIMD nibble2base via wide::u8x16::swizzle_relaxed (portable pshufb)

    • Port of htslib's simd.c nibble2base
    • 16 packed bytes (32 bases) per iteration
    • sequence_vec 150 bp: 3.8×, 300 bp: 6.0×
  4. 0955cfa — branchless BAM_CIGAR_TYPE = 0x3C1A7 bitmask (matches htslib)

    • consumes_query / consumes_ref become single shift+mask
    • Adds RawRecordView::cigar_lengths() for dual-return walk (ref_len + query_len in one iteration)

Benchmark summary

See the comparison table in PR description for the raw-byte-vs-RecordBuf speedups after all perf work: 14×–922× range, 13.8× on the previously-weakest set_sequence_and_qualities.

Test plan

  • cargo ci-test — all tests pass
  • cargo bench --bench raw_bam_accessors — SIMD numbers confirmed
  • cargo bench --bench raw_bam_vs_recordbuf — post-refactor speedups measured

Stack

  • PR 1: Core API + gap closures
  • PR 2: Migration
  • PR 3: Demotion (BREAKING)
  • PR 4: Tests + benchmarks
  • PR 5 (this): Post-refactor perf optimizations

Closes #272 (when the full stack lands). Supersedes #277.

@codecov

codecov Bot commented Apr 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.03%. Comparing base (9c6873f) to head (01baf28).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #282   +/-   ##
=======================================
  Coverage   90.02%   90.03%           
=======================================
  Files         122      122           
  Lines       61791    61791           
=======================================
+ Hits        55630    55631    +1     
+ Misses       6161     6160    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nh13
nh13 marked this pull request as ready for review April 15, 2026 08:38
@nh13

nh13 commented Apr 15, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@nh13 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 46 minutes and 27 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 46 minutes and 27 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c5fac576-79d1-40ec-a16f-ea3189199ffe

📥 Commits

Reviewing files that changed from the base of the PR and between cc7a203 and 01baf28.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • Cargo.toml
  • benches/raw_bam.rs
  • crates/fgumi-raw-bam/Cargo.toml
  • crates/fgumi-raw-bam/src/cigar.rs
  • crates/fgumi-raw-bam/src/fields.rs
  • crates/fgumi-raw-bam/src/raw_bam_record.rs
  • crates/fgumi-raw-bam/src/sequence.rs
  • crates/fgumi-raw-bam/src/tags.rs
📝 Walkthrough

Walkthrough

This pull request optimizes and extends the raw-byte BAM API in fgumi-raw-bam. Changes include moving dependencies to workspace-level declarations (upgrading wide to 1.3), adding SIMD-based sequence decoding for sequences ≥32 bases, introducing cigar_lengths() to compute reference and query lengths in a single pass, refactoring set_sequence_and_qualities to use in-place buffer resizing instead of allocation, and optimizing field access patterns via bitmask operations and reduced memory loads. Three new benchmarks exercise the sequence decoding path across different buffer sizes.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the primary change: performance optimizations including SIMD nibble-to-base conversion, matching the changeset's core objectives.
Description check ✅ Passed Description comprehensively details all six optimizations across three commits, benchmark improvements, test coverage, and the stack context, all directly related to the changeset.
Linked Issues check ✅ Passed PR implements post-refactor performance optimizations (#272 requirement) including SIMD nibble2base, in-place sequence editing, and CIGAR bitmask—closing the core objective gaps and enabling raw-byte path efficiency.
Out of Scope Changes check ✅ Passed All changes are focused on performance and API completeness for issue #272; workspace dependency alignment and benchmarks are supporting infrastructure for the optimization work.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch nh/raw-bam-api-5-perf

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nh13

nh13 commented Apr 15, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/fgumi-raw-bam/src/sequence.rs (1)

223-228: Fail fast on undersized dst.

This is a public API, but the length contract is only debug_assert!ed. In release builds, misuse turns into a later bounds panic instead of failing at the call boundary. Prefer an unconditional assert! with a clear message, or return a Result.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/fgumi-raw-bam/src/sequence.rs` around lines 223 - 228, The public API
pack_sequence_into_slice currently only uses debug_assert! to check dst length,
which fails to enforce the contract in release builds; replace the debug_assert!
with an unconditional assert! (e.g. assert!(dst.len() >= packed_len,
"pack_sequence_into_slice: destination slice too small; need {} bytes",
packed_len)) so callers immediately get a clear panic on misuse, or
alternatively change the function to return Result<(), Error> and return Err
when dst.len() < packed_len; apply this change inside pack_sequence_into_slice
where packed_len is computed and reference dst and bases accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/fgumi-raw-bam/src/cigar.rs`:
- Around line 56-64: The right-shift uses (op_type << 1) which can be >=32 and
panic in debug builds; add an explicit guard at the start of both consumes_ref
and consumes_query to return false for out-of-range op_type values (e.g., if
op_type >= 16 { return false }) before performing the (BAM_CIGAR_TYPE >>
(op_type << 1)) bit operations so the shift is always <32 and behavior for
unknown op codes remains false.

In `@crates/fgumi-raw-bam/src/sequence.rs`:
- Around line 769-785: The test
test_extract_sequence_simd_matches_scalar_over_lengths currently only
round-trips pack_sequence_into -> extract_sequence and doesn't verify SIMD vs
scalar; change it to compute an explicit expected sequence by decoding the same
packed bytes with the scalar decoder (call get_base on each packed nibble and
map via BAM_BASE_TO_ASCII) over the full alphabet (=ACMGRSVTWYHKDBN) for each
index, then assert extract_sequence(&bam) == expected; keep using
pack_sequence_into, seq_offset, make_bam_bytes and the same length cases
(including l >= 32) so the SIMD path is exercised while verifying the scalar
get_base/BAM_BASE_TO_ASCII result against extract_sequence.

---

Nitpick comments:
In `@crates/fgumi-raw-bam/src/sequence.rs`:
- Around line 223-228: The public API pack_sequence_into_slice currently only
uses debug_assert! to check dst length, which fails to enforce the contract in
release builds; replace the debug_assert! with an unconditional assert! (e.g.
assert!(dst.len() >= packed_len, "pack_sequence_into_slice: destination slice
too small; need {} bytes", packed_len)) so callers immediately get a clear panic
on misuse, or alternatively change the function to return Result<(), Error> and
return Err when dst.len() < packed_len; apply this change inside
pack_sequence_into_slice where packed_len is computed and reference dst and
bases accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea2009b3-6e28-4ce5-9b6a-2a5e14601ab4

📥 Commits

Reviewing files that changed from the base of the PR and between 6639a7d and cc7a203.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • Cargo.toml
  • benches/raw_bam_accessors.rs
  • crates/fgumi-raw-bam/Cargo.toml
  • crates/fgumi-raw-bam/src/cigar.rs
  • crates/fgumi-raw-bam/src/fields.rs
  • crates/fgumi-raw-bam/src/raw_bam_record.rs
  • crates/fgumi-raw-bam/src/sequence.rs
  • crates/fgumi-raw-bam/src/tags.rs

Comment thread crates/fgumi-raw-bam/src/cigar.rs Outdated
Comment thread crates/fgumi-raw-bam/src/sequence.rs
@nh13 nh13 added the raw-bam label Apr 16, 2026
@nh13
nh13 force-pushed the nh/raw-bam-api-4-tests branch 4 times, most recently from 40211c0 to 40ffceb Compare April 17, 2026 16:45
Base automatically changed from nh/raw-bam-api-4-tests to main April 17, 2026 16:48
@nh13
nh13 force-pushed the nh/raw-bam-api-5-perf branch from cc7a203 to f27ff46 Compare April 17, 2026 16:56
@nh13
nh13 temporarily deployed to github-actions April 17, 2026 16:56 — with GitHub Actions Inactive
Six optimizations on top of the raw-byte view/editor API:

- tag_value_size: #[inline(always)] so the inner dispatch of the hot
  find_tag_position loop inlines the table-lookup + match.
- find_tag_position: compare the 2-byte tag identifier as a single u16
  instead of a slice reference.
- aux_data_offset_from_record: single u64 load over offsets 12..20 to
  fetch n_cigar_op and l_seq in one go (flag at 14..15 masked off).
- set_sequence_and_qualities: shift aux in place with copy_within and
  write packed seq + qual directly into the record buffer, eliminating
  the intermediate Vec. Bench: set_sequence_and_qualities_grow
  300 ns -> 125 ns (-58%); vs-RecordBuf speedup 6x -> 13.8x.
- extract_sequence: SIMD nibble2base via wide::u8x16::swizzle_relaxed
  (portable pshufb). 16 packed bytes = 32 bases per iteration. 150 bp
  ~3.8x, 300 bp ~6.0x vs scalar. Scalar path retained for l_seq < 32.
- consumes_query / consumes_ref: single shift+mask against
  BAM_CIGAR_TYPE = 0x3C1A7 (htslib's sam.h). Adds
  RawRecordView::cigar_lengths() for a dual ref_len + query_len walk.

Also bumps workspace wide to 1.3 and adds bytemuck/wide to
fgumi-raw-bam.

Refs #272
@nh13
nh13 force-pushed the nh/raw-bam-api-5-perf branch from f27ff46 to 01baf28 Compare April 17, 2026 16:59
@nh13
nh13 temporarily deployed to github-actions April 17, 2026 16:59 — with GitHub Actions Inactive
@nh13
nh13 merged commit 05e89b8 into main Apr 17, 2026
7 of 8 checks passed
@nh13
nh13 deleted the nh/raw-bam-api-5-perf branch April 17, 2026 17:02
@nh13 nh13 mentioned this pull request Apr 17, 2026
nh13 added a commit that referenced this pull request Apr 17, 2026
… remaining 48-commit work

The final PR in the stacked series closes the full delta against the
48-commit backup. In addition to the original scope (vendored bam_codec
deletion + simulate migration), this amends to include:

- Missing new files: sort/keys.rs, 4 raw-bam bench files
- compare/bams.rs RawRecord migration
- codec_caller.rs cascade simplification
- group/filter/correct/extract/clip/bam_io.rs simplifications
- overlapping.rs raw-only API
- Test suite updates for test_compare_bams, test_group_command,
  test_e2e_regression
- Doc touch-ups in best-practices/performance-tuning

Verified: tree matches backup except for 6 main-only files
(prefetch_reader, os_hints, test_async_reader, template_coordinate,
and two benches) that came from main PRs #258/#261/#265/#270/#282
merged after our branch point.

Part 8 of 8 in the series closing #272. Stacks on #295.
nh13 added a commit that referenced this pull request Apr 20, 2026
… remaining 48-commit work

The final PR in the stacked series closes the full delta against the
48-commit backup. In addition to the original scope (vendored bam_codec
deletion + simulate migration), this amends to include:

- Missing new files: sort/keys.rs, 4 raw-bam bench files
- compare/bams.rs RawRecord migration
- codec_caller.rs cascade simplification
- group/filter/correct/extract/clip/bam_io.rs simplifications
- overlapping.rs raw-only API
- Test suite updates for test_compare_bams, test_group_command,
  test_e2e_regression
- Doc touch-ups in best-practices/performance-tuning

Verified: tree matches backup except for 6 main-only files
(prefetch_reader, os_hints, test_async_reader, template_coordinate,
and two benches) that came from main PRs #258/#261/#265/#270/#282
merged after our branch point.

Part 8 of 8 in the series closing #272. Stacks on #295.
nh13 added a commit that referenced this pull request Apr 20, 2026
… remaining 48-commit work

The final PR in the stacked series closes the full delta against the
48-commit backup. In addition to the original scope (vendored bam_codec
deletion + simulate migration), this amends to include:

- Missing new files: sort/keys.rs, 4 raw-bam bench files
- compare/bams.rs RawRecord migration
- codec_caller.rs cascade simplification
- group/filter/correct/extract/clip/bam_io.rs simplifications
- overlapping.rs raw-only API
- Test suite updates for test_compare_bams, test_group_command,
  test_e2e_regression
- Doc touch-ups in best-practices/performance-tuning

Verified: tree matches backup except for 6 main-only files
(prefetch_reader, os_hints, test_async_reader, template_coordinate,
and two benches) that came from main PRs #258/#261/#265/#270/#282
merged after our branch point.

Part 8 of 8 in the series closing #272. Stacks on #295.
nh13 added a commit that referenced this pull request Apr 20, 2026
… remaining 48-commit work

The final PR in the stacked series closes the full delta against the
48-commit backup. In addition to the original scope (vendored bam_codec
deletion + simulate migration), this amends to include:

- Missing new files: sort/keys.rs, 4 raw-bam bench files
- compare/bams.rs RawRecord migration
- codec_caller.rs cascade simplification
- group/filter/correct/extract/clip/bam_io.rs simplifications
- overlapping.rs raw-only API
- Test suite updates for test_compare_bams, test_group_command,
  test_e2e_regression
- Doc touch-ups in best-practices/performance-tuning

Verified: tree matches backup except for 6 main-only files
(prefetch_reader, os_hints, test_async_reader, template_coordinate,
and two benches) that came from main PRs #258/#261/#265/#270/#282
merged after our branch point.

Part 8 of 8 in the series closing #272. Stacks on #295.
nh13 added a commit that referenced this pull request Apr 20, 2026
… remaining 48-commit work

The final PR in the stacked series closes the full delta against the
48-commit backup. In addition to the original scope (vendored bam_codec
deletion + simulate migration), this amends to include:

- Missing new files: sort/keys.rs, 4 raw-bam bench files
- compare/bams.rs RawRecord migration
- codec_caller.rs cascade simplification
- group/filter/correct/extract/clip/bam_io.rs simplifications
- overlapping.rs raw-only API
- Test suite updates for test_compare_bams, test_group_command,
  test_e2e_regression
- Doc touch-ups in best-practices/performance-tuning

Verified: tree matches backup except for 6 main-only files
(prefetch_reader, os_hints, test_async_reader, template_coordinate,
and two benches) that came from main PRs #258/#261/#265/#270/#282
merged after our branch point.

Part 8 of 8 in the series closing #272. Stacks on #295.
nh13 added a commit that referenced this pull request Apr 20, 2026
… remaining 48-commit work

The final PR in the stacked series closes the full delta against the
48-commit backup. In addition to the original scope (vendored bam_codec
deletion + simulate migration), this amends to include:

- Missing new files: sort/keys.rs, 4 raw-bam bench files
- compare/bams.rs RawRecord migration
- codec_caller.rs cascade simplification
- group/filter/correct/extract/clip/bam_io.rs simplifications
- overlapping.rs raw-only API
- Test suite updates for test_compare_bams, test_group_command,
  test_e2e_regression
- Doc touch-ups in best-practices/performance-tuning

Verified: tree matches backup except for 6 main-only files
(prefetch_reader, os_hints, test_async_reader, template_coordinate,
and two benches) that came from main PRs #258/#261/#265/#270/#282
merged after our branch point.

Part 8 of 8 in the series closing #272. Stacks on #295.
nh13 added a commit that referenced this pull request Apr 21, 2026
… remaining 48-commit work

The final PR in the stacked series closes the full delta against the
48-commit backup. In addition to the original scope (vendored bam_codec
deletion + simulate migration), this amends to include:

- Missing new files: sort/keys.rs, 4 raw-bam bench files
- compare/bams.rs RawRecord migration
- codec_caller.rs cascade simplification
- group/filter/correct/extract/clip/bam_io.rs simplifications
- overlapping.rs raw-only API
- Test suite updates for test_compare_bams, test_group_command,
  test_e2e_regression
- Doc touch-ups in best-practices/performance-tuning

Verified: tree matches backup except for 6 main-only files
(prefetch_reader, os_hints, test_async_reader, template_coordinate,
and two benches) that came from main PRs #258/#261/#265/#270/#282
merged after our branch point.

Part 8 of 8 in the series closing #272. Stacks on #295.
nh13 added a commit that referenced this pull request Apr 21, 2026
… remaining 48-commit work (#296)

The final PR in the stacked series closes the full delta against the
48-commit backup. In addition to the original scope (vendored bam_codec
deletion + simulate migration), this amends to include:

- Missing new files: sort/keys.rs, 4 raw-bam bench files
- compare/bams.rs RawRecord migration
- codec_caller.rs cascade simplification
- group/filter/correct/extract/clip/bam_io.rs simplifications
- overlapping.rs raw-only API
- Test suite updates for test_compare_bams, test_group_command,
  test_e2e_regression
- Doc touch-ups in best-practices/performance-tuning

Verified: tree matches backup except for 6 main-only files
(prefetch_reader, os_hints, test_async_reader, template_coordinate,
and two benches) that came from main PRs #258/#261/#265/#270/#282
merged after our branch point.

Part 8 of 8 in the series closing #272. Stacks on #295.
@nh13 nh13 mentioned this pull request Apr 22, 2026

This branch was previously deployed

1 inactive deployment
github-actions — 01baf28e Deployed Apr 17, 2026 by nh13 via coverage #1174
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Complete the raw-byte BAM API in fgumi-raw-bam

1 participant