35 KiB
Performance experiment ledger
Campaign: OpenGL performance campaign.
Live work status: central Beads beads-jod2.
Record unsuccessful, incomplete and rejected experiments as well as accepted ones. Local game-derived artifacts are not release fixtures. Hashes below make the retained local evidence identifiable without distributing a savestate/ROM.
CRAB-DISCOVERY-001: verify a usable starting scene
Date: 2026-09-04 (session date). Verdict: exploratory evidence only; no candidate optimization, A/B comparison, production claim or correctness qualification.
- Host: Windows, Ryzen 7 9800X3D, 8 cores / 16 logical processors. Graphics adapters reported by the OS: RTX 3080 Ti, AMD integrated graphics, Meta virtual monitor. Actual GL device and power state were not recorded in this capture.
- Historical binary source:
_wt-ape-crabperf-20260901/build-dbg, CMake Release withPSX_DEBUG_TOOLS=ON. Existing report identifies buildv0.3.2-alpha-139-g1bf70960-dirty. Current source HEAD is not proof of binary provenance. This executable was not built from the campaign branch. - Executable SHA256:
3b27bda4417522eb1ab331e4d2b194828f1d38fb9bbb165d1a78eb2156142ba1. - State:
saves-dbg/scph1001/state_800A3660_slot01.pst, version 5, BIOS wordsumF67ECB99, entry800A3660, codegen hashA4319B6F, ABI 21, codegen version 10. SHA2562dfc142e65eb32e179b67d352f510d15f6d97efd22b3b43a9eef24301f3ad5a9. - Executable, saves, assets, BIOS assets and mods were copied into the campaign
worktree's
.local/crabby-baseline. Writable cards/settings use that copy. CLI selected OpenGL, no launcher, debug port 4680. Settings selected 2x SSAA and antialiasing.PSX_RUNTIME_PERF_DIAG=1; no host CPU cap was applied. - Restore receipt:
savestate_statusgeneration advanced from 0 to 1 withpending=0,last_ok=1,last_op=load,last_slot=1. Presented screenshot visibly confirms the sandcastle area on the beach facing the water. - Original
ApeEscapeRecomp/saves/scph1001slots 00/01 were v3 and slots 06/07/08/09/11 were v2; they cannot be used as v5 checkpoints.
The passive 10-second sample is retained locally at
.local/crabby-baseline/stall-10s.json, SHA256
448d6a77b08479e0cca9bf11ffa21af1b3c2408ba70b9a3f1a0a7696f4a10b28.
Snapshot start timestamps differ by 10.038749 seconds; commands are sequential,
so these are not atomic snapshots of a fixed amount of guest work.
| Observation | Value | Interpretation limit |
|---|---|---|
| Overlay native dispatch delta | 0 | Does not include statically compiled game execution |
| Overlay interpreter fallback delta | 33,702 | Dispatch events, not CPU-time share |
| Interpreted instruction delta | 425,410 | Some kernel fallback is expected |
| Interpreter block delta | 33,714 | No claim that reducing calls changes the primary bottleneck |
| Compilation runs/configured | 0 / 0 | Cache/compilation provenance differs from a prepared release campaign |
| Rolling phase samples: interpreter / static / GPU | 1.59% / 80.11% / 18.30% | Instrumented phase stamps, not an independent host CPU profiler |
This observation rejects the inference that zero overlay-native dispatches alone prove interpretation dominates the slowdown. It does not reject overlay optimization as a candidate. No controlled compiler/process/power-state audit was performed during this exploratory sample.
Separately queried frame_perf reported approximately 16.68 ms total and
16.65 ms emu_cpu_ms_avg. The latter is calculated from total wall time minus
present wall time, not OS thread CPU time. GPU queries span command-stream
intervals; do not interpret these fields as independent exclusive CPU/GPU busy
time or add their values together. Run without timer-query profiling and obtain
host-thread CPU samples before choosing an optimization from these values.
HOST-BUDGET-001: verify the throttle denominator
Date: 2026-09-04 (session date). Verdict: launcher calibration, not an accepted runtime optimization or a substitute for low-end hardware.
On the same 16-logical-CPU host, a single Python process busy-looped until
time.process_time() advanced by 2.5 seconds. Every run used affinity mask
0x1. The game was stopped. The sequence below was a calibration sequence,
not an interleaved optimization campaign. Reports live in
.local/host-calibration/{unrestricted,core50,core25}.json.
| Requested budget | Applied Job CpuRate (out of 10,000) | Wall seconds | Process CPU seconds |
|---|---|---|---|
| Unrestricted | none | 2.580994 | 2.500000 |
| 50% of one logical CPU | 313 | 4.679147 | 2.531250 |
| 25% of one logical CPU | 157 | 9.515031 | 2.500000 |
--cpu-percent is a percentage of the whole host's CPU scheduling budget.
--core-percent normalizes to one logical CPU equivalent independently of
affinity; it limits the whole launched job, including helper threads/processes.
This does not selectively slow the emulation thread, lower CPU frequency, or
simulate an older GPU/cache/memory subsystem. Reports retain requested and
applied rates, including integer rounding.
An earlier 0.5-CPU-second witness did not demonstrate effective throttling even at a 3% host budget. Longer witnesses did, so sub-second smoke timing is not a valid cap calibration. Repeat calibration on each host and use sustained game windows rather than assuming the scheduler's short-term behavior is linear.
ROUTE-SMOKE-001: live runner protocol validation
Date: 2026-09-04 (session date). Verdict: successful diagnostic smoke only. No optimization candidate, target-provenance manifest, or acceptance comparison.
Used the isolated executable/state from CRAB-DISCOVERY-001, OpenGL, no host cap,
PSX_RUNTIME_PERF_DIAG=1, and explicitly PSX_GL_PERF=0. A local shortened
route held neutral input for 120 ticks. The runner confirmed completed slot-1
restore (generation 1, last_ok=1) and route completion (active=false, one
step consumed, remaining=0). Raw evidence:
.local/crabby-baseline/runner-smoke.json.
- Route wall time: approximately 2.141 seconds, including setup/status overhead.
- Counter observation window: approximately 2.672 seconds and 161 frame ticks, including sequential snapshots/control traffic, not exactly 120 guest ticks.
- GL frame timing correctly reported unavailable with timer queries disabled.
- No native overlay compilation was configured; cache provenance remains unsuitable for a prepared-release acceptance baseline.
The process exited after the smoke. Original saves/cards were not modified. The committed 7,200-tick route is a longer stationary workload manifest; this smoke does not validate its full-duration timing or the analog approach route. See tool usage and remaining gates.
MEMORY-TRACE-001: remove empty production write-trace calls
Dates: 2026-09-04 to 2026-09-05. Verdict: retain as a narrowly scoped dead-work simplification. Local write benchmark improves; gameplay gain is unproven. This does not complete the campaign or establish the cause of the beach slowdown.
Change and correctness evidence
Guard the six RAM/scratchpad byte, halfword and word calls to
debug_server_trace_write_check with the existing PSX_NO_DEBUG_TOOLS switch.
That function already returns immediately in production. This also removes its
old-value argument loads. Debug builds keep the original calls. No functional
memory observer, store, cycle charge, MMIO path, runtime setting, ABI or state
layout changes. Separate -O2 -fno-lto object inspection found the baseline's
undefined trace symbol and confirmed its absence from the candidate object.
runtime/tests/test_memory_debug_trace_guard.py compiles actual memory.c
against real runtime headers, with external device/observer stubs. It checks
all six writes through four RAM mirrors and scratchpad aliases, expected bytes
and adjacent sentinels, observer/store counts, and production/debug trace-call
witnesses. Optional --baseline-memory also checks the old production source.
The compact state hash covers touched bytes and selected counters, not complete
guest/device state. Structural checks preserve functional RAM observer order.
An earlier synthetic store model and then a fake-header fixture were rejected
during review; neither is used by the committed test.
Build provenance
Framework baseline is 8ec6498d323a7abd04a3058afcbb5e36e62a8ec3; candidate differs
only by the six guards in runtime/src/memory.c. Source SHA256:
- Baseline:
693be507fa53fded3e8e276f4ac0f7293d3879f3d53a8044fa8c383b4e097b99. - Candidate:
4fdb391d4f74da1ef2d31ce7cd61a0e0b958abab8304da37d83a2c1bb0e85253.
Both title executables were rebuilt, using the same copied Ape Escape generated
code and assets from _wt-ape-crabperf-20260901. Provenance trees/build logs are
retained under .local/ape-build-provenance. CMake Release uses MinGW GCC/G++
15.2.0 from C:/msys64/mingw64/bin, -O3 -DNDEBUG, debug tools OFF, static runtime ON,
SDL3, recomp UI and rewind ON, netplay OFF, and block cycles ON. Vulkan was
enabled in the build but was not the selected/tested renderer. The first build
failed with the wrong windres shim; successful builds explicitly selected
C:/msys64/mingw64/bin/windres.exe.
- A executable SHA256:
f0c893a5743d8dfddcde75fe275d525c99c66294c5333fdf48b797de0b21096e. - B executable SHA256:
6fd00dc4ed8a7e9cf66f1bdd64ebaafd376d867dd5687c126bcd56f8e03dbf12. - A successful build-log SHA256:
c9a042d2ccab65d248a9b91b0b74d1106fc80fe74f611ea5eccfb27f350ad252. - B successful build-log SHA256:
3d5326d5fa5de696cb02fd3c021a2336b92362c04fcfc3f00a560a79ec34ad8e.
The generated BIOS warned that it was stale against the current emitter fingerprint. It was deliberately identical in A/B to retain compatibility with the available v5 checkpoint. No native overlay compilation/loading was configured. These are controlled local integration artifacts, not clean release builds or qualification of regenerated code and shipped overlay caches.
Local write benchmark
Actual memory implementation, external device stubs, and a genuinely empty
trace function in a separate translation unit; GCC C11 -O2 -fno-lto, production
macro enabled. Each run executes 50 million loops of six writes. Both artifacts
warm up with one million loops before measured A1/B1/A2/B2/A3/B3 order. Host is
the Ryzen 7 9800X3D, High Performance power plan, affinity 0x1, no CPU cap.
Primary metric is launch-to-completion wall seconds, lower is better.
| Pair | A seconds | B seconds |
|---|---|---|
| 1 | 1.4162425 | 1.1504406 |
| 2 | 1.4181166 | 1.1467513 |
| 3 | 1.4099258 | 1.1160858 |
| Minimum | 1.4099258 | 1.1160858 |
| Median | 1.4162425 | 1.1467513 |
Median improvement: 19.03%; minimum improvement: 20.84%. All six runs produced
identical selected state/counters: state=dcc19de5, 300 million stores,
150 million parity calls, 150 million card checks, zero trace calls. This
workload emphasizes write-call overhead and does not predict gameplay gain.
The compiler-process monitor reported no observed compilers; thermal/frequency
telemetry was not collected.
Crabby Beach OpenGL comparison
Same v5 state as CRAB-DISCOVERY-001, staged copies of saves/cards/settings. OpenGL context reported NVIDIA 3.3.0 driver 610.74, 2x SSAA and antialiasing, 165 Hz display, wall-clock 59.94 Hz pacing, driver vsync OFF. Both uncapped smokes sustained approximately 60 guest Hz with no reported audio underruns. A screenshot outside the acceptance runs confirmed the water-facing beach scene. Smoke timings are excluded: they are not three pairs and B's screenshot overlapped its smoke window.
Measured A/B uses PSX_LOAD_SLOT=1, PSX_RUNTIME_PERF_DIAG=1, PSX_GL_PERF=0,
PSX_BENCH_WINDOW=120:420. Primary metric is the runtime's exact 300-frame
BENCH wall_ms, not launcher lifespan. Every run uses a 25%-of-one-logical-core
Job budget (raw CpuRate 157/10000) and affinity 0xFFFF, limiting the entire
job. Every process is intentionally stopped after 35 seconds. Timed windows
complete before timeout. This scheduling cap is not low-end hardware emulation.
| Pair | A wall ms | B wall ms |
|---|---|---|
| 1 | 8458.662 | 8588.874 |
| 2 | 8312.503 | 8274.390 |
| 3 | 8341.652 | 7946.127 |
| Minimum | 8312.503 | 7946.127 |
| Median | 8341.652 | 8274.390 |
Median improvement: 0.81%, within observed noise; minimum improvement: 4.41%. No convincing scene-level gain. Each window reports 180,114 interpreted instructions, 15,564 fallback dispatches, and zero overlay loads, invalidations, or captures. Those matching counters are not full-state parity. Under the severe budget both builds slow down and underflow host audio. No compilers or monitor errors were observed; configuration/mod hashes remained unchanged. No screenshots were taken during these six runs. No runs were discarded.
Retained evidence and remaining gates
All following paths are relative to the worktree and are intentionally ignored:
| Artifact | SHA256 |
|---|---|
.local/memory-trace-bench/campaign.json |
fd1944a1fc3a8ea750e37ceda9fb12367d9bb85adc8f12d01fdc28df3a3b06ad |
.local/game-memory-ab/campaign.json |
9d0c70ae9b9d221bc601e24cf7563dcdc61f84fecbae97806e7a7d068d8b5e1d |
.local/run_memory_bench.py |
90f6fec928f33f3d5e6395d31ce25d7f86ba16359d79851dd8903ef9ef48057d |
.local/run_game_ab.py |
e3e9fd310600c3dbde14d4b2b4fff741cee2a063c14bbfc9ffe7f8416f71bff9 |
JSON retains per-run evidence and artifact/configuration hashes; game/state assets are not distributed. The focused compiled regression passes, as do the FMV quiet and dirty-text admission/continuation guard tests. The combined campaign/host-launcher/stall-report suite passes all 63 tests, and CMake's registration guard finds all 120 runtime/recompiler test files registered. These are not a full runtime CTest pass or cross-platform validation. Two unrelated structural tests also fail on the immutable baseline; details are in the audit.
Retain the change only as removal of already-empty production work, under the contract's simplification allowance, not as a 5% gameplay optimization. Full checkpoint parity, multi-title/low-end hardware, moving/transition routes, long-window frame consistency, clean-install and cross-platform release gates remain open. Broader GPU/audio history and GL costs remain separate candidates; the flat gameplay result does not justify focusing the campaign on memory.
PACER-COST-001: attribute idle pacing CPU cost
Date: 2026-09-05. Verdict: baseline attribution only, no pacing change or
gameplay speed claim. Compile actual frame_pacing.c and host_time.c against
SDL3 with GCC 15.2.0 -O2 -DPSX_SDL3. The driver calls frame_pacer_wait 600
times at 59.94 Hz with no guest work, using GetThreadTimes for calling-thread
CPU time and SDL's performance counter for wall time. The first call anchors
without waiting, so 599 periods take approximately 9.9933 seconds.
| Run | Wall seconds | Thread CPU seconds |
|---|---|---|
| 1 | 9.993298 | 0.812500 |
| 2 | 9.993297 | 0.859375 |
| 3 | 9.993297 | 0.765625 |
This is approximately 7.7-8.6% of one logical CPU spent on idle pacing on the Ryzen 7 9800X3D, High Performance plan, unrestricted scheduling and inherited affinity. The existing sleep decision stops sleeping below two milliseconds, then spins until the deadline. This local cost makes the spin tail worth measuring in gameplay; it does not establish an actual pacer bug or explain exclusive wall-time phase attribution under a Job cap. No candidate was tested. Agents held compilation during these runs; no continuous compiler-process or thermal monitor was attached to this exploratory probe.
Local retained driver .local/pacer-cost.c, SHA256
d98305437fb4e8c86769f31893e43bf63ade8568d761f522e0842817a92ac105;
executable .local/pacer-cost.exe, SHA256
7aa80698ca5d3a831d0d651601b3c5b2e8bc3665e2eec82f5e426c308eae7ddb;
raw output .local/pacer-cost-results.txt, SHA256
749fc5185fa512e3a00390f0022fa8939993763ca3b9f6e123ba76ff6654fea1.
HISTORY-002: isolated GPU and audio history candidates
Date: 2026-09-05. Correctness milestone; controlled resource/time comparison pending. No gameplay gain accepted from the correctness runs below.
Candidate boundaries
GP0-HISTORY-001: compile the GP0 command-history allocation, recording and diagnostic guest-stack scan only when debug tools are enabled. Production history accessors remain linkable but report zero capacity/count and empty dumps. Keep source tracking, opcode counters, WS census, functional overhang detection, and all command execution unchanged. Removes a 104 MiB allocation request; debug builds retain always-on history.AUDIO-PCM-001: compile out four PCM history arrays and their writes inPSX_NO_DEBUG_TOOLSbuilds. Preserve every tap's head, nonzero/audible/peak statistics, rates, event records and pump/underrun/mute counters. Production WAV dump returns the existing error result without opening a file; debug WAV history is unchanged. Actual GCC object BSS is 83,886,272 bytes with debug history and 16,777,408 without it: exactly 64 MiB less backing capacity.
Both use the existing build switch, not a new runtime selector or lazy allocator. Capacity is not equivalent to resident memory or a measured speed improvement. Packed production audio tap counters may share cache lines between callback and emulation threads; require the real bridge-audio path in performance checks.
Focused checks
The GPU test compiles actual gpu.c and real headers with external renderer
stubs. It compares exact serialized GPU snapshots and the entire VRAM at eleven
checkpoints across environment, fill, upload, copy, polyline and NOP commands.
It also checks debug history count, copy source/stack pointer and polyline
header, and production unavailability. This tests parser/state behavior, not
the rendering correctness of a stubbed backend. Known pre-existing polyline
source attribution was not changed or silently redefined by the test.
The audio test compiles actual audio_trace.c in both modes. All four taps'
observed statistics/events compare equally, including a new event after ring
wrap, signed extremes, audible thresholds, rates and resets. Debug WAV headers
and sample bytes are checked for all taps and for wrap/clamped eviction;
production must not create the requested WAV. Review rejected the first test's
hard-coded output comparison and replaced it with real observations.
Both focused tests passed root execution. The 63 campaign/host/stall-report tests passed, as did the memory-trace regression. CMake's registration guard finds 122 test files registered. This is not a full cross-platform CTest pass.
Isolated build provenance
B is the previous memory-guard baseline, C adds only the GP0 gate, and D adds
only the audio gate. All use identical local-only endpoint memory/restore/
renderer/audio witnesses and an optional checkpoint probe. Original B from
MEMORY-TRACE-001 is preserved. Source trees, exact options/commands/logs and
hashes are in .local/ape-build-provenance/builds-bcd-manifest.json, SHA256
176ed3d54939fab3498ced5d1e3dd38566a9ef76e7e4cb23f5514a8d9a740530.
| Variant | Executable SHA256 |
|---|---|
| B metrics | f1310b19eb3633d81e01717f36ab60f4d6cd4d53aa3838adf0e614d10bbf4914 |
| C GP0 | 74063d9dadef152d023c0dead18eabde854773c4399f7f52f49713fb67315045 |
| D PCM | e9f525296dfdb0be2a50596a1198bb9735be0371d21afa627cc6e08dfe05bd39 |
Release GCC 15.2.0, SDL3, static runtime, debug tools OFF, rewind ON, netplay OFF,
same donor generated game/BIOS and saved scene as MEMORY-TRACE-001. The stale
generated-BIOS warning persists. A default all-target build failed in an
unrelated donor title test on a long Windows dependency-file path; explicit
psx-runtime builds succeeded. No release qualification is claimed.
Real OpenGL checkpoint comparison
Separate uncapped 20-second processes restore the same slot-1 v5 beach state.
All variants report active OpenGL (gl_active=1, gr_backend=1), completed
restore (generation=1,pending=0,last_ok=1,last_op=load,last_slot=1), and active
non-legacy bridge output with advancing host-tap frames. The local-only probe
writes raw boot-state blobs at frames 120, 121 and 420, plus CPU timing sidecars.
For both C and D versus B, every blob and sidecar is byte-identical.
| Frame | Raw guest snapshot SHA256 (all B/C/D) |
|---|---|
| 120 | 505f7d94c5c7e518e099669ed1623296d9210abc30eab4bc907956e91ff652c6 |
| 121 | 1e0b19c3a913733aba9bb403b1e01a1c9d309cc919e3accd9c52f3d341d3429b |
| 420 | 55ebbe6a36ac2674952a4672575dfb619547ffec0a059f9a277bb955b9d074e2 |
Each blob is 3,685,569 bytes. The existing save format covers CPU registers, RAM, scratchpad, VRAM, SPU RAM and serialized device/IRQ/clock/cache/dirty state. The 411-byte sidecars add multiply/divide and GTE completion timestamps, all 33 read-absorb bytes and load-timing scalars. CPU function pointers, host audio queues, SDL/pacer/presentation histories and diagnostics are excluded. This is one scene's checkpoint evidence, not exhaustive state/restore or multi-title qualification. Full campaign correctness gates remain open.
Evidence: .local/history-correctness-002/report.json, SHA256
7feb56b0f0119688e460ff46b027d3aaf9549021e996a935830e26a6154b21f2;
driver .local/run_history_checks.py, SHA256
f6f29b505225fc0ff8688d9a86921be60590a81288980c5fd7d4c8b56961d0f4.
Raw game-derived snapshots remain local and uncommitted.
The first attempt, .local/history-correctness-001, failed closed because the
staged checkpoint hook was absent despite an earlier build report. Explicit
source and binary-string checks plus forced rebuilds corrected the artifact.
That failed attempt is retained, not counted as successful state comparison.
Checkpoint saves can publish deferred cycles and force GL readback. These runs also overlapped unrelated builds, so none of their timing or memory values is acceptance evidence. The timed runner explicitly unsets checkpoint capture. The preregistered primary metric is exact-frame-420 process PrivateUsage; the secondary metric is frames-120:420 wall time, with three interleaved pairs for each independent candidate and a validated 25%-one-core Job cap. It requires stable input/artifact hashes, active OpenGL/audio and completed restore, and aborts on compiler contamination or missing/nonfinite metrics.
Timing gate outcome and disposition
The benchmark agent monitored the host for ten minutes without finding 30
consecutive seconds free of compiler/benchmark activity. Concurrent SNES builds
included Mega Man X and Super Mario Kart. No timed candidate process was
launched and .local/game-gp0-memory-ab was not created. Unrelated work was
not stopped. The power plan remained High performance before and after;
thermal state was not measured.
The prepared twelve-run driver is .local/run_game_gpu_memory_ab.py, SHA256
ce01b28c627dd5a8d0abe3217a49e2fd1d576fc7128153de502487f69a96f64b.
It includes cc.exe in compiler-contamination detection. Resume the paired
campaign in a quiet host window before making retention or speedup claims.
Disposition: committed candidate implementation in the isolated performance worktree, pending performance acceptance, not release qualification. The 104 MiB GP0 allocation request and 64 MiB PCM static-storage capacity removals are established; resident-memory savings and gameplay speedups are not. Focused parity tests and real OpenGL checkpoints passed, but the broader correctness matrix and the quiet-host comparisons remain open.
UNCAP-HISTORY-003: uncapped OpenGL throughput
Date: 2026-09-05. User-requested follow-up to HISTORY-002. Uncapped frame throughput removes a limiter that can hide spare capacity; it does not isolate the process from concurrent host work or simulate lower-end hardware.
Mechanism and provenance
PSX_VSYNC=0 alone leaves the wall-clock pacer active. Debug/manual/load turbo
can skip presentation, and Ape's historical ape.framerate.uncapped plugin
actually selects frame interpolation. None is appropriate here. The native
VBlank-rate API already permits zero frontend pacing without changing guest
cycle accounting (mod_plugins.h, psx_mod_set_native_vblank_rate).
Identical local-only staged main.cpp hooks set g_frame_period_ms=0 and
g_video_vsync=0 after host-refresh selection and before GL context creation
when PSX_PERF_UNCAPPED=1. These are the same host-pacing effects as the native
API; the hook does not call the API or change guest clocks. It refuses active
interpolation. A separate endpoint [BENCH_PACING] reports actual period,
effective swap interval, wall-pacing decision, interpolation and load-turbo
state. Normal presentation and the audio bridge remain enabled.
The three incremental Release psx-runtime builds succeeded. Original paced
executables and the previous manifest remain unchanged; staged original
main.cpp files are backed up. Tracked runtime sources were not changed for
this experiment. New manifest:
.local/ape-build-provenance/uncapped-builds-manifest.json, SHA256
184dfa8a1d0305fc9f1d5aafdd6dda9cec4d0d24b8a73bf684775eefa7103ca4.
| Variant | Uncapped executable SHA256 |
|---|---|
| B baseline | 8050206bda873fd42a8cc790c0b9b556680cdcb966893a1414d3774bbbf11dd6 |
| C GP0 gate | a43233c44f9c6f6f1a8b7115bc77260de0292571c556e44a5afd97bb4b00d042 |
| D PCM gate | 566297db442e5e062b2b90864302a20d4cbdbe769496d6cdf7d2560089aff5f3 |
Uncapped correctness smoke
Root ran separate 12-second uncapped processes with checkpoint capture enabled. All B/C/D raw guest snapshots and CPU sidecars at frames 120, 121 and 420 are byte-identical to one another and to the paced B checkpoints in HISTORY-002. All restore, OpenGL and bridge-audio witnesses passed. Endpoint pacing reports zero period, swap interval, wall pacing, interpolation and load turbo. These checkpoint runs are not timing or memory acceptance measurements.
Evidence: .local/uncapped-correctness-001/report.json, SHA256
551732b3411c74a113d14edf46f185d364684863ec199d223f3b444ee9474709;
driver .local/check_uncapped_history.py, SHA256
8acb9e3894286237cfbba6b3f3e468c5ff3698c9762c2de488164fa151bd3e91.
The existing save-format coverage/exclusions from HISTORY-002 still apply.
Timed protocol
Three interleaved B/C and B/D pairs, reversing within-pair order for pair two:
B,C,B,D; C,B,D,B; B,C,B,D. Each process restores the same beach save and runs
with unrestricted requested host CPU budget, affinity 0xFFFF, the same
OpenGL 2x SSAA/AA settings and diagnostic counters, and no checkpoint capture.
Primary metrics are wall time for guest frames 120:420 and guest VBlanks/s
(300000 / wall_ms), not unique rendered game frames or physical display FPS.
PrivateUsage at frame 420 is secondary. Twelve-second process timeouts provide
bounded cleanup; whole-process CPU totals are not the fixed-window CPU cost.
The driver requires unchanged artifacts/settings/game/state/mod inventories, completed restore, active OpenGL/audio, effective uncapped pacing and matching guest-work counters. Compiler observations are retained instead of waiting for a quiet host; monitor failures invalidate results. No result is automatically accepted based only on the absence of observed compilers. Eight synthetic driver checks passed root execution.
Local driver .local/run_uncapped_history_ab.py, SHA256
ab3fd3efd56b3088a11221d907a5202101dbfff21fb19186b647cef97bf7c8d3;
tests .local/test_run_uncapped_history_ab.py, SHA256
3a4b19138e1272490534b3bea84099e32a856d9d922c368fa9f85329abf23044.
Uncapped audio production outruns the physical playback timeline. An active audio device and advancing host tap do not establish identical callback counts, absence of overflow or normal-speed listening quality. Neither title-wide correctness nor low-end realtime pacing/audio acceptance follows from this throughput experiment.
Short-window results
All twelve runs passed the fixed-window, effective-pacing, restore, backend,
audio and inventory checks. No monitored compiler processes or monitor errors
were observed. High performance power plan before/after; no thermal telemetry
or continuous monitoring of all other host workloads. Classification remains
exploratory_no_compiler_observed, not automatic acceptance.
| Comparison | Baseline wall ms (three runs) | Candidate wall ms (three runs) | Median VBlanks/s B -> candidate | Median throughput change |
|---|---|---|---|---|
| GP0 gate | 1205.440, 1247.664, 1181.284 | 1178.411, 1181.626, 1177.182 | 248.872 -> 254.580 | +2.29% |
| PCM gate | 1212.670, 1185.505, 1215.057 | 1165.711, 1208.837, 1179.628 | 247.388 -> 254.317 | +2.80% |
Within-pair throughput changes were +2.29%, +5.59%, +0.35% for GP0 and +4.03%, -1.93%, +3.00% for PCM. This spread, especially the PCM sign reversal, prevents treating the modest median gains as robust. Fastest-run throughput changes were only +0.35% and +1.70%, respectively. No additive combined gain is established: each candidate was tested independently.
Endpoint PrivateUsage fell in every pair: GP0 by 102.87, 103.63 and 105.49 MiB; PCM by 62.00, 63.31 and 64.07 MiB. This measures process private commit in this scene, not resident physical memory. The amount includes allocator/driver variation and is not an exact measurement of the removed arrays alone.
Raw report .local/game-uncapped-history-ab/campaign.json, SHA256
5e6477c3969eb8799aee300ffa153903d39c48010a814be76f2cfc19413afb4d;
power witness .local/game-uncapped-history-ab/power_plan.json, SHA256
034c141dd4dd57cdbd10819bf884aa01c628e1fb496dc1bee83979aa52a55da4.
All stdout/stderr and host reports are retained beside the report. Root
recomputed paired throughput and memory deltas from the raw rows.
Because the measured windows last only about 1.2 seconds, a separate replication uses frames 120:1920 (1,800 guest VBlanks), identical executables/settings and the same twelve-run order. This extends the workload past the GP0 history ring's wrap point without changing game speed settings or rendering quality. It uses a separately named driver/output directory and 15-second process timeouts; the short-window artifacts are preserved.
Longer-window replication
All twelve runs passed the same evidence checks at frames 120:1920. B/D GP0 history totals reached 1,180,535 commands, beyond the 1,048,576-entry capacity; C remained zero/zero. Work counters matched within each candidate comparison. This is a workload/wrap witness, not a new byte-level checkpoint at frame 1920.
| Comparison | Baseline wall ms (three runs) | Candidate wall ms (three runs) | Median VBlanks/s B -> candidate | Median throughput change |
|---|---|---|---|---|
| GP0 gate | 7102.496, 7222.937, 7202.571 | 7108.128, 7020.108, 6990.751 | 249.911 -> 256.406 | +2.60% |
| PCM gate | 7295.579, 7127.430, 7366.212 | 6982.187, 7070.005, 6977.142 | 246.725 -> 257.799 | +4.49% |
Within-pair throughput changes: GP0 -0.08%, +2.89%, +3.03%; PCM +4.49%, +0.81%, +5.58%. Fastest-run throughput changes: +1.60% and +2.15%. PrivateUsage fell in every pair: GP0 by 105.18, 106.13 and 106.69 MiB; PCM by 63.12, 61.83 and 63.25 MiB.
Compiler activity was observed in two runs: GP0 pair-one C (32 observations)
and PCM pair-one B (30). Observed names included cc.exe, cc1.exe,
cmake.exe, collect2.exe, g++.exe, gcc.exe, ld.exe and ninja.exe.
The monitor covers the full process lifetime, not precisely the measured
frame window. No monitor errors occurred. All runs remain in the report;
no post-hoc removal of the slower/contaminated runs was used. Classification:
exploratory_contaminated. High performance power plan before/after;
thermal state was not measured.
Evidence:
.local/run_uncapped_history_long_ab.py, SHA256459c852c71fd0f4c927a331a91867566704e1fb811b4f2be38fb1a55db6a19d9..local/game-uncapped-history-long-ab/campaign.json, SHA256f71891ad99b20ab5bb1f2e148931494c90951f713d25c8ddd6d4107b436007e7..local/game-uncapped-history-long-ab/power_plan.json, SHA2567f115cc8e9fa6998f4e01f557098113881fbe2b1264f0434060fd0621a7179a0.
Root reviewed the longer driver's delta: only window/frame-count/FPS numerator, output path, metric labels and timeout differ from the short driver. Synthetic checks accepted a correctly converted 1,800-frame observation and rejected the old 300-frame observation. Root recomputed paired changes from raw results.
Disposition
Uncapped benchmarking is useful here: it exposes approximately 250 guest VBlanks/s of throughput instead of hiding spare capacity behind the 60 Hz limiter. Both passes suggest modest gains, but run variation and the longer pass's contamination prevent claiming a reliable general speedup. These are not additive gains or evidence that Crabby Beach slowdowns are fixed.
Reduced process private commit is consistent across all twelve candidate pairs. Together with focused parity and the three exact guest checkpoints, this supports retaining the candidates in the isolated burndown branch for further qualification. Normal-speed audio/pacing, constrained-host comparisons, multi-title correctness and actual low-end hardware remain open. Do not ship the local uncap hook as a gameplay default.
MANUAL-INTEGRATION-004: user sign-off and master integration
Date: 2026-09-05. The user reviewed the Tomba 2 and Mega Man X6 manual builds, reported that they "look good", and explicitly authorized committing and merging the work to main/master. This is user acceptance of the supplied test builds, not an instrumented audio comparison, full-title playthrough or a new performance measurement.
Both manual builds used the combined guards from 04371d60, normal pacing,
OpenGL, recomp-ui, production debug-tools OFF, rewind ON, existing generated
game/BIOS code and isolated copied memory cards. Recomp-ui displayed verified
discs with BIOS paths supplied. Final executable SHA256 values:
- Tomba 2:
6d978d8e2a736aa8b94cb076091117edbe76f6fa7c7f061df227233be8a648ad. - Mega Man X6:
4c99e7a6092122b6675daf83f52eddb76a71b0b5290b474c7f4d494df84135b2.
The initial Tomba build disabled rewind to bypass a dependency lookup; review
rejected that workaround and the final build restored rewind. Mega Man X6's
older recomp-ui headers were incompatible with the runtime, so its manual
build used the compatible Tomba 2 recomp-ui checkout. Neither original game
installation was edited. Local build logs/settings/screenshots remain under
the original burndown worktree's .local/manual-validation directory.
Integration uses origin/master at 17f49ad3 as its base. Only the six campaign
commits 6488414a, d38f97e1, 8ec6498d, 28e9c844, 0cf93d57, and
04371d60 were transplanted; the older review-branch ancestry was excluded.
All six applied without conflicts. The runtime delta remains only the three
production diagnostic guards; benchmark uncapping and local game artifacts
are not part of the merge.
The first integration GPU test failed because its old polyline fixture supplied only one vertex before the terminator. Upstream now correctly requires two vertices. The fixture now supplies both; the upstream runtime fix is unchanged. On the integrated sources, all three actual-source guard regressions and the 63 campaign/host/stall-report tests pass. The previously tested game executables are not rebuilds of this newer upstream base; no such equivalence is claimed. The CMake registration guard also passes with 133 test files registered.
Disposition: user-approved integration of the scoped optimizations, tests and measurement tools. The original WIP label records the historical state at implementation time. The broader burndown, general speedup qualification and actual low-end hardware coverage remain open after this merge.