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>
This commit is contained in:
parent
f4e4418273
commit
86d7094451
3 changed files with 107 additions and 2 deletions
94
docs/research/2026-07-05-mp0-baseline.md
Normal file
94
docs/research/2026-07-05-mp0-baseline.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# 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.6–2.0 | 2.2–2.6 | 2.8–3.7 | 15–20 | 0.4 | 1.58–1.60 MB | ~80 / 3–13 / 3–5 |
|
||||
| Dungeon `0x0007` walk | **0.4–0.5** | 0.5–0.6 | 0.9 | 1.2–1.5 | 0.1 | 0.50–0.63 MB | 119 / **0** / **0** |
|
||||
| Town `0xCE94` pan/walk | 2.9–3.6 | 4.0–5.0 | 7.2–15.7 | 26–37 | 1.2–1.6 | 2.5–3.0 MB | ~60 / 5–22 / 5–11 |
|
||||
| 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.2–2.9 | 3.4–3.8 | 4.5–7.0 | 33 | 0.2–1.5 | (max 20–31 MB single frame) | ~80–93 / 15–26 / 5 |
|
||||
| Holtburg end-of-run moving | 2.6–2.9 | 3.3–5.1 | 8.5–**23.0** | 20–**87** | 2.5–2.7 | 2.14 MB | ~50–58 / 24–32 / 7–8 |
|
||||
| (run 3) town views | 1.7–2.4 | 2.7–3.4 | 7.9–15.8 | 29–39 | 0.4–2.2 | 1.7–2.2 MB | ~70–109 / 17–32 / 6–11 |
|
||||
|
||||
Stage attribution (`upd` / `upl` / `imgui`): **≈ 0.0 ms p50 in every window**
|
||||
(occasional upd p95 0.1–1.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.3–3.6 ms (~280–300 FPS); Holtburg ~1.6–2.4 ms (~400–600 FPS);
|
||||
dungeons 0.4–0.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 (20–87 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.5–3.0 MB per
|
||||
frame** (≈ 0.6–1.2 GB/s at these frame rates), driving gen2 collections
|
||||
roughly 1–2 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.5–3 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`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue