Skip to content

Reduce first-waiter overhead in Semaphore permit handoff #400

Open

Description

@tisonkun

On a fresh zero-permit semaphore, registering a pending request and handing it one permit took 232 ms versus 64 ms for Tokio over three million handoffs. The benchmark verifies that the waiter becomes ready and forgets the permit to return the semaphore to zero.

Apple M4 Max, macOS arm64, rustc 1.101.0-nightly. Each cell gives rank, elapsed time relative to Asyncband and the whole-batch median over 10 interleaved runs. Lower is faster. Supplemental measurements

Scenario Fixed rounds Asyncband Tokio async-lock
Hand one permit to a waiting caller 3,000,000 #2, 1.00× (232 ms) #1, 0.28× (64 ms) —
Try and return one available permit 30,000,000 #3, 1.00× (271 ms) #1, 0.67× (181 ms) #2, 0.84× (228 ms)

Object lifetime explains much of the first row on this host. With the same three million handoffs, a fresh semaphore each round took 233 ms for Asyncband and 65 ms for Tokio. Reusing one across rounds gave 86 and 63 ms. Allocation counting found two allocations per fresh Asyncband handoff and zero for Tokio. After warm-up both reused instances had zero allocations per handoff. Asyncband's first waiter goes through the queue lock and arena. Tokio stores its waiter node inside the acquisition future. Tokio's pinned implementation

First contribution

Reproduce both lifetimes with the same zero-permit protocol, then isolate the queue's first allocation. A change should improve first registration and keep the reused case competitive. Check multi-permit ordering, cancellation after a partial or full grant, and absence of missed wakeups. PR #394 addresses acquisition-future size and is related work. PR #394

To run the supplemental peer_checks command below, save and run peer-checks.rb from the linked comment in a disposable checkout of 6102089. The benchmark and library sources match 36ba6f2. Generator and instructions

cargo x bench --bench primitives -- semaphore::acquire::handoff_permit --repeat 10 --raw
cargo x bench --bench peer_checks -- semaphore/ --repeat 10 --raw

Performance tracking issue #396

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions