Repository navigation
perf(agc): extend pending write snapshots incrementally - #4889
Conversation
|
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). |
d839eed to
ac145e9
Compare
|
Rebased onto Performance reportCaptured as the Performance report form describes. Title and scene: PPSA99666 (ps5-doom v1.1.1 homebrew), 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
Both builds are clean checkouts ( Summary lines (capture order: {"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:
Digest: main, first captureframes 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 {"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)
Threads (ms per frame)
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
Digest: this PR, first captureframes 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 {"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)
Threads (ms per frame)
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
Digest: this PR, second captureframes 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 {"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)
Threads (ms per frame)
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
Digest: main, second captureframes 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 {"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)
Threads (ms per frame)
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
Tests on the rebased headWindows 11, NVIDIA GeForce RTX 3070 Laptop GPU, driver 617.42, WinLibs MinGW-w64 GCC 15.2.0 r7, Release, CTest output (28 of 28)AI-assisted (Claude Code). |
|
@AlxcBTW the PR overlap report lists #4978 against this PR. A trial 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). |
|
@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 |
|
@AlxcBTW understood, #4978 should not wait. The overlap report only clears when one side declares the order, so I listed #4978 in AI-assisted (Claude Code). |
|
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.
|
|
Checked the incremental snapshot extension against the full-union path: built merged onto current main, |
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.
No guest exports, runtime switches, dependencies or user setup are added.
Component correctness and CPU-work measurements are below. Summary lines and traces of
mainand 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.
758aca737plus this patch: built AGC andagc_driver_recorder_tests,agc_driver_graphics_tests,agc_driver_bda_device_testswith 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.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.d839eeda7, based on main2a55cfe1e: 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/mainandgit diff --checkpass. GitHub also reports the conventions check as successful.ac145e9be48162d75e8509144edbc217dafd41dc, based on main8cf6a0bc3: root configuration,ANYPS5_REQUIRE_VULKAN=1. The 28 CTests ofagc_driver_recorder_tests,agc_driver_graphics_testsandagc_driver_bda_device_testspass in 14.64 s, including the recorder tests added tomainsince the first publication. The output is in the same comment.Isolated CPU component measurement
Baseline: main
758aca737production 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::NotePendingWritecalls. 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.Reproduction: run
agc_driver_recorder_tests --benchmark-pending-write-snapshotfrom matching Release builds. For the baseline, keep main's productionRecorder.hppandRecorder.cppand compile the identical benchmark test source. Do not mix executables with another variant's libraries.Raw process medians (milliseconds, all four runs per variant)
Selected final CTest output before rebase
Published commit CTest output after rebase
Checklist
main; no other open PR found implementing this snapshot-union optimization