Skip to content

feat(scripts): hookshot_bench.py, a repeatable benchmark route through the control bridge - #2714

Open
Waryxxful wants to merge 1 commit into
NotRexed:mainfrom
Waryxxful:feat/bench-script
Open

Waryxxful wants to merge 1 commit into
NotRexed:mainfrom
Waryxxful:feat/bench-script

Conversation

@Waryxxful

Copy link
Copy Markdown
Contributor

Why. Most performance PRs say "not tested in the game yet", and the reports that do test can't be compared, because each tester stands somewhere else for a different time. #2595 asks for a repeatable route through the control bridge. This is one, run on real hardware: last night it measured six open PRs and five switches on an RX 5600 XT.

What it does

scripts/hookshot_bench.py GAME_DIR --name NAME [--save DIR] [--env NAME=VALUE]...

  1. Starts the game folder with the bridge on (hookshot_ctl.py launch), with the switches given.
  2. Waits for frame 1 in 50-minute steps, up to 8 h, because the bridge answers a wait within the hour and a first start's preparation can take longer: 1.6 h of pipelines on the RX 5600 XT.
  3. Presses A until the newest save is loaded.
  4. For each place (default KokiriForest_Child, HyruleField_Child): teleports there, waits until no event or load plays, settles 15 s, then measures 60 s standing.
  5. Takes a screenshot of each place, quits, and writes summary.json. For each place it holds the medians of the log's N presents fps and draws, GPU time, every part of replay time (ms), the highest VRAM used, the bridge's fps, the process's memory, and the share of the window an event played in.

Two things found the hard way, handled

  • The game saves by itself as it plays. A slot is rewritten in each run, and Continue loads the newest, so the second run started somewhere else. --save DIR (with --slot) starts every run from the same save:
    • Windows: the folder's user/save is set aside and put back after the game has closed.
    • Linux: launch --save copies it into the run's own data folder.
  • A message can wait for a button. The wake-up cucco hatches by the game's clock, and its message held a run in an endless "event". An event that lasts 8 s is closed with A, before the window and in it, and summary.json counts the presses.

Tests

  • tests/test_hookshot_bench.py (16 checks, no game, no socket) runs against a stand-in bridge on a fake clock:
    • the log sums from lines in the game's own format;
    • the first-frame wait going on after timeouts and giving up;
    • A until a save loads;
    • a refused teleport waited out;
    • no map wait when already there;
    • messages closed with A in both places;
    • saves_in setting aside and putting back, and refusing a folder with no slots or one left from an earlier run;
    • process memory and liveness on Windows and Linux.
  • python -I -B tests/run_all.py on Windows: the new check passes; the same 14 checks fail with and without this change (audio, menu i18n, docker packages, ... on this Windows box), none in files it touches.
  • In the game: Windows 11, RX 5600 XT, main de866017, the script itself with --save. Kokiri Forest 33.2 fps, Hyrule Field 35.1, which matches the local version that ran 23 times last night. The saves were back in place afterwards.

docs/control.md gets a "A benchmark route" section. Its Known limits now say the bridge has been driven inside a Windows game build (launch, status, wait, press, teleport, shot, quit), which it had not been before.

🤖 Generated with Claude Code

…h the control bridge

The same places, settling time and measurement window every run (teleport to Kokiri Forest
and Hyrule Field, settle, measure 60 s standing), summed from the game's own log lines into
summary.json: fps, draws, GPU time, every part of the replay time, VRAM, the process's memory.
--save starts every run from the same save (the game saves by itself as it plays, and Continue
loads the newest); a message that waits for a button is closed with A. Waits out a first
start's preparation in 50-minute steps (the bridge answers a wait within the hour).
tests/test_hookshot_bench.py runs the route against a stand-in bridge on a fake clock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@Joey-Magnus Joey-Magnus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I merged this into current main and ran tests/test_hookshot_bench.py, and all 16 checks pass. The log patterns match the lines main prints today: vk_replay.cpp:3112 and 3143, and vk_texture.cpp:4322. I read saves_in carefully because it moves user saves. A failed copy restores the folder. put_back runs after wait_exit, and if the rename back fails, the original is still in user/save.hookshot_bench, which the next run refuses to overwrite. So I don't see a path that loses the player's saves.

One thing I'd change before merge: the default run folder is bench-runs/- under the current directory (scripts/hookshot_bench.py:258). It holds game screenshots and the full log, and bench-runs/ isn't in .gitignore. Someone running it from the checkout root is one git add -A away from committing game-derived images, which CONTRIBUTING.md forbids. Defaulting under work/ (already ignored) or adding bench-runs/ to .gitignore would close that.

Nice that this gives the perf PRs a common route. #2709's and #2708's numbers would be easier to compare with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants