Skip to content

perf(agc): index the resource cache by a four-lane key hash - #6972

Open
meh7an wants to merge 1 commit into
boykopovar:mainfrom
meh7an:perf/agc-resource-cache-key-hash
Open

meh7an wants to merge 1 commit into
boykopovar:mainfrom
meh7an:perf/agc-resource-cache-key-hash

Conversation

@meh7an

@meh7an meh7an commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

What

ResourceCache holds the shader resource objects of draws and dispatches. Its keys are about a hundred words: the device, the stages and their bindings' guest descriptors. Every draw and every dispatch looks one up (Find, or Touch on a recipe hit). The cache indexes its LRU list with an std::unordered_map<Key, iterator, KeyHash>:

  • KeyHash is FNV-1a over every word: one multiply per word, each waiting on the one before.
  • KeyHash is noexcept, so libstdc++ keeps no hash code in the nodes. A lookup's bucket walk hashes the key of every node it passes again, to find where its bucket ends.

The index is now a HashSlotMap (Execution/include/HashSlotMap.hpp) keyed by the key's hash:

  • It uses open addressing in a power-of-two table kept at most half full. A lookup masks the hash, scans a compact array of hashes, and compares the one key it finds.
  • The hash is FNV-1a in four lanes over pairs of words, so their multiplies overlap. The lanes are then folded so that the low bits, which pick the slot, depend on all of them. The hash is taken before the mutex.
  • When two keys have the same 64-bit hash, the newer entry replaces the older one, counted as an eviction.
  • An entry keeps its hash for the evictions (the entry bound and the table element budget) and for RemoveImage.
  • Erasing shifts the entries after it back, so the table has no tombstones.
  • hashSlotMapTests (graphics tests) covers:
    • inserts, a repeated insert, and growth to 1003 keys;
    • erases, including the backward shift of an erase whose probe run wraps past the end of the table;
    • key 0, which is stored as 1;
    • clearing.

On the S2 page of Sonic Origins Plus's main menu, the queue worker spent, per frame (APS5 sampler, 15 s):

  • ResourceCache::Find: 0.52 to 0.27. In a profile of an earlier build, 45 of its 70 samples were its own code, mostly the inlined FNV over the key, and 23 the bucket walk.
  • std::_Hashtable::_M_find_before_node, the bucket walk: 0.26 to 0.06. What remains belongs to other hash tables.

That is about 1.5% of the worker's frame (31 samples).

#6492 adds another walk over the cache's entries that reads it->first and it->second. Whichever of the two lands second changes them to it->hash and it->resources.

Tested

Windows 11 (10.0.26300), WinLibs GCC 15.2.0 (UCRT), Release, NVIDIA GeForce RTX 2080 Ti, driver 617.14.

Metric Baseline This PR Change
frame_ms.p50 100.704 98.072 -2.6%
frame_ms.p90 106.216 101.147 -4.8%
mean_frame_ms 103.202 98.211 -4.8%
gpu_busy_ms_per_present 83.660 83.570 -0.1%
Driver.Packet (ms per frame) 101.155 96.211 -4.9%
Driver.Draw (ms per frame) 89.173 83.863 -6.0%

This pair overstates the change: its target is about 1.5% of the worker's frame, and windows of this page vary by a few percent at the median. The title FPS during the two captures was 10.82 and 11.12. The sampled pair, 10.56 to 10.84 FPS, is the better estimate.

Note: measuring base. These numbers come from my fork's dev, on main 0a56aaa. The resource cache this change indexes is the same on main 7d728b1, which adds the table element budget and RemoveImage to it.

Both carry these commits from my fork:

The comparison tool marks the window's first present as a configuration difference: the window opens 200 s into each run. Both summaries set trace_dropped, because the worker filled its event buffer at about 2,700 draws per frame. The phase totals above stay complete.

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
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 2080 Ti, driver 617.14, Windows 11
  • AI-assisted: yes

Traces and summary lines (baseline 245e355, whose summary says b1909f4; this change 557d4da, whose summary says 245e355):
keyhash-traces.zip

@github-actions

github-actions Bot commented Oct 16, 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 1395 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 4040 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5441 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5499 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5500 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5925 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6146 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6177 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6192 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6194 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6202 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6223 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6235 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6280 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6340 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6373 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6412 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6451 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6457 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6479 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6481 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6498 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6535 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6548 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6563 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6572 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6612 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6636 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6639 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6646 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6647 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6661 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6669 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6683 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6708 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6718 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6725 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6730 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6741 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6762 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6772 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6773 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6785 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6801 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6804 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6808 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6820 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6921 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6937 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6944 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6946 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6947 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6982 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7002 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7085 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7154 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7243 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7254 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7256 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7258 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7261 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7310 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7332 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7340 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7390 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7410 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7426 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7484 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7600 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7618 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7627 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7640 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7642 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7650 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7659 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7668 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7689 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7717 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7725 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7729 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp

@github-actions github-actions Bot added the agc libSceAgc* label Oct 16, 2026
@keravyn-ops

Copy link
Copy Markdown
Contributor

AMD / Windows run of this PR at 5b3c1ea: Radeon 780M (RDNA 3, 0x15bf), AMD driver 25.10.20.01 (32.0.21020.1007), Windows 11 Home 10.0.26100, WinLibs GCC 15.2.0 r7, Release.

Every ctest entry built from the test targets this PR changes passes (14):

  • agc_driver_undithered_alpha_to_coverage_state (0.11 s): 289: Existing undithered alpha-to-coverage states passed
  • agc_driver_alpha_to_coverage_state (0.02 s): 290: Alpha-to-coverage state and refusal tests passed
  • agc_driver_prepared_graphics_prebuild_unset (0.16 s): 292: prebuild policy native readback passed
  • agc_driver_prepared_graphics_prebuild_0 (0.13 s): 293: prebuild policy native readback passed
  • agc_driver_prepared_graphics_prebuild_1 (0.13 s): 294: prebuild policy native readback passed
  • agc_driver_graphics (4.93 s): 327: Graphics validation tests passed
  • agc_driver_prepared_graphics (0.13 s): 588: prepared graphics ABI tests passed
  • agc_driver_prepared_unregistered_graphics (0.15 s): 591: prepared unregistered graphics tests passed
  • agc_sparse_buffer_holes (0.04 s): 708: sparse buffer hole tests passed
  • agc_pipeline_journal (0.07 s): 712: pipeline journal recipe, record and replay tests passed
  • agc_descriptor_pool_reset_failure (0.02 s)
  • agc_driver_address_space_teardown (0.02 s): 767: address-space device teardown releases cached guest allocations
  • agc_compute_descriptor_layout_flags (0.02 s): 798: Descriptor layout native and captured binding flags passed
  • agc_driver_covered_centroid_state (0.02 s): 799: Covered-centroid and multisample state checks passed

AI-assisted: yes (runs made on the device above).

This branch has not been deployed

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

Labels

agc libSceAgc* needs rebase Conflicts with main, rebase needed perf numbers missing perf pull request without a before and after summary line perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants