Repository navigation
perf(agc): share unchanged shader registry chunks between published versions - #7288
Merged
oneandonlydean merged 1 commit intoOct 18, 2026
Merged
Conversation
…ersions PublishRegisteredShader copied the whole code-address map, with every header vector and snapshot reference, for each registration under the driver mutex, so a title registering its shaders while it loads paid O(n^2). The registry now keeps its entries in address-ordered chunks of at most 64 shared by every version that has not changed them; a write clones only the chunk it touches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
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.
|
9 tasks done
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.
What
PublishRegisteredShaderpublishes each registration as a new immutable registry. In-flight submissions keep the version they were enqueued with. To do that it copies the wholestd::mapof code addresses, every node, every header vector and every snapshot reference, under the driver mutex. The old version is freed node by node once its last reader drops it. So registrationncosts O(n), and a title that registers its shaders while it loads pays O(n²) overall.ShaderRegistrybecomes a small class with the same interface the driver and tests use (find,upper_bound,contains,at, bidirectionalconst_iterator,operator[],emplace,erase,clear). It keeps its entries in address-ordered chunks of at most 64 entries, held byshared_ptr. Copying a registry copies only the vector of chunk pointers. A write clones only the chunk it changes, and only when another version still shares that chunk. A chunk that grows past 64 entries splits in half.PublishRegisteredShaderitself is unchanged: it still copies the registry and edits the copy, so earlier versions stay as they were.Lookup order and results are those of the map.
RegisteredProgramand the draw keys still find the greatest code address at or below an address throughupper_boundand--.Tested
Linux (Ubuntu 24.04, GCC 13.3, Release), RTX 4070 Ti, NVIDIA 595.99.02;
main6447ed1.agc_driver_prepared_publication, newRegistryVersions:upper_bound,findandcontainsmust match astd::mapat and around every address.With
main'sShaderRegistry.hpp/.cppit fails 3 of 3 withpublishing a shader copied the registry's entries for other code addresses. With this change it passes 3 of 3.ctest
^agc_(671 tests): all pass.A local benchmark (not in the PR) publishes N shaders at random addresses through
PublishRegisteredShader, holding a few earlier versions as submissions do:mainmain82cad6b and this PR on it. A local print (not in the PR) logged the registry's size at every 1,000 code addresses, timed from the first registration. The title registers about 2,000 shaders at start-up and the rest in a burst starting about 60 s after the first registration.mainunsupported registered shader type 8lines, distinct addresses)The difference in presents is in the first 10 s, the loading screen (0.2 ms of GPU work per present): 53 and 54 on
main, 19 and 18 with this PR. I haven't looked at why.Shader.Registeris aPerformanceTimerscope, but the trace records only the threads that bind a trace buffer (AnyPS5, the queue workers,shader prepare,presenter). Forspoken registers from its own threads, so no trace window has that scope:APS5_TRACE_SECONDS=0:60and45:40held none on either build. That's why the registration timing above comes from a local print. The summary lines of a45:40window (45 to 85 s after the first present) from two interleaved rounds of 100 s (main922dc89, this PR's code on it at 0b1f9c6d9e, noAPS5_PROFILE_*switch):The type 8 headers registered within those 100 s runs were 1,826 and 2,294 on
mainand 2,726 in both runs with this PR.check_conventions.pypasses.pr_overlap.pycouldn't compare five conflicting PRs that edit the same two files ([HOLD] perf(agc): pre-warm deferred shaders on SET_SH_REG packet execution #5115, feat(agc): trace shader failures through draw submission batches #5431, feat(shader): sample converted unorm images in the shader #5958, fix(agc): name preparation-failure shader dumps apart from dispatch captures #6134, perf(agc): compile uncached draws ahead of queue 0 #6188). Of the open PRs it could compare, none changes the registry type. A PR that calls astd::mapmember this class doesn't have would need that member added.Not checked on Windows, macOS, AMD or Intel.
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code