acdream/docs/research/2026-07-05-mp0-baseline.md
Erik 86d7094451 docs(pipeline): MP0 baseline captured - gate PASSED, alloc-triage amendment
Full-route capture (Holtburg -> dungeon 0x0007 -> town 0xCE94 -> dungeon
-> Holtburg, 4 teleports) plus the supplemental town run. Verdict: the
render-side-CPU split is confirmed (GPU <= ~2.7ms, upd/upl/imgui ~= 0),
steady medians beat the spec assumption (worst town p50 3.6ms), and the
smoothness gap is GC: 1.5-3 MB allocated per frame drives gen2
collections 1-2/s and every town p99/max violation, while dungeon
windows (zero gen1/gen2) are spike-free at ~2000 fps. Teleport hitch
quantified at 211ms worst frame / 75.7MB single-frame allocation.

Gate decision: PROCEED to MP1 unchanged, with one recorded amendment -
a bounded post-MP1 allocation-triage session for churn sites outside
the MP3 rewrite surface. Fort Tethana axiom view still to be
re-measured at the MP2/MP3 gates.

MP0 complete: profiler shipped (7d74c68c..4b44a152) + baseline + gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 19:42:36 +02:00

94 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MP0 baseline — frame-profiler capture, attribution verdict, gate decision
**Date:** 2026-07-05. **Build:** Release, `ACDREAM_FRAME_PROF=1`, vsync off.
**Character:** `+Horan` (`0x5000000B`, testaccount2). **Logs:** `mp0-baseline.log`
(primary run: full route with 4 teleports, ~2 min) + `mp0-baseline-run3.log`
(supplemental: longer town session, same build) — both untracked in the worktree
root; the numbers below are transcribed from them.
**Route (reconstructed from log markers):** login → Holtburg outdoor
(`0xA9B4`) → movement/turning → teleport 1 → **dungeon `0x0007`** (dungeon
collapse streaming path) → walk → teleport 2 → **outdoor town `0xCE94`**
pan/walk → teleport 3 → **dungeon again** → walk → teleport 4 → Holtburg →
close (graceful).
## The numbers (per 5-second `[frame-prof]` window)
| State | cpu_ms p50 | p95 | p99 | max | gpu_ms p50 | alloc/frame p50 | GC gen0/gen1/gen2 per 5 s |
|---|---|---|---|---|---|---|---|
| Login settle (Holtburg) | 2.1 | 10.2 | **52.8** | **123.3** | 0.4 | 1.57 MB | 93 / **50** / **36** |
| Holtburg steady/turning | 1.62.0 | 2.22.6 | 2.83.7 | 1520 | 0.4 | 1.581.60 MB | ~80 / 313 / 35 |
| Dungeon `0x0007` walk | **0.40.5** | 0.50.6 | 0.9 | 1.21.5 | 0.1 | 0.500.63 MB | 119 / **0** / **0** |
| Town `0xCE94` pan/walk | 2.93.6 | 4.05.0 | 7.215.7 | 2637 | 1.21.6 | 2.53.0 MB | ~60 / 522 / 511 |
| Teleport→dungeon window | 2.8 | 3.3 | 14.1 | **211.2** | 1.3 | (max **75.7 MB** in one frame) | 62 / 11 / 10 |
| Teleport→outdoor windows | 1.22.9 | 3.43.8 | 4.57.0 | 33 | 0.21.5 | (max 2031 MB single frame) | ~8093 / 1526 / 5 |
| Holtburg end-of-run moving | 2.62.9 | 3.35.1 | 8.5**23.0** | 20**87** | 2.52.7 | 2.14 MB | ~5058 / 2432 / 78 |
| (run 3) town views | 1.72.4 | 2.73.4 | 7.915.8 | 2939 | 0.42.2 | 1.72.2 MB | ~70109 / 1732 / 611 |
Stage attribution (`upd` / `upl` / `imgui`): **≈ 0.0 ms p50 in every window**
(occasional upd p95 0.11.7 during streaming). GPU never exceeded p95 3.7 ms.
## Attribution verdict
1. **Steady-state medians are far better than the spec §1 assumption.** The
spec assumed ~6 ms / ~165 FPS dense-town CPU. Captured: worst steady town
view is p50 3.33.6 ms (~280300 FPS); Holtburg ~1.62.4 ms (~400600 FPS);
dungeons 0.40.5 ms (~2000 FPS). **Caveat:** the canonical Fort
Tethana/Arwic "dense worst-case axiom view" was NOT in this route — the
§1 numbers came from there. The 300-FPS throughput goal is close to met in
the captured views but must be re-verified at that view before any
"target met" claim.
2. **The frame is CPU-render-side, as assumed.** GPU ≤ ~2.7 ms everywhere;
upd/upl/imgui ≈ 0 → virtually all CPU time is unattributed render-side
submission. The spec's MP3 thesis stands.
3. **The smoothness gap is real, and it is GC.** Every town window violates
the ≤16 ms goal at max (2087 ms) and several at p99 (up to 23 ms), while
dungeon windows — the ONLY windows with **zero gen1/gen2 collections**
are spike-free (max 1.5 ms). Steady-state allocation is **1.53.0 MB per
frame** (≈ 0.61.2 GB/s at these frame rates), driving gen2 collections
roughly 12 per second in towns. The correlation is airtight across all
28 windows: spikes appear exactly where gen1/gen2 counts are non-zero.
4. **The hitch scenario is confirmed and quantified.** Teleport-into-dungeon
produced the worst frame of the session (**211 ms**) with a **75.7 MB**
single-frame allocation (decode + hydrate storm); login settle hit 123 ms
max with 36 gen2 collections in one window. This is exactly the class MP1
(bake — load becomes mmap reads, not managed decode) targets.
## Gate decision (spec §5)
**PROCEED to MP1, with one amendment.** The assumed cost split (render-side
CPU dominant, GPU idle, hitches at load boundaries) is CONFIRMED, so the
phase order stands. The amendment: the capture elevates **steady-state
allocation churn** from "MP4 cleanup" to a first-class smoothness lever —
1.53 MB/frame of per-frame garbage is the direct cause of the town p99/max
violations, and it is NOT load-related (it persists in steady windows).
**Amendment (recorded in the spec):** after MP1 ships, run a bounded
**steady-state allocation triage** (one session: `dotnet-trace` /
allocation-sampling on the live client, identify the top ~5 per-frame churn
sites). Sites *inside* the MP3 rewrite surface (per-frame submission
rebuild — the prime suspect for MB-scale per-frame lists) are left for MP3
to remove structurally; sites *outside* it get targeted fixes immediately.
The full zero-alloc pass remains MP4. This front-loads the biggest
smoothness win without letting "fix allocations" sprawl into an unphased
rewrite.
## Follow-ups noted (not gates)
- Re-measure the Fort Tethana axiom view at the MP2 and MP3 gates (the
degrade port materially changes exactly that view).
- `upd ≈ 0.0` everywhere is suspicious-adjacent but plausible (light sim in
these scenes); if a future capture shows heavy OnUpdate work still reading
0.0, verify the stage scope wasn't bypassed by an early return upstream.
- Dungeon at ~2000 FPS with zero GC pressure is the existence proof that the
engine's frame loop CAN run allocation-free at four-digit FPS — towns are
paying for churn, not for fundamentals.
## Apparatus state
`[frame-prof]` (env `ACDREAM_FRAME_PROF=1`, DebugPanel "Frame profiler"
checkbox) is PERMANENT — it is the measurement instrument for every MP gate.
Implementation: `src/AcDream.App/Diagnostics/` (FrameStatsBuffer /
GpuFrameTimer / FrameProfiler), plan
`docs/superpowers/plans/2026-07-05-mp0-frame-profiler.md`, commits
`7d74c68c`..`4b44a152`.