# 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`.