Skip to content

perf(sort): restore lock-free unpark via ArcSwap instead of Mutex - #396

Merged
nh13 merged 1 commit into
feat-runallfrom
feat-runall-05-restore-lockfree-unpark
Jun 15, 2026
Merged

nh13 merged 1 commit into
feat-runallfrom
feat-runall-05-restore-lockfree-unpark

Conversation

@nh13

@nh13 nh13 commented Jun 15, 2026

Copy link
Copy Markdown
Member

Stacked PR (stack position 05) of the #330 unified-pipeline landing. Targets the long-lived integration branch feat-runall (not main); #395 (streaming-sort API port) is its merged predecessor. One commit.

The streaming-sort port needs a runtime-settable pool main-thread handle (set_main_thread re-targets unpark from the chain-build thread to the framework worker that actually drives the fused sort). The first cut wrapped it in a parking_lot::Mutex<Thread>, which serialized the per-block unpark hot path on a single shared lock every worker contends on — a cache-line bounce that regresses parity with the lock-free baseline on both standalone and streaming sort, worse as threads scale.

Replace it with arc_swap::ArcSwap<Thread>: the 16 unpark sites become wait-free .load().unpark() (no mutual exclusion, matching the bare-Thread baseline's scaling); set_main_thread becomes a lock-free store. Correctness against the re-target race is identical to the Mutex form (neither guards a concurrent live re-target) and rests on the documented one-shot-at-drive-entry ordering + the condition-checked park loop, not mutual exclusion — see the set_main_thread doc.

Audited all 3 set_main_thread call sites (into_slot_setup ×3, each one-shot before the first park; standalone sort needs none — same-thread pool). Adds a unit test that set_main_thread re-targets the handle to the calling thread.


Expected CI (documented): this PR will be red on the 8 rejects-header tests (test_*_rejects_has_bgzf_eof, test_correct_command_rejects_streaming_threaded_integrity, test_duplex_command_*rejects*) — a pre-existing feat-runall-base failure family asserting the #332 "rejects BAM carries input @HD verbatim" contract, exposed once the streaming-sort API made the suite compile (at stack-03/#395). They are fixed cumulatively: 7 go green at the next PR (fix(correct), stack-06), the last (codec) at stack-07. Any CI failure outside that 8-test set is a real regression. This commit itself is a worker_pool.rs-only perf change and introduces no new failures.

@nh13
nh13 had a problem deploying to github-actions June 15, 2026 04:32 — with GitHub Actions Failure
The streaming-sort port needed a runtime-settable pool main-thread handle
(set_main_thread re-targets unpark from the chain-build thread to the framework
worker that actually drives the fused sort). The first cut wrapped it in a
parking_lot::Mutex<Thread>, which serialized the per-block unpark hot path on a
single shared lock every worker contends on — a cache-line bounce that regresses
parity with the lock-free baseline on BOTH standalone and streaming sort, worse
as threads scale.

Replace it with arc_swap::ArcSwap<Thread>: the 16 unpark sites become wait-free
.load().unpark() (no mutual exclusion, matching the bare-Thread baseline's
scaling); set_main_thread becomes a lock-free store. Correctness against the
re-target race is identical to the Mutex form (neither guards a concurrent live
re-target) and rests on the documented one-shot-at-drive-entry ordering + the
condition-checked park loop, not mutual exclusion — see the set_main_thread doc.

Audited all 3 set_main_thread call sites (into_slot_setup ×3, each one-shot
before the first park; standalone sort needs none — same-thread pool). Adds a
unit test that set_main_thread re-targets the handle to the calling thread.
@nh13
nh13 force-pushed the feat-runall-05-restore-lockfree-unpark branch from 990ecfa to e9c7305 Compare June 15, 2026 04:40
@nh13
nh13 had a problem deploying to github-actions June 15, 2026 04:40 — with GitHub Actions Failure
@nh13
nh13 merged commit 537c2b5 into feat-runall Jun 15, 2026
6 of 8 checks passed
@nh13
nh13 deleted the feat-runall-05-restore-lockfree-unpark branch June 15, 2026 05:05
nh13 added a commit that referenced this pull request Jun 18, 2026
The streaming-sort port needed a runtime-settable pool main-thread handle
(set_main_thread re-targets unpark from the chain-build thread to the framework
worker that actually drives the fused sort). The first cut wrapped it in a
parking_lot::Mutex<Thread>, which serialized the per-block unpark hot path on a
single shared lock every worker contends on — a cache-line bounce that regresses
parity with the lock-free baseline on BOTH standalone and streaming sort, worse
as threads scale.

Replace it with arc_swap::ArcSwap<Thread>: the 16 unpark sites become wait-free
.load().unpark() (no mutual exclusion, matching the bare-Thread baseline's
scaling); set_main_thread becomes a lock-free store. Correctness against the
re-target race is identical to the Mutex form (neither guards a concurrent live
re-target) and rests on the documented one-shot-at-drive-entry ordering + the
condition-checked park loop, not mutual exclusion — see the set_main_thread doc.

Audited all 3 set_main_thread call sites (into_slot_setup ×3, each one-shot
before the first park; standalone sort needs none — same-thread pool). Adds a
unit test that set_main_thread re-targets the handle to the calling thread.

This branch had an error being deployed

1 failed deployment
github-actions — e9c73052 Deployed Jun 15, 2026 by nh13 via coverage #1613
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant