Everything the next agent needs to run the Phase 2 optimisation loop on a machine that can launch the client: - analysis/client-perf/: LEVERS (ranked levers + corrections), BENCH-MATRIX (world, scenes, config IDs, blocks B0-B14 with decision rules), PLAYER-TUNING, SPAWN-TUNING, research briefs, the jar scanner and its output, observed default configs, and proposed-configs/ (build.py generates tiers and bench variants and fails on unknown keys; apply_variant.py applies a variant and merges options.txt). - analysis/client-perf/bench/onion-bench/: bench-world datapack (scene teleports, Create grid, mob pen, sound storm, 120 s teleport tour). - analysis/audit/: the static recipe/dependency audit, including gen_fixes.py, which generates the shipped Paxi datapack and was never tracked. - phase0/: per-machine measurement harness (Steam Deck, 7700K/1060, 6700K/1080 Ti). - .pi/journal.md: running work log; read it first. All of it is packwizignored, so nothing here ships to players.
9.7 KiB
Phase 0 — P0: Steam Deck
Setup and measurement procedure for the lowest-end test machine in the Onion MC client tuning fleet.
Profile
| CPU | AMD Zen 2, 4 cores / 8 threads, 2.4–3.5 GHz |
| GPU | AMD RDNA2 (Van Gogh), 8 CU, integrated |
| RAM | 16 GB LPDDR5, shared with the GPU |
| Display | 1280×800 — LCD is 60 Hz, OLED is 90 Hz |
| OS | SteamOS (Arch-based, read-only rootfs) |
| Binding constraint | GPU compute, memory bandwidth, shared memory pressure |
| What this tier tests | The floor. If the ladder holds here it holds anywhere. |
| Expected DH answer | Off, or the minimum viable preset |
Determine your panel
The LCD panel is 60 Hz. If this is an LCD Deck, targets of 120 and 144 are meaningless on this machine — it can only validate the 30 and 60 rows of the ladder. Record which panel you have; it changes what this machine can prove.
Shared measurement protocol
Applies to every machine in the fleet. Duplicated here so this document stands alone.
- Uncapped, vsync off during measurement. Apply the FPS cap only after tuning. With a cap or vsync active, every configuration "hits" the target and the ladder never fires.
- Metric is p99 frametime and 1% low, not average FPS.
- Discard 10–15 s of warmup per scene — JIT, chunk load, initial GC.
- Settle after any render-distance or DH change. Both trigger rebuilds; measuring immediately measures the rebuild, not the steady state.
- Three runs per configuration, report the median and the spread. A single run of anything is noise.
- One variable per run. If you change two things, you have learned nothing.
- Guardrails: if the FPS limiter is active, the governor moved, or RAM headroom changed materially, the run is invalid — discard rather than interpret.
Step 1 — Preconditions
- Plugged into the charger. Battery vs. AC changes APU power behaviour.
- Switch to Desktop Mode. All measurement happens here, launching Prism from a terminal. Gaming Mode routes the overlay through MangoApp, which cannot log.
- Instance installed on internal storage, not a microSD card. Card I/O affects chunk loading and DH LOD reads.
- Confirm panel refresh rate and record it.
Step 2 — Disable the competing overlay
SteamOS's built-in performance overlay is MangoApp, not MangoHud. It is an IPC bridge and cannot write CSV logs. Running it alongside MangoHud produces two stacked overlays and aborts logging.
- Quick Access Menu (
...) → Performance - Performance Overlay Level → 0
- Framerate Limit → Off (critical — otherwise every config "hits" the cap)
- TDP Limit → Off, or pin it to a fixed value (e.g. 15 W) and never change it between sessions. Whichever you choose, record it and keep it constant.
- Check that no per-game profile is re-enabling any of the above.
- If Decky Loader is installed, disable any MangoHud/benchmark plugin that routes through MangoApp.
Step 3 — CPU governor and thermals
The Deck's governor is normally schedutil. Two options:
- Recommended: leave it as SteamOS sets it, but record it
(
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor) and keep it identical across every session. - Pinning
performancegives more consistent clocks but increases heat on a handheld, which risks thermal throttling — usually a worse trade for repeatability.
Thermal soak: let the Deck play for ~5 minutes before the first measured run. A cold Deck boosts then throttles; the first runs of a session are not representative. This is the single biggest source of bogus deltas on this machine.
Step 4 — Install MangoHud
SteamOS's rootfs is read-only, and anything installed via pacman can be removed by a
SteamOS update. Re-check this before every session.
sudo steamos-readonly disable
sudo pacman -S --needed mangohud
sudo steamos-readonly enable
Then find the actual paths — do not assume them:
pacman -Ql mangohud | grep -E 'mangohud$|libMangoHud'
This tells you the wrapper binary and the shared library path. Note them; you will need them if the wrapper route fails.
Alternative if you don't want to touch the rootfs: MangoHudPy is built for SteamOS/Bazzite and manages MangoHud configs and log uploads. Verify it can write CSV logs before relying on it — some SteamOS MangoHud tooling routes through the MangoApp IPC shim, which explicitly cannot write logs.
Step 5 — MangoHud configuration
Generate the config from the packaged example rather than trusting a transcription:
mkdir -p ~/.config/MangoHud ~/mcbench/logs
cp /usr/share/doc/mangohud/MangoHud.conf ~/.config/MangoHud/MangoHud.conf # verify path with pacman -Ql
Then set these keys in ~/.config/MangoHud/MangoHud.conf:
output_folder=/home/deck/mcbench/logs # required for logging
autostart_log=1 # start logging automatically
log_duration=30 # seconds; match your scene length
fps_limit=0 # uncapped
frametime=1
frame_timing=1
# percentiles: see the packaged example for the exact key/syntax — it defines a
# '+'-separated list of percentiles emitted in the benchmark summary
Confirm the exact percentile key name against the packaged example file. Logging can also
be toggled at runtime (toggle_logging, default Shift_L+F2).
Step 6 — Launcher and JVM
Use Prism Launcher (or ATLauncher) with the pack imported, then launch it from a terminal in Desktop Mode so the environment is under your control.
Java: 21 (Arch jre21-openjdk or Temurin 21). Use the same JVM build across all
three machines where possible — different JVM builds are a confound.
Wrapper command — Prism → Edit Instance → Settings → Custom Commands → Wrapper command. This is the most reliable way to hook the Java process directly:
mangohud
If no overlay appears, or Minecraft fails to start, try:
mangohud --dlsym
JVM arguments (held identical across all three machines; only -Xmx differs):
-Xmx5G
-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200
-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC
-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M
-XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4
-XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90
-XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32
-XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1
On -Xmx5G: the Deck's 16 GB is shared with the GPU, so heap is not free. Start at
5 G, never exceed 6 G, and treat the final value as a Phase 0 output derived from GC
data, not a guess. Omit -XX:+AlwaysPreTouch here — committing the whole heap up front
costs memory you may not have.
Step 7 — Pin the in-game settings
These are controlled variables. Set them once, record them, and do not change them between runs unless the run is specifically testing that setting.
- Graphics: Fancy
- Render distance: 8 (matches the server's
view-distance) - Particles: All
- Clouds: Fancy
- Entity shadows: On
- Biome blend: fixed value, recorded
- Mipmap levels: 4
- GUI scale: fixed number (not Auto)
- Max framerate: Unlimited
- VSync: Off
- FOV, resolution, fullscreen mode: fixed and recorded
Step 8 — Verification run
Prove the harness works before collecting any real data.
- Launch the pack from Prism with the wrapper command set.
- Confirm the MangoHud overlay appears over Minecraft.
- Load the benchmark scene, play 30 s.
- Confirm a CSV file appeared in
~/mcbench/logs. - Open the CSV and confirm it contains a frametime column.
- Run the same configuration three times and check the spread. If the spread is large, nothing downstream is trustworthy — fix that before continuing.
Step 9 — Per-session checklist
- Charger connected
- Desktop Mode
- SteamOS overlay level 0, FPS limit off, TDP as recorded
- Governor matches previous sessions
- MangoHud still installed (SteamOS update may have removed it)
- 5-minute thermal soak completed
- CSV output folder writable
Step 10 — Recording sheet
Log one row per run:
| Field | Example |
|---|---|
| Date / session | 2026-09-28-a |
| Machine | P0-SteamDeck-LCD |
| Config ID | baseline / dh-off / emf-off / … |
| Scene | A-base / B-terrain / C-gui |
| Run # | 1 / 2 / 3 |
| CSV file | Minecraft_2026-09-28_14-22-01.csv |
| p50 / p95 / p99 frametime (ms) | |
| 1% low FPS | |
| Avg FPS | |
| Peak measured frametime (ms) | |
| Notes | e.g. "thermals settled", "DH disabled" |
Machine-specific caveats
- The overlay trap. SteamOS gives you MangoApp, which looks like MangoHud and cannot write logs. Getting CSV requires launching through the MangoHud wrapper, in Desktop Mode, not through Gaming Mode.
- VRAM is not measurable here. The GPU shares system memory, so there is no separate VRAM number to track. Watch total system RAM and swap instead; memory pressure is what you will actually see.
- SteamOS updates remove
pacman-installed packages. Verify MangoHud exists at the start of every session. - 60 Hz panel (LCD) cannot validate 120/144 targets. Document this rather than pretending those rows are tested.
- Smallest thermal envelope of the fleet. The warm-up soak is not optional.
- Per-core performance is much lower than the other two machines despite the identical 4C/8T topology. Do not assume a CPU-side result from P1/P2 transfers here at the same magnitude — only the direction should be expected to match.