Repository navigation
Conversation
… content recurs An image table column whose content (codes and words) and key count match a column any shader resolved before, through an image resource description that agrees in every field the decode reads, replays that column's decoded records and elements instead of decoding them again. The memo holds the decoded records per (content, usage) under a word budget (APS5_TABLE_COLUMN_MEMO_WORDS, default 1<<25), shares one content's codes and words across compiled variants and across shaders, and evicts by least recent use when the budget or the entry count is reached. APS5_NO_TABLE_COLUMN_MEMO resolves every column from its records as before. APS5_VERIFY_TABLE_COLUMN_MEMO also resolves every replayed snapshot from its records and counts the resolutions that differ in the column memo report of APS5_PROFILE_DRAW. APS5_TABLE_COLUMN_MEMO_DIAG extends that report with the distinct contents and usages of the window and the records that changed between a column's contents. The four switches change memo behaviour only, never the recompiled output, so they are listed as neutral to the shader disk cache key. Tests: agc_shader_table_column_memo, with the verify, off and diagnosed variants. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
This pull request is labeled |
|
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.
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.
|
|
@SleglJan thanks, the exact content and usage comparison before a replay makes the memo safe. Two things before this can go in:
|
…rofile noteColumnLookup fed the never-seen and changed-content counters of the column memo report on every lookup, taking the diagnostics mutex and inserting into its slot and content maps whether or not APS5_PROFILE_DRAW, the report's only reader, was set. It now returns first unless the draw profile is on, and the strict usage hash of APS5_TABLE_COLUMN_MEMO_DIAG is computed under the same condition. The column memo test gains a reported variant with APS5_PROFILE_DRAW=1 that expects the three first sights and the one content change, and a diagnosed variant without the profile switch; without it every variant expects those counters to stay at zero, and the diagnosed variant sets the profile switch its report needs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An A/B on plain On the overlap bot's list: #7223's nested columns add inputs (child tables and the pointers that key them) that this memo does not cover, so whichever lands second has to extend the key and the replay to the child tables and pointers, or exclude nested columns from the memo; if #7223 lands first, we do that on our side. #11957 shares only the test file and the test list with this PR. AI-assisted: yes (Claude Code) |
MarcZX10
left a comment
There was a problem hiding this comment.
Reviewed exact head f5cf0db16c28ee4a7575c7cd1dda342fd01a9fe6 and the updated PR discussion. The implementation has a focused verify mode and reports zero mismatches in the supplied run, but the remaining validation and overlap questions are material for this shader-driver change.
The required performance report is still missing: the submitted A/B uses a local base with other PRs, local logging, and a modified title executable, and no aps5-summary.jsonl lines or trace pair/digest are attached. CONTRIBUTING.md requires captures from current main and this PR using the same title, scene, and machine, with the traces; the perf label workflow also requests both summary lines and tools/trace_digest.py output. The maintainer's request for a current-main A/B and max RSS is still unanswered with a compliant comparison. Please provide that evidence or remove the performance claim/label and resolve the maintainer's request explicitly.
There is also an exact merge conflict with open #7223 in ResourceMaterializer.cpp (git merge-tree --write-tree reports a content conflict). The description recognizes that nested-table support must be extended or excluded depending on order, but the checklist says Depends on: none. Please agree the order with #7223’s author, record the dependency/plan, and validate the combined behavior before merge.
adriadam10
left a comment
There was a problem hiding this comment.
Thanks for the verify mode and the exact content/usage comparison before a replay. Still open on this head:
- Performance report (labeled
perf, CONTRIBUTING): paste theaps5-summary.jsonllines of a capture on currentmainand one with this change, same title, scene and machine, plus thetools/trace_digest.pyoutput. The 007 A/B is on a local base (other PRs, local logging, a patched title executable), and its run-validity rule was changed after the first runs (1 valid run of 6 for this change), so it doesn't give a verdict. - Max RSS for both sides (the default budget allows 128 MiB of estimated host memory;
docs/dev/memory rules ask for the bound and peak RSS before/after on a big workload). - Device memory at the level load: memory outside the texture caches went from 1,033-1,257 MiB to 1,206-2,528 MiB, with host placements in 3 of 6 runs against 1 of 6. Please find the cause or show it is noise with more runs before this lands; a perf change that raises peak memory needs that settled.
- The tests don't cover placement against earlier columns of the same resolution, eviction by budget/entry count, or the
APS5_TABLE_COLUMN_MEMO_WORDSparsing; please add them.
… and budget parsing agc_shader_table_column_memo_placement and _placement_before resolve thirty selected single-record tables and one merged column, whose narrowed domain binds its sixty-five keyed records and record 0, in one resolution, with the merged column resolved after or before the selected tables. Thirty of its records equal the selected tables' records: the replayed column must land them on the elements the selected tables placed, or the selected tables on the elements the replayed column placed, 66 elements in all, equal to the plain resolution. _placement_off runs the first order with the memo off. agc_shader_table_column_memo_evicted_by_count fills the memo to its 4,096 entries and reads through hits and misses that the least recently used entry leaves first; _evicted_by_budget does the same under APS5_TABLE_COLUMN_MEMO_WORDS=65536 with the first content replayed after every insertion, and _oversize_entry checks that an entry over a budget of 0x1 words is never kept. agc_shader_table_column_memo_words*: accepted values (unset, 1048576, 0x100000) resolve the same column twice and check that the memo keeps it; refused values (0, -1, empty, abc, 12x, a 20-digit overflow) check that the first resolution fails with the variable's message. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Resolves docs/dev/ENVIRONMENT.md: main's APS5_STRICT_DESCRIPTOR_WEBS row (now a string) is kept and the APS5_TABLE_COLUMN_MEMO_DIAG and APS5_TABLE_COLUMN_MEMO_WORDS rows follow it. Everything else merged automatically. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A column memo hit compares the stored usage's whole image resource and mode list (ImageResource's defaulted operator==), while the usage hash lists fields by name. Two fields were compared and not hashed: `sampledOnly`, which the image descriptor decode reads since boykopovar#11507 (a cube descriptor with fewer than six slices is poisoned unless the image is only sampled), and `optionalDescriptor`. Two usages that differed only in one of them shared a key; the hit check rejected the entry and the next miss replaced it, so the two missed in turn instead of replaying. The hash now mixes both, and the docs/dev/ENVIRONMENT.md row of APS5_NO_TABLE_COLUMN_MEMO says what a hit compares: every field but the descriptor source, the first use and the table index. Test: `agc_shader_table_column_memo_usage` resolves one column under a sampled-only usage, under the same usage with `sampledOnly` cleared, and under the same usage with `optionalDescriptor` set, each under its own variant key: every new usage misses once, and every usage then hits. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every other agc_shader_memory_tests entry prepends libc's directory to PATH on Windows; the 22 column memo tests did not. They need libc's directory on PATH there, like the other entries. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Thanks for the reviews, @adriadam10 and @MarcZX10, and for the earlier questions, @oneandonlydean. Head is now dc1e7e5 (tests only on f5cf0db). Below: what the PR claims now and the performance report (the capture pair on Performance report. What this PR claims now: the Captured on this machine (CachyOS, kernel 7.2.10, NVIDIA GeForce RTX 3080, driver 615.78.08, Ryzen 9 7950X3D, 64 GB), 007 First Light (PPSA11386), the walk after the resume of the first level, {"commit":"c547deaacb62","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":418164.785},"presents":150,"frame_ms":{"p50":2711.721,"p90":3216.898,"p99":3992.038,"max":4422.742},"gpu_busy_ms_per_present":477.688,"worker_busy_pct":{"queue worker 0x0":99.931,"queue worker 0x20":99.869,"queue worker 0x28":99.746,"queue worker 0x30":99.799,"queue worker 0x38":82.472},"top_phases_ms_per_frame":{"Driver.Packet":13395.303,"Driver.Packet.memory_wait":9050.250,"Driver.Packet.dispatch":2341.595,"GpuMutex.wait.hook":2314.830,"Driver.Dispatch":2091.833,"Resources.Complete":1952.857,"Driver.Packet.draw":1763.494,"Driver.Draw":1762.767},"trace_dropped":false,"trace":"aps5-trace-c547deaacb62-2.json.gz"}{"commit":"dc1e7e5695ab","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":436633.103},"presents":150,"frame_ms":{"p50":2882.072,"p90":3378.460,"p99":4499.485,"max":7033.048},"gpu_busy_ms_per_present":497.524,"worker_busy_pct":{"queue worker 0x0":99.946,"queue worker 0x20":99.900,"queue worker 0x28":99.815,"queue worker 0x38":82.658,"queue worker 0x30":99.844},"top_phases_ms_per_frame":{"Driver.Packet":13992.217,"Driver.Packet.memory_wait":9511.346,"GpuMutex.wait.hook":2578.339,"Driver.Packet.dispatch":2452.564,"Driver.Dispatch":2167.295,"Resources.Complete":2116.024,"Graphics.Draw":1816.352,"Driver.Packet.draw":1792.957},"trace_dropped":false,"trace":"aps5-trace-dc1e7e5695ab-2.json.gz"}Digests ( trace_digest, main c547deaframes 1085:150 from present 1085: 150 presents, frame p50 2711.7 / p90 3216.9 / p99 3992.0 / max 4422.7 ms, GPU busy 477.7 ms per present {"commit":"c547deaacb62","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":418164.785},"presents":150,"frame_ms":{"p50":2711.721,"p90":3216.898,"p99":3992.038,"max":4422.742},"gpu_busy_ms_per_present":477.688,"worker_busy_pct":{"queue worker 0x0":99.931,"queue worker 0x20":99.869,"queue worker 0x28":99.746,"queue worker 0x30":99.799,"queue worker 0x38":82.472},"top_phases_ms_per_frame":{"Driver.Packet":13395.303,"Driver.Packet.memory_wait":9050.25,"Driver.Packet.dispatch":2341.595,"GpuMutex.wait.hook":2314.83,"Driver.Dispatch":2091.833,"Resources.Complete":1952.857,"Driver.Packet.draw":1763.494,"Driver.Draw":1762.767},"trace_dropped":false,"trace":"aps5-trace-c547deaacb62-2.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 13386.6, Driver.Packet.memory_wait 9050.1, Driver.Packet.dispatch 2341.1, GpuMutex.wait.hook 2314.6, Driver.Dispatch 2090.7, Resources.Complete 1951.6, Driver.Packet.draw 1762.7, Driver.Draw 1761.9, Graphics.Draw 1730.5, Graphics.Draw.draw_and_resource_release 1677.6 Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
trace_digest, this PR dc1e7e5frames 1085:150 from present 1085: 150 presents, frame p50 2882.1 / p90 3378.5 / p99 4499.5 / max 7033.0 ms, GPU busy 497.5 ms per present {"commit":"dc1e7e5695ab","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":436633.103},"presents":150,"frame_ms":{"p50":2882.072,"p90":3378.46,"p99":4499.485,"max":7033.048},"gpu_busy_ms_per_present":497.524,"worker_busy_pct":{"queue worker 0x0":99.946,"queue worker 0x20":99.9,"queue worker 0x28":99.815,"queue worker 0x38":82.658,"queue worker 0x30":99.844},"top_phases_ms_per_frame":{"Driver.Packet":13992.217,"Driver.Packet.memory_wait":9511.346,"GpuMutex.wait.hook":2578.339,"Driver.Packet.dispatch":2452.564,"Driver.Dispatch":2167.295,"Resources.Complete":2116.024,"Graphics.Draw":1816.352,"Driver.Packet.draw":1792.957},"trace_dropped":false,"trace":"aps5-trace-dc1e7e5695ab-2.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 13983.7, Driver.Packet.memory_wait 9511.2, GpuMutex.wait.hook 2578.1, Driver.Packet.dispatch 2452.1, Driver.Dispatch 2166.2, Resources.Complete 2114.8, Graphics.Draw 1816.3, Driver.Packet.draw 1792.2, Driver.Draw 1791.5, Graphics.Draw.draw_and_resource_release 1765.9 Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
The pair's lines as they are: window 418.2 s against 436.6 s over 150 presents, p50 2,711.7 against 2,882.1 ms (p90 3,216.9 / 3,378.5, p99 3,992.0 / 4,499.5, max 4,422.7 / 7,033.0), GPU busy 477.7 against 497.5 ms per present; one pair, one run per side, read next to the three-pair A/B spread below. The Populate figures come from the profiled A/B runs below, not from the capture pair (no The 007 A/B on Your asks, one by one. oneandonlydean: a same-machine A/B on current Max RSS. The highest Device memory at the level load. Two quantities: adriadam10's figures are the memory outside the texture caches; ours, for the series on
The shared-journal series' PR seed was made with Tests. Tests only, no runtime change (dc1e7e5 adds to #7223. My comment on #7223 (#7223 (comment)) describes the conflict (one content conflict in Stack disclosure: in every run on AI-assisted: yes (Claude Code) |
adriadam10
left a comment
There was a problem hiding this comment.
Thanks for the tests and the full report. The tests cover what was asked and the hash fix is right. What is still open is the case for the change itself:
- No measured gain on
main. Your own numbers: Populate drops 171 → 68 ms per frame, but frames are ~2.8 s and the A/B walk rate is 0.360 vs 0.352 presents/s (within spread). The only capture pair onmainhas this PR slower (p50 +6.3 %, p99 +12.7 %, max +59 %, GPU busy +4.2 %), one run per side. The +11.5 % figure was only on a local base. AperfPR needs a gain that reproduces onmain: more capture pairs (or a scene where Populate is on the critical path) showing it beats the spread, not one pair against three. - Device memory at the level load is still unexplained. The capture pair peaks at 9,883 MiB against 9,042 MiB (+841 MiB, above your own 9,850 MiB limit) with host placements only on this side; the shared-journal series is mixed in sign. Please show with more pairs that it is noise, or find the cause.
- Cost vs benefit. The change adds a ~570-line memo in
ResourceMaterializer.cpp, a 128 MiB host budget, 4 env switches (APS5_NO_TABLE_COLUMN_MEMO,APS5_VERIFY_TABLE_COLUMN_MEMO,APS5_TABLE_COLUMN_MEMO_DIAG,APS5_TABLE_COLUMN_MEMO_WORDS) and 22 ctest entries. Without a frame-time gain that is not justified; if you can't show one, please close this or reduce it to what pays for itself. - Retitling without
perfdoesn't change this: the memory and complexity cost needs a benefit that is measured.
|
@adriadam10 thanks, agreed. I'm converting this to draft and running three more capture pairs: AI-assisted: yes (Claude Code) |
|
@adriadam10 @oneandonlydean The three capture pairs promised in the comment above:
p50 = The rule, from that comment: "It counts as a gain only if each of this PR's three frame p50s is below the lowest Window lines, main first in each pairPair 1, {"commit":"f8f5b24b77ad","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":407238.833},"presents":150,"frame_ms":{"p50":2639.830,"p90":3155.179,"p99":4478.997,"max":4619.159},"gpu_busy_ms_per_present":465.909,"worker_busy_pct":{"queue worker 0x0":99.939,"queue worker 0x20":99.888,"queue worker 0x28":99.786,"queue worker 0x30":99.825,"queue worker 0x38":87.430},"top_phases_ms_per_frame":{"Driver.Packet":13183.350,"Driver.Packet.memory_wait":8848.245,"GpuMutex.wait.hook":2427.414,"Driver.Packet.dispatch":2406.809,"Driver.Dispatch":2145.158,"Resources.Complete":1926.502,"Driver.Packet.draw":1690.764,"Driver.Draw":1690.066},"trace_dropped":false,"trace":"aps5-trace-f8f5b24b77ad-2.json.gz"}Pair 1, this PR c5dcde9 (cp12051-C-1): {"commit":"c5dcde982eb6","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":411524.710},"presents":150,"frame_ms":{"p50":2728.224,"p90":3171.006,"p99":4191.625,"max":4261.778},"gpu_busy_ms_per_present":472.881,"worker_busy_pct":{"queue worker 0x0":99.920,"queue worker 0x20":99.884,"queue worker 0x28":99.796,"queue worker 0x38":82.066,"queue worker 0x30":99.824},"top_phases_ms_per_frame":{"Driver.Packet":13165.727,"Driver.Packet.memory_wait":8864.371,"GpuMutex.wait.hook":2545.316,"Driver.Packet.dispatch":2326.633,"Driver.Dispatch":2052.613,"Resources.Complete":1983.210,"Graphics.Draw":1751.883,"Driver.Packet.draw":1728.312},"trace_dropped":false,"trace":"aps5-trace-c5dcde982eb6-2.json.gz"}Pair 2, {"commit":"f8f5b24b77ad","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":431649.655},"presents":150,"frame_ms":{"p50":2828.455,"p90":3302.503,"p99":4231.105,"max":4354.292},"gpu_busy_ms_per_present":503.631,"worker_busy_pct":{"queue worker 0x0":99.937,"queue worker 0x20":99.891,"queue worker 0x28":99.795,"queue worker 0x38":82.988,"queue worker 0x30":99.832},"top_phases_ms_per_frame":{"Driver.Packet":13847.888,"Driver.Packet.memory_wait":9462.661,"GpuMutex.wait.hook":2474.951,"Driver.Packet.dispatch":2279.130,"Driver.Dispatch":2038.701,"Resources.Complete":2011.380,"Driver.Packet.draw":1852.938,"Driver.Draw":1852.213},"trace_dropped":false,"trace":"aps5-trace-f8f5b24b77ad-2.json.gz"}Pair 2, this PR c5dcde9 (cp12051-C-2): {"commit":"c5dcde982eb6","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":375957.074},"presents":150,"frame_ms":{"p50":2451.578,"p90":2926.542,"p99":3471.788,"max":4043.945},"gpu_busy_ms_per_present":418.902,"worker_busy_pct":{"queue worker 0x0":99.938,"queue worker 0x20":99.903,"queue worker 0x28":99.809,"queue worker 0x30":99.843,"queue worker 0x38":85.649},"top_phases_ms_per_frame":{"Driver.Packet":12119.899,"Driver.Packet.memory_wait":8117.253,"GpuMutex.wait.hook":2322.025,"Driver.Packet.dispatch":2184.985,"Driver.Dispatch":1945.673,"Resources.Complete":1827.441,"Graphics.Draw":1577.501,"Driver.Packet.draw":1561.313},"trace_dropped":false,"trace":"aps5-trace-c5dcde982eb6-2.json.gz"}Pair 3, {"commit":"f8f5b24b77ad","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":396172.640},"presents":150,"frame_ms":{"p50":2605.890,"p90":3040.989,"p99":3369.986,"max":4454.722},"gpu_busy_ms_per_present":441.490,"worker_busy_pct":{"queue worker 0x0":99.940,"queue worker 0x20":99.892,"queue worker 0x28":99.780,"queue worker 0x30":99.819,"queue worker 0x38":85.230},"top_phases_ms_per_frame":{"Driver.Packet":12768.100,"Driver.Packet.memory_wait":8637.775,"GpuMutex.wait.hook":2291.509,"Driver.Packet.dispatch":2227.289,"Driver.Dispatch":1985.304,"Resources.Complete":1856.957,"Driver.Packet.draw":1660.973,"Driver.Draw":1660.274},"trace_dropped":false,"trace":"aps5-trace-f8f5b24b77ad-2.json.gz"}Pair 3, this PR c5dcde9 (cp12051-C-3): {"commit":"c5dcde982eb6","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":409847.870},"presents":150,"frame_ms":{"p50":2684.171,"p90":3184.105,"p99":3644.970,"max":4145.218},"gpu_busy_ms_per_present":467.834,"worker_busy_pct":{"queue worker 0x0":99.941,"queue worker 0x20":99.922,"queue worker 0x38":80.339,"queue worker 0x28":99.827,"queue worker 0x30":99.855},"top_phases_ms_per_frame":{"Driver.Packet":13072.828,"Driver.Packet.memory_wait":8937.961,"GpuMutex.wait.hook":2419.026,"Driver.Packet.dispatch":2149.819,"Resources.Complete":1961.375,"Driver.Dispatch":1886.346,"Graphics.Draw":1753.861,"Driver.Packet.draw":1750.046},"trace_dropped":false,"trace":"aps5-trace-c5dcde982eb6-2.json.gz"}Per run: route and trace window (validity), memory (recorded only)Six runs in order, each a fresh title start from the copied caches; times CET. Level-load window = Resume press to the first frame event at or past f1055. Memory counts are given twice: in that window and over the whole run (title start to exit).
Exhaustion triggers (1 s Declared extras, not tests (PR − Validity rules, fixed before the first run
Two other GPU jobs between title runsTwo jobs of ours ran on the RTX 3080 between title runs, each one run of two prebuilt #10333 test binaries ( The six trace digests ( AI-assisted: yes (Claude Code) |
|
The six digests of the capture pairs in the comment above ( trace_digest, pair 1, main f8f5b24 (cp12051-B-1)frames 1085:150 from present 1085: 150 presents, frame p50 2639.8 / p90 3155.2 / p99 4479.0 / max 4619.2 ms, GPU busy 465.9 ms per present {"commit":"f8f5b24b77ad","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":407238.833},"presents":150,"frame_ms":{"p50":2639.83,"p90":3155.179,"p99":4478.997,"max":4619.159},"gpu_busy_ms_per_present":465.909,"worker_busy_pct":{"queue worker 0x0":99.939,"queue worker 0x20":99.888,"queue worker 0x28":99.786,"queue worker 0x30":99.825,"queue worker 0x38":87.43},"top_phases_ms_per_frame":{"Driver.Packet":13183.35,"Driver.Packet.memory_wait":8848.245,"GpuMutex.wait.hook":2427.414,"Driver.Packet.dispatch":2406.809,"Driver.Dispatch":2145.158,"Resources.Complete":1926.502,"Driver.Packet.draw":1690.764,"Driver.Draw":1690.066},"trace_dropped":false,"trace":"aps5-trace-f8f5b24b77ad-2.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 13174.5, Driver.Packet.memory_wait 8848.0, GpuMutex.wait.hook 2427.2, Driver.Packet.dispatch 2406.3, Driver.Dispatch 2144.0, Resources.Complete 1925.3, Driver.Packet.draw 1689.7, Driver.Draw 1689.0, Graphics.Draw 1677.7, Graphics.Draw.draw_and_resource_release 1642.4 Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
trace_digest, pair 1, this PR c5dcde9 (cp12051-C-1)frames 1085:150 from present 1085: 150 presents, frame p50 2728.2 / p90 3171.0 / p99 4191.6 / max 4261.8 ms, GPU busy 472.9 ms per present {"commit":"c5dcde982eb6","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":411524.71},"presents":150,"frame_ms":{"p50":2728.224,"p90":3171.006,"p99":4191.625,"max":4261.778},"gpu_busy_ms_per_present":472.881,"worker_busy_pct":{"queue worker 0x0":99.92,"queue worker 0x20":99.884,"queue worker 0x28":99.796,"queue worker 0x38":82.066,"queue worker 0x30":99.824},"top_phases_ms_per_frame":{"Driver.Packet":13165.727,"Driver.Packet.memory_wait":8864.371,"GpuMutex.wait.hook":2545.316,"Driver.Packet.dispatch":2326.633,"Driver.Dispatch":2052.613,"Resources.Complete":1983.21,"Graphics.Draw":1751.883,"Driver.Packet.draw":1728.312},"trace_dropped":false,"trace":"aps5-trace-c5dcde982eb6-2.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 13157.1, Driver.Packet.memory_wait 8864.2, GpuMutex.wait.hook 2545.1, Driver.Packet.dispatch 2326.2, Driver.Dispatch 2051.5, Resources.Complete 1982.0, Graphics.Draw 1751.7, Driver.Packet.draw 1727.5, Driver.Draw 1726.8, Graphics.Draw.draw_and_resource_release 1698.7 Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
trace_digest, pair 2, main f8f5b24 (cp12051-B-2)frames 1085:150 from present 1085: 150 presents, frame p50 2828.5 / p90 3302.5 / p99 4231.1 / max 4354.3 ms, GPU busy 503.6 ms per present {"commit":"f8f5b24b77ad","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":431649.655},"presents":150,"frame_ms":{"p50":2828.455,"p90":3302.503,"p99":4231.105,"max":4354.292},"gpu_busy_ms_per_present":503.631,"worker_busy_pct":{"queue worker 0x0":99.937,"queue worker 0x20":99.891,"queue worker 0x28":99.795,"queue worker 0x38":82.988,"queue worker 0x30":99.832},"top_phases_ms_per_frame":{"Driver.Packet":13847.888,"Driver.Packet.memory_wait":9462.661,"GpuMutex.wait.hook":2474.951,"Driver.Packet.dispatch":2279.13,"Driver.Dispatch":2038.701,"Resources.Complete":2011.38,"Driver.Packet.draw":1852.938,"Driver.Draw":1852.213},"trace_dropped":false,"trace":"aps5-trace-f8f5b24b77ad-2.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 13838.8, Driver.Packet.memory_wait 9462.4, GpuMutex.wait.hook 2474.7, Driver.Packet.dispatch 2278.7, Driver.Dispatch 2037.6, Resources.Complete 2010.2, Driver.Packet.draw 1852.1, Driver.Draw 1851.4, Graphics.Draw 1814.7, Graphics.Draw.draw_and_resource_release 1730.4 Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
trace_digest, pair 2, this PR c5dcde9 (cp12051-C-2)frames 1085:150 from present 1085: 150 presents, frame p50 2451.6 / p90 2926.5 / p99 3471.8 / max 4043.9 ms, GPU busy 418.9 ms per present {"commit":"c5dcde982eb6","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":375957.074},"presents":150,"frame_ms":{"p50":2451.578,"p90":2926.542,"p99":3471.788,"max":4043.945},"gpu_busy_ms_per_present":418.902,"worker_busy_pct":{"queue worker 0x0":99.938,"queue worker 0x20":99.903,"queue worker 0x28":99.809,"queue worker 0x30":99.843,"queue worker 0x38":85.649},"top_phases_ms_per_frame":{"Driver.Packet":12119.899,"Driver.Packet.memory_wait":8117.253,"GpuMutex.wait.hook":2322.025,"Driver.Packet.dispatch":2184.985,"Driver.Dispatch":1945.673,"Resources.Complete":1827.441,"Graphics.Draw":1577.501,"Driver.Packet.draw":1561.313},"trace_dropped":false,"trace":"aps5-trace-c5dcde982eb6-2.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 12111.2, Driver.Packet.memory_wait 8117.1, GpuMutex.wait.hook 2321.8, Driver.Packet.dispatch 2184.5, Driver.Dispatch 1944.6, Resources.Complete 1826.2, Graphics.Draw 1577.3, Driver.Packet.draw 1560.2, Driver.Draw 1559.6, Graphics.Draw.draw_and_resource_release 1540.5 Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
trace_digest, pair 3, main f8f5b24 (cp12051-B-3)frames 1085:150 from present 1085: 150 presents, frame p50 2605.9 / p90 3041.0 / p99 3370.0 / max 4454.7 ms, GPU busy 441.5 ms per present {"commit":"f8f5b24b77ad","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":396172.64},"presents":150,"frame_ms":{"p50":2605.89,"p90":3040.989,"p99":3369.986,"max":4454.722},"gpu_busy_ms_per_present":441.49,"worker_busy_pct":{"queue worker 0x0":99.94,"queue worker 0x20":99.892,"queue worker 0x28":99.78,"queue worker 0x30":99.819,"queue worker 0x38":85.23},"top_phases_ms_per_frame":{"Driver.Packet":12768.1,"Driver.Packet.memory_wait":8637.775,"GpuMutex.wait.hook":2291.509,"Driver.Packet.dispatch":2227.289,"Driver.Dispatch":1985.304,"Resources.Complete":1856.957,"Driver.Packet.draw":1660.973,"Driver.Draw":1660.274},"trace_dropped":false,"trace":"aps5-trace-f8f5b24b77ad-2.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 12759.3, Driver.Packet.memory_wait 8637.6, GpuMutex.wait.hook 2291.3, Driver.Packet.dispatch 2226.8, Driver.Dispatch 1984.2, Resources.Complete 1855.8, Driver.Packet.draw 1659.9, Driver.Draw 1659.2, Graphics.Draw 1632.9, Graphics.Draw.draw_and_resource_release 1597.3 Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
trace_digest, pair 3, this PR c5dcde9 (cp12051-C-3)frames 1085:150 from present 1085: 150 presents, frame p50 2684.2 / p90 3184.1 / p99 3645.0 / max 4145.2 ms, GPU busy 467.8 ms per present {"commit":"c5dcde982eb6","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":409847.87},"presents":150,"frame_ms":{"p50":2684.171,"p90":3184.105,"p99":3644.97,"max":4145.218},"gpu_busy_ms_per_present":467.834,"worker_busy_pct":{"queue worker 0x0":99.941,"queue worker 0x20":99.922,"queue worker 0x38":80.339,"queue worker 0x28":99.827,"queue worker 0x30":99.855},"top_phases_ms_per_frame":{"Driver.Packet":13072.828,"Driver.Packet.memory_wait":8937.961,"GpuMutex.wait.hook":2419.026,"Driver.Packet.dispatch":2149.819,"Resources.Complete":1961.375,"Driver.Dispatch":1886.346,"Graphics.Draw":1753.861,"Driver.Packet.draw":1750.046},"trace_dropped":false,"trace":"aps5-trace-c5dcde982eb6-2.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 13064.1, Driver.Packet.memory_wait 8937.7, GpuMutex.wait.hook 2418.8, Driver.Packet.dispatch 2149.3, Resources.Complete 1960.2, Driver.Dispatch 1885.2, Graphics.Draw 1753.7, Driver.Packet.draw 1749.3, Driver.Draw 1748.5, Graphics.Draw.draw_and_resource_release 1689.2 Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
AI-assisted: yes (Claude Code) |
What
When the result memo misses and the table resolution reuse misses too, an image table column is resolved from its records: each record's decode is looked up in the decode memo (one global mutex per record), null descriptors are checked, each element is hashed and placed, and the map is written. On a scene with large tables the same column content comes back on most of these misses, read through image resources that agree in every field but the descriptor source, the first use and the table index. This PR keeps a column's decoded records and replays them when the same content recurs:
SharedValues::Hash), its key count and its records-outside-the-snapshot state, plus the usage: the image resource without its descriptor source, first use and table index, its runtime mode list and the reducing-sampler state. Columns of at least 64 keys, in the runtime resolution; the registration-timePopulatepath does not use the memo.APS5_TABLE_COLUMN_MEMO_WORDS, default 33,554,432 words of estimated host memory) and an entry count of 4,096.APS5_PROFILE_DRAWcounts hits, misses never seen and misses whose content changed; the last two keep one slot per usage (up to 131,072) under a mutex, only whileAPS5_PROFILE_DRAWis set.APS5_NO_TABLE_COLUMN_MEMO=1resolves every column from its records as before.APS5_VERIFY_TABLE_COLUMN_MEMO=1also resolves every replayed snapshot from its records and compares the map, elements, samplers, poison records and faults; the first twenty differences are printed and the count goes into the report line.APS5_TABLE_COLUMN_MEMO_DIAG=1extends that line with the distinct contents and usages of the window and, for the changed-content misses whose previous column is still pinned, the keys whose descriptor differs and the 1,024-key chunks holding them; it takes effect only withAPS5_PROFILE_DRAW.NeutralSwitches).agc_shader_table_column_memo(a replayed resolution equals a fresh one across a second variant, another first use and another descriptor source; a changed mode list or decode input misses; the hit and miss counters), with the verified, off, reported, diagnosed and diagnosed-unreported variants. dc1e7e5 addsagc_shader_table_column_memo_placement,_placement_beforeand_placement_off(thirty selected single-record tables and one merged column in one resolution, the merged column resolved after or before them; its narrowed domain binds its 65 keyed records and record 0, thirty of its records equal the selected tables' records and land on the same elements, 66 elements in all, equal to the plain resolution),_evicted_by_count(4,096 distinct contents, then the least recently used entry leaves first, read through hits and misses),_evicted_by_budget(APS5_TABLE_COLUMN_MEMO_WORDS=65536, 200 contents with the first replayed after every insertion: the newest and the first kept, the least recently used evicted) and_oversize_entry(APS5_TABLE_COLUMN_MEMO_WORDS=0x1: nothing kept), and nine_words*registrations (the same column resolved twice per value: kept on the second resolution under unset,1048576and0x100000; the first resolution fails with the variable's message for0,-1, empty,abc,12xand a 20-digit overflow).Related open PRs: #6340, #10193, #7642 and #10256 work on the driver's image table entries and device tables. #7223 (nested image tables through runtime pointers) changes the same resolution loop and adds child tables and the pointers that key them, which this memo does not cover: whichever lands second has to extend the key and the replay to them, or exclude nested columns from the memo. What the second to land changes is proposed on #7223 (#7223 (comment)): keep the pointer-keyed parent column out of the memo (its child tables still go through the resolution as ordinary columns and stay eligible), or key the memo on the child content; the order itself is open with #7223's author.
Tested
CachyOS Linux (kernel 7.2.10), NVIDIA GeForce RTX 3080, driver 615.78.08, AMD Ryzen 9 7950X3D, 64 GB; GCC 16.2.1, CMake 4.4.4.
ctest -R "^agc"on this PR at dc1e7e5: 1,073 passed, 10 skipped, 1 failed of 1,084. The one failure,agc_driver_mesh_barycentric_emulation, fails the same way on plainmainc547dea on this machine ("AGC graphics: the pixel shader did not emulate barycentrics", NVIDIA 615.78.08).ctest --test-dir build -R "^agc_shader_" -VwithANYPS5_REQUIRE_VULKAN=1,ANYPS5_NO_SHADER_CACHE=1andVK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation: 37/37 onmainc547dea, 58/58 on this PR at dc1e7e5 (the 21 extra are the column memo tests). Neither log haswas not found but was requested by env var VK_INSTANCE_LAYERS, and neither has aVUID-line.What this change claims now: the
[recompile]Populate time is down onmain(171 / 169 / 172 ms per frame against 67 / 69 / 72 in the A/B below); no frame-rate gain onmainwithin the run spread (walk presents per second 0.369 / 0.369 / 0.341 against 0.358 / 0.326 / 0.371); the +11.5 % walk gain below was measured only on the local base and does not reproduce onmain.Capture pair, 007 First Light (PPSA11386), the walk after the resume of the first level:
mainat the PR's base c547dea (2026-10-28, 12:04 to 12:47 CET) and this PR at its head dc1e7e5 (12:51 to 13:34 CET), same machine and boot, a build and a test run in between,APS5_TRACE_FRAMES=1085:150on both sides. Not as the form asks:APS5_TRACE_EVENTS=4194304on both sides, because queue worker 0x0 records about 10,700 events per present here and the default buffer of 262,144 events (docs/dev/BUILD.md) holds about 25 presents;APS5_TRACE_DIRfor the output directory;APS5_TIME_SCALE=0.1and scripted input throughAPS5_PAD_INPUT_FILE, both visible in the lines'env; and, not visible there, the log written to a file, the NVIDIA shader disk cache on and pointed at a per-run directory copied from a seed run (a 16 GiB size cap, its cleanup skipped), the shader disk cache and the journal warm from that seed run rather than from a restart, and the title in a scope with swap turned off. No otherAPS5_TRACE_*switch and noAPS5_PROFILE_*switch is set. Both sides the same way:mainfrom its own seed; this PR from a copy of the PR's seed withmain's journal records (the journal header's source version set to the PR's), so the journal records and the NVIDIA cache are identical on both sides while the shader disk cache is each side's own, the shader cache source versions being 41abaa3b8f8b9199 onmainand 75f9ad0bc594cabf on this PR. The title executable is unedited.{"commit":"c547deaacb62","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":418164.785},"presents":150,"frame_ms":{"p50":2711.721,"p90":3216.898,"p99":3992.038,"max":4422.742},"gpu_busy_ms_per_present":477.688,"worker_busy_pct":{"queue worker 0x0":99.931,"queue worker 0x20":99.869,"queue worker 0x28":99.746,"queue worker 0x30":99.799,"queue worker 0x38":82.472},"top_phases_ms_per_frame":{"Driver.Packet":13395.303,"Driver.Packet.memory_wait":9050.250,"Driver.Packet.dispatch":2341.595,"GpuMutex.wait.hook":2314.830,"Driver.Dispatch":2091.833,"Resources.Complete":1952.857,"Driver.Packet.draw":1763.494,"Driver.Draw":1762.767},"trace_dropped":false,"trace":"aps5-trace-c547deaacb62-2.json.gz"}{"commit":"dc1e7e5695ab","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TIME_SCALE":"0.1","APS5_TRACE_DIR":"<path>","APS5_TRACE_EVENTS":"4194304","APS5_TRACE_FRAMES":"1085:150"},"gpu":"NVIDIA GeForce RTX 3080","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","cpu":"AMD Ryzen 9 7950X3D 16-Core Processor","cpu_threads":32,"memory_mib":63428,"title_id":"PPSA11386","title":"007 First Light","content_version":"01.018.000","resolution":"3840x2160","window":{"spec":"frames 1085:150","first_present":1085,"ms":436633.103},"presents":150,"frame_ms":{"p50":2882.072,"p90":3378.460,"p99":4499.485,"max":7033.048},"gpu_busy_ms_per_present":497.524,"worker_busy_pct":{"queue worker 0x0":99.946,"queue worker 0x20":99.900,"queue worker 0x28":99.815,"queue worker 0x38":82.658,"queue worker 0x30":99.844},"top_phases_ms_per_frame":{"Driver.Packet":13992.217,"Driver.Packet.memory_wait":9511.346,"GpuMutex.wait.hook":2578.339,"Driver.Packet.dispatch":2452.564,"Driver.Dispatch":2167.295,"Resources.Complete":2116.024,"Graphics.Draw":1816.352,"Driver.Packet.draw":1792.957},"trace_dropped":false,"trace":"aps5-trace-dc1e7e5695ab-2.json.gz"}tools/trace_digest.pyoutput) and the two traces: pre-release https://github.com/SleglJan/AnyPS5/releases/tag/perf-traces-shader-column-memo on my fork, both files over the 25 MB attachment limit (31.7 and 32.4 MB), sha256 e44ae16fa69649761e15a3f5cd9a394f8089e4a51db7e34c59d2590ff518e6e5 (main) and 22b1ef75f9c6c30a4c75a5552866af2d790655ae1ede305a18e25a1f5e5d1fd7 (this PR).tools/performance_compare.pyon the lines: no configuration difference; this PR minusmain: frame p50 +170 ms (+6.3 %), p90 +162 (+5.0 %), p99 +507 (+12.7 %), max +2,610 (+59 %), mean frame +123 (+4.4 %), GPU busy per present +20 (+4.2 %); one pair, one run per side. HighestVmHWM24,371 against 25,134 MiB, both including the trace buffers (seven threads at 160 MiB each, 1,120 MiB, on both sides).main's run passes every check readable here (collapse is not readable; peak device memory used 9,550 MiB over the run, 9,042 MiB at the level load, every other figure under its limit), this change's run invalid: it peaks at 9,883 MiB at frame 1,036 (the level load, before the walk and outside the trace window), over our 9,850 MiB limit; its next-highest 1 s sample is 9,782 MiB at frame 1,248. First reading: both invalid, because the staging-shadow refusal lines count as unrecovered refusals there (main2, its full count; this change 4, a lower bound, four prints per run at most).mainc547dea withAPS5_PROFILE_DRAW=1andAPS5_TRACE_SUMMARY_EVERY=60(three alternated pairs, 2026-10-27 22:41 to 2026-10-28 03:00 CET, this change at f5cf0db,mainat the PR's base c547dea whilemainitself was 32 merges past it, journals unequal, the cache and swap settings as above): walk presents per second under the first reading, declared before the series (any unrecovered allocation refusal invalid), n = 1 / 1,main0.341 against this change 0.326; under the later reading, which counts staging-shadow refusal lines as handled and was declared after pair 1's results, which made both its runs invalid only through these lines, while pair 2's first run was running, n = 3 / 3,main0.369 / 0.369 / 0.341 (mean 0.360) against this change 0.358 / 0.326 / 0.371 (mean 0.352); four of the six runs differ between the two readings, all on that line.[recompile]Populate 171 / 169 / 172 against 67 / 69 / 72 ms per frame. HighestVmHWMper runmain23,651 / 24,614 / 24,036 MiB, this change 24,460 / 25,557 / 23,802 MiB.The earlier alternated A/B, the same title and walk, measured before this rebase on a local base, not on
main: upstreammain5357acd plus #5372 (squashed, with its 662a50b change reverted) and #10423, plus local logging and scripted input, and the title's two feedback-wait limits widened in its executable as described in #6172 (local only). Both sides run withAPS5_WRITTEN_SHADOW_MAX_KIB=2048 APS5_NO_WRITTEN_SHADOW=1 APS5_PROFILE_DRAW=1and a warm shader disk cache from a seed run per side; 2026-10-27, six pairs alternated base / this change, 20 minutes each, the same machine and session.APS5_FLIP_INFLIGHT=0) cut the held-entry difference between the sides from 2.09x to 1.29x and showed no streaks, an observation from one pair, with no cause read from it.Populatems per frame, all sixAPS5_VERIFY_TABLE_COLUMN_MEMO=1, 106,481 hits and 7,958 misses over 92 ten-second lines (93.0 %), 29,618 replayed resolutions re-resolved from their records, 0 mismatches. Every miss was a column whose content changed; the memo held 323-402 entries.mainseries, the 1 s peak ofnvidia-smimemory used by all processes between the resume and frame 1,055, with the memory outside the texture caches read at the[gpu]budget line nearest that peak and the title's own device memory as the highestnvidia-smi pmonsample in that window. Local-base series: base 1,033-1,257 MiB against this change 1,206-2,528 MiB outside the caches, with first host placements in 3 of 6 runs against 1 of 6 (Fisher, one-sided, 0.27); the series had one seed per side (its own shader disk cache, frozen NVIDIA cache and journal) and the PR side loaded the smaller journal, so the cause there is not established. Onmainc547dea, each series in one session,mainalways from one seed, this change minusmain:main175)mainline 26 s from the peak)mainline 37 s from the peak)Over the eight shared-journal pairs the means are
main9,321 against this change 9,260 MiB; without the three-pair series' pair 3 (itsmainrun had six shader disk cache misses) 7 / 7, 9,384 against 9,298. Both groupings, 8 / 8 and 7 / 7, were declared before the five-pair series ran; both include that series' four runs which the same declaration's disk-cache rule makes invalid, and the declaration did not say how to treat them. The sign is not consistent across pairs; the one series with every pair higher on this change is the one with unequal journals. Four of the eight pairs have a run with 4 to 6 misses in the boot, none later (cause not chased); grouped after seeing the data, the four pairs without one give +445 / −541 / +83 / −434 MiB. Host placements by frame 1,055:mainin 2 of its 8 shared-journal runs ([bufferpool] at least 3 in one, at least 1 in the other), this change in 3 of 8 ([gpu] at least 3 with [bufferpool] at least 1 in one, [bufferpool] at least 1 in each of the other two); the capture pair: this change [gpu] at least 8,mainnone.Checklist
main(mainf8f5b24 merged in at c5dcde9, after the results above were posted); no other open PR implements the same functions.mdfiles or images added to the repository🤖 Generated with Claude Code