bench: split ping_pong_oneshot — spawn_pair_control + ping_pong_steady; refresh baseline (job e982b5b5)

general.rs sections 5/6: spawn_pair_control is ping_pong_oneshot with the
messages removed (2 spawn + 2 join per round); ping_pong_steady is one
persistent pair × 10k roundtrips over unbounded MPSC (smarm::channel vs
tokio::sync::mpsc::unbounded_channel). Box (5900X, 3729fff, rq-mpmc):
oneshot 804/control 633 → 79% spawn+join; steady 142 ns vs tokio 128
(0.90×) at 1T, 1.8 µs/roundtrip at 20T. history.md finding 16.

baseline.json regenerated from the same run (20T labels, 14 benches).
This commit is contained in:
claude-asm-audit
2026-08-21 12:22:46 +00:00
parent 5ddd122711
commit 77938cd31d
2 changed files with 337 additions and 145 deletions
+195 -143
View File
@@ -2,313 +2,365 @@
"chained_spawn": { "chained_spawn": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 1000, "result": 1000,
"median": 466, "median": 449,
"min": 420, "min": 440,
"max": 503 "max": 452
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 1000, "result": 1000,
"median": 2087, "median": 2102,
"min": 1966, "min": 1936,
"max": 2462 "max": 2226
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 1000, "result": 1000,
"median": 108, "median": 109,
"min": 101, "min": 108,
"max": 119 "max": 125
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 1000, "result": 1000,
"median": 185, "median": 186,
"min": 162, "min": 156,
"max": 196 "max": 211
} }
}, },
"yield_many": { "yield_many": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 200000, "result": 200000,
"median": 12513, "median": 10563,
"min": 11098, "min": 10181,
"max": 12846 "max": 10589
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 200000, "result": 200000,
"median": 44080, "median": 43218,
"min": 43502, "min": 42523,
"max": 44754 "max": 43864
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 200000, "result": 200000,
"median": 5378, "median": 5258,
"min": 4781, "min": 5251,
"max": 5612 "max": 5864
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 200000, "result": 200000,
"median": 6096, "median": 5583,
"min": 5424, "min": 5512,
"max": 7701 "max": 6563
} }
}, },
"fan_out_compute": { "fan_out_compute": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 33860, "result": 33860,
"median": 15121, "median": 15030,
"min": 13878, "min": 14584,
"max": 15143 "max": 15039
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 33860, "result": 33860,
"median": 2452, "median": 2362,
"min": 2389, "min": 2274,
"max": 2833 "max": 2426
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 33860, "result": 33860,
"median": 14113, "median": 14040,
"min": 12681, "min": 14037,
"max": 14123 "max": 14042
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 33860, "result": 33860,
"median": 2308, "median": 2386,
"min": 1724, "min": 2342,
"max": 2575 "max": 2418
} }
}, },
"ping_pong_oneshot": { "ping_pong_oneshot": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 1000, "result": 1000,
"median": 839, "median": 805,
"min": 755, "min": 789,
"max": 861 "max": 829
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 1000, "result": 1000,
"median": 7437, "median": 7503,
"min": 7278, "min": 7005,
"max": 8044 "max": 7677
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 1000, "result": 1000,
"median": 416, "median": 410,
"min": 399, "min": 396,
"max": 430 "max": 440
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 1000, "result": 1000,
"median": 8963, "median": 8911,
"min": 8918, "min": 8844,
"max": 10302 "max": 9198
} }
}, },
"spawn_storm_busy": { "spawn_storm_busy": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 10000, "result": 10000,
"median": 109585, "median": 103743,
"min": 103839, "min": 103453,
"max": 116230 "max": 104373
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 10000, "result": 10000,
"median": 15582, "median": 15364,
"min": 15229, "min": 14982,
"max": 17187 "max": 15642
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 10000, "result": 10000,
"median": 1072, "median": 1071,
"min": 979, "min": 1063,
"max": 1106 "max": 1079
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 10000, "result": 10000,
"median": 11858, "median": 12183,
"min": 11074, "min": 11551,
"max": 13463 "max": 12852
} }
}, },
"mpsc_contention": { "mpsc_contention": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 320000, "result": 320000,
"median": 6123, "median": 6711,
"min": 6084, "min": 6703,
"max": 6830 "max": 6722
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 320000, "result": 320000,
"median": 35813, "median": 35331,
"min": 34901, "min": 34287,
"max": 36057 "max": 36335
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 320000, "result": 320000,
"median": 5428, "median": 6207,
"min": 5388, "min": 5495,
"max": 6025 "max": 6278
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 320000, "result": 320000,
"median": 67484, "median": 72132,
"min": 50512, "min": 66649,
"max": 74416 "max": 75892
} }
}, },
"many_timers": { "many_timers": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 10000, "result": 10000,
"median": 123609, "median": 117002,
"min": 114597, "min": 103516,
"max": 124898 "max": 118009
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 10000, "result": 10000,
"median": 54895, "median": 53418,
"min": 53552, "min": 52807,
"max": 56470 "max": 53785
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 10000, "result": 10000,
"median": 12427, "median": 12444,
"min": 12422, "min": 12389,
"max": 12565 "max": 12483
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 10000, "result": 10000,
"median": 14004, "median": 13948,
"min": 13884, "min": 13791,
"max": 14367 "max": 14268
} }
}, },
"multi_thread_scaling": { "multi_thread_scaling": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 33860, "result": 33860,
"median": 15117, "median": 15036,
"min": 15083, "min": 15029,
"max": 15143 "max": 15060
}, },
"smarm 2-thread": { "smarm 2-thread": {
"result": 33860, "result": 33860,
"median": 7988, "median": 7987,
"min": 7911, "min": 7965,
"max": 8031 "max": 8027
}, },
"smarm 4-thread": { "smarm 4-thread": {
"result": 33860, "result": 33860,
"median": 4302, "median": 4299,
"min": 4275, "min": 4269,
"max": 4311 "max": 4309
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 33860, "result": 33860,
"median": 2413, "median": 2381,
"min": 2379, "min": 2321,
"max": 2474 "max": 2409
}, },
"tokio multi 1-thread": { "tokio multi 1-thread": {
"result": 33860, "result": 33860,
"median": 14266, "median": 14300,
"min": 14259, "min": 14213,
"max": 16632 "max": 14386
}, },
"tokio multi 2-thread": { "tokio multi 2-thread": {
"result": 33860, "result": 33860,
"median": 7288, "median": 7356,
"min": 7196, "min": 7308,
"max": 8657 "max": 7408
}, },
"tokio multi 4-thread": { "tokio multi 4-thread": {
"result": 33860, "result": 33860,
"median": 3760, "median": 3725,
"min": 3716, "min": 3714,
"max": 4078 "max": 3728
}, },
"tokio multi 20-thread": { "tokio multi 20-thread": {
"result": 33860, "result": 33860,
"median": 2381, "median": 2402,
"min": 1935, "min": 2383,
"max": 2631 "max": 2421
} }
}, },
"deep_recursion": { "deep_recursion": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 1, "result": 1,
"median": 293, "median": 291,
"min": 286, "min": 288,
"max": 322 "max": 323
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 1, "result": 1,
"median": 729, "median": 673,
"min": 683, "min": 627,
"max": 752 "max": 740
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 1, "result": 1,
"median": 12, "median": 14,
"min": 12, "min": 13,
"max": 13 "max": 17
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 1, "result": 1,
"median": 54, "median": 53,
"min": 50, "min": 50,
"max": 61 "max": 54
} }
}, },
"yield_in_hot_loop": { "yield_in_hot_loop": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 1000000, "result": 1000000,
"median": 40171, "median": 30361,
"min": 38692, "min": 29592,
"max": 42902 "max": 30509
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 1000000, "result": 1000000,
"median": 63828, "median": 69408,
"min": 63683, "min": 67891,
"max": 70517 "max": 70101
} }
}, },
"uncontended_channel": { "uncontended_channel": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 1000000, "result": 1000000,
"median": 12441, "median": 11962,
"min": 12286, "min": 11943,
"max": 13828 "max": 12052
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 1000000, "result": 1000000,
"median": 15035, "median": 14664,
"min": 15014, "min": 14584,
"max": 16722 "max": 14702
} }
}, },
"catch_unwind_panics": { "catch_unwind_panics": {
"smarm 1-thread": { "smarm 1-thread": {
"result": 10000, "result": 10000,
"median": 127342, "median": 121767,
"min": 122307, "min": 120583,
"max": 132850 "max": 122123
}, },
"smarm 20-thread": { "smarm 20-thread": {
"result": 10000, "result": 10000,
"median": 20430, "median": 19950,
"min": 19417, "min": 19260,
"max": 20735 "max": 20565
}, },
"tokio current_thread": { "tokio current_thread": {
"result": 10000, "result": 10000,
"median": 10716, "median": 10184,
"min": 10325, "min": 10037,
"max": 11039 "max": 10660
}, },
"tokio multi-thread": { "tokio multi-thread": {
"result": 10000, "result": 10000,
"median": 2500, "median": 2430,
"min": 2352, "min": 2339,
"max": 2656 "max": 2628
}
},
"ping_pong_steady": {
"smarm 1-thread": {
"result": 10000,
"median": 1427,
"min": 1419,
"max": 1437
},
"smarm 20-thread": {
"result": 10000,
"median": 18485,
"min": 17162,
"max": 18897
},
"tokio current_thread": {
"result": 10000,
"median": 1285,
"min": 1281,
"max": 1287
},
"tokio multi-thread": {
"result": 10000,
"median": 79958,
"min": 77547,
"max": 82155
}
},
"spawn_pair_control": {
"smarm 1-thread": {
"result": 1000,
"median": 632,
"min": 624,
"max": 634
},
"smarm 20-thread": {
"result": 1000,
"median": 5017,
"min": 4707,
"max": 5149
},
"tokio current_thread": {
"result": 1000,
"median": 287,
"min": 277,
"max": 335
},
"tokio multi-thread": {
"result": 1000,
"median": 8621,
"min": 8415,
"max": 8828
} }
} }
} }
+142 -2
View File
@@ -13,7 +13,18 @@
//! completeness. //! completeness.
//! 4. ping_pong_oneshot — N rounds of (spawn pair, send oneshot, await). //! 4. ping_pong_oneshot — N rounds of (spawn pair, send oneshot, await).
//! Closer to a request/response workload than channel //! Closer to a request/response workload than channel
//! ping-pong. //! ping-pong. NOTE: 2 spawns + 2 channel allocs + 2
//! joins per round; the message path is a minority
//! of it. Sections 5 and 6 split it apart.
//! 5. spawn_pair_control — section 4 with the messages removed: same
//! spawn/join shape, actors return immediately.
//! (4 − 5) ≈ per-round message-path cost.
//! 6. ping_pong_steady — ONE persistent pair, N roundtrips over unbounded
//! MPSC channels (smarm::channel vs
//! tokio::sync::mpsc::unbounded_channel — both
//! unbounded, non-blocking send). Steady-state
//! park/unpark cost per roundtrip, no spawn in the
//! loop.
use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -418,6 +429,120 @@ fn bench_pp_tokio_multi() -> (u64, u128) {
(PP_ROUNDS, start.elapsed().as_micros()) (PP_ROUNDS, start.elapsed().as_micros())
} }
// ---------------------------------------------------------------------------
// 5. spawn_pair_control — section 4 minus the messages
// ---------------------------------------------------------------------------
fn bench_ctl_smarm(threads: usize) -> (u64, u128) {
let start = Instant::now();
smarm::runtime::init(bench_cfg(threads)).run(|| {
for _ in 0..PP_ROUNDS {
let hb = smarm::spawn(|| {});
let ha = smarm::spawn(|| {});
ha.join().unwrap();
hb.join().unwrap();
}
});
(PP_ROUNDS, start.elapsed().as_micros())
}
fn bench_ctl_tokio_current() -> (u64, u128) {
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
let start = Instant::now();
let local = tokio::task::LocalSet::new();
local.block_on(&rt, async move {
for _ in 0..PP_ROUNDS {
let hb = tokio::task::spawn_local(async {});
let ha = tokio::task::spawn_local(async {});
let _ = ha.await;
let _ = hb.await;
}
});
(PP_ROUNDS, start.elapsed().as_micros())
}
fn bench_ctl_tokio_multi() -> (u64, u128) {
let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(available_threads())
.build()
.unwrap();
let start = Instant::now();
rt.block_on(async move {
for _ in 0..PP_ROUNDS {
let hb = tokio::spawn(async {});
let ha = tokio::spawn(async {});
let _ = ha.await;
let _ = hb.await;
}
});
(PP_ROUNDS, start.elapsed().as_micros())
}
// ---------------------------------------------------------------------------
// 6. ping_pong_steady — one persistent pair, PP_STEADY roundtrips
// ---------------------------------------------------------------------------
const PP_STEADY: u64 = 10_000;
fn bench_steady_smarm(threads: usize) -> (u64, u128) {
let start = Instant::now();
smarm::runtime::init(bench_cfg(threads)).run(|| {
let (tx_ab, rx_ab) = smarm::channel::<u64>();
let (tx_ba, rx_ba) = smarm::channel::<u64>();
let echo = smarm::spawn(move || {
for _ in 0..PP_STEADY {
let v = rx_ab.recv().unwrap();
tx_ba.send(v + 1).unwrap();
}
});
for i in 0..PP_STEADY {
tx_ab.send(i).unwrap();
let v = rx_ba.recv().unwrap();
assert_eq!(v, i + 1);
}
echo.join().unwrap();
});
(PP_STEADY, start.elapsed().as_micros())
}
async fn steady_tokio_body() {
let (tx_ab, mut rx_ab) = tokio::sync::mpsc::unbounded_channel::<u64>();
let (tx_ba, mut rx_ba) = tokio::sync::mpsc::unbounded_channel::<u64>();
let echo = tokio::spawn(async move {
for _ in 0..PP_STEADY {
let v = rx_ab.recv().await.unwrap();
tx_ba.send(v + 1).unwrap();
}
});
for i in 0..PP_STEADY {
tx_ab.send(i).unwrap();
let v = rx_ba.recv().await.unwrap();
assert_eq!(v, i + 1);
}
echo.await.unwrap();
}
fn bench_steady_tokio_current() -> (u64, u128) {
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
let start = Instant::now();
rt.block_on(steady_tokio_body());
(PP_STEADY, start.elapsed().as_micros())
}
fn bench_steady_tokio_multi() -> (u64, u128) {
let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(available_threads())
.build()
.unwrap();
let start = Instant::now();
rt.block_on(steady_tokio_body());
(PP_STEADY, start.elapsed().as_micros())
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// main // main
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -453,7 +578,8 @@ fn main() {
); );
println!( println!(
"CHAIN_DEPTH={CHAIN_DEPTH}, YIELD_TASKS={YIELD_TASKS}×{YIELD_ROUNDS}, \ "CHAIN_DEPTH={CHAIN_DEPTH}, YIELD_TASKS={YIELD_TASKS}×{YIELD_ROUNDS}, \
PRIME_N={PRIME_N}/{PRIME_WORKERS} workers, PP_ROUNDS={PP_ROUNDS}" PRIME_N={PRIME_N}/{PRIME_WORKERS} workers, PP_ROUNDS={PP_ROUNDS}, \
PP_STEADY={PP_STEADY}"
); );
// ---- 1. chained_spawn ---- // ---- 1. chained_spawn ----
@@ -491,4 +617,18 @@ fn main() {
run_n(&format!("smarm {n}-thread"), ITERS, || bench_pp_smarm(n)); run_n(&format!("smarm {n}-thread"), ITERS, || bench_pp_smarm(n));
run_n("tokio current_thread", ITERS, bench_pp_tokio_current); run_n("tokio current_thread", ITERS, bench_pp_tokio_current);
run_n("tokio multi-thread", ITERS, bench_pp_tokio_multi); run_n("tokio multi-thread", ITERS, bench_pp_tokio_multi);
// ---- 5. spawn_pair_control ----
print_header(&format!("spawn_pair_control: {PP_ROUNDS} rounds, no messages"));
run_n("smarm 1-thread", ITERS, || bench_ctl_smarm(1));
run_n(&format!("smarm {n}-thread"), ITERS, || bench_ctl_smarm(n));
run_n("tokio current_thread", ITERS, bench_ctl_tokio_current);
run_n("tokio multi-thread", ITERS, bench_ctl_tokio_multi);
// ---- 6. ping_pong_steady ----
print_header(&format!("ping_pong_steady: 1 pair × {PP_STEADY} roundtrips"));
run_n("smarm 1-thread", ITERS, || bench_steady_smarm(1));
run_n(&format!("smarm {n}-thread"), ITERS, || bench_steady_smarm(n));
run_n("tokio current_thread", ITERS, bench_steady_tokio_current);
run_n("tokio multi-thread", ITERS, bench_steady_tokio_multi);
} }