perf(runtime): reject non-Live slots lock-free in the root-exit sweep
`shutdown_forest_roots` locked every slot's `cold` to discover `actor == None`. The slab is `max_actors` entries (16_384 by default) and is almost entirely vacant at root exit, so the sweep cost one uncontended mutex round-trip per slot: a fixed ~152 µs per run on the 5900X, visible as deep_recursion 1T 289 -> 441 µs and the same +152 on chained_spawn 1T, fan_out_compute 1T and deep_recursion 20T. `general.rs` times `init` and `run` together, so it landed in every smarm bench number while no tokio section paid it. `is_live_for` is a lock-free snapshot of the slot word; a non-Live slot has no actor to shut down, and the ones that survive the check take the lock below as before. The sweep is not weakened: the snapshot can go Live just after we pass it, but that was already true of a spawn landing after the scan finished, and there is no second sweep either way. Suite green under reltest, including upstream's root_exit / shutdown / supervisor_shutdown / root_sweep_trace (the last also under --features smarm-trace, which is what asserts the sweep actually visits its targets).
This commit is contained in:
@@ -2056,6 +2056,22 @@ fn shutdown_forest_roots(inner: &Arc<RuntimeInner>, root: Pid) {
|
||||
if pid == root {
|
||||
continue;
|
||||
}
|
||||
// Lock-free reject first. The slab is `max_actors` entries (16_384 by
|
||||
// default) and is almost entirely vacant at root exit, so locking every
|
||||
// slot's `cold` to discover `actor == None` made this scan cost one
|
||||
// uncontended mutex round-trip per slot — a fixed ~150 µs per run on a
|
||||
// 5900X, and `general.rs` times `init` + `run` together, so it landed
|
||||
// in every smarm bench number. A non-Live slot has no actor to shut
|
||||
// down, and the lock is taken again below for the ones that do.
|
||||
//
|
||||
// This does not weaken the sweep. `is_live_for` is a snapshot, so a
|
||||
// slot can go Live just after we pass it — but that was already true
|
||||
// of a spawn landing after the scan finished, and there is no second
|
||||
// sweep either way (an actor that outlives this scan is its spawner's
|
||||
// business, per the rule below).
|
||||
if !slot.is_live_for(pid) {
|
||||
continue;
|
||||
}
|
||||
// Read the parent under the cold lock (generation-verified); act
|
||||
// outside it — `request_shutdown_inner` sends and may unpark.
|
||||
let parent = {
|
||||
|
||||
Reference in New Issue
Block a user