mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-27 10:38:46 -04:00
631 lines
35 KiB
Markdown
631 lines
35 KiB
Markdown
# Performance experiment ledger
|
|
|
|
Campaign: [OpenGL performance campaign](../PERFORMANCE_CAMPAIGN.md).
|
|
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
|
|
with `PSX_DEBUG_TOOLS=ON`. Existing report identifies build
|
|
`v0.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 wordsum
|
|
`F67ECB99`, entry `800A3660`, codegen hash `A4319B6F`, ABI 21, codegen version 10.
|
|
SHA256 `2dfc142e65eb32e179b67d352f510d15f6d97efd22b3b43a9eef24301f3ad5a9`.
|
|
- 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_status` generation advanced from 0 to 1 with
|
|
`pending=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/scph1001` slots 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](TOOLS.md).
|
|
|
|
## 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](RUNTIME_AUDIT.md#validation-gaps).
|
|
|
|
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 in
|
|
`PSX_NO_DEBUG_TOOLS` builds. 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`, SHA256
|
|
`459c852c71fd0f4c927a331a91867566704e1fb811b4f2be38fb1a55db6a19d9`.
|
|
- `.local/game-uncapped-history-long-ab/campaign.json`, SHA256
|
|
`f71891ad99b20ab5bb1f2e148931494c90951f713d25c8ddd6d4107b436007e7`.
|
|
- `.local/game-uncapped-history-long-ab/power_plan.json`, SHA256
|
|
`7f115cc8e9fa6998f4e01f557098113881fbe2b1264f0434060fd0621a7179a0`.
|
|
|
|
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.
|