diff --git a/docs/JOURNAL.md b/docs/JOURNAL.md index f8848f7..c9bcb88 100644 --- a/docs/JOURNAL.md +++ b/docs/JOURNAL.md @@ -7728,3 +7728,98 @@ arm-close pattern-binders don't dec what they shouldn't; it does not start dec'ing what they should. Net effect on Implicit fixtures: same correctness as `--alloc=gc` (no regression), allocate-path tax only (matches the 18f bench). + +## 2026-05-08 — Iter 18f.2: tail-latency bench, Decision 10 supported on the latency axis + +`ailang-bencher` ran the tail-latency bench that the 18f +throughput bench couldn't speak to. New harness: +`bench/latency_harness.py` — PTY-line-buffered stdout + +`monotonic_ns` per line + inter-arrival distribution. Paired +fixtures: `bench_latency_{implicit,explicit}.ailx`. + +Hypothesis: under sustained alloc pressure with a large +persistent live working set (depth-19 tree, ~16 MB), Boehm has +a long STW tail (p99 ≫ median); explicit-mode RC has p99 within +a small constant factor of median. + +### Numbers (5 runs, AMD 5900X) + +``` +arm | wall(s) | RSS(MB) | median | p99 | p99.9 | max | p99/med +implicit-mode @ Boehm GC | 0.238 | 66 | 96.2 | 7131 | 7987 | 7989 | 74.1× +explicit-mode @ RC | 0.348 | 511 | 280.3 | 453 | 521 | 526 | 1.62× +implicit-mode @ RC (control) | 0.340 | 511 | 278.5 | 450 | 456 | 492 | 1.61× +``` + +Units µs unless stated. + +### Latency-axis verdict: SUPPORTED + +Boehm's max (~7.99 ms) is **83× its median**. RC's max is +**1.85× median**. Boehm's STW pauses are real and ~7 ms wide. +RC has no comparable tail. The signal sits two orders of +magnitude above the harness noise floor (~27 µs printf+pipe +roundtrip), so it's not an artefact. + +This is the first piece of evidence for Decision 10's +real-time claim. Boehm-retirement is *not* unblocked yet — see +the new finding below — but the latency axis, which 18f +admitted it didn't measure, now has signal. + +### Surprise finding: explicit-mode RC leaks at the same rate as implicit-mode RC + +Both RC arms peak at 511 MB RSS. Implicit-mode RC leaking is +expected (18c.3 documented debt). Explicit-mode RC leaking the +same amount is **not** what Decision 10 + the 18-arc promised. +The mode annotations + `(reuse-as)` + `(drop-iterative)` are +all present in `bench_latency_explicit.ailx`'s hot path +(`sum_list_acc`, `cons_n_acc`), and they should drive prompt +deallocation of each per-op IntList. + +Bencher's diagnosis: the hot path is tail-recursive +(`tail-app sum_list_acc t ...`); the pattern-binder `t` is +*consumed* into the tail-call, so its `consume_count > 0` at +arm-close, so 18d.4 Iter A skips. The outer LCons cell +(scrutinee `xs`) has all its pointer fields moved out (`h` is +Int, `t` was moved into the tail-call), so the outer cell is a +husk — but no drop site emits the shallow `ailang_rc_dec` for +it. moved_slots correctly records the fields are gone; nothing +wires "all fields moved → outer cell can shallow-dec". + +This is a genuine 18d.4 implementation gap, not a bug in the +existing emission seams. Iter A and Iter B are correct as +specified — they handle the *binder*-level drop. What's +missing is the *outer-cell* shallow-dec when the moved-from +cell becomes a husk inside a tail-recursive arm. + +### What this implies for the retirement question + +The 18f throughput bench failed its 1.3× target. This bench +shows that target was the wrong axis: on the *correct* axis +(tail latency), RC wins decisively. But the leak finding means +"explicit-mode RC works as designed" is not yet established. +Two open questions, both implementer territory: + +1. **Outer-cell shallow-dec for moved-from scrutinees.** The + immediate fix the bencher's finding points to. Should + close the leak path on the canonical tail-recursive + list/tree fixtures. +2. **Re-bench after the fix.** Confirm RSS drops to live-set + + small constant on the explicit arm. Median latency may + tick down (less alloc pressure → fewer libc-malloc calls). + Tail latency on the explicit arm should tighten further. + +After both land, the retirement decision (Path A vs Path B +from 18f's entry) gets a real evidence base. + +### What this iter (18f.2) ships + +- `bench/latency_harness.py` (committed in `ac70011`). +- `examples/bench_latency_{implicit,explicit}.{ailx,ail.json}`. +- This entry. No DESIGN.md change yet — the leak is an impl + gap, not a Decision 10 revision. +- A new task (`#82` outer-cell shallow-dec) is queued. + +The 18f throughput entry's "Path A vs Path B" framing remains +open and is now joined by the outer-cell-shallow-dec finding; +both feed the eventual retirement decision.