Skip to content

perf(shader): keep memoized results in a set-associative table - #6733

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
meh7an:perf/shader-result-memo-sets
Oct 19, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
meh7an:perf/shader-result-memo-sets

Conversation

@meh7an

@meh7an meh7an commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

What

materializePreparedMemoized keeps each source's materialized results by variant and snapshot hash, so a capture that reproduces a snapshot gets the shared result instead of a fresh Populate. The memo is a std::list in LRU order with an unordered_map index (256 entries). Every hit splices the list. Every insert allocates a list node and a hash node, and evicts the oldest, which frees two more.

The memo is now a fixed table of 64 sets of 4 entries per source, allocated with its first insert:

  • an entry's set is its index with the high half folded into the low;
  • a lookup reads the 4 entries of one set;
  • an insert takes the set's least recently used entry by a per-source clock, so no node is allocated or freed;
  • the table holds 256 entries as before, and the counters are the same (an insert over a live entry counts as an eviction).

The eviction policy changes from LRU over all 256 entries to LRU within a set of 4.

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

  • on the memo itself (materializePreparedMemoized minus the materializeResult it calls on a miss): 1.87 to 1.92 in three runs without this change, 1.33 to 1.60 in four runs with it;
  • on materializeResult, the misses' work: 2.3 to 2.9 in all seven runs, so the sets do not miss noticeably more.

That is about 1.2% of the worker's frame (31 to 33 samples), so the frame times below move within run-to-run noise.

The change is in the recompiler's sources, so the shader cache version changes with it.

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 105.812 103.241 -2.4%
frame_ms.p90 113.658 107.636 -5.3%
mean_frame_ms 107.688 103.748 -3.7%
gpu_busy_ms_per_present 89.495 91.014 +1.7%
Driver.Packet (ms per frame) 105.641 101.713 -3.7%
Driver.Draw (ms per frame) 93.013 89.222 -4.1%

The FPS shown in the title went from 10.36 to 10.48 (median of six readings), and a sampled pair taken about 40 minutes earlier went from 10.50 to 10.82. Last night's windows of this page varied by about 5% at the median, so this pair's gap is mostly noise.

Note: measuring base. These numbers come from my fork's dev, on main 0a56aaa. The memo this change replaces is the same on main 5d9dcc4.

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 40a9184, whose summary says 390f624; this change 11882cc, whose summary says 40a9184):
memo-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 3247 core/shader/recompiler/Recompiler.cpp
PR 4072 core/shader/recompiler/Recompiler.cpp
PR 5021 core/shader/recompiler/Recompiler.cpp
PR 5500 core/shader/recompiler/Recompiler.cpp
PR 5609 core/shader/recompiler/Recompiler.cpp
PR 5656 core/shader/recompiler/Recompiler.cpp
PR 6177 core/shader/recompiler/Recompiler.cpp
PR 6539 core/shader/recompiler/Recompiler.cpp
PR 6612 core/shader/recompiler/Recompiler.cpp
PR 6762 core/shader/recompiler/Recompiler.cpp
PR 6879 core/shader/recompiler/Recompiler.cpp
PR 6924 core/shader/recompiler/Recompiler.cpp
PR 6941 core/shader/recompiler/Recompiler.cpp
PR 6946 core/shader/recompiler/Recompiler.cpp
PR 6947 core/shader/recompiler/Recompiler.cpp
PR 6977 core/shader/recompiler/Recompiler.cpp
PR 7201 core/shader/recompiler/Recompiler.cpp
PR 7223 core/shader/recompiler/Recompiler.cpp
PR 7332 core/shader/recompiler/Recompiler.cpp
PR 7390 core/shader/recompiler/Recompiler.cpp
PR 7395 core/shader/recompiler/Recompiler.cpp
PR 7484 core/shader/recompiler/Recompiler.cpp
PR 7642 core/shader/recompiler/Recompiler.cpp

@parl0v

parl0v commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Data point from a CPU-bound scene on Windows: RTX 3060 12 GB (NVIDIA 617.42), i5-12400F, Windows 10 19045, MinGW GCC Release. Minecraft Dungeons II (PPSA16064 01.100.100), title screen, no input, 200 s rows, APS5_PROFILE_DRAW=1 APS5_PROFILE_GPU=1; main af0fff7 vs main + this PR, interleaved with five other PRs in one batch, two rounds. FPS is the mean of the last 10 [present] windows, GPU busy and idle gaps per frame over the last 8. This scene is CPU-bound on this machine (44-47 ms of idle gaps per frame).

libs FPS GPU busy idle gaps
main 6.61 / 6.76 105 / 104 ms 46 / 44 ms
+ this PR (92e5b97) 6.70 / 6.63 (-0.3 %) 104 / 104 ms 45 / 46 ms

Within the run-to-run spread (main itself moved 6.61 -> 6.76 between rounds), no regression, 0 fatal.

AI-assisted: yes (Claude Code)

@github-actions github-actions Bot added perf Performance change perf numbers missing perf pull request without a before and after summary line labels Oct 18, 2026
@adriadam10 adriadam10 self-assigned this Oct 19, 2026
@adriadam10
adriadam10 merged commit aaaff21 into boykopovar:main Oct 19, 2026
9 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the hit/insert paths under source.mutex, victim selection (empty ways first, then least recently used), the unchanged counters and capacity; the shader cache version bump is automatic. Merged.

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

Labels

perf numbers missing perf pull request without a before and after summary line perf Performance change shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants