Skip to content

perf(shader): skip redundant fault-buffer discovery - #13570

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
Filip722:perf/shader-info-fault-scan-20261030
Oct 31, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
Filip722:perf/shader-info-fault-scan-20261030

Conversation

@Filip722

Copy link
Copy Markdown
Contributor

What

Shader-info collection walks all instructions looking for a 64-bit shared atomic even when the fault-buffer flag is already true. Short-circuit that pure discovery scan once its result cannot affect the flag.

  • Keep the identical predicate and order when the incoming flag is false.
  • Preserve all earlier validation and later metadata collection.
  • Reuse the existing shader-memory and LDS atomic fixtures; no new test infrastructure or diagnostic enters the patch.

cb28abeb89b added the atomic fault requirement; cd329c060aa made it unconditional on sharedMemoryBytes. That requirement remains, including workgroup-backed LDS. SharedAccessOf is a total pure switch, and the scan is discovery, not validation. Normal Recompile and the diagnostic deserializer receive the same complete ShaderInfo. No guest instruction, FP, EXEC, fault or memory-ordering semantics change.

Tested

Debian 13 / Linux 7.2.12-x64v3-xanmod1, Ryzen 5 7640HS, AMD Radeon 760M, RADV Mesa 25.0.7-2+deb13u1. Main cde94eb55a65 and candidate 7fa759dc64ec pass the same five focused tests: agc_shader_memory, agc_spirv_lds_atomic_lock, agc_driver_buffer_descriptor_runtime, agc_driver_lds_mixed_width_atomics and agc_driver_lds_lock_budget. Actual hardware includes mixed-width locking and misalignment faults on device-backed/workgroup LDS. Both arms require Vulkan, disable shader caching and insert Khronos validation on all three Radeon fixtures: zero VUID errors, missing layers or skips. Initial skipped build stubs were detected; the real LDS source was enabled before both final matched checks. These are local results; CI is not claimed.

Private same-process checks run the actual original/candidate Collect bodies on the same programs after restoring input ShaderInfo/completion, with a separate baseline pixel-input copy. All 392 complete ShaderInfo, completion flags and pixel-coverage results match. ShaderMemory has 382 calls: 61 already-true inputs and 321 false-to-false. SpirvLdsAtomicLock has 10: six false-to-true and four false-to-false. Atomic-predicate visits 15,666→10,258, with all required false-flag searches unchanged. No new production counter or fixture is added.

Native tradeoff: identical GCC 15.2 Release flags emit the expected flag branch bypassing the search loop. Main grows 1,670→1,674 instructions while bytes fall 8,446→8,442; branches 262→264, static calls 108 unchanged. Cold stays 221 instructions/40 branches/40 calls, bytes 1,136→1,144. Combined bytes 9,582→9,586. Both retain 872 local stack bytes and six saved-GPR pushes; spills were not measured. Production text sections match the uninstrumented private candidate. This is eliminated executed CPU work, with no static code-size, native GPU instruction or elapsed compilation gain claim.

Verified timing-only evidence includes all four original traces, original summaries, upstream digests, protocol, per-run audits, work/native statistics, validation and exact source/library provenance. Raw objects, ISA, cache files, game/save data, screenshots and console logs remain local. The overlap checker could not merge stale PRs #9748/#12619; their exact patches were manually reviewed: target-merge layered image metadata and flat pixel-input aliases respectively, with no shared changed lines or fault-scan mechanism. No dependency is required.

Sons of Sparta (PPSA28997 v01.008.001), restored camp, 1920x1080 native / focused 1152x648 Wayland client, mailbox, 25:12s windows. Both initial warmups use the same retained same-driver RADV cache and empty source shader caches, then independently warm and restart. All four A1/B1/B2/A2 captures pass with no exclusions or replacements: 21.75316→21.74201 FPS (observed -0.051%; pairs +0.173%/-0.275%). GPU busy 42.8125→42.7600 ms/present. The few warmed scene runs do not establish a significant/general gameplay gain or measure cold compilation latency.

Timing used main 4bc9e779aa7a and candidate 3815c275a08f. The full candidate runtime set is independently verified: shader library differs; VideoOut differs only in ten bytes of embedded revision text, all other bytes identical. All 50 native/9 guest loaded-library hashes are pinned. Source-revisions.json distinguishes timed builds from submission revisions after any upstream refresh; the collector source is byte-identical through that refresh. The submission refresh changes only the release workflow timeout; runtime sources and build flags are unchanged. Refreshed heads are not claimed to have been timed.

Original summaries in A1/B1/B2/A2 order:

{"commit":"4bc9e779aa7a","dirty":true,"env":{"APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"25:12"},"gpu":"AMD Radeon 760M (RADV PHOENIX)","driver":"radv Mesa 25.0.7-2+deb13u1","os":"Linux 7.2.12-x64v3-xanmod1","cpu":"AMD Ryzen 5 7640HS w/ Radeon 760M Graphics","cpu_threads":12,"memory_mib":23820,"title_id":"PPSA28997","title":"God of War Sons of Sparta","content_version":"01.008.001","resolution":"1920x1080","window":{"spec":"seconds 25:12","first_present":549,"ms":12015.108},"presents":261,"frame_ms":{"p50":45.965,"p90":46.452,"p99":47.622,"max":50.127},"gpu_busy_ms_per_present":42.830,"worker_busy_pct":{"queue worker 0x0":78.428},"top_phases_ms_per_frame":{"Driver.Packet":35.978,"Driver.Packet.draw":33.471,"Driver.Draw":33.431,"Driver.Draw.draw_enqueued":29.765,"Recorder.Sync":28.711,"VideoOut.Flip":9.063,"Driver.Present":9.030,"VideoOut.Flip.present":9.026},"trace_dropped":false,"trace":"aps5-trace-4bc9e779aa7a-3906520.json.gz"}
{"commit":"3815c275a08f","dirty":true,"env":{"APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"25:12"},"gpu":"AMD Radeon 760M (RADV PHOENIX)","driver":"radv Mesa 25.0.7-2+deb13u1","os":"Linux 7.2.12-x64v3-xanmod1","cpu":"AMD Ryzen 5 7640HS w/ Radeon 760M Graphics","cpu_threads":12,"memory_mib":23820,"title_id":"PPSA28997","title":"God of War Sons of Sparta","content_version":"01.008.001","resolution":"1920x1080","window":{"spec":"seconds 25:12","first_present":541,"ms":12040.281},"presents":262,"frame_ms":{"p50":45.936,"p90":46.329,"p99":46.792,"max":47.791},"gpu_busy_ms_per_present":42.747,"worker_busy_pct":{"queue worker 0x0":78.377},"top_phases_ms_per_frame":{"Driver.Packet":35.883,"Driver.Packet.draw":33.374,"Driver.Draw":33.334,"Driver.Draw.draw_enqueued":29.821,"Recorder.Sync":28.574,"VideoOut.Flip":9.075,"Driver.Present":9.064,"VideoOut.Flip.present":9.037},"trace_dropped":false,"trace":"aps5-trace-3815c275a08f-3907543.json.gz"}
{"commit":"3815c275a08f","dirty":true,"env":{"APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"25:12"},"gpu":"AMD Radeon 760M (RADV PHOENIX)","driver":"radv Mesa 25.0.7-2+deb13u1","os":"Linux 7.2.12-x64v3-xanmod1","cpu":"AMD Ryzen 5 7640HS w/ Radeon 760M Graphics","cpu_threads":12,"memory_mib":23820,"title_id":"PPSA28997","title":"God of War Sons of Sparta","content_version":"01.008.001","resolution":"1920x1080","window":{"spec":"seconds 25:12","first_present":546,"ms":12014.509},"presents":261,"frame_ms":{"p50":45.942,"p90":46.601,"p99":47.733,"max":49.419},"gpu_busy_ms_per_present":42.773,"worker_busy_pct":{"queue worker 0x0":78.443},"top_phases_ms_per_frame":{"Driver.Packet":35.974,"Driver.Packet.draw":33.407,"Driver.Draw":33.365,"Driver.Draw.draw_enqueued":29.544,"Recorder.Sync":28.440,"VideoOut.Flip":9.066,"Driver.Present":9.054,"VideoOut.Flip.present":9.027},"trace_dropped":false,"trace":"aps5-trace-3815c275a08f-3908557.json.gz"}
{"commit":"4bc9e779aa7a","dirty":true,"env":{"APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"25:12"},"gpu":"AMD Radeon 760M (RADV PHOENIX)","driver":"radv Mesa 25.0.7-2+deb13u1","os":"Linux 7.2.12-x64v3-xanmod1","cpu":"AMD Ryzen 5 7640HS w/ Radeon 760M Graphics","cpu_threads":12,"memory_mib":23820,"title_id":"PPSA28997","title":"God of War Sons of Sparta","content_version":"01.008.001","resolution":"1920x1080","window":{"spec":"seconds 25:12","first_present":562,"ms":12027.354},"presents":262,"frame_ms":{"p50":45.836,"p90":46.373,"p99":47.437,"max":48.209},"gpu_busy_ms_per_present":42.795,"worker_busy_pct":{"queue worker 0x0":78.435},"top_phases_ms_per_frame":{"Driver.Packet":35.875,"Driver.Packet.draw":33.379,"Driver.Draw":33.338,"Driver.Draw.draw_enqueued":29.490,"Recorder.Sync":28.448,"VideoOut.Flip":9.075,"Driver.Present":9.065,"VideoOut.Flip.present":9.037},"trace_dropped":false,"trace":"aps5-trace-4bc9e779aa7a-3909485.json.gz"}

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
  • Fixes: none
  • Unblocks: none
  • GPUs tested: AMD Radeon 760M (RADV PHOENIX), Mesa 25.0.7-2+deb13u1, Debian GNU/Linux 13 / Linux 7.2.12-x64v3-xanmod1
  • AI-assisted: yes

@github-actions github-actions Bot added the perf Performance change label Oct 30, 2026
@github-actions

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 9748 core/shader/recompiler/Optimization/src/ShaderInfoCollector.cpp
PR 12619 core/shader/recompiler/Optimization/src/ShaderInfoCollector.cpp

@Noxy-HNR

Copy link
Copy Markdown
Contributor

Windows data point for 7fa759dc64: Windows 11 (build 26300), Intel Core Ultra 7 255HX, NVIDIA GeForce RTX 5070 Ti Laptop GPU (driver 617.14), WinLibs MinGW-w64 GCC 15.2.0, Release, ANYPS5_REQUIRE_VULKAN=1, with the RTX selected as the Vulkan device.

On this PR and on its base cde94eb55a, built the same way, the five tests from the description pass on both: agc_spirv_lds_atomic_lock, agc_shader_memory, agc_driver_buffer_descriptor_runtime, agc_driver_lds_mixed_width_atomics, agc_driver_lds_lock_budget.

The change is a straight || short-circuit of the same predicate, and the scan has no side effects, so the flag ends up the same either way. Looks good to me.

@adriadam10 adriadam10 self-assigned this Oct 31, 2026
@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 7fa759d merged onto main 6b48aee · tested 2026-10-31 02:29 UTC · 22 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,314 passed · 4 failed (0 new, 3 also fail on main, 1 unstable on main) · 41 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,359 of 3,041 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (863 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_graphics 33.4 s, ⚠️ agc_driver_graphics_maps_fallback 31.8 s, ⚠️ agc_driver_bda_device 31.3 s
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)
agc_submit_progress: failed in 6 of the last 10 main runs
Failing on main too (3, not counted against this PR)
agc_submit_progress_no_timeline
guest_mmap_executable
guest_socket_options_multicast
Validation IDs already present on main (3 IDs in 380 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (380 tests): agc_compute_pipeline_replay, agc_driver, agc_driver_address_passes, agc_driver_address_passes_draw_transitions, agc_driver_address_passes_targets_split, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, and 372 more
VUID-vkCmdCopyImage-srcImage-01548 (12 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_plane_sampling, and 4 more
VUID-vkCmdCopyImage-srcImage-01551 (12 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_plane_sampling, and 4 more
Skipped (41)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_msaa_dcc_compared_import_2: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_msaa_dcc_compared_import_4: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_msaa_dcc_compared_import_8: skipped, the device reports host imports that keep write protection, so the write-watch probe compares none of them
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_driver_stencil_ref_export: skipped, the device lacks VK_EXT_shader_stencil_export
agc_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_main: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_fresh: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_labels: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is eithe
Reproduce
git fetch origin 7fa759dc64ec9b1a26011019e194ac9ac726487e 6b48aee5d2ea9fce6155163d78f8ce8dc84f7827
git checkout 6b48aee5d2ea9fce6155163d78f8ce8dc84f7827 && git merge --no-ff 7fa759dc64ec9b1a26011019e194ac9ac726487e
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@adriadam10
adriadam10 merged commit 6475267 into boykopovar:main Oct 31, 2026
13 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the diff: usesFaultBuffer || any_of(...) keeps the same predicate and only skips the pure scan when the flag is already true; no other state depends on the scan. Windows run by @Noxy-HNR on the five listed tests and the NVIDIA run by @TechLevelZero also pass. The one red Windows test, check_compile_preprocessor, timed out at 20 s and is unrelated to this diff; merged.

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

Labels

perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants