From a3a932092af1225d32e038f37f91241da3fd7d0a Mon Sep 17 00:00:00 2001 From: Hiroshi Shinaoka Date: Thu, 29 Oct 2026 22:27:42 +0900 Subject: [PATCH 01/13] benches: wait scenarios (short sections, gaps, pool held vs fresh, width, foreign load) with Rayon and libgomp references Co-Authored-By: Claude Opus 5.5 --- Cargo.toml | 5 + README.md | 36 +++ benches/omp/wait_omp.c | 113 +++++++ benches/wait_scenarios.rs | 497 +++++++++++++++++++++++++++++ docs/design/waiting-data/README.md | 6 + scripts/bench-waits.sh | 52 +++ 6 files changed, 709 insertions(+) create mode 100644 benches/omp/wait_omp.c create mode 100644 benches/wait_scenarios.rs create mode 100644 docs/design/waiting-data/README.md create mode 100755 scripts/bench-waits.sh diff --git a/Cargo.toml b/Cargo.toml index 43299cc..400aecc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,3 +83,8 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(loom)'] } [[bench]] name = "cost_lookup" harness = false + +[[bench]] +name = "wait_scenarios" +harness = false +required-features = ["parallel"] diff --git a/README.md b/README.md index efd0948..2b936d1 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,42 @@ Consumers assert `ledger::max_live(root) <= budget` in their own tests, and keep a test binary that runs serial and pooled work and then checks that `rayon::ThreadPoolBuilder::new().build_global()` still succeeds. +## Wait benchmarks + +`benches/wait_scenarios.rs` measures how team threads wait, the way callers use them; the design +is in [`docs/design/waiting.md`](docs/design/waiting.md). A change to the waits is judged by running +it on the base and on the head of the change, on a quiet host and on a many-core shared host. + +| scenario | a call is | reports | +| --- | --- | --- | +| `sections` | 200 sections of 5, 20 or 50 µs, team held | per call, and the overhead over `sections * work` | +| `gaps` | 10 sections of 5 µs, the caller sleeps 0 / 100 µs / 1 ms / 10 ms between calls | the first section (wake latency) and the call | +| `acquire` | 50 sections of 20 µs: the team held (a token per call), the pool held (members acquired per call), a new pool per call | per call; for a new pool also the total from build to drop | +| `nested` | 100 splits of the team into pairs, each pair one 20 µs section | per call | + +Each scenario runs at width = all CPUs of the affinity set and at three quarters of them, on +threadteam and on a Rayon `scope`; `benches/omp/wait_omp.c` runs `sections` and `gaps` on libgomp +(one `omp parallel` region per section, runtime defaults). `--load K:P` adds `K` child processes, +each busy `P` % of every 10 ms, for the whole run: the stand-in for another user's processes. + +```sh +# one checkout, both passes (quiet, then 8 processes at 10 %), rows appended to +# docs/design/waiting-data/.csv +scripts/bench-waits.sh