docs: client-perf analysis, bench harness and work journal

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.
This commit is contained in:
logan committed 2026-10-14 18:15:32 -04:00
1 parent d80f85b3f6
commit 611a1a5952
102 files changed
+25853

No files matched your search

+249
View File
@@ -0,0 +1,249 @@
# 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.
1. **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.
2. **Metric is p99 frametime and 1% low, not average FPS.**
3. **Discard 10–15 s of warmup** per scene — JIT, chunk load, initial GC.
4. **Settle after any render-distance or DH change.** Both trigger rebuilds; measuring
immediately measures the rebuild, not the steady state.
5. **Three runs per configuration, report the median and the spread.** A single run of
anything is noise.
6. **One variable per run.** If you change two things, you have learned nothing.
7. 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 `performance` gives 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.
```bash
sudo steamos-readonly disable
sudo pacman -S --needed mangohud
sudo steamos-readonly enable
```
Then find the actual paths — **do not assume them**:
```bash
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:
```bash
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`:
```ini
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.
+243
View File
@@ -0,0 +1,243 @@
# Phase 0 — P1: i7-7700K / GTX 1060 6 GB (Windows)
Setup and measurement procedure for the VRAM-bound machine in the Onion MC client tuning
fleet.
---
## Profile
| | |
| --- | --- |
| CPU | Intel i7-7700K, 4 cores / 8 threads, 4.2 GHz base (Kaby Lake) |
| GPU | NVIDIA GTX 1060, **6 GB VRAM** (Pascal, GP106) |
| RAM | 32 GB — **not a constraint on this machine** |
| OS | **Windows** (the fleet's only Windows box) |
| **Binding constraint** | **VRAM** |
| **What this tier tests** | GPU/VRAM ladder steps with CPU and RAM held non-binding |
| **Expected DH answer** | **On, with quality/distance reduced — VRAM is the wall** |
### Why this machine matters
- **32 GB of RAM removes RAM/GC as a confound**, so this machine isolates pure GPU and
VRAM effects. That is where DH's quality preset and CTM/texture fidelity live.
- **Its CPU is the same class as P2** (both 4C/8T ~4.2 GHz). Comparing this machine against
P2 therefore isolates the GPU/VRAM axis while holding CPU-side mod cost roughly constant.
That pairing is the fleet's built-in control — see the taxonomy self-check at the end.
- **It is the only Windows machine**, so the OS axis is confounded with the GPU axis here.
A result that differs from P2 could be the GPU or the driver stack, and this rig cannot
separate them. Record it as a known limitation.
---
## Shared measurement protocol
Applies to every machine in the fleet. Duplicated here so this document stands alone.
1. **Uncapped, vsync off** during measurement. Apply the FPS cap only *after* tuning.
2. **Metric is p99 frametime and 1% low, not average FPS.**
3. **Discard 10–15 s of warmup** per scene — JIT, chunk load, initial GC.
4. **Settle after any render-distance or DH change.**
5. **Three runs per configuration, report median and spread.**
6. **One variable per run.**
7. Guardrails: FPS limiter active, power plan changed, or GPU throttling → invalid run.
---
## Step 1 — Windows power and background load
```powershell
powercfg /list
powercfg /setactive SCHEME_MIN # High performance
```
- [ ] Power plan set to **High performance** (or Ultimate Performance) and recorded.
- [ ] No pending Windows Update or reboot.
- [ ] **Xbox Game Bar off:** Settings → Gaming → Xbox Game Bar → Off.
- [ ] **Game DVR / background recording off:** Settings → Gaming → Captures →
*Record in the background while I'm playing* → Off. This is a real frametime cost.
- [ ] Close browsers, Discord, OneDrive, and any streaming/recording software.
- [ ] **Exclude the instance folder from Windows Defender real-time scanning** to remove
I/O spikes during chunk loading. Record that you did it.
## Step 2 — GPU settings
**NVIDIA Control Panel → Manage 3D settings → Program Settings → (Prism's `javaw.exe`):**
- [ ] Power management mode → **Prefer maximum performance**
- [ ] Vertical sync → **Off**
- [ ] Low Latency Mode → fixed value, recorded (it changes frame pacing — don't vary it)
- [ ] **Threaded Optimization** → fixed value, recorded (it affects OpenGL apps directly)
- [ ] Texture filtering quality → fixed value, recorded
**Hardware-Accelerated GPU Scheduling (HAGS):** Settings → System → Display → Graphics →
*Change default graphics settings*. Record On/Off and **keep it constant**. HAGS changes
frame pacing and will show up in your p99 numbers.
**Fullscreen:** run Minecraft in the **same display mode every session** (fullscreen at
native resolution, or borderless — pick one). Also disable *Fullscreen optimizations* for
`javaw.exe` (right-click → Properties → Compatibility) so Windows doesn't add compositor
work. Record the choice.
## Step 3 — Confirm GPU state
`nvidia-smi` ships with the NVIDIA driver on Windows too. **Use the identical command as
the Linux machine** so both NVIDIA rigs produce the same CSV schema:
```powershell
& "$env:SystemRoot\System32\nvidia-smi.exe" -q -d PERFORMANCE # check for throttle reasons
New-Item -ItemType Directory -Force ~\mcbench\logs | Out-Null
& "$env:SystemRoot\System32\nvidia-smi.exe" `
--query-gpu=timestamp,memory.used,clocks.sm,clocks.mem,power.draw,temperature.gpu,utilization.gpu `
--format=csv -l 1 > ~\mcbench\logs\gpu-$(Get-Date -f yyyy-MM-dd-HHmmss).csv
```
- [ ] No `SW Power Cap` or `HW Slowdown` in the throttle reasons.
- [ ] `memory.used` logging running. **On a 6 GB card this is your headline metric** —
peak VRAM tells you when DH, CTM and texture fidelity have crossed the line.
## Step 4 — Measurement tooling: PresentMon
MangoHud does not exist on Windows. Use **PresentMon** (open source, ETW-based, and it
covers OpenGL as well as DX/Vulkan).
**Option A — the Frame Time Analysis package** (simplest; download from
<https://boringboredom.github.io/Frame-Time-Analysis/>). It ships a `Run.bat`:
```bat
pushd %~dp0
cd captures
..\presentmon.exe --multi_csv --no_console_stats --hotkey "F10"
```
Run it **as Administrator** (ETW capture requires elevation), then press **F10** to
start/stop each capture. `--multi_csv` writes a new CSV per capture cycle into `captures/`.
**Option B — target the Minecraft process explicitly** so only MC is captured:
```powershell
presentmon.exe --process_name javaw.exe --output_file ~\mcbench\logs\pm.csv --timed 30
```
- [ ] Confirm the process name. Prism launches Minecraft as **`javaw.exe`**; verify in Task
Manager rather than assuming.
- [ ] PresentMon emits **two CSVs per capture**: the raw per-frame data and a **stats
summary that already contains average / min / max / percentile FPS**. Use the summary
for a quick read and the raw file for the real analysis.
- [ ] Verify a capture produces a CSV with a frametime column before collecting real data.
## Step 5 — Analysis: one tool for the whole fleet
Use **Frame Time Analysis** (<https://boringboredom.github.io/Frame-Time-Analysis/>). It
reads CSV from **PresentMon, CapFrameX, OCAT, MangoHud** and FrameView, all in the browser,
with no upload to a third party.
- [ ] Percentiles, **lows (1% / 0.1%)**, box plots, bar charts and summary tables.
- [ ] **Merge multiple CSV files** — this is what lets you put the three runs of one
configuration, and the MangoHud CSVs from the Linux machines, side by side on one
chart.
- [ ] Screenshot export for the record.
This tool is the reason the fleet does not need a custom analyzer: raw capture stays
platform-native (MangoHud on Linux, PresentMon on Windows) and analysis is unified.
## Step 6 — Launcher and JVM
Use **Prism Launcher** and launch from a shell so the environment is under your control.
**Java:** 21 — the **same JVM build as the Linux machines** (Temurin 21 is a good choice for
all three). A different JVM build is a confound.
**JVM arguments** (identical across the fleet except `-Xmx`):
```
-Xmx8G
-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
```
32 GB means heap is not a variable here. Keep `-Xmx8G` fixed and spend your attention on
VRAM.
## Step 7 — Pin the in-game settings
Controlled variables — set once, record, do not change between runs unless the run is
testing that setting.
- Graphics: Fancy
- Render distance: 8
- Particles: All
- Clouds: Fancy
- Entity shadows: On
- Biome blend: fixed, recorded
- Mipmap levels: 4
- GUI scale: fixed number
- **Max framerate: Unlimited**
- **VSync: Off** (also off in the NVIDIA panel — check both)
- FOV, resolution, fullscreen mode: fixed and recorded
## Step 8 — Verification run
- [ ] PresentMon capture produces a raw CSV **and** a stats summary CSV.
- [ ] `nvidia-smi` VRAM logging is producing a CSV.
- [ ] MangoHud is not expected here — confirm you are actually capturing through PresentMon.
- [ ] Run the same configuration three times and record the spread. Establish this before
interpreting anything.
- [ ] Confirm peak VRAM is being recorded — it is the whole point of this machine.
## Step 9 — Per-session checklist
- [ ] Power plan = High performance
- [ ] Game Bar and background recording off
- [ ] Defender exclusion in place
- [ ] NVIDIA power mode = prefer max performance; vsync off; HAGS and Threaded Optimization
unchanged since last session
- [ ] `nvidia-smi` throttle check clean
- [ ] VRAM logging started
- [ ] PresentMon running as Administrator
- [ ] Display mode and resolution unchanged
- [ ] No pending Windows Update
## Step 10 — Recording sheet
| Field | Example |
| --- | --- |
| Date / session | 2026-09-28-a |
| Machine | P1-7700K-1060 |
| Config ID | baseline / dh-low / ctm-off / emf-off / … |
| Scene | A-base / B-terrain / C-gui |
| Run # | 1 / 2 / 3 |
| CSV file (raw + summary) | |
| p50 / p95 / p99 frametime (ms) | |
| 1% low FPS | |
| Avg FPS | |
| **VRAM peak (MB)** | the headline number for this rig |
| Throttle flag | none / SW Power Cap / HW Slowdown |
| Notes | |
---
## Machine-specific caveats
- **VRAM is the binding constraint, so watch for the cliff, not the slope.** On a 6 GB card
the failure mode is a sharp p99 regression once DH + CTM + texture fidelity exceed
capacity — not a smooth FPS decline. Record peak VRAM alongside every result.
- **Two vsync switches exist** (in-game and NVIDIA panel). Verify both are off, every
session. A single missed vsync makes every configuration look like it hits the target.
- **Beware dynamic clocking.** Verify no throttle reasons before and after a block of runs.
- **This is the only Windows machine, and it is also the weakest GPU** — the OS axis is
confounded with the GPU axis. A divergence from P2 cannot be attributed to the OS.
- **32 GB makes this the fleet's clean tier for GPU-only effects.** If a knob you classified
as GPU/VRAM shows a large delta here and almost nothing on P2, the taxonomy is confirmed.
If a knob you classified as CPU-render diverges between this machine and P2 *in direction*,
the classification is wrong — both share the same CPU class, so CPU-side effects should
track closely.
- **Windows measurement is ETW-based** (PresentMon) while Linux is MangoHud-based. The two
do not measure identically, and the fleet has no same-hardware cross-OS pair, so
**absolute numbers are not cross-comparable between OSes — only within-OS comparisons
are.** Derive ladder orderings per OS, then check that the *orderings* agree.
+282
View File
@@ -0,0 +1,282 @@
# Phase 0 — P2: i7-6700K / GTX 1080 Ti (Linux, Docker present)
Setup and measurement procedure for the CPU-and-RAM-bound machine in the Onion MC client
tuning fleet.
---
## Profile
| | |
| --- | --- |
| CPU | Intel i7-6700K, 4 cores / 8 threads, 4.0 GHz base / 4.2 GHz turbo (Skylake) |
| GPU | NVIDIA GTX 1080 Ti, **11 GB VRAM** (Pascal) |
| RAM | 16 GB total, **~8 GB occupied by Docker** |
| OS | Linux |
| **Binding constraint** | **CPU (main thread) + RAM/GC pressure** |
| **What this tier tests** | CPU-render and RAM/GC ladder steps on a capable GPU |
| **Expected DH answer** | **On, with the CPU/thread preset lowered — quality preset stays up** |
### The important inversion
This machine's GPU is the second-strongest in the fleet by a wide margin, and 11 GB of VRAM
is more than most current mid-range cards. **DH's GPU cost is not the problem here.** The
constraints are a 4C/8T Skylake main thread and a heap that has to fit in roughly 8 GB.
Consequence: for this tier, **turn DH's CPU/thread preset down, not its quality preset.**
That is the opposite lever from the other two machines, and it is the clearest example of
why the ladder cannot be a single global ordering.
### Standing constraint for this machine
> **Do not alter Docker or any other running process for the sake of these measurements.**
> Assume the existing load is constant and consistent, and treat it as a fixed property of
> this test rig.
That changes the guardrail from *"abort if RAM is low"* to *"record the baseline and verify
it stayed constant."* See Step 3 and Step 9.
---
## Shared measurement protocol
Applies to every machine in the fleet. Duplicated here so this document stands alone.
1. **Uncapped, vsync off** during measurement. Apply the FPS cap only *after* tuning.
2. **Metric is p99 frametime and 1% low, not average FPS.**
3. **Discard 10–15 s of warmup** per scene — JIT, chunk load, initial GC.
4. **Settle after any render-distance or DH change.**
5. **Three runs per configuration, report median and spread.**
6. **One variable per run.**
7. Guardrails: FPS limiter active, governor moved, or RAM headroom shifted materially →
the run is invalid.
---
## Step 1 — Preconditions
- [ ] Confirm the **proprietary NVIDIA driver** is in use. `nouveau` would invalidate both
the performance and the measurements.
```bash
nvidia-smi # must succeed
glxinfo -B | grep -E 'OpenGL renderer|OpenGL version'
```
- [ ] Confirm the compositor is not forcing vsync. If on X11/KDE, disable compositing for
the measurement session; on Wayland, disable any tearing/queueing control.
- [ ] Confirm the display resolution and refresh rate, and record them. Resolution is a
bigger GPU lever than most mod settings.
## Step 2 — GPU power state and throttling
Do this before every session. A GPU that is power-capped or thermally throttled produces
numbers that look like mod effects.
```bash
# Prefer maximum performance instead of adaptive clocks
nvidia-settings -a '[gpu:0]/GPUPowerMizerMode=1'
# Check for throttle reasons — SW Power Cap / HW Slowdown must be absent
nvidia-smi -q -d PERFORMANCE
```
Start background logging of VRAM, clocks, power and temperature. **Use this exact command
on the Windows machine too** — identical tooling on both NVIDIA boxes:
```bash
mkdir -p ~/mcbench/logs
nvidia-smi --query-gpu=timestamp,memory.used,clocks.sm,clocks.mem,power.draw,temperature.gpu,utilization.gpu \
--format=csv -l 1 > ~/mcbench/logs/gpu-$(date +%F-%H%M%S).csv &
```
`memory.used` is your VRAM series. On this machine it should stay comfortable; it is the
control against the 6 GB machine.
## Step 3 — Establish the noise floor (do this first)
Because Docker's load is assumed constant rather than eliminated, **you must measure the
noise before you can interpret any delta.** Otherwise you cannot tell a real 3% mod effect
from Docker doing something.
- [ ] Run the **same configuration, same scene, three times**, with no changes at all.
- [ ] Record p50/p95/p99 spread across those three runs.
- [ ] **That spread is your detection threshold.** Any later measurement smaller than this
spread is not evidence.
If the spread is large, Docker's activity is the first suspect. Record it as a known
limitation of this rig rather than trying to fix it.
## Step 4 — Record the RAM baseline
Do not change the running load — measure and freeze it.
```bash
free -h
cat /proc/meminfo | grep -E 'MemAvailable|SwapTotal|SwapFree'
```
- [ ] Record `MemAvailable` at session start.
- [ ] Repeat the reading before and after each block of runs. **If it drifts materially,
Docker's footprint changed and the runs are not comparable.** That is the check that
makes the "constant load" assumption falsifiable instead of merely asserted.
- [ ] Confirm no swap is being touched during runs:
```bash
grep -E 'pswpin|pswpout' /proc/vmstat # before and after; both should not move
```
Swapping during a run invalidates the p99 frametime numbers outright.
## Step 5 — CPU governor
The governor is a system setting, not a running process, and pinning it removes DVFS noise
on a 4C/8T Skylake. This is the one system-level change recommended on this machine.
```bash
sudo cpupower frequency-set -g performance
# or:
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
```
- [ ] Record the governor value before and after, and keep it identical across sessions.
- [ ] Revert to your normal governor when the measurement work is done.
> Also worth noting for the tier guide, independent of this benchmarking: a mild overclock
> on this CPU is a larger and cheaper win than most mod tuning. Measure at stock first so
> the baseline is comparable.
## Step 6 — MangoHud
```bash
sudo pacman -S --needed mangohud # or your distro's package
```
Config lives at `~/.config/MangoHud/MangoHud.conf`. Start from the packaged example
(`pacman -Ql mangohud | grep MangoHud.conf` to locate it) rather than a transcription, then
set:
```ini
output_folder=/home/<user>/mcbench/logs
autostart_log=1
log_duration=30
fps_limit=0
frametime=1
frame_timing=1
# percentiles — confirm the exact key/syntax in the packaged example
```
## Step 7 — Launcher and JVM
Use **Prism Launcher** (or ATLauncher) and launch from a terminal so the environment is
under your control.
**Java:** 21 — **the same JVM build as the other two machines**, to avoid a confound.
**Wrapper command** — Prism → *Edit Instance → Settings → Custom Commands → Wrapper
command*:
```
mangohud
```
Fallback if it fails to hook: `mangohud --dlsym`.
**JVM arguments** (identical across the fleet except `-Xmx`):
```
-Xmx6G
-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
```
**Heap sizing rule for this machine:** `-Xmx` = min(6 GB, `MemAvailable` − 2 GB). With
~8 GB available that lands at 6 G; if the baseline reading is lower, lower the heap.
**Omit `-XX:+AlwaysPreTouch` on this machine.** It commits the entire heap up front, which
is exactly the wrong thing when Docker already holds half the RAM.
> **Read this before interpreting GC results.** Because heap is capped by Docker's
> footprint, GC pressure on this rig will be **higher than on an otherwise identical
> machine without Docker running.** This rig is therefore expected to *over-weight* the
> RAM/GC ladder steps and to show worse p99 lows than the same hardware would in the wild.
> Record it as a property of the rig; do not attribute it to a mod.
## Step 8 — Pin the in-game settings
Controlled variables — set once, record, do not change between runs unless the run is
testing that setting.
- Graphics: Fancy
- Render distance: 8
- Particles: All
- Clouds: Fancy
- Entity shadows: On
- Biome blend: fixed, recorded
- Mipmap levels: 4
- GUI scale: fixed number
- **Max framerate: Unlimited**
- **VSync: Off**
- FOV, resolution, fullscreen mode: fixed and recorded
## Step 9 — Verification run
- [ ] Launch, confirm the MangoHud overlay appears over Minecraft.
- [ ] Confirm a CSV lands in `~/mcbench/logs` with a frametime column.
- [ ] Confirm `nvidia-smi` logging is producing a CSV.
- [ ] Run the Step 3 noise-floor test and record the spread.
- [ ] Confirm `MemAvailable` and swap counters are stable across the three runs.
## Step 10 — Per-session checklist
- [ ] `nvidia-smi` works; power mizer set to max performance; no throttle reasons
- [ ] `nvidia-smi` background logging started
- [ ] Governor recorded (and pinned to `performance` if using that policy)
- [ ] `MemAvailable` recorded; swap counters checked
- [ ] Compositor vsync disabled
- [ ] MangoHud overlay visible, CSV output folder writable
- [ ] Noise floor re-established if the session is a new day
## Step 11 — Recording sheet
| Field | Example |
| --- | --- |
| Date / session | 2026-09-28-a |
| Machine | P2-6700K-1080Ti |
| Config ID | baseline / dh-cpu-preset-low / emf-off / … |
| Scene | A-base / B-terrain / C-gui |
| Run # | 1 / 2 / 3 |
| CSV file | |
| p50 / p95 / p99 frametime (ms) | |
| 1% low FPS | |
| Avg FPS | |
| VRAM peak (MB) | |
| Throttle flag | none / SW Power Cap / HW Slowdown |
| `MemAvailable` before / after | |
| Swap delta | must be 0 |
| Notes | |
---
## Machine-specific caveats
- **Docker is not removed, so RAM is a live variable that must be monitored, not assumed
away.** The Step 4 before/after check is what keeps the results honest.
- **This rig will over-weight RAM/GC ladder steps** relative to identical hardware without
Docker. Documented, not corrected.
- **Establish the noise floor before interpreting anything.** With a constant-but-unknown
background load, small deltas are unreadable until you know the spread.
- **CPU is the bottleneck, so CPU-side ladder steps are expected to show their largest
deltas here** — EMF/ETF and Fresh Animations, DH's thread preset, Sound Physics reverb,
LambDynamicLights. GPU-side steps may show almost nothing, and that is a real result, not
a failed measurement.
- **Pascal is a legacy driver branch.** Verify the driver is still current before drawing
comparisons against newer hardware.
- **11 GB VRAM means this is the fleet's control for "VRAM is not the constraint."**
Comparing this machine against the 6 GB GTX 1060 isolates GPU/VRAM effects, because both
machines share the same 4C/8T CPU class. If a knob you classified as CPU-render diverges
between the two, your classification is wrong — that is the taxonomy self-check.