Repository navigation
Remove the AVX2 gather extend kernels (x86 stalls); race-safe bench runs - #48
Merged
Merged
Conversation
On x86 the end-to-end extend used an AVX2 kernel for wavefronts of 256+ diagonals that gathered 4 bytes of pattern and text for 8 diagonals at a time. On a Xeon Gold 6150 (Skylake-SP), bench/sweep.py had Rust up to 2.16x slower than C's scalar extend on long or divergent edit/indel/linear alignments while executing ~0.6x the instructions; the EPYC 7713 showed the same pattern. perf on l10k_5 indel score: 88% of the time in extend_end2end_avx2, 65% of that on its two vpgatherdd; 0.49 G stall cycles vs C's 0.013 G, with negligible cache misses, store-buffer stalls and 4K aliasing, so gather latency. Remove extend_end2end_avx2, extend_end2end_max_avx2 (BiWFA) and their lzcnt helper; x86 uses the blockwise 64-bit scalar extend, as ARM does. Output is unchanged. AVX2 compute kernels are unaffected. Part of #31. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Several hosts running bench/sweep.py from one shared checkout could collide on the two things they share: - Datasets: each process now writes its own temporary file and renames it into place (the content is deterministic, so a lost race is harmless). - C builds (build_c.sh): build in a private directory and move it into place only if no finished build exists; a lost race (BSD mv fails, GNU mv nests) keeps the other run's build. A directory without the binary, left by an interrupted older run, is rebuilt. Tested with 3x3 concurrent C builds (all succeed, one clean build, no leftovers) and two concurrent sweeps generating the same datasets (intact, identical to a single generation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 16, 2026
Open
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.
Part of #31. This removes the AVX2 gather-based extend kernels, which made Rust up to 2× slower than C on x86 for long or divergent alignments.
Evidence
bench/sweep.pyonhpcbio(Xeon Gold 6150, Skylake-SP;mainaa091cf) had Rust up to 2.16× slower than generic (scalar) C on long or divergent edit/indel/linear alignments (l10k_5,m1k_20), while executing only about 0.6× the instructions. The EPYC 7713 quick run showed the same pattern (indel 1.22–1.25×). The Apple M2 never takes this path.perfonl10k_5 indel score:extend_end2end_avx2, and 65% of that is on its twovpgatherdd. That kernel gathers 4 bytes of pattern and text for 8 diagonals at a time.Change
extend_end2end_avx2,extend_end2end_max_avx2(the BiWFA variant) and their lzcnt helper. x86 now uses the blockwise 64-bit scalar extend, the same one ARM uses. The AVX2 compute kernels are unaffected, since they don't gather.x86-64-v3build..claude/AVX2_MIGRATION.md, whose original analysis predicted that a gather extend was "unlikely to help".Also: race-safe benchmark runs from a shared checkout
So several cluster nodes can run
bench/sweep.pyfrom one checkout at the same time:build_c.sh): each run builds in a private directory and moves it into place only if no finished build exists. If it loses the race, it keeps the other run's build; BSDmvfails and GNUmvnests, and both cases are handled. A directory left without a binary by an interrupted older run is rebuilt.To confirm
Re-run
bench/sweep.pyonhpcbioandhpcbioamdonce this is merged, or from this branch. Expected:l10k_5andm1k_20edit/indel/linear;🤖 Generated with Claude Code