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>
5.7 KiB
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
- 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.
- 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.
- 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.
- 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.0everywhere 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.