WIP: fix(host): the core kept for the replay is one the process may run on #522
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!522
Loading…
Reference in a new issue
No description provided.
Delete branch "HumanBean/Longshot:fix/reserved-core-affinity"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
When the game is kept to some of the PC's processors (taskset, a launcher's affinity, a container), the core Longshot keeps for the replay could lie outside them. The replay then ran on a processor the game was not meant to use, beside whatever else was there.
What changed
hos_reserved_cpus()'s fallback inhost/hos_thread.ccounts only the cores whose logical processors are all in the process's affinity mask, and keeps the last of those (none under 8 allowed logical processors, as before). With every processor allowed nothing changes. The hybrid path (last_fastest_core) is as it was, andHOS_RESERVE_CORE_MASKstill overrides.tests/test_reserved_core.pychecks the fallback's condition in the source.It follows #445 (the replay on the reserved core on Linux too), whose measurements this skewed: the correction is in #445 (comment).
Flags and settings
None new.
HOS_RESERVE_CORE_MASK=<hex>(existing) still names the core by hand.Measurements
A fix, shown by the log line and the frames that failed before; not a performance change on a PC where the game may use every processor (the reserved core is the same one there).
The change was built and run as this commit's patch applied to the local test merge 318acabe (the same
hos_reserved_cpuscode; the hunk applied 10 lines lower), not as a build of this branch alone. Before and after, sessions kept to CPUs 0-5 and 12-17:Hardware: RTX 3090, NVIDIA 620.70.06, Ryzen 9 7900X, 32 GB, CachyOS (Linux 7.3.3)
Scene: Castle Town Market, the sessions of #445's measurements, kept to CPUs 0-5 and 12-17 with
sched_setaffinityMethod: the game's log and
RX_VK_FRAME_LOGframe timesHow to reproduce:
taskset -c 0-5,12-17 ./longshoton a CPU with more cores than that, a build running on the others; read the log'sreserved core maskline and the worst frameHOS_RESERVE_CORE_MASK=20020(where the fix now puts it by itself)reserved core mask (fallback): 0x800800(CPUs 11, 23: outside the session's)replays run on logical processors 0x20020 while they replay(CPUs 5, 17: inside)What this did to measurements is in #445 (comment): with the pin outside the set, standing in the Market measured +9 %; with it inside, +4.5 %. Some of those sessions also had frames of several seconds; they came with heavy swapping and also occurred with the core inside the set, so they are not shown to be this and are not claimed here.
With the fix, the same kind of session and no override:
0x20020 is CPUs 5 and 17, the last core of the session's own set.
Testing
Tested: in the game on Linux (RTX 3090, NVIDIA 620.70.06, Ryzen 9 7900X, CachyOS): one session kept to CPUs 0-5 and 12-17, built from the local test merge 318acabe with this commit's change applied; the log shows the reserved core inside the set (above), the game reached the Market and ran the route. The game-free checks were not run locally (CI runs them).
Not tested: a build of this branch alone. A session with every processor allowed on the fixed build (the code keeps the last core as before when no processor is excluded; read, not run). Windows (the same code path:
GetProcessAffinityMaskandGetLogicalProcessorInformation). CPUs with performance and efficiency cores (their path is unchanged). A PC with more than 64 logical processors (only the first group's mask is read, as before).Needs other testers: None
Screenshots
Nothing on screen.
Risk and rollback
On a PC where the game may run on every processor the choice is the same as before. A process kept to fewer than 8 logical processors now has no reserved core where it had one outside its set before; that is the intent. Reverting the commit restores the old choice;
HOS_RESERVE_CORE_MASKandHOS_RESERVE_CORE=0override it either way.Reviewer notes
The whole change is the affinity mask read and one condition in the loop over the cores.
Issues
None
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above). Not run locally: waiting for CI.third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.tests/that reads changed source updated in this PR, not weakened.🤖 Generated with Claude Code
https://claude.ai/code/session_017vw8e34avQ5cTCWow16MXn
hos_reserved_cpus' fallback took the last core of every logical processor the PC has. A process kept to some of them (taskset, a launcher's affinity) then had its replay pinned outside its set, which a thread may leave: the replay thread (RX_VK_ASYNC) and every synchronous replay under RX_VK_REPLAY_PIN ran beside whatever else was there. Seen on a Ryzen 9 7900X, Linux: sessions kept to CPUs 0-5,12-17 with sched_setaffinity logged "reserved core mask (fallback): 0x800800" (CPUs 11 and 23, the other CCD) and replayed there. With builds running on that CCD the replay thread was starved: frames of 2-8 s ("slow present: 4818.7 ms", "vcores: ... ran without a core after 4713.8 ms"); with none it had a 13th core the session was not meant to have, so timings of anything that moves work onto that core were off either way. With HOS_RESERVE_CORE_MASK=20020 (CPUs 5 and 17, inside the set) the same sessions had no such frames (worst 42 ms). Now the fallback counts only the cores whose logical processors are all in the process's affinity mask, and keeps the last of those (none under 8 allowed logical processors, as before). With every processor allowed nothing changes. The hybrid path (last_fastest_core) is as it was. HOS_RESERVE_CORE_MASK still overrides. Not built and not run: a host change needs a game build. tests/test_reserved_core.py checks the fallback's condition in the source. Co-Authored-By: Claude Fable 5.2 <[email protected]> Claude-Session: https://claude.ai/code/session_017vw8e34avQ5cTCWow16MXn53d2c2bd6c63976e479cThe commit's message and the description no longer attribute the multi-second frames of the test sessions to this: they also occurred with the core inside the set and came with heavy swapping. What is shown is where the replay ran (the log lines) and what that did to the timings of #445.
Built and run: with the change, a session kept to CPUs 0-5 and 12-17 and no override logs
reserved core mask (fallback): 0x20020(CPUs 5 and 17, inside the set) where it logged 0x800800 before. Built as this commit's patch on the local test merge 318acabe, not as this branch alone; the description says so.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.