Files
smarm/benches/baseline.json
T
smarm 7746dca69b fix(runtime): handle timer firing while actor is still Runnable in sleep()
While running benchmarks, a hang surfaced in timer-only workloads — actors
sleeping with no IO in flight. Tracing it down, the race lives in sleep():
between the call to `timers.insert_sleep` and the subsequent `park_current`
yield, the actor is still in State::Runnable. If the timer fires in that
window, the old code's `if matches!(slot.state, State::Parked)` guard silently
drops the wakeup. The actor then parks normally and never gets re-queued —
it sleeps forever.

The fix mirrors what scheduler::unpark() and the IO FdReady path already do:
when the timer fires and the slot is still Runnable, set `pending_unpark`
instead of re-queuing immediately. The upcoming Park yield sees the flag and
re-queues the actor rather than suspending it, closing the race without any
new synchronisation.

Adds a regression test: 100 actors doing pure timer sleeps across ≥2
scheduler threads. The test asserts both correctness (all actors complete)
and timeliness (wall time < 2×sleep duration), which is enough signal to
catch a stuck actor even on a single-core CI runner.
2026-05-26 21:58:14 +02:00

314 lines
5.8 KiB
JSON

{
"chained_spawn": {
"smarm 1-thread": {
"result": 1000,
"median": 266,
"min": 242,
"max": 351
},
"smarm 24-thread": {
"result": 1000,
"median": 742,
"min": 696,
"max": 860
},
"tokio current_thread": {
"result": 1000,
"median": 62,
"min": 61,
"max": 68
},
"tokio multi-thread": {
"result": 1000,
"median": 190,
"min": 169,
"max": 207
}
},
"yield_many": {
"smarm 1-thread": {
"result": 200000,
"median": 19071,
"min": 18776,
"max": 19396
},
"smarm 24-thread": {
"result": 200000,
"median": 172454,
"min": 166246,
"max": 174230
},
"tokio current_thread": {
"result": 200000,
"median": 4737,
"min": 4644,
"max": 5065
},
"tokio multi-thread": {
"result": 200000,
"median": 8738,
"min": 7852,
"max": 9770
}
},
"fan_out_compute": {
"smarm 1-thread": {
"result": 33860,
"median": 13234,
"min": 13196,
"max": 13390
},
"smarm 24-thread": {
"result": 33860,
"median": 2244,
"min": 2162,
"max": 2380
},
"tokio current_thread": {
"result": 33860,
"median": 14049,
"min": 14035,
"max": 14300
},
"tokio multi-thread": {
"result": 33860,
"median": 1474,
"min": 1285,
"max": 1823
}
},
"ping_pong_oneshot": {
"smarm 1-thread": {
"result": 1000,
"median": 751,
"min": 727,
"max": 913
},
"smarm 24-thread": {
"result": 1000,
"median": 1308,
"min": 1227,
"max": 1396
},
"tokio current_thread": {
"result": 1000,
"median": 407,
"min": 400,
"max": 444
},
"tokio multi-thread": {
"result": 1000,
"median": 10869,
"min": 8683,
"max": 11688
}
},
"spawn_storm_busy": {
"smarm 1-thread": {
"result": 10000,
"median": 112045,
"min": 99936,
"max": 117329
},
"smarm 24-thread": {
"result": 10000,
"median": 137105,
"min": 130852,
"max": 147707
},
"tokio current_thread": {
"result": 10000,
"median": 1128,
"min": 1123,
"max": 1435
},
"tokio multi-thread": {
"result": 10000,
"median": 19674,
"min": 16013,
"max": 27234
}
},
"mpsc_contention": {
"smarm 1-thread": {
"result": 320000,
"median": 3667,
"min": 3608,
"max": 4126
},
"smarm 24-thread": {
"result": 320000,
"median": 45681,
"min": 31908,
"max": 51287
},
"tokio current_thread": {
"result": 320000,
"median": 6228,
"min": 6210,
"max": 6514
},
"tokio multi-thread": {
"result": 320000,
"median": 66173,
"min": 42208,
"max": 83255
}
},
"many_timers": {
"smarm 1-thread": {
"result": 10000,
"median": 119988,
"min": 107308,
"max": 123557
},
"smarm 24-thread": {
"result": 10000,
"median": 218842,
"min": 182009,
"max": 256988
},
"tokio current_thread": {
"result": 10000,
"median": 12432,
"min": 12308,
"max": 13468
},
"tokio multi-thread": {
"result": 10000,
"median": 16311,
"min": 15026,
"max": 16897
}
},
"multi_thread_scaling": {
"smarm 1-thread": {
"result": 33860,
"median": 14908,
"min": 14857,
"max": 15218
},
"smarm 2-thread": {
"result": 33860,
"median": 7834,
"min": 7717,
"max": 8033
},
"smarm 4-thread": {
"result": 33860,
"median": 4393,
"min": 4326,
"max": 4435
},
"smarm 24-thread": {
"result": 33860,
"median": 2173,
"min": 2068,
"max": 2405
},
"tokio multi 1-thread": {
"result": 33860,
"median": 14432,
"min": 14219,
"max": 14763
},
"tokio multi 2-thread": {
"result": 33860,
"median": 7333,
"min": 7222,
"max": 7477
},
"tokio multi 4-thread": {
"result": 33860,
"median": 3741,
"min": 3681,
"max": 3876
},
"tokio multi 24-thread": {
"result": 33860,
"median": 1513,
"min": 1375,
"max": 1979
}
},
"deep_recursion": {
"smarm 1-thread": {
"result": 1,
"median": 102,
"min": 96,
"max": 123
},
"smarm 24-thread": {
"result": 1,
"median": 597,
"min": 576,
"max": 682
},
"tokio current_thread": {
"result": 1,
"median": 13,
"min": 11,
"max": 35
},
"tokio multi-thread": {
"result": 1,
"median": 56,
"min": 46,
"max": 65
}
},
"yield_in_hot_loop": {
"smarm 1-thread": {
"result": 1000000,
"median": 80680,
"min": 80308,
"max": 81845
},
"tokio current_thread": {
"result": 1000000,
"median": 72606,
"min": 72154,
"max": 77206
}
},
"uncontended_channel": {
"smarm 1-thread": {
"result": 1000000,
"median": 9257,
"min": 9223,
"max": 12049
},
"tokio current_thread": {
"result": 1000000,
"median": 16925,
"min": 16848,
"max": 17019
}
},
"catch_unwind_panics": {
"smarm 1-thread": {
"result": 10000,
"median": 116821,
"min": 111345,
"max": 128261
},
"smarm 24-thread": {
"result": 10000,
"median": 117487,
"min": 107011,
"max": 129307
},
"tokio current_thread": {
"result": 10000,
"median": 10425,
"min": 10141,
"max": 10604
},
"tokio multi-thread": {
"result": 10000,
"median": 6418,
"min": 3715,
"max": 7144
}
}
}