Conversation
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
Try one checked CAS in
Semaphore::releasewhenpermits > 0, falling back to thewaiterslock when the balance is zero or the CAS fails.Mutexguards use the internalrelease_all_heldpath to skip the probe.This is a draft for discussion and to preserve the experiment. The change improves the measured Linux workloads, but macOS shows regressions in tight two-thread acquire/release loops. I am not proposing to merge it in its current form.
Design Notes
The existing queue protocol drains the balance before linking a waiter and returns permits to the balance only after the queue is empty. The CAS validates that the observed positive balance has not changed before adding permits.
Fast releases can also update a positive balance while the queue lock is held, so the locked path uses a checked CAS there to preserve overflow detection. Balance updates remain read-modify-write operations. Tests cover fast and locked releases, waiter handoff, concurrent acquisition/release, overflow, and release-sequence ordering.
Falling back after one failed CAS does not stop other threads from using the fast paths. Earlier macOS diagnostic runs found substantially more failed acquire and locked-release CAS attempts; restoring locked releases largely recovered baseline performance. Bounded backoff experiments did not preserve the gains across the control workloads and are not included in this diff.
Benchmarks
Historical measurements: baseline
da30f7aversus3768717, Rust 1.96.0. The branch now merges upstream main at87017f9in9c09ca1; these benchmarks have not been rerun after that merge. An out-of-tree probe links the variants into one executable and runs seven randomized, interleaved rounds of one million iterations per worker, with startup barriers. The semaphore has 64 permits and acquires/releases two per iteration; the read-lock loop pollsread(). Each loop drops the guard immediately without added computation.Values are medians across rounds of elapsed wall time divided by iterations per worker, in ns; lower is better. Percentages compare against the baseline on the same machine, not across platforms.
Linux: Hygon C86 7360 (x86-64), 24 physical cores / 48 hardware threads; benchmark workers pinned to up to 8 distinct physical cores. Two threads share an L3; four stay within one NUMA node; eight span two nodes. Memory placement is fixed. Pre/post checks, including SMT siblings, showed at least 97% idle for the main matrix.
macOS: Apple M5, 10 cores (4 performance cores + 6 efficiency cores), with up to 8 benchmark workers and no core pinning. This was a repeat under background load, with CPU activity and swap-ins recorded; it is not an idle-machine validation. These results reproduce the two-thread regression but do not isolate how much background load affects its magnitude.
The open question is whether the fast-path gains can be retained without the macOS tight-contention regression or changes to permit limits and fairness.
Validation
After merging upstream main:
cargo x test(607 passed),cargo x check, andcargo x lint. The merge preserves upstream wake-panic handling and adds a regression test for overflow in the locked release path during unwinding.