Skip to content

fix(agc): keep hundreds of raw shader snapshots cached - #10174

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
ntamas94:fix/agc-raw-shader-cache-eviction
Oct 26, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
ntamas94:fix/agc-raw-shader-cache-eviction

Conversation

@ntamas94

@ntamas94 ntamas94 commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What

ReadRawShader caches snapshots of unregistered shader programs and evicts the least recently used one past 64 entries or 8 MiB. Each snapshot owns its prepared artifacts (snapshot.prepared), so an evicted program loses them, and its next use reads a new snapshot and prepares it again (was not registered; preparing its artifact at first use).

PS4 titles never register their shaders, so every program they draw with goes through this cache. Knowledge is Power (CUSA09558) uses 383 programs in its menus: with 64 entries the cache cycled through all of them and prepared them 341 136 times in a 240 s run, about 890 per program.

This raises the limit to 4096 entries or 64 MiB. The existing eviction check in tests/Submit.cpp now reads 400 more programs and requires the first one to keep its snapshot, then reads past 4096 and requires it to be evicted. The new check fails with the old limit.

Related open PRs, neither of which changes the limit:

Tested

Windows 11 Pro 10.0.26200, NVIDIA GeForce RTX 2080, driver 617.14.

  • agc_driver, agc_driver_readonly_resummarize, agc_driver_eop_interrupts, agc_driver_small_copy_sync on main (8eb8e39) and on this branch with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ANYPS5_NO_SHADER_CACHE=1, ANYPS5_REQUIRE_VULKAN=1 and ctest -V: all pass on both, neither log reports was not found but was requested by env var VK_INSTANCE_LAYERS, and neither has any VUID- error.
  • With the limit set back to 64, agc_driver fails with raw shader cache evicted a program while a title used only 401.
  • Knowledge is Power (CUSA09558), intro, then Cross every 15 s through APS5_PAD_INPUT_FILE into the menus, 240 s, with and without this change. It needs open PRs that main does not have yet (see Knowledge is Power: Decades (CUSA12435) #9718), so both runs used the same local stack and only libSceAgcDriver.prx differed:
before after
preparing its artifact at first use/dispatch lines 341 136 383
distinct programs 383 383
presents per 10 s in the menus (APS5_PROFILE_GPU) about 120 about 147

These are profile-log numbers from that stack, not a performance trace of main, so this is not a perf claim. One of two runs with the change stopped presenting after about 30 s (no crash event, ended by the timeout); the repeat ran the full 240 s. I don't know the cause or whether the run without the change can do the same.

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 (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none (measured on CUSA09558's menus; Knowledge is Power: Decades (CUSA12435) #9718 is the thread of Knowledge is Power: Decades, CUSA12435, not measured there yet)
  • GPUs tested: NVIDIA GeForce RTX 2080, driver 617.14, Windows 11 Pro 10.0.26200
  • AI-assisted: yes

ReadRawShader evicted snapshots past 64 entries or 8 MiB. A snapshot owns
its prepared artifacts, so an evicted unregistered shader was recompiled
on its next use. PS4 titles do not register their shaders: Knowledge is
Power cycles through 383 of them in its menus and recompiled them 341 136
times in 240 s. Raise the limit to 4096 entries or 64 MiB.

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

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

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 5115 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 6977 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 7642 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 7682 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 8592 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 9431 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 9432 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 9508 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 10193 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp

@MarcZX10 MarcZX10 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.

Reviewed exact head e284395f586dda6808250210cb225aef4df8021e. The snapshot list is refreshed on equal-content hits, so the raised limits preserve the existing LRU behavior; the updated test checks both retention through 401 programs and eviction after crossing 4096. The author also reports controlled before/after Windows GPU runs and that the new test fails when the old 64-entry limit is restored. Eligibility, conventions, intake, labels and report pass, while hosted product jobs are skipped by path policy. I commented separately on #10103 because its 80-entry churn will no longer force eviction after this limit change; that is a coverage interaction for the stacked change, not a correctness blocker in this PR.

@ntamas94

Copy link
Copy Markdown
Contributor Author

Measured on Knowledge is Power: Decades (CUSA12435) as well, the title of #9718. Two builds on today's main plus the same local stack, differing only in the ShaderRegistry.cpp limit line: A = main (64 entries / 8 MiB), B = this PR (4096 / 64 MiB). Four 230 s runs each, alternating A/B, the last one of each with a thread sampler. Windows 11 Pro 10.0.26200, RTX 2080, driver 617.14.

run was not registered; preparing its artifact at first use lines distinct programs load (s) presents / 10 s, 100–140 s presents / 10 s, 170–225 s (title / menu) result
A-1 403 407 505 27.5 151.8 159.1 ok
B-1 548 505 25.7 195.7 220.3 ok
A-2 433 176 505 25.9 155.9 164.8 ok
B-2 548 505 25.4 195.8 223.4 ok
A-3 28 495 496 – 0 0 stopped presenting at 88 s
B-3 548 505 25.4 197.3 222.7 ok
A-s 439 749 505 25.1 156.0 167.1 ok
B-s 548 505 25.6 192.5 219.3 ok
  • With this PR every program is prepared about once (548 lines for 505 programs); with 64 entries the cache cycles and prepares them about 800 times each.
  • The stall you saw once came up here only without the change: in A-3 the frame counter stops at 88.4 s, then only Forcing submitDone to avoid TRC R4089 breach every 3 s. Just before it, the same five shaders log recompiling with that dimension twice in a row; A-3 has 963 such lines, B-3 46. A likely mechanism, not proven: the GCN image-dimension notes live on the snapshot, so a snapshot evicted at 64 entries comes back without them. None of the four B runs stalled.
  • Sampled cost of ReadRawShader on the packet thread: about 20.7 % with 64 entries (mostly re-decoding and re-encoding after misses), about 7.2 % with this PR. The cache's linear std::list search stays under 1 % of that thread with up to 505 entries, so an index is not needed for this title; about a third of the remaining ReadRawShader time is the ZwQueryVirtualMemory call behind the committed-range check.

These are profile-log numbers from a local stack, not a trace_digest pair of main, so they are evidence for the fix, not a perf claim. Logs and the sampler output are available if you want them.

🤖 Generated with Claude Code

@oneandonlydean oneandonlydean self-assigned this Oct 23, 2026
@oneandonlydean
oneandonlydean merged commit 426e1db into boykopovar:main Oct 26, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc*

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants