Skip to content

perf(agc): extend pending write snapshots incrementally - #4889

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
Dripl1x:codex/agc-pending-write-snapshots
Oct 14, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
Dripl1x:codex/agc-pending-write-snapshots

Conversation

@Dripl1x

@Dripl1x Dripl1x commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What

Extend the immutable pending-GPU-write union when new ranges are added instead of rebuilding and sorting every raw write note from all outstanding batches. Repeated covered notes stay in the batch history, so previously each new uncovered range sorted that repeated history again.

  • A single valid addition uses binary search and merges touching/overlapping ranges into a new immutable snapshot.
  • Bulk additions sort the previous compressed union plus the new ranges.
  • Retirement, inactive-recorder mutations, owner changes and malformed/wrapping ranges keep the full rebuild path. A weak reference identifies the recorder's own published snapshot; a reused address or another recorder's snapshot is not accepted.
  • Invalidate the incremental state before publication allocations, so a failed publication recovers through a full rebuild on the next publication.
  • Preserve raw write chronology/values, atomic publication, fences and generation increments. Older readers retain an unchanged snapshot.

No guest exports, runtime switches, dependencies or user setup are added.

Component correctness and CPU-work measurements are below. Summary lines and traces of main and of this change, from the same machine and scene, are in this comment. The available homebrew scene (ps5-doom, timedemo) is limited by the 60 Hz present and barely exercises this path, so the captures show no regression and no speedup. This PR makes no game FPS claim.

Related: #4978 changes how pending reads are noted in the same recorder and does not change the pending-write snapshot. A trial merge of the two conflicts only in tests/Recorder.cpp, where both add test functions at the same place; both are kept. Neither is a functional prerequisite of the other, and its author prefers not to make #4978 wait, so this PR declares the order on its side and is rebased after #4978 merges (discussion).

Tested

Windows, NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA driver 617.42, WinLibs GCC 15.2, Release, BUILD_TESTING=ON, default ANYPS5_ENABLE_SPIRV_TOOLS=OFF.

  • On main 758aca737 plus this patch: built AGC and agc_driver_recorder_tests, agc_driver_graphics_tests, agc_driver_bda_device_tests with their dependencies from the standard root CMake configuration. Selected CTest suite: 21 passed, zero failures, 54.92 seconds total, longest test 12.99 seconds. Timeout stays 30 seconds.
  • New agc_pending_write_snapshot: differential comparison with a full-sort union after deterministic and randomized additions; overlap, adjacency, covered/bulk/fill/zero-size/wrapping notes; old-snapshot immutability; two concurrent readers; submitted/finishing batch lifetime; open/in-flight label writes; inactive mutations/retirement and recorder replacement.
  • Existing selected checks: graphics validation, Vulkan BDA execution, pipeline cache/library variants, CPU stamps, storage upload lifetime/failure, import unmap paths, descriptor recycling/reset failure, snapshot caps, multisample guest access, draw inputs and descriptor layout flags.
  • On this NVIDIA/Windows configuration the tests internally omit unit shadows and watched highest-index reuse. The draw-input host-import path does execute. The omitted branches are not claimed as verified.
  • On published commit d839eeda7, based on main 2a55cfe1e: rebuilt the same AGC/recorder/graphics/BDA targets and dependencies; the same 21 CTests pass, zero failures, 14.17 seconds total, longest test 6.99 seconds. The four touched files are unchanged in main between the measured base and this base. tools/check_conventions.py --base upstream/main and git diff --check pass. GitHub also reports the conventions check as successful.
  • On the rebased head ac145e9be48162d75e8509144edbc217dafd41dc, based on main 8cf6a0bc3: root configuration, ANYPS5_REQUIRE_VULKAN=1. The 28 CTests of agc_driver_recorder_tests, agc_driver_graphics_tests and agc_driver_bda_device_tests pass in 14.64 s, including the recorder tests added to main since the first publication. The output is in the same comment.
  • Full all-component Windows/Linux builds and Linux/lavapipe runtime coverage have not been performed. Allocation-failure recovery was reviewed in source, without allocation fault injection.

Isolated CPU component measurement

Baseline: main 758aca737 production recorder. Comparison: that same base plus only this patch. Both executables include the same benchmark test source and run with their own matching libraries on the same machine.

Order: baseline, optimized, optimized, baseline, optimized, baseline, baseline, optimized. Four processes per variant; each reports the median of five samples per scenario. The table is the median of the four process medians. Each initial range note is followed by the stated number of duplicate notes of that range.

The timer covers actual Recorder::NotePendingWrite calls. Command-batch creation and final GPU-fence waiting are outside it. These are synthetic CPU metadata workloads, not title or frame-time measurements; very small timings are sensitive to machine load.

Distinct ranges Duplicate notes per range Main ms This patch ms Ratio
8 0 0.00700 0.00620 1.13x
8 8 0.01740 0.01070 1.63x
8 64 0.06435 0.02900 2.22x
32 0 0.02365 0.01945 1.22x
32 8 0.09115 0.03205 2.84x
32 64 0.57555 0.10475 5.49x
512 0 1.84090 0.46775 3.94x
512 8 16.88580 0.66860 25.26x
512 64 160.05450 2.83265 56.50x

Reproduction: run agc_driver_recorder_tests --benchmark-pending-write-snapshot from matching Release builds. For the baseline, keep main's production Recorder.hpp and Recorder.cpp and compile the identical benchmark test source. Do not mix executables with another variant's libraries.

Raw process medians (milliseconds, all four runs per variant)
Distinct ranges Duplicate notes per range Main process medians Patch process medians
8 0 0.0069, 0.0056, 0.0071, 0.0072 0.0064, 0.0055, 0.0074, 0.006
8 8 0.0161, 0.0159, 0.0187, 0.0195 0.0116, 0.011, 0.0104, 0.0099
8 64 0.0559, 0.0688, 0.0652, 0.0635 0.0279, 0.0296, 0.0299, 0.0284
32 0 0.0238, 0.0235, 0.0259, 0.0221 0.02, 0.0182, 0.0218, 0.0189
32 8 0.0911, 0.0913, 0.089, 0.0912 0.0319, 0.0322, 0.0343, 0.0315
32 64 0.5709, 0.6765, 0.5802, 0.5666 0.1107, 0.1043, 0.1052, 0.1003
512 0 1.8071, 1.8747, 1.979, 1.7775 0.4649, 0.4002, 0.4706, 0.4857
512 8 15.5224, 16.5606, 17.211, 20.2864 0.7446, 0.612, 0.6695, 0.6677
512 64 153.855, 161.012, 159.097, 194.405 2.921, 2.8358, 2.7987, 2.8295
Selected final CTest output before rebase
 1/21 Test #175: agc_pipeline_cache ....................   Passed    2.54 sec
 2/21 Test #176: agc_pipeline_library ..................   Passed    2.09 sec
 3/21 Test #177: agc_pipeline_library_off ..............   Passed    1.04 sec
 4/21 Test #178: agc_pipeline_library_fast_only ........   Passed    1.38 sec
 5/21 Test #179: agc_unchanged_cpu_stamps ..............   Passed    3.98 sec
 6/21 Test #180: agc_storage_baseline_settled ..........   Passed    2.52 sec
 7/21 Test #181: agc_storage_integer_clear .............   Passed    1.94 sec
 8/21 Test #182: agc_storage_upload_lifetime ...........   Passed    1.47 sec
 9/21 Test #183: agc_storage_upload_failure ............   Passed    2.80 sec
10/21 Test #184: agc_host_import_unmap .................   Passed    3.57 sec
11/21 Test #185: agc_parked_import_unmap ...............   Passed    5.64 sec
186: host imports are compared, not watched: unit shadows not tested
12/21 Test #186: agc_unit_shadow .......................   Passed    1.85 sec
13/21 Test #187: agc_descriptor_pool_recycling .........   Passed    1.61 sec
14/21 Test #188: agc_draw_snapshot_cap .................   Passed    1.38 sec
15/21 Test #189: agc_multisample_guest_access ..........   Passed    1.76 sec
190: host imports are compared, not watched: kept highest indices not tested
16/21 Test #190: agc_draw_inputs_in_place ..............   Passed    1.94 sec
17/21 Test #191: agc_pending_write_snapshot ............   Passed    2.29 sec
18/21 Test #219: agc_driver_graphics ...................   Passed   12.99 sec
19/21 Test #220: agc_driver_bda_device .................   Passed    1.61 sec
20/21 Test #550: agc_descriptor_pool_reset_failure .....   Passed    0.08 sec
21/21 Test #569: agc_compute_descriptor_layout_flags ...   Passed    0.09 sec
100% tests passed, 0 tests failed out of 21
Total Test time (real) =  54.92 sec
Published commit CTest output after rebase
 1/21 Test #175: agc_pipeline_cache ....................   Passed    0.37 sec
 2/21 Test #176: agc_pipeline_library ..................   Passed    0.31 sec
 3/21 Test #177: agc_pipeline_library_off ..............   Passed    0.30 sec
 4/21 Test #178: agc_pipeline_library_fast_only ........   Passed    0.29 sec
 5/21 Test #179: agc_unchanged_cpu_stamps ..............   Passed    0.37 sec
 6/21 Test #180: agc_storage_baseline_settled ..........   Passed    0.34 sec
 7/21 Test #181: agc_storage_integer_clear .............   Passed    0.34 sec
 8/21 Test #182: agc_storage_upload_lifetime ...........   Passed    0.35 sec
 9/21 Test #183: agc_storage_upload_failure ............   Passed    0.37 sec
10/21 Test #184: agc_host_import_unmap .................   Passed    0.38 sec
11/21 Test #185: agc_parked_import_unmap ...............   Passed    0.46 sec
186: host imports are compared, not watched: unit shadows not tested
12/21 Test #186: agc_unit_shadow .......................   Passed    0.38 sec
13/21 Test #187: agc_descriptor_pool_recycling .........   Passed    0.33 sec
14/21 Test #188: agc_draw_snapshot_cap .................   Passed    0.39 sec
15/21 Test #189: agc_multisample_guest_access ..........   Passed    0.37 sec
190: host imports are compared, not watched: kept highest indices not tested
16/21 Test #190: agc_draw_inputs_in_place ..............   Passed    0.35 sec
17/21 Test #191: agc_pending_write_snapshot ............   Passed    0.35 sec
18/21 Test #219: agc_driver_graphics ...................   Passed    6.99 sec
19/21 Test #220: agc_driver_bda_device .................   Passed    0.47 sec
20/21 Test #553: agc_descriptor_pool_reset_failure .....   Passed    0.03 sec
21/21 Test #572: agc_compute_descriptor_layout_flags ...   Passed    0.02 sec
100% tests passed, 0 tests failed out of 21
Total Test time (real) =  14.17 sec

Checklist

  • Based on current main; no other open PR found implementing this snapshot-union optimization
  • One topic per PR; follow-ups go in a new PR
  • No new comments in code
  • Existing unsupported paths retain their errors; no stubs added
  • No notes, investigation files or images added to the repository; evidence is included in this description
  • No new third-party code
  • Generic behaviour, not specific to one title
  • Depends on: perf(agc): note an address space's in-place reads by reference #4978 (merge order only; see Related)
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 3070 Laptop GPU, driver 617.42, Windows 11
  • AI-assisted: yes (OpenAI Codex, Claude Code)

@Scramblrrrr

Copy link
Copy Markdown
Contributor

Prepared performance stack now native-validated/staged: codex/first-light-range-compare-memo-cross-test at b45e164. Contains author-preserving #4889 d839eed as1197d10f0, then merged #2802 ca99658 asb45e164b0, on5900427f5. #4889 production hunks clean; conflict resolution only retained our fixture/CMake modes. #2802 conflict preserves our Windows fresh-page tracking while adding stamps for uncovered stores. Scoped conventions/diff checks pass; source clean.

Windows/RTX5070Ti/Release/toolsOFF, Vulkan required:9/9 PASS8.31s: pending-write snapshot, range write tracking, Windows backend, storage baseline/unit-shadow/CPU-snapshot, mocked graphics, DCC (including uniform cases), guest memory. Production-only negative changes NewestStamp to return the global generation, fixtures retained: range-tracking FAIL because a store advances another unwatched range's stamp; eight controls PASS7.92s. Restore/touch/rebuild:9/9 PASS8.01s. The tracking executable embeds GuestMemory.cpp, so it was explicitly rebuilt for the valid negative; an initial attempt without that rebuild is discarded.

Only patched graphics now E3ACA8E6F8D3EDFF38F3CBBE4ADF6EA6AC213E88049842CB06593CED8B0C2C09; libc DE052483.../kernel unchanged. Warm007 comparison launched with the same normal asynchronous draw/cache/profile/guard settings. This is a combined-stack game comparison, not an isolated #4889 speed claim; earlier snapshot rebuild cost was only636ms cumulative. No title code/captures/dumps/assets uploaded. AI-assisted (Codex).

@Dripl1x
Dripl1x marked this pull request as ready for review October 13, 2026 04:29
@github-actions github-actions Bot added build agc libSceAgc* labels Oct 13, 2026
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 13, 2026
@Dripl1x
Dripl1x force-pushed the codex/agc-pending-write-snapshots branch from d839eed to ac145e9 Compare October 13, 2026 18:18
@Dripl1x

Dripl1x commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main 8cf6a0bc3: head ac145e9be. The conflict was only in tests/Recorder.cpp, where main added the --copied-direct-only mode next to the two modes this PR adds; both are kept. The production hunks are unchanged.

Performance report

Captured as the Performance report form describes.

Title and scene: PPSA99666 (ps5-doom v1.1.1 homebrew), -timedemo demo1, presents 600 to 1499 (APS5_TRACE_FRAMES=600:900), 1920x1080.

What changed: nothing measurable in this scene. All four captures are limited by the 60 Hz present: frame p50 is 16.67 to 16.69 ms and p99 17.16 to 17.26 ms for main and for this PR. The queue worker is busy 0.2 ms per frame, so this homebrew barely exercises the pending-write snapshot. These captures show no regression; they do not demonstrate a speedup. The measured effect of this change remains the isolated CPU component benchmark in the description. I have no title with many outstanding write ranges to capture.

Build Commit p50 ms p90 ms p99 ms max ms GPU busy ms per present Trace
main 8cf6a0bc3a17 16.688 16.986 17.185 17.521 4.129 aps5-trace-8cf6a0bc3a17-31364.json.gz
this PR ac145e9be481 16.685 16.991 17.174 17.529 4.662 aps5-trace-ac145e9be481-14580.json.gz
this PR ac145e9be481 16.673 16.978 17.256 23.395 4.592 aps5-trace-ac145e9be481-37524.json.gz
main 8cf6a0bc3a17 16.681 16.987 17.159 17.407 4.547 aps5-trace-8cf6a0bc3a17-32572.json.gz

Both builds are clean checkouts (dirty false) built with WinLibs MinGW-w64 GCC 15.2.0 r7, Release. All libraries come from the main build; only libSceAgcDriver.prx differs between the captures. The traces and the summary lines are in Dripl1x/AnyPS5@d64017d30.

Summary lines (capture order: main, this PR, this PR, main):

{"commit":"8cf6a0bc3a17","dirty":false,"env":{"APS5_TRACE_FRAMES":"600:900"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"frames 600:900","first_present":600,"ms":15014.904},"presents":900,"frame_ms":{"p50":16.688,"p90":16.986,"p99":17.185,"max":17.521},"gpu_busy_ms_per_present":4.129,"worker_busy_pct":{"queue worker 0x0":98.556},"top_phases_ms_per_frame":{"Driver.Packet":16.435,"Driver.Packet.rendering_wait":16.177,"Driver.Present":2.832,"Vulkan.Retire":1.750,"Driver.Present.render_fence_wait":1.749,"Vulkan.Retire.wait":1.741,"Driver.Present.present_display_buffer":0.831,"Vulkan.Present":0.827},"trace_dropped":false,"trace":"aps5-trace-8cf6a0bc3a17-31364.json.gz"}
{"commit":"ac145e9be481","dirty":false,"env":{"APS5_TRACE_FRAMES":"600:900"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"frames 600:900","first_present":600,"ms":15014.758},"presents":900,"frame_ms":{"p50":16.685,"p90":16.991,"p99":17.174,"max":17.529},"gpu_busy_ms_per_present":4.662,"worker_busy_pct":{"queue worker 0x0":98.635},"top_phases_ms_per_frame":{"Driver.Packet":16.448,"Driver.Packet.rendering_wait":16.197,"Driver.Present":3.378,"Vulkan.Retire":2.299,"Driver.Present.render_fence_wait":2.298,"Vulkan.Retire.wait":2.288,"Driver.Present.present_display_buffer":0.848,"Vulkan.Present":0.844},"trace_dropped":false,"trace":"aps5-trace-ac145e9be481-14580.json.gz"}
{"commit":"ac145e9be481","dirty":false,"env":{"APS5_TRACE_FRAMES":"600:900"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"frames 600:900","first_present":600,"ms":15015.355},"presents":900,"frame_ms":{"p50":16.673,"p90":16.978,"p99":17.256,"max":23.395},"gpu_busy_ms_per_present":4.592,"worker_busy_pct":{"queue worker 0x0":98.940},"top_phases_ms_per_frame":{"Driver.Packet":16.500,"Driver.Packet.rendering_wait":16.209,"Driver.Present":3.449,"Driver.Present.render_fence_wait":2.218,"Vulkan.Retire":2.217,"Vulkan.Retire.wait":2.205,"Driver.Present.present_display_buffer":0.853,"Vulkan.Present":0.849},"trace_dropped":false,"trace":"aps5-trace-ac145e9be481-37524.json.gz"}
{"commit":"8cf6a0bc3a17","dirty":false,"env":{"APS5_TRACE_FRAMES":"600:900"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"frames 600:900","first_present":600,"ms":15015.647},"presents":900,"frame_ms":{"p50":16.681,"p90":16.987,"p99":17.159,"max":17.407},"gpu_busy_ms_per_present":4.547,"worker_busy_pct":{"queue worker 0x0":98.457},"top_phases_ms_per_frame":{"Driver.Packet":16.420,"Driver.Packet.rendering_wait":16.150,"Driver.Present":3.311,"Vulkan.Retire":2.133,"Driver.Present.render_fence_wait":2.132,"Vulkan.Retire.wait":2.121,"Driver.Present.present_display_buffer":0.859,"Vulkan.Present":0.855},"trace_dropped":false,"trace":"aps5-trace-8cf6a0bc3a17-32572.json.gz"}

Capture:

  • The caches were warm: each build ran the scene once before its captures, and the title was restarted for every capture.
  • No other APS5_TRACE_* or APS5_PROFILE_* switch was set, and the log was not redirected (the title ran in its own console window).
  • The captures come from the same machine, scene and settings, in one session.
Digest: main, first capture

frames 600:900 from present 600: 900 presents, frame p50 16.7 / p90 17.0 / p99 17.2 / max 17.5 ms, GPU busy 4.1 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 1920x1080, commit 8cf6a0b, dropped: no

{"commit":"8cf6a0bc3a17","dirty":false,"env":{"APS5_TRACE_FRAMES":"600:900"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"frames 600:900","first_present":600,"ms":15014.904},"presents":900,"frame_ms":{"p50":16.688,"p90":16.986,"p99":17.185,"max":17.521},"gpu_busy_ms_per_present":4.129,"worker_busy_pct":{"queue worker 0x0":98.556},"top_phases_ms_per_frame":{"Driver.Packet":16.435,"Driver.Packet.rendering_wait":16.177,"Driver.Present":2.832,"Vulkan.Retire":1.75,"Driver.Present.render_fence_wait":1.749,"Vulkan.Retire.wait":1.741,"Driver.Present.present_display_buffer":0.831,"Vulkan.Present":0.827},"trace_dropped":false,"trace":"aps5-trace-8cf6a0bc3a17-31364.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 1100: 17.5 ms at 8342 ms: Driver.Packet (queue worker 0x0) 17.4, Driver.Packet.rendering_wait (queue worker 0x0) 17.1, batch (gpu) 3.6, Driver.Present (presenter) 2.7
  • present 1264: 17.5 ms at 11078 ms: Driver.Packet (queue worker 0x0) 17.4, Driver.Packet.rendering_wait (queue worker 0x0) 17.1, batch (gpu) 4.0, Driver.Present (presenter) 2.8
  • present 1146: 17.4 ms at 9109 ms: Driver.Packet (queue worker 0x0) 17.3, Driver.Packet.rendering_wait (queue worker 0x0) 17.0, batch (gpu) 3.9, Driver.Present (presenter) 2.7
  • present 1127: 17.3 ms at 8792 ms: Driver.Packet (queue worker 0x0) 17.2, Driver.Packet.rendering_wait (queue worker 0x0) 17.0, batch (gpu) 3.8, Driver.Present (presenter) 2.7
  • present 959: 17.2 ms at 5989 ms: Driver.Packet (queue worker 0x0) 17.2, Driver.Packet.rendering_wait (queue worker 0x0) 17.0, batch (gpu) 4.6, Driver.Present (presenter) 2.9

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 0.2 (1 %) 16.4 (98 %) 0.1 0.1 Driver.Packet 16.4, Driver.Completion 0.0
presenter 1.1 (6 %) 1.8 (10 %) 13.9 0.1 Driver.Present 2.8
gpu 4.1 (25 %) 0.0 (0 %) 12.6 0.0 batch 4.1

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 16.4, Driver.Packet.rendering_wait 16.2, batch 4.1, Driver.Present 2.8, Driver.Present.render_fence_wait 1.7, Vulkan.Retire 1.7

Longest waits

  • Driver.Packet.rendering_wait (queue worker 0x0) 17.5 ms at 7027 ms, present 1021
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.4 ms at 2405 ms, present 744
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.3 ms at 2372 ms, present 742
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.3 ms at 2656 ms, present 759
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.2 ms at 9046 ms, present 1142
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.2 ms at 12066 ms, present 1323
Digest: this PR, first capture

frames 600:900 from present 600: 900 presents, frame p50 16.7 / p90 17.0 / p99 17.2 / max 17.5 ms, GPU busy 4.7 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 1920x1080, commit ac145e9, dropped: no

{"commit":"ac145e9be481","dirty":false,"env":{"APS5_TRACE_FRAMES":"600:900"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"frames 600:900","first_present":600,"ms":15014.758},"presents":900,"frame_ms":{"p50":16.685,"p90":16.991,"p99":17.174,"max":17.529},"gpu_busy_ms_per_present":4.662,"worker_busy_pct":{"queue worker 0x0":98.635},"top_phases_ms_per_frame":{"Driver.Packet":16.448,"Driver.Packet.rendering_wait":16.197,"Driver.Present":3.378,"Vulkan.Retire":2.299,"Driver.Present.render_fence_wait":2.298,"Vulkan.Retire.wait":2.288,"Driver.Present.present_display_buffer":0.848,"Vulkan.Present":0.844},"trace_dropped":false,"trace":"aps5-trace-ac145e9be481-14580.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 696: 17.5 ms at 1601 ms: Driver.Packet (queue worker 0x0) 16.7, Driver.Packet.rendering_wait (queue worker 0x0) 16.5, batch (gpu) 5.3, Driver.Present (presenter) 3.6
  • present 1154: 17.4 ms at 9242 ms: Driver.Packet (queue worker 0x0) 17.3, Driver.Packet.rendering_wait (queue worker 0x0) 17.1, batch (gpu) 4.5, Driver.Present (presenter) 3.5
  • present 849: 17.4 ms at 4154 ms: Driver.Packet (queue worker 0x0) 17.3, Driver.Packet.rendering_wait (queue worker 0x0) 16.9, batch (gpu) 4.8, Driver.Present (presenter) 3.8
  • present 886: 17.3 ms at 4771 ms: Driver.Packet (queue worker 0x0) 17.0, Driver.Packet.rendering_wait (queue worker 0x0) 16.7, batch (gpu) 4.6, Driver.Present (presenter) 3.5
  • present 839: 17.3 ms at 3987 ms: Driver.Packet (queue worker 0x0) 17.3, Driver.Packet.rendering_wait (queue worker 0x0) 17.0, batch (gpu) 4.9, Driver.Present (presenter) 3.6

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 0.2 (1 %) 16.4 (98 %) 0.1 0.1 Driver.Packet 16.4, Driver.Completion 0.0
presenter 1.1 (6 %) 2.3 (14 %) 13.3 0.1 Driver.Present 3.4
gpu 4.7 (28 %) 0.0 (0 %) 12.0 0.0 batch 4.7

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 16.4, Driver.Packet.rendering_wait 16.2, batch 4.7, Driver.Present 3.4, Driver.Present.render_fence_wait 2.3, Vulkan.Retire 2.3

Longest waits

  • Driver.Packet.rendering_wait (queue worker 0x0) 18.0 ms at 9512 ms, present 1170
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.6 ms at 9679 ms, present 1180
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.4 ms at 10296 ms, present 1217
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.3 ms at 7761 ms, present 1065
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.3 ms at 13700 ms, present 1421
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.3 ms at 370 ms, present 622
Digest: this PR, second capture

frames 600:900 from present 600: 900 presents, frame p50 16.7 / p90 17.0 / p99 17.3 / max 23.4 ms, GPU busy 4.6 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 1920x1080, commit ac145e9, dropped: no

{"commit":"ac145e9be481","dirty":false,"env":{"APS5_TRACE_FRAMES":"600:900"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"frames 600:900","first_present":600,"ms":15015.355},"presents":900,"frame_ms":{"p50":16.673,"p90":16.978,"p99":17.256,"max":23.395},"gpu_busy_ms_per_present":4.592,"worker_busy_pct":{"queue worker 0x0":98.94},"top_phases_ms_per_frame":{"Driver.Packet":16.5,"Driver.Packet.rendering_wait":16.209,"Driver.Present":3.449,"Driver.Present.render_fence_wait":2.218,"Vulkan.Retire":2.217,"Vulkan.Retire.wait":2.205,"Driver.Present.present_display_buffer":0.853,"Vulkan.Present":0.849},"trace_dropped":false,"trace":"aps5-trace-ac145e9be481-37524.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 933: 23.4 ms at 5556 ms: Driver.Packet (queue worker 0x0) 23.3, Driver.Packet.rendering_wait (queue worker 0x0) 23.0, batch (gpu) 4.0, Driver.Present (presenter) 3.7
  • present 799: 17.7 ms at 3320 ms: Driver.Packet (queue worker 0x0) 17.3, Driver.Packet.rendering_wait (queue worker 0x0) 17.0, batch (gpu) 4.6, Driver.Present (presenter) 3.5
  • present 1321: 17.5 ms at 12029 ms: Driver.Packet (queue worker 0x0) 17.4, Driver.Packet.rendering_wait (queue worker 0x0) 17.2, batch (gpu) 4.6, Driver.Present (presenter) 3.7
  • present 608: 17.5 ms at 134 ms: Driver.Packet (queue worker 0x0) 17.4, Driver.Packet.rendering_wait (queue worker 0x0) 17.1, batch (gpu) 4.6, Driver.Present (presenter) 3.8
  • present 833: 17.4 ms at 3887 ms: Driver.Packet (queue worker 0x0) 17.3, Driver.Packet.rendering_wait (queue worker 0x0) 17.0, batch (gpu) 4.7, Driver.Present (presenter) 2.9

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 0.3 (2 %) 16.3 (98 %) 0.1 0.1 Driver.Packet 16.5, Driver.Completion 0.0
presenter 1.2 (7 %) 2.2 (13 %) 13.2 0.1 Driver.Present 3.4
gpu 4.6 (27 %) 0.0 (0 %) 12.1 0.0 batch 4.6

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 16.5, Driver.Packet.rendering_wait 16.2, batch 4.6, Driver.Present 3.4, Driver.Present.render_fence_wait 2.2, Vulkan.Retire 2.2

Longest waits

  • Driver.Packet.rendering_wait (queue worker 0x0) 21.8 ms at 5561 ms, present 933
  • Driver.Packet.rendering_wait (queue worker 0x0) 19.3 ms at 7762 ms, present 1065
  • Driver.Packet.rendering_wait (queue worker 0x0) 18.2 ms at 7111 ms, present 1026
  • Driver.Packet.rendering_wait (queue worker 0x0) 18.0 ms at 6910 ms, present 1014
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.9 ms at 11198 ms, present 1271
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.9 ms at 3974 ms, present 838
Digest: main, second capture

frames 600:900 from present 600: 900 presents, frame p50 16.7 / p90 17.0 / p99 17.2 / max 17.4 ms, GPU busy 4.5 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 1920x1080, commit 8cf6a0b, dropped: no

{"commit":"8cf6a0bc3a17","dirty":false,"env":{"APS5_TRACE_FRAMES":"600:900"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"frames 600:900","first_present":600,"ms":15015.647},"presents":900,"frame_ms":{"p50":16.681,"p90":16.987,"p99":17.159,"max":17.407},"gpu_busy_ms_per_present":4.547,"worker_busy_pct":{"queue worker 0x0":98.457},"top_phases_ms_per_frame":{"Driver.Packet":16.42,"Driver.Packet.rendering_wait":16.15,"Driver.Present":3.311,"Vulkan.Retire":2.133,"Driver.Present.render_fence_wait":2.132,"Vulkan.Retire.wait":2.121,"Driver.Present.present_display_buffer":0.859,"Vulkan.Present":0.855},"trace_dropped":false,"trace":"aps5-trace-8cf6a0bc3a17-32572.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 1169: 17.4 ms at 9493 ms: Driver.Packet (queue worker 0x0) 17.3, Driver.Packet.rendering_wait (queue worker 0x0) 17.1, batch (gpu) 4.4, Driver.Present (presenter) 3.7
  • present 1499: 17.4 ms at 14998 ms: Driver.Packet (queue worker 0x0) 4.1, Driver.Packet.rendering_wait (queue worker 0x0) 3.9, Driver.Present (presenter) 3.8, Driver.Present.render_fence_wait (presenter) 2.7
  • present 1130: 17.4 ms at 8842 ms: Driver.Packet (queue worker 0x0) 16.9, Driver.Packet.rendering_wait (queue worker 0x0) 16.6, batch (gpu) 6.0, Driver.Present (presenter) 3.4
  • present 1418: 17.3 ms at 13647 ms: Driver.Packet (queue worker 0x0) 16.8, Driver.Packet.rendering_wait (queue worker 0x0) 16.4, batch (gpu) 3.8, Driver.Present (presenter) 2.8
  • present 1393: 17.3 ms at 13230 ms: Driver.Packet (queue worker 0x0) 17.3, Driver.Packet.rendering_wait (queue worker 0x0) 17.0, batch (gpu) 4.7, Driver.Present (presenter) 3.7

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 0.3 (2 %) 16.4 (98 %) 0.1 0.1 Driver.Packet 16.4, Driver.Completion 0.0
presenter 1.2 (7 %) 2.1 (13 %) 13.4 0.1 Driver.Present 3.3
gpu 4.5 (27 %) 0.0 (0 %) 12.1 0.0 batch 4.5

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 16.4, Driver.Packet.rendering_wait 16.1, batch 4.5, Driver.Present 3.3, Driver.Present.render_fence_wait 2.1, Vulkan.Retire 2.1

Longest waits

  • Driver.Packet.rendering_wait (queue worker 0x0) 18.1 ms at 14734 ms, present 1483
  • Driver.Packet.rendering_wait (queue worker 0x0) 18.0 ms at 4958 ms, present 897
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.7 ms at 13050 ms, present 1382
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.7 ms at 4224 ms, present 853
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.6 ms at 9914 ms, present 1194
  • Driver.Packet.rendering_wait (queue worker 0x0) 17.6 ms at 14818 ms, present 1488

Tests on the rebased head

Windows 11, NVIDIA GeForce RTX 3070 Laptop GPU, driver 617.42, WinLibs MinGW-w64 GCC 15.2.0 r7, Release, BUILD_TESTING=ON, root configuration, ANYPS5_REQUIRE_VULKAN=1. The 28 CTests of agc_driver_recorder_tests, agc_driver_graphics_tests and agc_driver_bda_device_tests pass in 14.64 s. As before on this configuration, agc_unit_shadow and agc_draw_inputs_in_place skip their watched-import subcases (host imports are compared, not watched).

CTest output (28 of 28)
Test project <build>
      Start 200: agc_pipeline_cache
 1/28 Test #200: agc_pipeline_cache ........................   Passed    0.35 sec
      Start 201: agc_pipeline_library
 2/28 Test #201: agc_pipeline_library ......................   Passed    0.34 sec
      Start 202: agc_pipeline_library_off
 3/28 Test #202: agc_pipeline_library_off ..................   Passed    0.30 sec
      Start 203: agc_pipeline_library_fast_only
 4/28 Test #203: agc_pipeline_library_fast_only ............   Passed    0.31 sec
      Start 204: agc_unchanged_cpu_stamps
 5/28 Test #204: agc_unchanged_cpu_stamps ..................   Passed    0.36 sec
      Start 205: agc_storage_baseline_settled
 6/28 Test #205: agc_storage_baseline_settled ..............   Passed    0.35 sec
      Start 206: agc_storage_integer_clear
 7/28 Test #206: agc_storage_integer_clear .................   Passed    0.33 sec
      Start 207: agc_storage_upload_lifetime
 8/28 Test #207: agc_storage_upload_lifetime ...............   Passed    0.35 sec
      Start 208: agc_storage_upload_failure
 9/28 Test #208: agc_storage_upload_failure ................   Passed    0.36 sec
      Start 209: agc_storage_written_buffer_order
10/28 Test #209: agc_storage_written_buffer_order ..........   Passed    0.34 sec
      Start 210: agc_copied_direct_ordering
11/28 Test #210: agc_copied_direct_ordering ................   Passed    0.35 sec
      Start 211: agc_host_import_unmap
12/28 Test #211: agc_host_import_unmap .....................   Passed    0.34 sec
      Start 212: agc_parked_import_unmap
13/28 Test #212: agc_parked_import_unmap ...................   Passed    0.42 sec
      Start 213: agc_host_import_retirement
14/28 Test #213: agc_host_import_retirement ................   Passed    0.35 sec
      Start 214: agc_unit_shadow
15/28 Test #214: agc_unit_shadow ...........................   Passed    0.35 sec
      Start 215: agc_descriptor_pool_recycling
16/28 Test #215: agc_descriptor_pool_recycling .............   Passed    0.33 sec
      Start 216: agc_draw_snapshot_cap
17/28 Test #216: agc_draw_snapshot_cap .....................   Passed    0.34 sec
      Start 217: agc_multisample_guest_access
18/28 Test #217: agc_multisample_guest_access ..............   Passed    0.35 sec
      Start 218: agc_draw_inputs_in_place
19/28 Test #218: agc_draw_inputs_in_place ..................   Passed    0.34 sec
      Start 219: agc_pending_write_snapshot
20/28 Test #219: agc_pending_write_snapshot ................   Passed    0.35 sec
      Start 222: agc_driver_vertex_target_range_copied
21/28 Test #222: agc_driver_vertex_target_range_copied .....   Passed    0.36 sec
      Start 223: agc_driver_vertex_target_range_imported
22/28 Test #223: agc_driver_vertex_target_range_imported ...   Passed    0.36 sec
      Start 251: agc_driver_graphics
23/28 Test #251: agc_driver_graphics .......................   Passed    6.34 sec
      Start 252: agc_driver_bda_device
24/28 Test #252: agc_driver_bda_device .....................   Passed    0.42 sec
      Start 564: agc_sparse_buffer_holes
25/28 Test #564: agc_sparse_buffer_holes ...................   Passed    0.05 sec
      Start 606: agc_descriptor_pool_reset_failure
26/28 Test #606: agc_descriptor_pool_reset_failure .........   Passed    0.03 sec
      Start 625: agc_compute_descriptor_layout_flags
27/28 Test #625: agc_compute_descriptor_layout_flags .......   Passed    0.02 sec
      Start 626: agc_driver_covered_centroid_state
28/28 Test #626: agc_driver_covered_centroid_state .........   Passed    0.03 sec

100% tests passed, 0 tests failed out of 28

Total Test time (real) =  14.64 sec

AI-assisted (Claude Code).

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 13, 2026
@Dripl1x

Dripl1x commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

@AlxcBTW the PR overlap report lists #4978 against this PR. A trial git merge-tree of ac145e9be with a6970f1af conflicts only in core/libs/prx/libSceAgcDriver/tests/Recorder.cpp: both add new test functions at the same place (pendingWriteSnapshotTests and its benchmark here, readListTests in yours). Keeping both resolves it; the production files merge cleanly, since this PR changes the pending-write snapshot and yours the pending-read notes.

Neither change builds on the other. Proposed order: this PR first, since it is older, and #4978 rebases with that resolution and lists this PR as its dependency, so the report stops listing the pair. If you prefer the opposite order, say so and I will list #4978 here and rebase after it.

AI-assisted (Claude Code).

@AlxcBTW

AlxcBTW commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

@Dripl1x thanks for checking. Agreed that it's test-only: both new test functions stay, and the production files don't touch each other. Since neither builds on the other, I'd rather not declare a dependency, so neither PR waits on the other's review. Whichever lands second takes the one-hunk rebase in tests/Recorder.cpp. If yours lands first, I'll rebase #4978 the same day.

@Dripl1x

Dripl1x commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

@AlxcBTW understood, #4978 should not wait. The overlap report only clears when one side declares the order, so I listed #4978 in Depends on here only: it is a merge order, not a prerequisite, and nothing changes for your PR. I rebase this one after #4978 lands. If a reviewer wants this one first, I drop the line and you rebase as you said.

AI-assisted (Claude Code).

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

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.

Pull request Conflicting files (lines on main) Same exports Same new files
#5465 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp L580

@adriadam10 adriadam10 self-assigned this Oct 14, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the incremental snapshot extension against the full-union path: built merged onto current main, agc_pending_write_snapshot passes, and breaking the touching-range merge in the single-addition path makes it fail. Ownership (weak_ptr), inactive-recorder and wrapping-range fallbacks to the full rebuild look right. The only failing test in the AgcDriver scope, agc_driver_tessellation, is a known RADV segfault unrelated to this change. Merging once the full Build is green.

@adriadam10
adriadam10 merged commit 42e3b32 into boykopovar:main Oct 14, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants