roadmap: ship v0.9, promote Process groups to up-next
- Compact v0.9 (Wake-path latency) into Shipped; record the RFC 004 spinning excision as a deviation (preserved on branch rfc-004-spinning). - Drop the v0.7 entry, folding its reference into the Shipped history pointer. - Promote Process groups from Later into the up-next slot v0.9 vacated; Per-switch cost now leads Later/Highest priority.
This commit is contained in:
+21
-59
@@ -2,20 +2,9 @@
|
||||
|
||||
## Shipped (compacted — full cycle plans and deviation records live in git history)
|
||||
|
||||
Cycles before v0.7 (v0.4 actor primitives, v0.5 runtime decomposition &
|
||||
pluggable run queue, v0.6 actor ergonomics): see `git log ROADMAP.md`.
|
||||
|
||||
### v0.7 — select, on epoch-stamped consuming wakes ✅
|
||||
A 24-bit park-epoch packed into the slot word gives every wait an identity:
|
||||
registrations carry `(pid, epoch)`, every successful wake **consumes** the
|
||||
epoch, stale wakes die at one failed CAS. Subsumed the per-primitive wait
|
||||
seqs (channel, mutex, timer); the only wildcard wake left is `request_stop`
|
||||
(terminal). On top: `select`/`select_timeout` — ready-index wait over many
|
||||
receivers, priority order, no cancellation pass. Loom theorems re-proved on
|
||||
the new word. Notable deviations: `retire_wait` for the no-park exit path
|
||||
(plan missed it); the Drop-guard deregistration was superseded by relaxed
|
||||
single-receiver asserts; a closed arm is ready *forever* (documented gotcha).
|
||||
Commits `4913835`…`00128f3`, `a0a93b6`.
|
||||
Cycles before v0.8 (v0.4 actor primitives, v0.5 runtime decomposition &
|
||||
pluggable run queue, v0.6 actor ergonomics, v0.7 select on epoch-stamped
|
||||
consuming wakes): see `git log ROADMAP.md`.
|
||||
|
||||
### v0.8 — gen_server: handle_info / handle_down + io fd hygiene ✅
|
||||
Spent `select` on the server loop: static info arms (`type Info`,
|
||||
@@ -27,6 +16,19 @@ entry permanently poisoned the fd). Deviation: the plain-inbox fast path
|
||||
narrowed; servers holding a `Watcher` select forever.
|
||||
Commits `e5d1b3b`, `24b95c9`, `f6969e5`.
|
||||
|
||||
### v0.9 — Wake-path latency ✅
|
||||
Attacked per-wake latency with the RFC 005 **wake slot**: a per-scheduler,
|
||||
thread-local, capacity-one wake cache checked before the shared queue, pushed
|
||||
only from actor context, slot-then-shared pop with the waker's residual slice
|
||||
as the starvation bound (`slot_hits`/`slot_displacements`). Benched via the
|
||||
slot on/off dimension of `rq_runtime` — ping-pong-pairs (win), yield-storm
|
||||
(regression guard), spawn-storm (neutrality); results annotated in RFC 005.
|
||||
The RFC 004 spinning-workers experiment, originally scoped here, was evaluated
|
||||
and **excised** (not worth the code cost; preserved on branch
|
||||
`rfc-004-spinning`). Also a false-sharing fix (`align(64)` on `SchedulerStats`)
|
||||
and a termination wake for idle siblings.
|
||||
Commits `2708042`, `37d9319`, `eddf3fe`.
|
||||
|
||||
---
|
||||
|
||||
## Decision record — queue topology 🔒 CLOSED (2026-06-10)
|
||||
@@ -48,51 +50,7 @@ Consequences:
|
||||
|
||||
---
|
||||
|
||||
## v0.9 — Wake-path latency
|
||||
|
||||
Goal: attack per-wake latency — the measured ceiling — with the two specified
|
||||
mechanisms, each benched against a clean baseline before the next lands.
|
||||
Order: RFC 005 first (the slot is measured against the just-benched idle
|
||||
policy), then RFC 004 (measured against the slot-accepted baseline), then an
|
||||
interaction pass.
|
||||
|
||||
Full specs: `rfc_005-wake-slot.md`, `rfc_004-tunable-scheduler-idle-policy.md`
|
||||
(artefacts.kalsbeek.dev).
|
||||
|
||||
### 1. Wake slot (RFC 005)
|
||||
Per-scheduler, thread-local, capacity-one wake cache, checked before the
|
||||
shared queue. Runtime-selected via `Config { wake_slot: bool }`, default off
|
||||
until accepted (one binary benches both arms).
|
||||
- **Push policy:** slot-eligible iff the wake originates from actor context
|
||||
(`current_pid().is_some()`). Scheduler-context wakes (timer/IO drain) and
|
||||
spawns always go shared.
|
||||
- **Displacement:** newest wake takes the slot, occupant pushed shared (Go
|
||||
semantics); the branch swap is the fallback if benches look pathological.
|
||||
- **Pop order:** slot, then shared. Slot-popped actors inherit the waker's
|
||||
remaining timeslice — a handoff chain is bounded by one slice, so the
|
||||
shared queue is consulted at least once per slice per scheduler (the
|
||||
starvation bound, zero new counters).
|
||||
- **Invariant care:** the slot push replaces `run_queue.push` at the tail of
|
||||
the `Parked → Queued` CAS; at-most-once-enqueued holds verbatim (pid in
|
||||
slot ⊕ shared queue). Stall blast radius grows by exactly one actor.
|
||||
- Counters: `slot_hits`, `slot_displacements`.
|
||||
|
||||
### 2. Slot shootout
|
||||
Extend `rq_runtime`/`bench_rq.sh` with the slot on/off dimension (cheap —
|
||||
it's a Config knob, not a feature rebuild). Same sweep as the rq shootout.
|
||||
- **ping-pong-pairs** — target metric; expect the win, single- and
|
||||
multi-scheduler.
|
||||
- **yield-storm** — regression guard; yields never touch the slot, any delta
|
||||
is pop-path overhead.
|
||||
- **spawn-storm** — neutrality check; spawns bypass the slot by policy.
|
||||
Acceptance flips the default on and re-baselines for RFC 004.
|
||||
This is done, see results annotated in RFC005.
|
||||
|
||||
---
|
||||
|
||||
## Later
|
||||
### Highest priority
|
||||
#### Process groups: the primitive pubsub & channels should have sat on
|
||||
## Up next — Process groups: the primitive pubsub & channels should have sat on
|
||||
Context: urus is a webserver written on top of smarm to provide a testing target.
|
||||
A named pid→multiset map with monitor-backed removal: `registry.rs` generalised
|
||||
from name↔pid *bimap* to name→*multiset*, the death hook reused verbatim. Local
|
||||
@@ -103,6 +61,10 @@ member), with different netsplit consequences. Urus shipped pubsub/channels pred
|
||||
and want reframing on top of it. Foundational, so early in the post-v0.9 stack.
|
||||
Needs an RFC.
|
||||
|
||||
---
|
||||
|
||||
## Later
|
||||
### Highest priority
|
||||
#### Per-switch cost (context shims, epoch protocol)
|
||||
The shootout's residual: per-wake latency is 0.16–0.18 µs at N=1 and
|
||||
0.8–1.2 µs at N=8+, dominated by the context-switch shims and the epoch
|
||||
|
||||
Reference in New Issue
Block a user