Repository navigation
Conversation
This was referenced Nov 3, 2026
Member
Author
|
Release the lock - anyone can pick up this performance improvement. |
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.
Summary
Speed up one-shot wait group completion. Participants share one allocation reference, so cloning and dropping a worker updates only the participant count. The first pending observer registers an inline waker. Additional observers use the existing cancellable waker set.
Extend the fixed-workload comparisons with late waits, nested workers, four scheduled tasks, and four independent observers of the same drain. The drain case requires each observer to be notified and reach Ready. It exercises the completion side of a graceful shutdown.
Design Notes
A participant can finish by dropping its handle or can finish and wait for its peers by consuming the handle. Cloning a
Waitobserves completion without adding work. This distinction letsShutdownGuardkeep the drain pending while clonedShutdownhandles independently await it. A supervisor interested in a single batch can simply give workers handles to drop and await its own.Go also wakes multiple waiters at zero. Its
Waitonly observes, work is counted separately, and a new generation can start after earlier waits return. Asyncband follows the one-shot participant model also used by Crossbeam. Go WaitGroup · Crossbeam WaitGroupParticipants collectively hold one reference through final notification. Each observer owns a separate reference and the last release reclaims the allocation. The inline waker and overflow registrations share a single standard-library write lock. Poll and cancellation recheck the participant count under that lock. The last participant detaches all wakers under the same lock and wakes them after unlocking. This eliminates the unsafe waker cell and the atomic handoff protocol. Unsafe code remains in the allocation ownership implementation.
Benchmarks
Apple M4 Max, Darwin arm64, rustc 1.101.0-nightly (
8006091eb), Cargo bench profile. Each median is elapsed milliseconds for ten equal-work repetitions with rotating adapter order. The revised head is540858b. Base and first draft use the same benchmark code as the revision under review. Slashes denote separate launches. Compare peers within the same launch.complete-waitercomplete-4-workerswait-after-worknested-4-workerstasks-4-workers-4wdrain-4-observersThe four-observer row requires four independent wakeups. It compares native completion futures to
waitgroupplusFutureExt::sharedand to a closed TokioTaskTracker. The scheduled row includes spawning and joining four tasks and should be interpreted separately from the hand-polled workloads.Why the first draft regressed on four observers
The first observer avoided the mutex and arena, but the second observer initialized a boxed registry, a pthread mutex on this Darwin toolchain, and arena storage. A counting allocator observed one allocation at setup and three during overflow registration. The revised registry has one setup allocation and two during overflow registration. The original main implementation made one at setup and two at the first registration.
A separate 64-group batched diagnostic, in forward and reverse process order, placed the largest costs in registration and cleanup. In nanoseconds per group, the first draft spent 3.7–3.8 on the first observer, 55–56 on registering the next three and 34–35 on cleanup. The revised registry spent about 4, 32–36 and 14–16 respectively. The revised notification phase took 24–27 ns against 17–18 ns for the first draft. These phase timings are diagnostic and do not reproduce the allocation locality of the official one-group-per-round benchmark.
In a separate arm64 Linux VM control (rustc 1.95.0), a standalone driver repeated the same four-observer lifecycle and rotated all three Asyncband implementations. The ten-run medians were 159 ms for main, 182.5 ms for the first draft and 164 ms for the revised PR. This closed most of the gap on Linux; the revised implementation remained about 3% above main in that control.
Raw samples
Base
First draft
Revised PR, first launch
Revised PR, second launch
Validation and review
Workspace lint, tests and the benchmark smoke suite passed. On
540858bthe WaitGroup Miri target passed on all eight seeds with strict provenance, symbolic alignment checks and a preemption rate of 0.25. Each seed ran 14 tests. All 11 targets selected bycargo x miripassed locally with explicit--target x86_64-unknown-linux-gnu, strict provenance, symbolic alignment checks and the four CI seeds. The OS-backed Tokio integration case runs in the native suite. The full native macOS Miri workflow passed WaitGroup before encountering unsupportedkqueuein the existing broadcast tests. The new test drops the last observer from inside its wake callback and exercises the participant anchor through notification.Kimi Code independently reviewed the waiter registry, reference ownership, memory ordering, reentrant cancellation/wake and benchmark fairness. It reported no blocking finding on
e01ccff. A registration already detached by completion can still receive a wake after a Ready poll. That legal spurious wake does not justify another lock or a generation counter. A second Kimi review of the final540858bdiff found no blocking issue. It verified the explicit count acquisition on every pointer duplication and the reentrant last-observer test.The full GitHub Actions Linux Miri job passed on
540858bin 5m17s. Miri CI on this revisionReproduction