Skip to content

feat(libkernel): support cpuset affinity by guest thread ID - #6540

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
JJenkx:fix/kernel-cpuset-thread-id
Oct 17, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
JJenkx:fix/kernel-cpuset-thread-id

Conversation

@JJenkx

@JJenkx JJenkx commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

What

With CPU_LEVEL_WHICH / CPU_WHICH_TID, cpuset_getaffinity and cpuset_setaffinity currently throw when the requested TID belongs to another live guest thread. Resolve that guest TID in the live-thread registry and read or update the selected thread's affinity. Lookup and access hold the registry lock so removal and release cannot pass between them; a thread that exits before the setter's final lookup returns ESRCH.

The worker observes the new affinity, sceKernelGetCurrentCpu reports a CPU within it, and a subsequently created child inherits it. The calling thread's mask stays intact. Existing mask validation, process-wide operations and unsupported ROOT/CPUSET levels remain covered.

Thread selection follows FreeBSD 11.4 cpuset_which and kern_cpuset_getaffinity/kern_cpuset_setaffinity. This expands the existing guest affinity model: affinity is recorded for guest CPU reporting and inheritance, not applied to host scheduler affinity. PS5 hardware behavior is unmeasured; the library debt entries record the remaining limits. No new exports or title/FPS gain is claimed.

Tested

Arch Linux, Ryzen 9 7950X, Release, bundled dependencies, main 44df21632125dbe3113a19173e7ebb879da53003.

  • Full libs build passed. Seven checks passed, zero skips: guest_available_cpumask, guest_current_cpu, guest_pthread_start, guest_thread_cpu_clock, guest_pthread_join_self, guest_pthread_destructor_lifetime, guest_pthread_attr.
  • Expanded affinity regression checks another live TID with 8- and 32-byte masks; zero padding and an output-tail guard; available-CPU clipping; rejected masks leaving the target intact; caller isolation; worker-visible affinity/current CPU; child inheritance; and ESRCH with an untouched output after join. Existing self/process, invalid argument and unsupported-level checks remain.
  • Negative control: updated regression on main aborts at cpuset_getaffinity other than the calling thread or process not implemented.
  • Targeted setter negative control: reporting success without updating a non-calling thread fails the expanded regression. Restoring the setter passes all seven checks. Test executable SHA-256 is unchanged across fixed / targeted-fault / restored runs: 60798920d5b6c0d174f72ad27b17f7d62806b9891b2c40f5d52b35161f78d452.
  • Conventions, test registration and whitespace checks passed. No Windows, native-title or PS5 hardware run.

External Windows validation

screamm’s independent report tests head 7777219ee merged onto main 5d9dcc42d, using Windows11, Ryzen75700X, RTX4070 and MinGW GCC15.2. Runtime libraries build, and the seven affinity/thread checks pass three repetitions (21runs). Parent-source and no-op-setter negative controls fail; restoration passes. Their broader build still encounters main’s known MinGW64KiB-alignment AGC test issue. Reported load-related non-GPU test failures pass on serial reruns; this is not a new full-suite pass claimed here.

Their diagnostic title runs reach only the calling-thread query path. No title exercises another-thread affinity, and the timed runs end by termination. No title unblock, ordinary-close stability or FPS improvement is established. These are contributor-reported Windows results, separate from our Linux checks above.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw; no silent stubs added
  • No notes, investigation .md files or images added to the repository
  • New third-party code is a submodule built from source (none added)
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 6908 docs/dev/debt/libkernel.md L149-151
PR 7135 core/libs/prx/libkernel/Pthread/Posix/Thread.cpp L63-69, L76-80, L101-106, L119-120
core/libs/prx/libkernel/Pthread/include/Pthread.hpp L165
core/libs/tests/GuestAvailableCpumask.cpp L319-321
docs/dev/debt/libkernel.md L150-151

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 3986 core/libs/prx/libkernel/Pthread/src/Thread.cpp
PR 5021 core/libs/prx/libkernel/Pthread/include/Pthread.hpp
core/libs/prx/libkernel/Pthread/src/Thread.cpp
docs/dev/debt/libkernel.md
PR 6044 core/libs/tests/GuestAvailableCpumask.cpp
PR 6222 core/libs/prx/libkernel/Pthread/include/Pthread.hpp
core/libs/prx/libkernel/Pthread/src/Thread.cpp
docs/dev/debt/libkernel.md
PR 6447 core/libs/prx/libkernel/Pthread/Posix/Thread.cpp
PR 6510 docs/dev/debt/libkernel.md
PR 6710 docs/dev/debt/libkernel.md
PR 6962 docs/dev/debt/libkernel.md
PR 7201 core/libs/prx/libkernel/Pthread/src/Thread.cpp

@screamm

screamm commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Windows run of head 7777219ee, merged alone onto main 5d9dcc42d (clean merge).

  • Host: Windows 11 Pro 26220, Ryzen 7 5700X, RTX 4070 (driver 596.21), WinLibs MinGW-w64 GCC 15.2.0 r7, Ninja, Release.
  • Build: everything builds except the known MinGW 64 KiB alignas AGC test (test(agc): align the indirect arguments block at run time #6452/fix(agc): allocate indirect arguments test block dynamically on Windows #6478), and libs passes. The only warning in Posix/Thread.cpp (rtprio_thread, -Wreturn-type) also appears on main.
  • --repeat until-fail:3, 21/21 runs: guest_available_cpumask, guest_current_cpu, guest_pthread_start, guest_thread_cpu_clock, guest_pthread_join_self, guest_pthread_destructor_lifetime, guest_pthread_attr.
  • Negative controls:
    • With the three Pthread sources from main and the test kept, the test aborts with cpuset_getaffinity other than the calling thread or process not implemented.
    • With the setter returning success without storing for a thread other than the caller, the test aborts on a Require.
    • With the sources restored, it passes.
  • Non-GPU suite (ctest -j8 --timeout 120 -E '^agc_driver_|^video_out_flip'): the host was heavily loaded by other builds, so 19 tests timed out or aborted on the first pass. All 19 passed on serial reruns. guest_kqueue, guest_file_lock_process and guest_video_out_high_frame_rate passed on the first rerun, and the conventions_function_bodies shards and hardware_oracle_compare on the second.
  • tools/check_conventions.py --base 5d9dcc42d and git diff --check pass. There are no new exports.

Titles. In the relinked titles I have, cpuset_getaffinity is imported by PPSA99002, PPSA99008 and PPSA99082, and cpuset_setaffinity by PPSA68091, PPSA97358, PPSA99002, PPSA99008 and PPSA99203. I ran all six for 45 s with a local diagnostic libkernel that logs these calls. Only OpenNOW PPSA99082 calls cpuset_getaffinity, 6 times, all with level=3 which=1 id=-1 (the calling thread). No title calls cpuset_setaffinity in that window, and none passes another thread's TID, so the new path is not reached by any title here. The calling-thread path now goes through the registry lookup, so I ran before/after on PPSA99082, and on PPSA99008, which imports both. Each run was 130 s, with 2 alternating runs per side. Neither side has a stop line, and every run was killed at the time limit:

main r1 / r2 this PR r1 / r2
PPSA99082 frames (FPS at the end) 2629 (19.0) / 2658 (20.4) 2516 (20.2) / 3213 (19.4)
PPSA99008 frames (FPS at the end) 7530 (59.9) / 7390 (59.4) 7393 (59.5) / 7435 (59.9)

PPSA99082's logs are the same on both sides apart from pointers and paths.

Not checked: Linux, PS5 hardware, and any title that sets or queries another thread's affinity (none available here). #6447 edits the same cpuset_* lines in Posix/Thread.cpp.

Written with Claude Code assistance (validation by a subagent, reviewed in this session).

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants