Repository navigation
perf(agc): data-only draw hits compare only the user words a stage reads - #5656
Conversation
CnRJay
left a comment
There was a problem hiding this comment.
Comparing only the user words a stage depends on is a natural refinement of #494. Running Hades II with APS5_VERIFY_DRAW_DATA_HITS=1 and 0 differing stages is the right correctness check.
On the evidence: both summary lines were captured with APS5_PROFILE_DRAW=1 set (it is in their env). The Performance report form asks for runs with no APS5_PROFILE_* switch, because the draw profiler times every draw and changes the cost being measured, here on the draw path itself. Please capture the two lines again with only APS5_HOST_IMPORT_MIB and APS5_TRACE_SECONDS. If the p50 gain (34.0 → 26.9 ms) holds without the profiler, that settles it. Both lines also show trace_dropped: true, so the attached traces are incomplete; a shorter window keeps them whole.
One question on the mask: are user words a stage uses as plain values, read straight from user SGPRs into ALU work rather than through the SRT walk or forwarded shader data, always covered by userDataRegisterReads? If a stage can consume a user word that neither source records, a change to that word would leave it outside the mask and reuse a stage compiled for the old value. Either a sentence saying which path covers it, or a test with a pixel stage that does arithmetic on a user word (and nothing else), would close that.
|
Measured on DAVE THE DIVER (PPSA19115), as announced in #5436. Short version: data-only hits trigger on almost every keyless draw, but the frame time barely moves, because the user words that change in this title are pointers the stages read. Setup. Windows 11, RTX 5060 (596.36), Ryzen 7 5800X; build with Median over the 10 s intervals after the first 50 s:
The gain is within run-to-run noise (the #5656 run had 9 intervals in the scene, the base 28). From the
So the shape lookup works and the decode is skipped nearly everywhere, but the stages are still captured and compiled. A churn trace on the base (exact key vs shape, logged per user word) showed 288 shapes against ~456k exact keys in a few minutes, every new key differing only in user words, about 95% of the changed words increasing: ring-buffer pointers that the SRT walk reads, so Port notes, in case they are useful for a rebase:
Most of the frame in this title is on the resource side ( AI-assisted: yes |
|
Stacked this on #6188 (0eb0d89) over d92a8da in Astro's Playroom on Linux (RTX 5080, heavy in-game scene, one 20 s run each,
So with 6188 compiling ahead, 5656's data-only hits cover almost every draw in this scene. In the merge I applied the user-word mask in 6188's |
1b62f59 to
9809434
Compare
|
Thanks. Rebased on c4c2b3a, and the format and size points are fixed:
LLM assistance used. |
9809434 to
fe87a2c
Compare
|
@Raghav314 This one is reviewed and CI was green on fe87a2c, but it conflicts with current #4650 has merged (b876d43). It moved
Once it's pushed we'll check the resolution, run full CI again ( |
A data-only hit (boykopovar#494) reused a cached stage only when every user data word of the stage was unchanged. A stage records the user words it depends on when it is captured: the words its SRT walk reads as values or bases (SrtUserDataUse), the words its binding layout forwards into shader data (userDataRegisterReads), and the vertex fetch table words of its vertex stage info. A cached stage is now a candidate when only words outside that set changed; its captured memory is validated as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… SGPR follows a change of that word The word reaches the data-only mask through userDataRegisterReads (the stage layout's user-data registers). Dropping those bits from the mask makes the draw reuse the old stage (it writes 127, expected 191) and verify mode abort. LLM assistance used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fe87a2c to
5892c84
Compare
…povar#6946 onto 4b462ef (programs table, AppendContentKey order, test name clash with the Windows near macro) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Retested your current head This is integration evidence, not an isolated main-versus-PR acceptance test: the preserved baseline On AMD Radeon RX 6650 XT / RADV Mesa 26.2.4-1, Arch Linux:
Evidence archive includes the complete focused logs, source delta/history, native reports/logs and reviewed hub captures. Native runs themselves did not enable core validation. No FPS claim: these runs differ in capture timing/duration and do not contain matched official performance traces. |
|
Follow-up with matched Hades II (PPSA36082, 01.006.000) hub traces on the same RX 6650 XT/RADV machine. The four runs use baseline → candidate → candidate → baseline order, warm caches with title restart, the exact same eight-file save manifest, identical scheduled inputs, window and settings. Reviewed 155/175-second captures show the same character/camera position in the idle hub; animation phases differ.
Both candidate medians are lower than both baseline medians. The average of the two run medians is about 9% lower, and shader compile/link time per present about 23% lower. This is limited evidence from two five-second idle-hub captures per build, not a gameplay-wide speed claim. As in the earlier comment, baseline Capture: Trace/evidence archive contains all four traces and Official summary lines, in run order: {"commit":"50d7ce6043ef","dirty":false,"env":{"APS5_DRAW_CACHE_ENTRIES":"4096","APS5_HOST_IMPORT_MIB":"16384","APS5_PAD_INPUT_FILE":"<path>","APS5_PIPELINED_DRAWS":"1","APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"160:5"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","cpu":"AMD Ryzen 9 7950X 16-Core Processor","cpu_threads":32,"memory_mib":127901,"title_id":"PPSA36082","title":"Hades II","content_version":"01.006.000","resolution":"1920x1080","window":{"spec":"seconds 160:5","first_present":9061,"ms":5018.886},"presents":193,"frame_ms":{"p50":24.104,"p90":30.687,"p99":35.452,"max":37.382},"gpu_busy_ms_per_present":9.881,"worker_busy_pct":{"queue worker 0x0":98.212},"top_phases_ms_per_frame":{"Driver.Packet":25.511,"Driver.Packet.draw":22.967,"Driver.Draw":22.819,"Driver.Draw.shader_compile_and_link":13.106,"Graphics.Draw":12.756,"Graphics.Draw.draw_and_resource_release":11.108,"Shader.DrawStage":9.543,"Driver.Draw.draw_enqueued":7.12},"trace_dropped":false,"trace":"aps5-trace-50d7ce6043ef-2273323.json.gz"}
{"commit":"00e194906025","dirty":false,"env":{"APS5_DRAW_CACHE_ENTRIES":"4096","APS5_HOST_IMPORT_MIB":"16384","APS5_PAD_INPUT_FILE":"<path>","APS5_PIPELINED_DRAWS":"1","APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"160:5"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","cpu":"AMD Ryzen 9 7950X 16-Core Processor","cpu_threads":32,"memory_mib":127901,"title_id":"PPSA36082","title":"Hades II","content_version":"01.006.000","resolution":"1920x1080","window":{"spec":"seconds 160:5","first_present":9129,"ms":5016.902},"presents":228,"frame_ms":{"p50":21.286,"p90":26.482,"p99":29.974,"max":31.317},"gpu_busy_ms_per_present":9.533,"worker_busy_pct":{"queue worker 0x0":98.14},"top_phases_ms_per_frame":{"Driver.Packet":21.57,"Driver.Packet.draw":19.305,"Driver.Draw":19.175,"Graphics.Draw":11.556,"Graphics.Draw.draw_and_resource_release":10.172,"Driver.Draw.shader_compile_and_link":9.83,"Driver.Draw.draw_enqueued":7.179,"Shader.DrawStage":6.804},"trace_dropped":false,"trace":"aps5-trace-00e194906025-2357397.json.gz"}
{"commit":"00e194906025","dirty":false,"env":{"APS5_DRAW_CACHE_ENTRIES":"4096","APS5_HOST_IMPORT_MIB":"16384","APS5_PAD_INPUT_FILE":"<path>","APS5_PIPELINED_DRAWS":"1","APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"160:5"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","cpu":"AMD Ryzen 9 7950X 16-Core Processor","cpu_threads":32,"memory_mib":127901,"title_id":"PPSA36082","title":"Hades II","content_version":"01.006.000","resolution":"1920x1080","window":{"spec":"seconds 160:5","first_present":9260,"ms":5006.487},"presents":224,"frame_ms":{"p50":21.771,"p90":26.388,"p99":30.162,"max":30.76},"gpu_busy_ms_per_present":9.723,"worker_busy_pct":{"queue worker 0x0":98.259},"top_phases_ms_per_frame":{"Driver.Packet":21.938,"Driver.Packet.draw":19.753,"Driver.Draw":19.627,"Graphics.Draw":11.441,"Graphics.Draw.draw_and_resource_release":10.045,"Driver.Draw.shader_compile_and_link":10.011,"Driver.Draw.draw_enqueued":7.387,"Shader.DrawStage":6.799},"trace_dropped":false,"trace":"aps5-trace-00e194906025-2432685.json.gz"}
{"commit":"50d7ce6043ef","dirty":false,"env":{"APS5_DRAW_CACHE_ENTRIES":"4096","APS5_HOST_IMPORT_MIB":"16384","APS5_PAD_INPUT_FILE":"<path>","APS5_PIPELINED_DRAWS":"1","APS5_TRACE_EVENTS":"1048576","APS5_TRACE_SECONDS":"160:5"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","cpu":"AMD Ryzen 9 7950X 16-Core Processor","cpu_threads":32,"memory_mib":127901,"title_id":"PPSA36082","title":"Hades II","content_version":"01.006.000","resolution":"1920x1080","window":{"spec":"seconds 160:5","first_present":8890,"ms":5011.761},"presents":198,"frame_ms":{"p50":23.322,"p90":30.306,"p99":38.693,"max":59.096},"gpu_busy_ms_per_present":9.689,"worker_busy_pct":{"queue worker 0x0":98.152},"top_phases_ms_per_frame":{"Driver.Packet":24.815,"Driver.Packet.draw":22.333,"Driver.Draw":22.192,"Driver.Draw.shader_compile_and_link":12.618,"Graphics.Draw":12.463,"Graphics.Draw.draw_and_resource_release":10.911,"Shader.DrawStage":9.24,"Driver.Draw.draw_enqueued":6.984},"trace_dropped":false,"trace":"aps5-trace-50d7ce6043ef-2512164.json.gz"} |
…povar#6946 onto 4b462ef (programs table, AppendContentKey order, test name clash with the Windows near macro) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Module records are SPIR-V and take almost all of a journal's bytes, so APS5_PIPELINE_JOURNAL_MAX_MIB fills with modules and later pipelines are not recorded (boykopovar#8309). A module record now keeps its identity, stage and encoded size, followed by a zstd frame (level 1) of the encoded result; loading and replay expand it before decoding. The journal format becomes 6 (main took 5 for the recipe codec change of boykopovar#5656). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A small positive result on ASTRO BOT now that #7844 removes the import-budget regression that hid it in my earlier A/B. Builds: the merge parent
Both post medians are below both pre medians: about 2 % lower frame time, with a tighter p99. GPU busy time per present is unchanged (~136 ms), so the gain is on the CPU side. Edit: where the remaining data-only misses come from on this level (corrected). A local counter in
So on this title the per-draw cost comes from per-object descriptor tables in memory, at a new address and with new contents for each draw. The existing relocation ( Tested and written by Claude (AI assistant) on a contributor's machine. |
Pipeline creation and SPIR-V validation read State::vertexPoints and the three point sizes, so the pipeline journal's recipe codec and canonical state now carry them, the State layout guard names its new size and the journal format becomes 6 (main took 5 for the recipe codec change of boykopovar#5656). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pipeline journal guards State and ShaderStages, which this branch extends. The recipe codec and canonical state now carry the hull wave size, the geometry stage after tessellation, the merged hull flag (TessellationConfiguration keeps its size, so its guard can't see it) and rasterizer discard, and the journal format becomes 6 (main took 5 for the recipe codec change of boykopovar#5656). A pipeline drawn with a tessellation capture validates against that draw's capture buffers, which a replay doesn't have, so it isn't journaled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pipeline creation and SPIR-V validation read State::vertexPoints and the three point sizes, so the pipeline journal's recipe codec and canonical state now carry them, the State layout guard names its new size and the journal format becomes 6 (main took 5 for the recipe codec change of boykopovar#5656). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
A data-only draw hit (#494) reuses a cached stage only when every user data word of the stage is unchanged. A title that changes a user word per draw that a stage never reads (a per-draw counter, a pointer only another stage follows) gets no reuse for that stage, though its compiled result and captured memory would be the same.
SrtUserDataUse::asValue | asBase);userDataRegisterReads), which covers words a stage reads straight from its SGPRs;PPSA36082
In Hades II most draws change user words between draws (a per-draw counter and ring pointers). In the level UI/menu, the stage preparation in the draw path (
Shader.DrawStage) goes from 6.5 to 5.1 ms per frame and the frame time p50 from 18.5 to 17.6 ms (530 to 560 presents in 10 s). The picture is unchanged.Level UI/menu standing still,
APS5_HOST_IMPORT_MIB=6784, noAPS5_PROFILE_*switch,APS5_TRACE_EVENTS=1048576so the traces are whole, shader cache warmed for each build, one run each (measured onmain93e54ce):main:The frame time moves with the window position (an earlier pair at
150:10gave 466 to 574 presents), so the stage time is the steadier number.Tested
Linux (CachyOS), x86-64, GCC, 7800X3D / RTX 4090, NVIDIA 615.78.08, on
main0d8c51a.agc_driver_draw_data_hit_user_words: the pixel stage loads a buffer descriptor through user words 0 and 1 and never reads word 2. A draw that changes only word 2 is a data-only hit that reuses both stages; a draw that points words 0 and 1 at another descriptor compiles the pixel stage again and reuses the vertex stage._verifyruns the same draws withAPS5_VERIFY_DRAW_DATA_HITS=1.userDataRegisterReadsleft out of the mask the draw reuses the old stage, writes 127, and verify mode aborts.main's second-sight admission needs.build.ymlrun locally on perf(agc): draw finisher pipeline (APS5_DRAW_PIPELINE) #6946's branch, which is this PR with perf(agc): draw finisher pipeline (APS5_DRAW_PIPELINE) #6946 on top: configure with SPIRV tools on, test registration check, build, libs, the whole ctest and conventions. 1693/1693 pass, 16 expected skips, conventions OK.APS5_VERIFY_DRAW_DATA_HITS=1 APS5_VERIFY_DRAW_ENTRIES=1 APS5_VERIFY_REGISTER_KEYS=1on the earlier perf(agc): draws that differ only in user data reuse their shape's decode and stages #494-based version of this change: 0 stages differed, picture fine.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)