Repository navigation
perf(shader): drop window stores no relative read can see - #7560
Conversation
|
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.
|
|
Apple GPU / MoltenVK run, as a second vendor next to the RTX 3060/4060 runs. The pass changes the SPIR-V that SPIRV-Cross turns into Metal for every program with a vector window. Machine: Apple M2 Max, macOS 27.2, x86-64 build under Rosetta. Head c7a652e. Method: macos-port @ b7eb6b6 + ImportWatched + PR diff, not main. The pass, its header and the Test set: the 31 tests matching
The port doesn't have GPUs tested: Apple M2 Max (MoltenVK 1.4.2 and MoltenVK main + SPIRV-Cross #2704) Written with AI assistance (Claude Code). I ran the builds and tests above on my machine. |
|
Frame check on the RTX 3060 12 GB, MCD2 title screen, default settings, every 200th frame saved, two alternating rounds of
The differences with the change match the run-to-run differences of |
|
Thanks, the liveness looks right to me, and the reaching-store walks in the emitter keep their stores, because a store a load can reach is never dead. One test gap: the new |
c7a652e to
ca01351
Compare
|
Added
Every lane's loaded value is checked, in wave32 and wave64. As a mutation check I made |
|
This pull request is labeled |
|
Traces of the performance capture in the description (they open in ui.perfetto.dev): |
|
Intel and AMD Windows data: Windows 11 Pro 26300, WinLibs GCC 15.2.0 r7, Release, every execution test built,
This is a correctness check only; I measured no speed. I also ran full CTest with this PR and the 13 other open AGC and shader PRs I tested in the same batch merged together (#7668, #7659, #7504, #7432, #7426, #7413, #7480, #7465, #7466, #7464, #7449, #7489, #7673). Neither GPU showed a failure beyond AI-assisted: yes (Claude Code) |
|
First AMD-on-Linux (RADV) run of this PR. Merged onto AMD Radeon RX 7900 XT (RADV NAVI31, gfx1100), Mesa 25.2.8, Linux Mint 22.3 (Ubuntu 24.04 base), kernel 7.0.0-38, GCC 13.3, Release. Full suite ( GPUs tested: AMD Radeon RX 7900 XT (RADV NAVI31, gfx1100), Mesa 25.2.8, Linux Mint 22.3 / kernel 7.0.0-38 AI-assisted: yes |
What
A program that uses relative VGPR addressing (
v_movrels*/v_movreld*) gets a per-invocation vector window, and every write to a register inside the window is also stored into it so relative reads see the value (IrBuilder::SetVectorReg). In Minecraft Dungeons II's hottest compute programs almost none of those stores can be read: program 0x1c00843000 has 2,196 window stores and 3 relative reads, and 2,117 of the stores are overwritten or reach the end of the program before any window load could see them. They still cost GPU time.MaskedSelectEliminatorcounts a window store as a reader of every lane, so the EXEC merge it stores stays (95 % of the merges left in that program are kept only by a window store), andDenormalFlushEliminatorthen keeps the input flushes behind those merges.VectorWindowStoreEliminatorruns after the read-lane step and beforeMaskedSelectEliminator. It is a backward liveness over the window slots: a constant-indexLoadVectorWindowreads its slot, a dynamic one reads every slot (dynamic indexes are clamped into the window), a constant-indexStoreVectorWindowoverwrites its slot, and a dynamic store overwrites nothing and is never removed. A constant-index store whose slot is not live after it is deleted. The window is per-invocation Function memory that onlyLoadVectorWindowreads, and a window store is an unconditionalOpStoreof the already merged value, so no loaded value changes in any lane. The existing passes then remove the merges and flushes those stores kept alive.agc_vector_window_testsgets a case where a window register is written twice before a relative read; it must leave as many window stores as writing it once. Without the pass it fails with "window stores: written twice 4, written once 3".Tested
Windows 10 19045, MinGW GCC, Release.
main1c523bd againstmainplus this commit: 8.14 / 8.10 / 8.10 / 8.08 FPS against 8.28 / 8.29 / 8.25 / 8.28 (+2.1 %). GPU time per frame of the three hottest window programs: 7.9 → 7.0 ms, 6.2 → 5.3 ms, 2.55 → 2.41 ms.agc_shader_replay --spv): program 0x1c00843000 goes from 238,094 to 212,781 SPIR-V words and from 7,509 to 5,921OpSelect; 0x1bc05c4000 from 212,409 to 190,772 words.APS5_TEXTURE_CACHE_MIB=3072, 4 rounds: the two hottest window programs go from 5.6 to 5.0 ms and from 4.5 to 4.0 ms per frame, but FPS stays within this box's noise (8.13 / 8.23 / 8.23 / 8.32 against 8.33 / 8.23 / 8.20 / 8.23): GPU busy drops from 96 to 95 ms and the idle gaps grow by about as much, so the frame there is set by more than the GPU.main385ed71: the 44 recompiler, window, relative-addressing, lane, DPP, denormal and masked-select tests pass, among themagc_vector_window,agc_vector_window_stage_inputs,agc_driver_relative_indexing,agc_driver_scalar_relative_indexing,agc_driver_relative_stage_inputs,agc_driver_relative_ancillary,agc_driver_vector_window_direct_access,agc_driver_vector_window_narrowing,agc_masked_select,agc_denormal_flush_elimination,agc_driver_read_lane,agc_shader_memory, theagc_structurizervariants and the DPP and denormal-mode execution tests. With the pass disabled, the new case inagc_vector_windowfails.agc_driver_vector_window_liveness(new,tests/execution/VectorWindowLiveness.cpp): a window register written before a scalar branch and overwritten on one side only, then read by a constant-indexv_movrelsafter the join (both sides run), and a register read at the top of a three-iteration loop and overwritten after the read; every lane's loaded value is checked in wave32 and wave64. WithliveOutignoring the successors it fails.tools/check_conventions.py --base origin/mainpasses.Performance capture (as the Performance report form describes): Minecraft Dungeons II (PPSA16064) title screen, RTX 3060 12 GB (i5-12400F), NVIDIA 617.42, Windows 10.0.19045, 3840x2160 output. Only
APS5_TRACE_SECONDS=120:12set, caches warm (the title ran once on the build and was restarted), stderr not redirected.main48d61f5 against this PR's head ca01351:Frame and GPU times (ms):
Top phases (ms per frame):
{"commit":"48d61f53b46f","dirty":false,"env":{"APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 3060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2158,"ms":12053.995},"presents":99,"frame_ms":{"p50":117.162,"p90":145.047,"p99":158.422,"max":158.422},"gpu_busy_ms_per_present":100.711,"worker_busy_pct":{"queue worker 0x0":99.421,"queue worker 0x20":99.581},"top_phases_ms_per_frame":{"Driver.Packet":242.204,"Driver.Packet.dispatch":86.382,"Driver.Dispatch":85.879,"Driver.Packet.memory_wait":68.067,"Vulkan.Dispatch":40.265,"Vulkan.Dispatch.shader_resources":38.025,"Driver.Packet.device_lock":34.172,"Driver.Packet.prepare_memory":30.126},"trace_dropped":false,"trace":"aps5-trace-48d61f53b46f-9720.json.gz"} {"commit":"ca01351ff882","dirty":false,"env":{"APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 3060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2169,"ms":12017.926},"presents":101,"frame_ms":{"p50":114.665,"p90":143.229,"p99":164.200,"max":165.107},"gpu_busy_ms_per_present":97.535,"worker_busy_pct":{"queue worker 0x0":99.409,"queue worker 0x20":99.595},"top_phases_ms_per_frame":{"Driver.Packet":236.692,"Driver.Packet.dispatch":83.295,"Driver.Dispatch":82.809,"Driver.Packet.memory_wait":66.238,"Vulkan.Dispatch":38.789,"Vulkan.Dispatch.shader_resources":36.507,"Driver.Packet.device_lock":34.858,"Driver.Packet.prepare_memory":28.812},"trace_dropped":false,"trace":"aps5-trace-ca01351ff882-11512.json.gz"}Traces:
aps5-trace-48d61f53b46f-9720.json.gz(main) andaps5-trace-ca01351ff882-11512.json.gz(this PR), attached below.trace_digest.py, main
seconds 120:12 from present 2158: 99 presents, frame p50 117.2 / p90 145.0 / p99 158.4 / max 158.4 ms, GPU busy 100.7 ms per present
NVIDIA GeForce RTX 3060, NVIDIA 617.42, Windows 10.0.19045, 3840x2160, commit 48d61f5, dropped: no
{"commit":"48d61f53b46f","dirty":false,"env":{"APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 3060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2158,"ms":12053.995},"presents":99,"frame_ms":{"p50":117.162,"p90":145.047,"p99":158.422,"max":158.422},"gpu_busy_ms_per_present":100.711,"worker_busy_pct":{"queue worker 0x0":99.421,"queue worker 0x20":99.581},"top_phases_ms_per_frame":{"Driver.Packet":242.204,"Driver.Packet.dispatch":86.382,"Driver.Dispatch":85.879,"Driver.Packet.memory_wait":68.067,"Vulkan.Dispatch":40.265,"Vulkan.Dispatch.shader_resources":38.025,"Driver.Packet.device_lock":34.172,"Driver.Packet.prepare_memory":30.126},"trace_dropped":false,"trace":"aps5-trace-48d61f53b46f-9720.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 235.3, batch 100.7, Driver.Packet.dispatch 86.1, Driver.Dispatch 85.2, Driver.Packet.memory_wait 68.0, Vulkan.Dispatch 39.4, Vulkan.Dispatch.shader_resources 37.1, Driver.Packet.device_lock 32.2, Driver.Packet.prepare_memory 27.8, Recorder.Sync 20.7
Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
trace_digest.py, this PR
seconds 120:12 from present 2169: 101 presents, frame p50 114.7 / p90 143.2 / p99 164.2 / max 165.1 ms, GPU busy 97.5 ms per present
NVIDIA GeForce RTX 3060, NVIDIA 617.42, Windows 10.0.19045, 3840x2160, commit ca01351, dropped: no
{"commit":"ca01351ff882","dirty":false,"env":{"APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 3060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2169,"ms":12017.926},"presents":101,"frame_ms":{"p50":114.665,"p90":143.229,"p99":164.2,"max":165.107},"gpu_busy_ms_per_present":97.535,"worker_busy_pct":{"queue worker 0x0":99.409,"queue worker 0x20":99.595},"top_phases_ms_per_frame":{"Driver.Packet":236.692,"Driver.Packet.dispatch":83.295,"Driver.Dispatch":82.809,"Driver.Packet.memory_wait":66.238,"Vulkan.Dispatch":38.789,"Vulkan.Dispatch.shader_resources":36.507,"Driver.Packet.device_lock":34.858,"Driver.Packet.prepare_memory":28.812},"trace_dropped":false,"trace":"aps5-trace-ca01351ff882-11512.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 229.8, batch 98.5, Driver.Packet.dispatch 83.0, Driver.Dispatch 82.1, Driver.Packet.memory_wait 66.2, Vulkan.Dispatch 37.9, Vulkan.Dispatch.shader_resources 35.5, Driver.Packet.device_lock 32.9, Driver.Packet.prepare_memory 26.5, Recorder.WaitSerial 19.9
Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
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)