Repository navigation
Runtime: the game's render thread on the reserved core (HOS_PIN_RENDER=0: off) - #1034
Merged
Merged
Conversation
…R=0: off) hos_reserved_cpus keeps the last physical core free of the game's threads for the Vulkan back end's replay thread, which exists only with RX_VK_ASYNC=1. In the default synchronous mode the replay runs on the thread that submits, and the core stayed empty. OoT's "Presentation Thread" submits 4 of its 6 queues, so most of each frame's replay is on it: it now gets the reserved core (the mask hos_reserved_cpus works out, so any CPU with 8+ logical processors), and it alone. No core is taken from the game that was not already. Not with RX_VK_ASYNC=1 (the replay thread's then); HOS_PIN still decides over it. Ryzen 9 3900X, Kokiri Forest, the same as HOS_PIN=Presentation=C00000 measured: the replay ~24 -> ~22 ms a frame, 34 -> 36 fps, in two runs each. Assisted-by: Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jordanella
added a commit
to jordanella/Hookshot
that referenced
this pull request
Nov 9, 2026
…e thread's own processor group; the replay pin on Windows only Review of NotRexed#1158: - A hybrid CPU with few performance cores (i5-1235U: 2 of them and 8 efficiency cores) kept one of its two from the game. pick_reserved_core now wants 4+ cores of the fastest kind, and 8+ logical processors as before (a CPU of one kind with 8+ has 4+ cores); else none is kept: on an efficiency core the replay was slower than on no reserved core at all (NotRexed#1158: an i7-14700KF, an i7-13700K). - The cores were group 0's; the affinity calls' masks are the calling thread's group's (GetThreadGroupAffinity). - On Linux a thread made inside a pinned replay inherited the pin (the capture's copy helpers, the shader workers, the pool imports, ... are made on first use), and the fastest-kind choice is Windows-only: replay_pin_mask is 0 there, as before NotRexed#1034. - tests/test_reserved_core.py is in run_all.py's table (g++), and checks the thresholds: the hybrid laptop CPUs, Lunar Lake, CPUs under 8 logical processors. Assisted-by: Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
In the default synchronous mode (
RX_VK_ASYNCunset), the Vulkan back end replays each submission on the game thread that submits it. In OoT that is mostly the "Presentation Thread", which submits 4 of the 6 queues. Meanwhilehos_reserved_cpus()keeps the last physical core free of every game thread for the async replay thread, which only exists withRX_VK_ASYNC=1. So on any machine with 8+ logical processors that core sat empty, and the replay shared cores with the game's threads.This change gives the Presentation Thread the reserved core, and that thread alone. The mask is the one
hos_reserved_cpus()already works out, so nothing is CPU-specific and no core is taken from the game that wasn't already reserved. It is skipped withRX_VK_ASYNC=1, where the core belongs to the replay thread, andHOS_PINstill takes precedence.HOS_PIN_RENDER=0turns it off. The log says once which processors it got.Measured on a Ryzen 9 3900X (12 cores / 24 threads, 4 CCXs) with an RTX 3080 on Windows 11. Kokiri Forest, standing still after loading a save, headless, input timed in game frames (
HOS_INPUT_FRAME_CLOCK=1), the same route every run, live numbers over presents 3120-5520:submitphase)Every replay phase got faster by about the same fraction, which fits contention rather than any one piece of code: the same frame replayed in isolation (
RX_VK_BENCH) was ~25% faster than during play before the change. Giving more threads cores of their own (MainThread, or a whole CCX for the two) measured within noise of this, and so did raising the thread's priority.Not measured: CPUs with 6 or 8 physical cores, where the reserved core is a bigger share of the machine. The reservation itself is unchanged by this PR, though, so the trade is the same as today's: the core was already kept from the game.
The numbers were measured on v2.0.5 (232eecb). The branch is rebased onto main 3b4347d; the rebase did not change the patch (
git range-diffshows it identical), andhost/hos_thread.chas no upstream changes since.python -I -B tests/run_all.py: 104 passed, 3 failed, 13 skipped on Windows. The three failures (test_changelog.py,test_fps_overlay_order.py,test_precompile_compute_guard.py) fail the same way on main 3b4347d on this machine.🤖 Generated with Claude Code