Skip to content

perf(agc): wait for a storage refresh's pending writer before taking the GPU mutex - #9400

Closed
parl0v wants to merge 1 commit into
boykopovar:mainfrom
parl0v:perf/presync-storage-writer
Closed

parl0v wants to merge 1 commit into
boykopovar:mainfrom
parl0v:perf/presync-storage-writer

Conversation

@parl0v

@parl0v parl0v commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

A dispatch served from the resource cache revalidates its object under the GPU mutex, and Revalidate refreshes the storage images it binds (StorageTexture::Refresh). When another image has results pending in that memory, the refresh's FlushPending first waits for the newest batch that writes or leases the memory, so an address-based dispatch's write marks land before the store chooses which blocks to keep (#6364). That wait is a Sync of the open batch or a FinishUpTo of a batch in flight, both with the GPU mutex held, and the other queue workers wait behind it.

This change moves that wait into the stage-A pre-sync (VulkanDevice::presync), which already waits without the mutex for surfaces and, since #6631, for DCC key writers:

  • For an object from the resource cache, ShaderResources::PresyncSurfaces also lists the memory of every storage image it binds, of the image each of its sampled views reads, and of its imported regions (PresyncSurface::writerOnly), whether or not a host import serves them.
  • presync waits for such a range only when another image has a pending unit inside it (StorageTexture::OthersPendingInside: the listing FlushPending makes, without an image of exactly that surface, which is the refreshed image itself or its alias; lock-free through the registry's published ranges when nothing pending overlaps) and, in the short locked section it already takes, recorded work writes or leases the range (Recorder::PendingWriterSerial, the test FlushPending makes before it waits). If that batch is the open one it is submitted; the wait itself runs without the mutex, and the dispatch reaps the batch before Revalidate, so the locked FlushPending finds no writer.
  • Work recorded after the pre-sync still gets the locked wait, as before. APS5_NO_WRITER_PRESYNC=1 leaves the new ranges out (row in ENVIRONMENT.md); APS5_NO_PRESYNC=1 still disables the whole pre-sync.

Counters, printed with APS5_PROFILE_DRAW=1 on the existing 10 s cadence: the [presync] line adds the writer ranges checked and the pre-syncs that only a writer required, and a new [flushwait] line counts FlushPending's writer waits by open batch or batch in flight and by lease only or write, with their time and how many ran inside a caller's hold of the mutex. FinishUpTo now takes the sync source, so FlushPending's drain of a batch in flight shows up in the [recorder] site table as a pending-write or address-based sync instead of "idle".

Test: agc_driver_storage_presync_writer caches a dispatch that stores into storage image B, leaves image A pending over B, then records an address-based global store over A. A dispatch built under the mutex waits once for that store under the mutex (the control case). After PrepareDispatch the pre-sync has waited for it, with the store in the open batch and with it in flight, and the locked dispatch does not wait again. A pending image that no recorded work writes or leases makes neither wait. The data checks are the ones from StorageFlushOrdering: the pending image's texel outside B is stored, and the newer address-based store is not overwritten. ARCHITECTURE.md's pre-sync paragraph describes the new ranges.

Why

On main 64e2a81, at the Minecraft Dungeons II (PPSA16064) title screen on an RTX 3060, queue 0x20 held the GPU mutex in this wait for about 900 ms per 10 s: about 460 ms as a Sync of the open batch and about 440 ms as a FinishUpTo of a batch in flight, which the [recorder] site table listed as "idle". The path is a resource-cache hit, Revalidate, the storage image lookup, StorageTexture::Refresh and FlushPending(..., "storage refresh"). The wait itself is needed, so this change moves it out of the lock instead of removing it.

The title screen is GPU-bound (GPU busy about 92 ms per present at a 111 ms frame p50 on the RTX 3060), so the same move changes its frame time by 0.8 % against main 36f60df and by about 3 % against main e5c5329. Gameplay is bound by the queue workers: in the main trace below, queue worker 0x0 is 99.7 % busy and the GPU is busy 140.7 ms of a 669.5 ms frame p50, so worker time that no longer goes to locked waits can become frames there.

Measured

Refreshed on current main (2026-10-24). This branch at 4d578a4 against main 5d3ab77, built the same way (Release, same toolchain), MCD2 relinked with that main's relinker. All on the RTX 4060 8 GB (NVIDIA 617.42), Windows 10 19045, i5-14400F; my RTX 3060 machine was not available.

  • Title screen, two capture pairs, alternating (warm run before the first of each build, APS5_TEXTURE_CACHE_MIB=3072 APS5_TRACE_SECONDS=120:12): frame p50 123.6 and 121.2 ms on main, 118.3 and 117.9 ms with this change (-4.3 % and -2.7 %, ahead in both pairs). The mean frame moves -2.7 % in the first pair and +0.3 % in the second, so I read the title gain as a few percent on the median, not on every frame. Unlocked Recorder.WaitSerial grows from 29.5 / 29.3 to 53.0 / 60.3 ms per frame, the wait leaving the lock.
  • Gameplay, one capture each (APS5_TRACE_SECONDS=105:12; the load got shorter on this main, so the earlier 85 s window now lands on the load): frame p50 324.5 ms (34 presents) on main and 565.7 ms (23 presents) with this change, so this pair favours main. I don't attribute it to the change: over this change's window its writer-only pre-sync counter stayed at 1,967, so the pre-sync did not fire in gameplay, while the two rows ran with different storage image cache budgets (1,361 MiB on main, 899 MiB with this change, set from the reported heap usage) and this change's row created 18,700 storage images against 8,450. That budget moves between runs of the same build (512 to 1,614 MiB on main across my rows this week) and decides gameplay frame time on this card far more than this change does; on 2026-10-22 the gameplay pair went the other way (588 against 439 ms). main stopped twice in the menu before this capture at storing storage image results pending over memory outside the write watch without the guest bytes saved before them is not implemented (fix(agc): save the guest bytes of results that become pending over a surface that is no longer fully write-watched #7048 covers it).
Summary lines, 2026-10-24
{"commit":"5d3ab7791dc4","dirty":false,"env":{"APS5_TEXTURE_CACHE_MIB":"3072","APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"Intel(R) Core(TM) i5-14400F","cpu_threads":16,"memory_mib":16220,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2143,"ms":12083.887},"presents":98,"frame_ms":{"p50":123.589,"p90":126.849,"p99":132.591,"max":132.591},"gpu_busy_ms_per_present":99.794,"worker_busy_pct":{"queue worker 0x0":99.424,"queue worker 0x20":99.514},"top_phases_ms_per_frame":{"Driver.Packet":245.153,"Driver.Packet.dispatch":89.772,"Driver.Dispatch":87.539,"Driver.Packet.memory_wait":61.43,"Driver.Packet.pipeline_drain":41.632,"Vulkan.Dispatch":36.664,"Vulkan.Dispatch.shader_resources":33.979,"Recorder.WaitSerial":29.545},"trace_dropped":false,"trace":"aps5-trace-5d3ab7791dc4-18548.json.gz"}
{"commit":"4d578a4df71c","dirty":false,"env":{"APS5_TEXTURE_CACHE_MIB":"3072","APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"Intel(R) Core(TM) i5-14400F","cpu_threads":16,"memory_mib":16220,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2175,"ms":12114.621},"presents":101,"frame_ms":{"p50":118.28,"p90":125.697,"p99":130.373,"max":198.353},"gpu_busy_ms_per_present":101.243,"worker_busy_pct":{"queue worker 0x0":99.389,"queue worker 0x20":99.524},"top_phases_ms_per_frame":{"Driver.Packet":238.46,"Driver.Packet.dispatch":90.698,"Driver.Dispatch":88.401,"Driver.Packet.memory_wait":66.27,"Recorder.WaitSerial":53.015,"Driver.Packet.prepare_memory":31.587,"Driver.Packet.pipeline_drain":27.102,"Graphics.Draw":23.093},"trace_dropped":false,"trace":"aps5-trace-4d578a4df71c-5920.json.gz"}
{"commit":"5d3ab7791dc4","dirty":false,"env":{"APS5_TEXTURE_CACHE_MIB":"3072","APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"Intel(R) Core(TM) i5-14400F","cpu_threads":16,"memory_mib":16220,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2175,"ms":12034.486},"presents":99,"frame_ms":{"p50":121.172,"p90":125.992,"p99":129.074,"max":129.074},"gpu_busy_ms_per_present":100.361,"worker_busy_pct":{"queue worker 0x0":99.354,"queue worker 0x20":99.486},"top_phases_ms_per_frame":{"Driver.Packet":241.575,"Driver.Packet.dispatch":87.385,"Driver.Dispatch":85.431,"Driver.Packet.memory_wait":60.612,"Driver.Packet.pipeline_drain":41.468,"Vulkan.Dispatch":33.645,"Vulkan.Dispatch.shader_resources":30.944,"Recorder.WaitSerial":29.312},"trace_dropped":false,"trace":"aps5-trace-5d3ab7791dc4-19204.json.gz"}
{"commit":"4d578a4df71c","dirty":false,"env":{"APS5_TEXTURE_CACHE_MIB":"3072","APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"Intel(R) Core(TM) i5-14400F","cpu_threads":16,"memory_mib":16220,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2174,"ms":12073.682},"presents":99,"frame_ms":{"p50":117.86,"p90":129.64,"p99":245.437,"max":245.437},"gpu_busy_ms_per_present":100.172,"worker_busy_pct":{"queue worker 0x0":99.402,"queue worker 0x20":99.68},"top_phases_ms_per_frame":{"Driver.Packet":242.675,"Driver.Packet.dispatch":94.115,"Driver.Dispatch":91.582,"Driver.Packet.memory_wait":71.838,"Recorder.WaitSerial":60.344,"Driver.Packet.prepare_memory":27.644,"Driver.Packet.pipeline_drain":26.756,"Graphics.Draw":22.659},"trace_dropped":false,"trace":"aps5-trace-4d578a4df71c-18624.json.gz"}
{"commit":"5d3ab7791dc4","dirty":false,"env":{"APS5_LAB_HEAP_CENSUS":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_PROFILE_DRAW":"1","APS5_TRACE_SECONDS":"105:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"Intel(R) Core(TM) i5-14400F","cpu_threads":16,"memory_mib":16220,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 105:12","first_present":1774,"ms":12116.112},"presents":34,"frame_ms":{"p50":324.529,"p90":550.252,"p99":600.124,"max":600.124},"gpu_busy_ms_per_present":119.002,"worker_busy_pct":{"queue worker 0x0":99.511,"queue worker 0x20":99.281},"top_phases_ms_per_frame":{"Driver.Packet":708.176,"Graphics.Draw":228.492,"Graphics.Draw.draw_and_resource_release":221.742,"Driver.Packet.memory_wait":221.275,"Driver.Packet.draw":158.564,"Driver.Draw":158.267,"Driver.Packet.dispatch":141.879,"Driver.Dispatch":140.89},"trace_dropped":false,"trace":"aps5-trace-5d3ab7791dc4-16984.json.gz"}
{"commit":"4d578a4df71c","dirty":false,"env":{"APS5_LAB_HEAP_CENSUS":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_PROFILE_DRAW":"1","APS5_TRACE_SECONDS":"105:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"Intel(R) Core(TM) i5-14400F","cpu_threads":16,"memory_mib":16220,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 105:12","first_present":1793,"ms":12382.799},"presents":23,"frame_ms":{"p50":565.721,"p90":658.451,"p99":681.142,"max":681.142},"gpu_busy_ms_per_present":168.416,"worker_busy_pct":{"queue worker 0x0":99.689,"queue worker 0x20":96.897},"top_phases_ms_per_frame":{"Driver.Packet":1058.104,"Graphics.Draw":325.253,"Graphics.Draw.draw_and_resource_release":317.691,"Driver.Packet.memory_wait":312.325,"Driver.Packet.dispatch":242.549,"Driver.Dispatch":241.311,"Driver.Packet.draw":213.403,"Driver.Draw":213.091},"trace_dropped":false,"trace":"aps5-trace-4d578a4df71c-10812.json.gz"}
tools/performance_compare.py, title screen pair 1, 2026-10-24

Performance comparison

Capture Commit Trace Presents Window (ms)
baseline 5d3ab77 aps5-trace-5d3ab7791dc4-18548.json.gz 98 12083.887
candidate 4d578a4 aps5-trace-4d578a4df71c-5920.json.gz 101 12114.621
  • Compare captures from the same machine, title, content version and scene; matching recorded metadata cannot verify the physical machine or scene.
  • Changes are candidate minus baseline. A negative frame-time change means a shorter frame interval.
  • A missing top phase is unreported, not zero; its change is unavailable.
  • Recorded configuration differs; these measurements do not isolate the code change.
Configuration differences
Setting Baseline Candidate
window.first_present 2143 2175
Frame and GPU times (ms)
Metric Baseline Candidate Change Change (%)
frame_ms.p50 123.589 118.280 -5.309 -4.296
frame_ms.p90 126.849 125.697 -1.152 -0.908
frame_ms.p99 132.591 130.373 -2.218 -1.673
frame_ms.max 132.591 198.353 +65.762 +49.598
mean_frame_ms 123.305 119.947 -3.358 -2.724
gpu_busy_ms_per_present 99.794 101.243 +1.449 +1.452
Top phases (ms per frame)
Metric Baseline Candidate Change Change (%)
Driver.Dispatch 87.539 88.401 +0.862 +0.985
Driver.Packet 245.153 238.460 -6.693 -2.730
Driver.Packet.dispatch 89.772 90.698 +0.926 +1.032
Driver.Packet.memory_wait 61.430 66.270 +4.840 +7.879
Driver.Packet.pipeline_drain 41.632 27.102 -14.530 -34.901
Driver.Packet.prepare_memory n/a 31.587 n/a n/a
Graphics.Draw n/a 23.093 n/a n/a
Recorder.WaitSerial 29.545 53.015 +23.470 +79.438
Vulkan.Dispatch 36.664 n/a n/a n/a
Vulkan.Dispatch.shader_resources 33.979 n/a n/a n/a
tools/performance_compare.py, title screen pair 2, 2026-10-24

Performance comparison

Capture Commit Trace Presents Window (ms)
baseline 5d3ab77 aps5-trace-5d3ab7791dc4-19204.json.gz 99 12034.486
candidate 4d578a4 aps5-trace-4d578a4df71c-18624.json.gz 99 12073.682
  • Compare captures from the same machine, title, content version and scene; matching recorded metadata cannot verify the physical machine or scene.
  • Changes are candidate minus baseline. A negative frame-time change means a shorter frame interval.
  • A missing top phase is unreported, not zero; its change is unavailable.
  • Recorded configuration differs; these measurements do not isolate the code change.
Configuration differences
Setting Baseline Candidate
window.first_present 2175 2174
Frame and GPU times (ms)
Metric Baseline Candidate Change Change (%)
frame_ms.p50 121.172 117.860 -3.312 -2.733
frame_ms.p90 125.992 129.640 +3.648 +2.895
frame_ms.p99 129.074 245.437 +116.363 +90.152
frame_ms.max 129.074 245.437 +116.363 +90.152
mean_frame_ms 121.560 121.956 +0.396 +0.326
gpu_busy_ms_per_present 100.361 100.172 -0.189 -0.188
Top phases (ms per frame)
Metric Baseline Candidate Change Change (%)
Driver.Dispatch 85.431 91.582 +6.151 +7.200
Driver.Packet 241.575 242.675 +1.100 +0.455
Driver.Packet.dispatch 87.385 94.115 +6.730 +7.702
Driver.Packet.memory_wait 60.612 71.838 +11.226 +18.521
Driver.Packet.pipeline_drain 41.468 26.756 -14.712 -35.478
Driver.Packet.prepare_memory n/a 27.644 n/a n/a
Graphics.Draw n/a 22.659 n/a n/a
Recorder.WaitSerial 29.312 60.344 +31.032 +105.868
Vulkan.Dispatch 33.645 n/a n/a n/a
Vulkan.Dispatch.shader_resources 30.944 n/a n/a n/a
tools/performance_compare.py, gameplay, 2026-10-24

Performance comparison

Capture Commit Trace Presents Window (ms)
baseline 5d3ab77 aps5-trace-5d3ab7791dc4-16984.json.gz 34 12116.112
candidate 4d578a4 aps5-trace-4d578a4df71c-10812.json.gz 23 12382.799
  • Compare captures from the same machine, title, content version and scene; matching recorded metadata cannot verify the physical machine or scene.
  • Changes are candidate minus baseline. A negative frame-time change means a shorter frame interval.
  • A missing top phase is unreported, not zero; its change is unavailable.
  • Recorded configuration differs; these measurements do not isolate the code change.
Configuration differences
Setting Baseline Candidate
window.first_present 1774 1793
Frame and GPU times (ms)
Metric Baseline Candidate Change Change (%)
frame_ms.p50 324.529 565.721 +241.192 +74.321
frame_ms.p90 550.252 658.451 +108.199 +19.664
frame_ms.p99 600.124 681.142 +81.018 +13.500
frame_ms.max 600.124 681.142 +81.018 +13.500
mean_frame_ms 356.356 538.383 +182.026 +51.080
gpu_busy_ms_per_present 119.002 168.416 +49.414 +41.524
Top phases (ms per frame)
Metric Baseline Candidate Change Change (%)
Driver.Dispatch 140.890 241.311 +100.421 +71.276
Driver.Draw 158.267 213.091 +54.824 +34.640
Driver.Packet 708.176 1058.104 +349.928 +49.413
Driver.Packet.dispatch 141.879 242.549 +100.670 +70.955
Driver.Packet.draw 158.564 213.403 +54.839 +34.585
Driver.Packet.memory_wait 221.275 312.325 +91.050 +41.148
Graphics.Draw 228.492 325.253 +96.761 +42.348
Graphics.Draw.draw_and_resource_release 221.742 317.691 +95.949 +43.271

Traces from 2026-10-24: https://github.com/parl0v/AnyPS5/releases/tag/perf-traces-2026-10-24 (title screen aps5-trace-5d3ab7791dc4-18548.json.gz / aps5-trace-4d578a4df71c-5920.json.gz and aps5-trace-5d3ab7791dc4-19204.json.gz / aps5-trace-4d578a4df71c-18624.json.gz, gameplay aps5-trace-5d3ab7791dc4-16984.json.gz / aps5-trace-4d578a4df71c-10812.json.gz).

Earlier, on main e5c5329 (2026-10-22). This branch at 114c160 against main e5c5329, built the same way (Release, same toolchain), MCD2 relinked with that main's relinker.

  • Title screen, A/B. RTX 3060 12 GB (NVIDIA 617.42), Windows 10 19045, i5-12400F, PPSA16064 title screen, 200 s rows alternating, APS5_PROFILE_DRAW=1 APS5_PROFILE_GPU=1, FPS over the last ten 10 s windows: main 10.50, 10.52, 10.50; this change 10.81, 10.82 (+3.0 %, ahead in both complete rounds; GPU busy 78 ms per present on both, GPU idle gaps 18 ms on main and 15 ms with this change). This change's third row stopped about 20 s in at storing storage image results pending over memory outside the write watch without the guest bytes saved before them is not implemented; main e5c5329 stopped at the same check in one of my gameplay rows on the RTX 4060 today (fix(agc): save the guest bytes of results that become pending over a surface that is no longer fully write-watched #7048 covers it).
  • Title screen, one capture each, APS5_TRACE_SECONDS=120:12: frame p50 91.9 ms on main and 88.4 ms with this change (-3.8 %), p90 104.0 and 104.0 ms. The time queue workers spent waiting for the GPU mutex (Driver.Packet.device_lock) fell from 32.6 to 19.4 ms per frame, and 40.5 ms per frame of unlocked Recorder.WaitSerial appears in its place.
  • Gameplay, one capture each (RTX 4060, the saved game and walk as below, APS5_TRACE_SECONDS=85:12): frame p50 588.1 ms (21 presents) on main and 438.7 ms (28 presents) with this change. I don't attribute that to this change: over this window the counter of pre-syncs only a storage refresh's writer required stayed at 1,558, so the writer pre-sync did not fire there, and the difference is within what scene and run variance gave me before. My untraced gameplay rows on this base were too short and too often stopped by crashes on main and on this change alike (a game access violation, and the check above) to compare.
Summary lines, 2026-10-22
{"commit":"e5c5329251d0","dirty":false,"env":{"APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 3060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"12th Gen Intel(R) Core(TM) i5-12400F","cpu_threads":12,"memory_mib":32609,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2391,"ms":12061.136},"presents":129,"frame_ms":{"p50":91.881,"p90":104.044,"p99":109.957,"max":110.223},"gpu_busy_ms_per_present":76.475,"worker_busy_pct":{"queue worker 0x0":99.175,"queue worker 0x20":99.68},"top_phases_ms_per_frame":{"Driver.Packet":185.791,"Driver.Packet.dispatch":64.775,"Driver.Dispatch":63.954,"Driver.Packet.memory_wait":49.708,"Driver.Packet.device_lock":32.649,"Vulkan.Dispatch":26.413,"Vulkan.Dispatch.shader_resources":24.107,"Graphics.Draw":21.421},"trace_dropped":false,"trace":"aps5-trace-e5c5329251d0-8084.json.gz"}
{"commit":"114c1604ccbd","dirty":false,"env":{"APS5_TRACE_SECONDS":"120:12"},"gpu":"NVIDIA GeForce RTX 3060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"12th Gen Intel(R) Core(TM) i5-12400F","cpu_threads":12,"memory_mib":32609,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 120:12","first_present":2424,"ms":12064.59},"presents":133,"frame_ms":{"p50":88.413,"p90":103.953,"p99":110.805,"max":110.861},"gpu_busy_ms_per_present":77.763,"worker_busy_pct":{"queue worker 0x0":99.207,"queue worker 0x20":99.682},"top_phases_ms_per_frame":{"Driver.Packet":180.312,"Driver.Packet.dispatch":70.917,"Driver.Dispatch":68.867,"Driver.Packet.memory_wait":53.753,"Recorder.WaitSerial":40.463,"Driver.Packet.device_lock":19.443,"Graphics.Draw":17.852,"Driver.Packet.draw":16.886},"trace_dropped":false,"trace":"aps5-trace-114c1604ccbd-1748.json.gz"}
{"commit":"e5c5329251d0","dirty":false,"env":{"APS5_LAB_HEAP_CENSUS":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_PROFILE_DRAW":"1","APS5_TRACE_SECONDS":"85:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"Intel(R) Core(TM) i5-14400F","cpu_threads":16,"memory_mib":16220,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 85:12","first_present":1693,"ms":12083.621},"presents":21,"frame_ms":{"p50":588.078,"p90":623.739,"p99":669.041,"max":669.041},"gpu_busy_ms_per_present":131.814,"worker_busy_pct":{"queue worker 0x0":99.655,"queue worker 0x20":97.562},"top_phases_ms_per_frame":{"Driver.Packet":1134.411,"Driver.Packet.memory_wait":371.162,"Resources.Complete":342.24,"Driver.Packet.dispatch":325.152,"Driver.Dispatch":323.565,"Graphics.Draw":251.268,"Vulkan.Dispatch":245.607,"Graphics.Draw.draw_and_resource_release":241.542},"trace_dropped":false,"trace":"aps5-trace-e5c5329251d0-25748.json.gz"}
{"commit":"114c1604ccbd","dirty":false,"env":{"APS5_LAB_HEAP_CENSUS":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_PROFILE_DRAW":"1","APS5_TRACE_SECONDS":"85:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","cpu":"Intel(R) Core(TM) i5-14400F","cpu_threads":16,"memory_mib":16220,"title_id":"PPSA16064","title":"Minecraft Dungeons II","content_version":"01.100.100","resolution":"3840x2160","window":{"spec":"seconds 85:12","first_present":1734,"ms":12117.222},"presents":28,"frame_ms":{"p50":438.665,"p90":486.369,"p99":489.309,"max":489.309},"gpu_busy_ms_per_present":120.109,"worker_busy_pct":{"queue worker 0x0":99.574,"queue worker 0x20":98.331},"top_phases_ms_per_frame":{"Driver.Packet":855.892,"Driver.Packet.memory_wait":297.175,"Resources.Complete":237.457,"Driver.Packet.dispatch":219.699,"Driver.Dispatch":218.34,"Graphics.Draw":210.568,"Graphics.Draw.draw_and_resource_release":202.358,"Vulkan.Dispatch":161.632},"trace_dropped":false,"trace":"aps5-trace-114c1604ccbd-18792.json.gz"}
tools/performance_compare.py, title screen, 2026-10-22

Performance comparison

Capture Commit Trace Presents Window (ms)
baseline e5c5329 aps5-trace-e5c5329251d0-8084.json.gz 129 12061.136
candidate 114c160 aps5-trace-114c1604ccbd-1748.json.gz 133 12064.590
  • Compare captures from the same machine, title, content version and scene; matching recorded metadata cannot verify the physical machine or scene.
  • Changes are candidate minus baseline. A negative frame-time change means a shorter frame interval.
  • A missing top phase is unreported, not zero; its change is unavailable.
  • Recorded configuration differs; these measurements do not isolate the code change.
Configuration differences
Setting Baseline Candidate
window.first_present 2391 2424
Frame and GPU times (ms)
Metric Baseline Candidate Change Change (%)
frame_ms.p50 91.881 88.413 -3.468 -3.774
frame_ms.p90 104.044 103.953 -0.091 -0.087
frame_ms.p99 109.957 110.805 +0.848 +0.771
frame_ms.max 110.223 110.861 +0.638 +0.579
mean_frame_ms 93.497 90.711 -2.786 -2.980
gpu_busy_ms_per_present 76.475 77.763 +1.288 +1.684
Top phases (ms per frame)
Metric Baseline Candidate Change Change (%)
Driver.Dispatch 63.954 68.867 +4.913 +7.682
Driver.Packet 185.791 180.312 -5.479 -2.949
Driver.Packet.device_lock 32.649 19.443 -13.206 -40.448
Driver.Packet.dispatch 64.775 70.917 +6.142 +9.482
Driver.Packet.draw n/a 16.886 n/a n/a
Driver.Packet.memory_wait 49.708 53.753 +4.045 +8.138
Graphics.Draw 21.421 17.852 -3.569 -16.661
Recorder.WaitSerial n/a 40.463 n/a n/a
Vulkan.Dispatch 26.413 n/a n/a n/a
Vulkan.Dispatch.shader_resources 24.107 n/a n/a n/a
tools/performance_compare.py, gameplay, 2026-10-22

Performance comparison

Capture Commit Trace Presents Window (ms)
baseline e5c5329 aps5-trace-e5c5329251d0-25748.json.gz 21 12083.621
candidate 114c160 aps5-trace-114c1604ccbd-18792.json.gz 28 12117.222
  • Compare captures from the same machine, title, content version and scene; matching recorded metadata cannot verify the physical machine or scene.
  • Changes are candidate minus baseline. A negative frame-time change means a shorter frame interval.
  • A missing top phase is unreported, not zero; its change is unavailable.
  • Recorded configuration differs; these measurements do not isolate the code change.
Configuration differences
Setting Baseline Candidate
window.first_present 1693 1734
Frame and GPU times (ms)
Metric Baseline Candidate Change Change (%)
frame_ms.p50 588.078 438.665 -149.413 -25.407
frame_ms.p90 623.739 486.369 -137.370 -22.024
frame_ms.p99 669.041 489.309 -179.732 -26.864
frame_ms.max 669.041 489.309 -179.732 -26.864
mean_frame_ms 575.411 432.758 -142.653 -24.791
gpu_busy_ms_per_present 131.814 120.109 -11.705 -8.880
Top phases (ms per frame)
Metric Baseline Candidate Change Change (%)
Driver.Dispatch 323.565 218.340 -105.225 -32.521
Driver.Packet 1134.411 855.892 -278.519 -24.552
Driver.Packet.dispatch 325.152 219.699 -105.453 -32.432
Driver.Packet.memory_wait 371.162 297.175 -73.987 -19.934
Graphics.Draw 251.268 210.568 -40.700 -16.198
Graphics.Draw.draw_and_resource_release 241.542 202.358 -39.184 -16.222
Resources.Complete 342.240 237.457 -104.783 -30.617
Vulkan.Dispatch 245.607 161.632 -83.975 -34.191

Traces from 2026-10-22: https://github.com/parl0v/AnyPS5/releases/tag/perf-traces-2026-10-22 (title screen aps5-trace-e5c5329251d0-8084.json.gz and aps5-trace-114c1604ccbd-1748.json.gz, gameplay aps5-trace-e5c5329251d0-25748.json.gz and aps5-trace-114c1604ccbd-18792.json.gz).

Earlier measurements, base 36f60df. In short, on that base: title screen +0.8 %, gameplay +4-12 % across sessions. Every number below was measured at 96c7091cd, the same change on base 36f60df. The rebase onto current main changed none of its lines: the two conflicts were context only, WaitForFlushing from #7769 next to the new WriterWaitCounts in Texture.cpp, and a neighbouring ARCHITECTURE.md line.

Gameplay. RTX 4060 8 GB (NVIDIA 617.42), Windows 10 19045, PPSA16064 01.100.100, a saved game and a scripted walk, automatic texture budgets, main 36f60df against this change at 96c7091cd. Ten rounds over two sessions, the two builds alternating; FPS is the mean of the gameplay 10 s windows of a row.

build session 1, FPS per row session 2, FPS per row mean FPS
main 36f60df 1.23, 1.23, 1.83, 1.63, 1.50 (1.48) 1.87, 2.00, 1.63, 1.50, 1.70 (1.74) 1.61
this change 96c7091cd 1.70, 1.53, 2.07, 1.73, 2.05 (1.82) 1.87, 2.00, 1.77, 1.43, 2.00 (1.81) 1.82 (+12.6 %)

The change is ahead in 7 rounds, tied in 2 and behind in 1. Welch's t 1.89; a one-sided permutation test over the 184,756 splits of the 20 rows gives p = 0.039. The gain is +22 % in session 1 and +4.3 % in session 2. The change stayed at 1.82 and 1.81 FPS; main moved from 1.48 to 1.74 between the sessions, so I read the effect as somewhere in that range, not as the pooled 12.6 %.

In the last five gameplay windows of each session-1 row, with APS5_PROFILE_DRAW=1:

per 10 s, gameplay, session 1 main rows this change's rows
pre-syncs 68-115 115-167
of them only a storage refresh's writer required n/a 7-34
of them a writer together with texels or keys n/a 5-19
time the pre-syncs waited, without the mutex 50-95 ms 126-210 ms
FlushPending writer waits left under the mutex ([flushwait]) not counted 91-138, 155-228 ms

The counters show waits moving out of the lock; they do not split the FPS gain further, and part of the writer waits stays locked (work recorded after the pre-sync, and lookups the pre-sync does not list, such as a build that misses the resource cache).

One traced gameplay row on each side (session 1), APS5_TRACE_SECONDS=85:12: frame p50 669.5 ms (18 presents in the window) on main and 557.0 ms (21 presents) with this change, mean frame 666.9 and 605.0 ms, p90 760.4 and 779.9 ms. In this traced row with the change, the writer pre-sync fired 0.2 times per 10 s in gameplay, so this window shows little of the mechanism (its locked Recorder.Sync time is 849 ms against 698 ms on main); the title captures below show it. APS5_LAB_HEAP_CENSUS in both summary lines is a variable of my run script; neither commit reads it.

{"commit":"36f60df9edb3","dirty":false,"env":{"APS5_LAB_HEAP_CENSUS":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_PROFILE_DRAW":"1","APS5_TRACE_SECONDS":"85:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","resolution":"3840x2160","window":{"spec":"seconds 85:12","first_present":1651,"ms":12005.055},"presents":18,"frame_ms":{"p50":669.478,"p90":760.423,"p99":808.679,"max":808.679},"gpu_busy_ms_per_present":140.701,"worker_busy_pct":{"queue worker 0x0":99.705,"queue worker 0x20":97.928},"top_phases_ms_per_frame":{"Driver.Packet":1317.635,"Driver.Packet.memory_wait":425.336,"Driver.Packet.dispatch":366.131,"Driver.Dispatch":364.816,"Resources.Complete":358.141,"Graphics.Draw":331.012,"Graphics.Draw.draw_and_resource_release":299.075,"Driver.Packet.draw":257.558},"trace_dropped":false,"trace":"aps5-trace-36f60df9edb3-18888.json.gz"}
{"commit":"96c7091cd26f","dirty":false,"env":{"APS5_LAB_HEAP_CENSUS":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_PROFILE_DRAW":"1","APS5_TRACE_SECONDS":"85:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","resolution":"3840x2160","window":{"spec":"seconds 85:12","first_present":1658,"ms":12704.108},"presents":21,"frame_ms":{"p50":557.018,"p90":779.851,"p99":806.963,"max":806.963},"gpu_busy_ms_per_present":133.644,"worker_busy_pct":{"queue worker 0x0":99.639,"queue worker 0x20":97.503},"top_phases_ms_per_frame":{"Driver.Packet":1192.200,"Driver.Packet.memory_wait":380.283,"Driver.Packet.dispatch":358.650,"Driver.Dispatch":356.822,"Resources.Complete":319.993,"Graphics.Draw":261.948,"Vulkan.Dispatch":254.628,"Vulkan.Dispatch.shader_resources":249.327},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-12372.json.gz"}

Traces, they open in ui.perfetto.dev: https://github.com/parl0v/AnyPS5/releases/tag/perf-traces-2026-10-21 (aps5-trace-36f60df9edb3-18888.json.gz and aps5-trace-96c7091cd26f-12372.json.gz for gameplay, aps5-trace-36f60df9edb3-11636.json.gz and aps5-trace-96c7091cd26f-6628.json.gz for the title screen)

tools/performance_compare.py

Performance comparison

Capture Commit Trace Presents Window (ms)
baseline 36f60df aps5-trace-36f60df9edb3-18888.json.gz 18 12005.055
candidate 96c7091cd26f aps5-trace-96c7091cd26f-12372.json.gz 21 12704.108
  • Compare captures from the same machine, title and scene; summaries do not record the CPU, title or scene.
  • Changes are candidate minus baseline. A negative frame-time change means a shorter frame interval.
  • A missing top phase is unreported, not zero; its change is unavailable.
  • Recorded configuration differs; these measurements do not isolate the code change.
Configuration differences
Setting Baseline Candidate
window.first_present 1651 1658
Frame and GPU times (ms)
Metric Baseline Candidate Change Change (%)
frame_ms.p50 669.478 557.018 -112.460 -16.798
frame_ms.p90 760.423 779.851 +19.428 +2.555
frame_ms.p99 808.679 806.963 -1.716 -0.212
frame_ms.max 808.679 806.963 -1.716 -0.212
mean_frame_ms 666.947 604.958 -61.990 -9.295
gpu_busy_ms_per_present 140.701 133.644 -7.057 -5.016
Top phases (ms per frame)
Metric Baseline Candidate Change Change (%)
Driver.Dispatch 364.816 356.822 -7.994 -2.191
Driver.Packet 1317.635 1192.200 -125.435 -9.520
Driver.Packet.dispatch 366.131 358.650 -7.481 -2.043
Driver.Packet.draw 257.558 n/a n/a n/a
Driver.Packet.memory_wait 425.336 380.283 -45.053 -10.592
Graphics.Draw 331.012 261.948 -69.064 -20.865
Graphics.Draw.draw_and_resource_release 299.075 n/a n/a n/a
Resources.Complete 358.141 319.993 -38.148 -10.652
Vulkan.Dispatch n/a 254.628 n/a n/a
Vulkan.Dispatch.shader_resources n/a 249.327 n/a n/a

The configuration difference it reports is the window's first present (1651 against 1658): the window is set in seconds, so it starts at a different present.

tools/trace_digest.py, main 36f60df

seconds 85:12 from present 1651: 18 presents, frame p50 669.5 / p90 760.4 / p99 808.7 / max 808.7 ms, GPU busy 140.7 ms per present
NVIDIA GeForce RTX 4060, NVIDIA 617.42, Windows 10.0.19045, 3840x2160, commit 36f60df, dropped: no

{"commit":"36f60df9edb3","dirty":false,"env":{"APS5_LAB_HEAP_CENSUS":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_PROFILE_DRAW":"1","APS5_TRACE_SECONDS":"85:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","resolution":"3840x2160","window":{"spec":"seconds 85:12","first_present":1651,"ms":12005.055},"presents":18,"frame_ms":{"p50":669.478,"p90":760.423,"p99":808.679,"max":808.679},"gpu_busy_ms_per_present":140.701,"worker_busy_pct":{"queue worker 0x0":99.705,"queue worker 0x20":97.928},"top_phases_ms_per_frame":{"Driver.Packet":1317.635,"Driver.Packet.memory_wait":425.336,"Driver.Packet.dispatch":366.131,"Driver.Dispatch":364.816,"Resources.Complete":358.141,"Graphics.Draw":331.012,"Graphics.Draw.draw_and_resource_release":299.075,"Driver.Packet.draw":257.558},"trace_dropped":false,"trace":"aps5-trace-36f60df9edb3-18888.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 1651: 808.7 ms at 0 ms: Driver.Packet (queue worker 0x0) 797.0, Driver.Packet (queue worker 0x20) 665.4, Driver.Packet.memory_wait (queue worker 0x20) 439.6, Driver.Packet.draw (queue worker 0x0) 328.9
  • present 1653: 760.4 ms at 1478 ms: Driver.Packet (queue worker 0x20) 758.7, Driver.Packet (queue worker 0x0) 751.0, Driver.Packet.memory_wait (queue worker 0x20) 527.5, Driver.Packet.draw (queue worker 0x0) 325.1
  • present 1656: 757.8 ms at 3712 ms: Driver.Packet (queue worker 0x20) 755.9, Driver.Packet (queue worker 0x0) 747.9, Driver.Packet.memory_wait (queue worker 0x20) 520.8, Driver.Packet.draw (queue worker 0x0) 346.1
  • present 1658: 752.2 ms at 5206 ms: Driver.Packet (queue worker 0x20) 750.4, Driver.Packet (queue worker 0x0) 743.2, Driver.Packet.memory_wait (queue worker 0x20) 521.1, Driver.Packet.draw (queue worker 0x0) 318.3
  • present 1655: 751.2 ms at 2960 ms: Driver.Packet (queue worker 0x20) 748.4, Driver.Packet (queue worker 0x0) 741.9, Driver.Packet.memory_wait (queue worker 0x20) 517.2, Driver.Packet.draw (queue worker 0x0) 294.4

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
shader prepare 0.3 (0 %) 0.0 (0 %) 666.7 0.0 Shader.PrepareArtifact 0.3
shader prepare 0.1 (0 %) 0.0 (0 %) 666.8 0.0 Vulkan.GraphicsPipelinePrebuild 0.1
queue worker 0x0 595.8 (89 %) 62.0 (9 %) 9.1 48.4 Driver.Packet 657.8
draw committer 181.1 (27 %) 45.6 (7 %) 440.2 4.6 Graphics.Draw 176.2, Recorder.Submit 7.8
queue worker 0x20 103.8 (16 %) 550.9 (83 %) 12.2 6.9 Driver.Packet 651.3, Driver.EndSubmission 0.4
presenter 1.1 (0 %) 0.2 (0 %) 665.6 0.1 VideoOut.Flip 1.2, Driver.Present 0.1
title 1.1 (0 %) 0.0 (0 %) 665.8 0.0 Shader.ResolveAbi 1.1, Shader.Register 0.0
title 0.0 (0 %) 0.0 (0 %) 666.9 0.0 Shader.Register 0.0
gpu 132.1 (20 %) 0.0 (0 %) 534.8 0.0 batch 132.1

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 1309.1, Driver.Packet.memory_wait 425.2, Driver.Packet.dispatch 365.7, Driver.Dispatch 364.3, Resources.Complete 357.4, Graphics.Draw 330.4, Graphics.Draw.draw_and_resource_release 298.3, Driver.Packet.draw 257.0, Driver.Draw 256.6, Vulkan.Dispatch 250.5

Longest waits

  • Driver.Packet.memory_wait (queue worker 0x20) 256.9 ms at 2107 ms, present 1653
  • Driver.Packet.memory_wait (queue worker 0x20) 253.3 ms at 3579 ms, present 1655
  • Driver.Packet.memory_wait (queue worker 0x20) 245.4 ms at 4357 ms, present 1656
  • Driver.Packet.memory_wait (queue worker 0x20) 238.9 ms at 2849 ms, present 1654
  • Driver.Packet.memory_wait (queue worker 0x20) 231.2 ms at 1367 ms, present 1652
  • Driver.Packet.memory_wait (queue worker 0x20) 227.2 ms at 5852 ms, present 1658
  • Driver.Packet.memory_wait (queue worker 0x20) 207.0 ms at 11386 ms, present 1667
  • Driver.Packet.memory_wait (queue worker 0x20) 206.0 ms at 10147 ms, present 1665
  • Driver.Packet.memory_wait (queue worker 0x20) 199.5 ms at 5135 ms, present 1657
  • Driver.Packet.memory_wait (queue worker 0x20) 195.7 ms at 8912 ms, present 1663

Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)

  • batch 347: 18.7 ms at 1492 ms, present 1653: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 26.6, Driver.Packet.prepare_memory (queue worker 0x0) 19.0, Driver.Packet.dispatch (queue worker 0x0) 7.1, Driver.Dispatch (queue worker 0x0) 7.1
  • batch 677: 18.2 ms at 2976 ms, present 1655: GPU no ranges; recorded by Recorder.Submit (draw committer) 0.3
  • batch 1370: 18.2 ms at 5973 ms, present 1659: GPU no ranges; recorded by Recorder.Sync (queue worker 0x0) 18.3, Recorder.Submit (queue worker 0x0) 0.1
  • batch 510: 18.0 ms at 2251 ms, present 1654: GPU no ranges; recorded by Recorder.Reap (draw committer) 0.5, Recorder.Submit (draw committer) 0.0
  • batch 2706: 18.0 ms at 11474 ms, present 1668: GPU no ranges; recorded by Recorder.Sync (queue worker 0x0) 18.1, Recorder.Submit (queue worker 0x0) 0.1
tools/trace_digest.py, this change 96c7091cd

seconds 85:12 from present 1658: 21 presents, frame p50 557.0 / p90 779.9 / p99 807.0 / max 807.0 ms, GPU busy 133.6 ms per present
NVIDIA GeForce RTX 4060, NVIDIA 617.42, Windows 10.0.19045, 3840x2160, commit 96c7091cd26f, dropped: no

{"commit":"96c7091cd26f","dirty":false,"env":{"APS5_LAB_HEAP_CENSUS":"1","APS5_NO_PAD_INPUT":"1","APS5_PAD_INPUT_FILE":"<path>","APS5_PROFILE_DRAW":"1","APS5_TRACE_SECONDS":"85:12"},"gpu":"NVIDIA GeForce RTX 4060","driver":"NVIDIA 617.42","os":"Windows 10.0.19045","resolution":"3840x2160","window":{"spec":"seconds 85:12","first_present":1658,"ms":12704.108},"presents":21,"frame_ms":{"p50":557.018,"p90":779.851,"p99":806.963,"max":806.963},"gpu_busy_ms_per_present":133.644,"worker_busy_pct":{"queue worker 0x0":99.639,"queue worker 0x20":97.503},"top_phases_ms_per_frame":{"Driver.Packet":1192.2,"Driver.Packet.memory_wait":380.283,"Driver.Packet.dispatch":358.65,"Driver.Dispatch":356.822,"Resources.Complete":319.993,"Graphics.Draw":261.948,"Vulkan.Dispatch":254.628,"Vulkan.Dispatch.shader_resources":249.327},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-12372.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 1659: 807.0 ms at 782 ms: Driver.Packet (queue worker 0x20) 804.3, Driver.Packet (queue worker 0x0) 795.3, Driver.Packet.memory_wait (queue worker 0x20) 590.9, Driver.Packet.draw (queue worker 0x0) 329.9
  • present 1658: 781.8 ms at 0 ms: Driver.Packet (queue worker 0x0) 770.2, Driver.Packet (queue worker 0x20) 622.1, Driver.Packet.memory_wait (queue worker 0x20) 331.8, Driver.Packet.draw (queue worker 0x0) 285.6
  • present 1678: 779.9 ms at 11924 ms: Driver.Packet (queue worker 0x0) 770.4, Driver.Packet (queue worker 0x20) 706.2, Driver.Packet.memory_wait (queue worker 0x20) 433.0, Driver.Packet.draw (queue worker 0x0) 312.2
  • present 1674: 764.2 ms at 9034 ms: Driver.Packet (queue worker 0x20) 761.9, Driver.Packet (queue worker 0x0) 753.9, Driver.Packet.memory_wait (queue worker 0x20) 525.8, Driver.Packet.draw (queue worker 0x0) 313.2
  • present 1677: 743.2 ms at 11181 ms: Driver.Packet (queue worker 0x20) 740.8, Driver.Packet (queue worker 0x0) 733.5, Driver.Packet.memory_wait (queue worker 0x20) 492.2, Driver.Packet.draw (queue worker 0x0) 291.9

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
shader prepare 0.3 (0 %) 0.0 (0 %) 604.7 0.0 Shader.PrepareArtifact 0.3
shader prepare 0.2 (0 %) 0.0 (0 %) 604.8 0.0 Shader.PrepareArtifact 0.2
shader prepare 0.1 (0 %) 0.0 (0 %) 604.9 0.0 Vulkan.GraphicsPipelinePrebuild 0.1
queue worker 0x0 529.1 (87 %) 66.1 (11 %) 9.7 51.2 Driver.Packet 595.2, Vulkan.Dispatch 0.0
draw committer 149.8 (25 %) 38.6 (6 %) 416.6 4.9 Graphics.Draw 142.7, Recorder.Submit 8.3
queue worker 0x20 106.1 (18 %) 486.4 (80 %) 12.5 7.0 Driver.Packet 588.0, Driver.EndSubmission 0.4
presenter 1.1 (0 %) 0.2 (0 %) 603.7 0.1 VideoOut.Flip 1.2, Driver.Present 0.1
title 0.4 (0 %) 0.0 (0 %) 604.6 0.0 Shader.ResolveAbi 0.4, Shader.Register 0.0
title 0.2 (0 %) 0.0 (0 %) 604.8 0.0 Shader.ResolveAbi 0.2, Shader.ResolveGraphicsStagesAbi 0.0
title 0.0 (0 %) 0.0 (0 %) 604.9 0.0 Shader.Register 0.0
title 0.0 (0 %) 0.0 (0 %) 604.9 0.0 Shader.Register 0.0, Shader.ResolveGraphicsStagesAbi 0.0
title 0.0 (0 %) 0.0 (0 %) 605.0 0.0 Shader.ResolveGraphicsStagesAbi 0.0, Shader.ResolveAbi 0.0
title 0.2 (0 %) 0.0 (0 %) 604.8 0.0 Shader.ResolveAbi 0.2, Shader.ResolveGraphicsStagesAbi 0.0
gpu 131.5 (22 %) 0.0 (0 %) 473.4 0.0 batch 131.5

Largest slices (ms per frame, inclusive, all threads): Driver.Packet 1183.2, Driver.Packet.memory_wait 380.1, Driver.Packet.dispatch 358.2, Driver.Dispatch 356.3, Resources.Complete 319.2, Graphics.Draw 261.2, Vulkan.Dispatch 254.0, Vulkan.Dispatch.shader_resources 248.5, Graphics.Draw.draw_and_resource_release 245.7, Driver.Packet.draw 211.1

Longest waits

  • Driver.Packet.memory_wait (queue worker 0x20) 357.5 ms at 1403 ms, present 1659
  • Driver.Packet.memory_wait (queue worker 0x20) 258.1 ms at 672 ms, present 1658
  • Driver.Packet.memory_wait (queue worker 0x20) 246.0 ms at 2101 ms, present 1660
  • Driver.Packet.memory_wait (queue worker 0x20) 245.1 ms at 4618 ms, present 1665
  • Driver.Packet.memory_wait (queue worker 0x20) 241.3 ms at 11836 ms, present 1677
  • Driver.Packet.memory_wait (queue worker 0x20) 237.9 ms at 10379 ms, present 1675
  • Driver.Packet.memory_wait (queue worker 0x20) 228.7 ms at 3088 ms, present 1662
  • Driver.Packet.memory_wait (queue worker 0x20) 224.5 ms at 8964 ms, present 1673
  • Driver.Packet.memory_wait (queue worker 0x20) 222.2 ms at 9710 ms, present 1674
  • Driver.Packet.memory_wait (queue worker 0x20) 220.3 ms at 5680 ms, present 1667

Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)

  • batch 5: 20.8 ms at 15 ms, present 1658: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 29.3, Driver.Packet.prepare_memory (queue worker 0x0) 20.0, Driver.Packet.dispatch (queue worker 0x0) 8.0, Driver.Dispatch (queue worker 0x0) 8.0
  • batch 1848: 18.1 ms at 6910 ms, present 1670: GPU no ranges; recorded by Recorder.Sync (queue worker 0x0) 18.5, Driver.Packet (queue worker 0x0) 0.8, Driver.Packet.dispatch (queue worker 0x0) 0.8, Driver.Dispatch (queue worker 0x0) 0.8
  • batch 539: 17.6 ms at 2222 ms, present 1661: GPU no ranges; recorded by Driver.Packet (queue worker 0x0) 24.8, Driver.Packet.prepare_memory (queue worker 0x0) 17.6, Driver.Packet.dispatch (queue worker 0x0) 6.7, Driver.Dispatch (queue worker 0x0) 6.7
  • batch 1415: 17.5 ms at 5265 ms, present 1667: GPU no ranges; recorded by Recorder.Sync (queue worker 0x0) 17.7, Recorder.Submit (queue worker 0x0) 0.1
  • batch 959: 17.3 ms at 3666 ms, present 1664: GPU no ranges; recorded by Recorder.Sync (queue worker 0x0) 17.6, Recorder.Submit (queue worker 0x0) 0.1

Title screen, main against this change. RTX 3060 12 GB (NVIDIA 617.42), Windows 10 19045, PPSA16064 title screen, APS5_TRACE_SECONDS=120:12, main 36f60df against 96c7091cd in one session, alternating. Times are per 12 s capture window, from the traces:

build frame p50 (ms) Recorder.Sync under the mutex, all threads (ms) Recorder.WaitSerial without it (ms) queue worker 0x0 waiting for the GPU mutex, Driver.Packet.device_lock (ms)
main 36f60df 111.004, 111.029, 110.879 1367, 1408, 1413 2148, 2077, 2106 2890, 2914, 2750
this change 96c7091cd 109.923, 110.434, 109.894 674, 676, 646 3793, 3851, 3918 2268, 2253, 2190

The change is faster in 3 of 3 pairs, by 0.8 % on the mean p50 (110.08 against 110.97 ms). The locked Recorder.Sync time halves and the unlocked WaitSerial time grows (a FinishUpTo of a batch in flight has no slice of its own, so not every locked wait shows up as Recorder.Sync). Worker 0x0 waits about 610 ms less per window for the mutex; at the title the GPU, not the workers, sets the frame time.

{"commit":"36f60df9edb3","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":2207,"ms":12098.423},"presents":105,"frame_ms":{"p50":111.029,"p90":142.616,"p99":147.086,"max":149.996},"gpu_busy_ms_per_present":92.106,"worker_busy_pct":{"queue worker 0x0":99.346,"queue worker 0x20":99.467},"top_phases_ms_per_frame":{"Driver.Packet":228.960,"Driver.Packet.dispatch":81.176,"Driver.Dispatch":79.967,"Driver.Packet.memory_wait":64.383,"Vulkan.Dispatch":34.012,"Vulkan.Dispatch.shader_resources":31.692,"Graphics.Draw":30.984,"Driver.Packet.device_lock":29.598},"trace_dropped":false,"trace":"aps5-trace-36f60df9edb3-11636.json.gz"}
{"commit":"96c7091cd26f","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":2211,"ms":12056.745},"presents":105,"frame_ms":{"p50":110.434,"p90":142.814,"p99":150.711,"max":154.314},"gpu_busy_ms_per_present":92.135,"worker_busy_pct":{"queue worker 0x0":99.345,"queue worker 0x20":99.694},"top_phases_ms_per_frame":{"Driver.Packet":228.430,"Driver.Packet.dispatch":84.716,"Driver.Dispatch":83.773,"Driver.Packet.memory_wait":68.882,"Recorder.WaitSerial":36.680,"Graphics.Draw":32.086,"Graphics.Draw.draw_and_resource_release":30.493,"Driver.Packet.draw":27.594},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-6628.json.gz"}
summary lines, the other title captures (main, then this change)
{"commit":"36f60df9edb3","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":2204,"ms":12054.478},"presents":105,"frame_ms":{"p50":111.004,"p90":143.503,"p99":147.456,"max":148.244},"gpu_busy_ms_per_present":91.934,"worker_busy_pct":{"queue worker 0x0":99.345,"queue worker 0x20":99.603},"top_phases_ms_per_frame":{"Driver.Packet":228.292,"Driver.Packet.dispatch":81.759,"Driver.Dispatch":80.702,"Driver.Packet.memory_wait":64.181,"Vulkan.Dispatch":32.987,"Graphics.Draw":30.758,"Vulkan.Dispatch.shader_resources":30.678,"Driver.Packet.device_lock":29.394},"trace_dropped":false,"trace":"aps5-trace-36f60df9edb3-7060.json.gz"}
{"commit":"36f60df9edb3","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":2206,"ms":12037.624},"presents":105,"frame_ms":{"p50":110.879,"p90":142.387,"p99":148.784,"max":150.711},"gpu_busy_ms_per_present":92.000,"worker_busy_pct":{"queue worker 0x0":99.359,"queue worker 0x20":99.239},"top_phases_ms_per_frame":{"Driver.Packet":227.569,"Driver.Packet.dispatch":81.980,"Driver.Dispatch":81.075,"Driver.Packet.memory_wait":63.799,"Vulkan.Dispatch":33.107,"Vulkan.Dispatch.shader_resources":30.879,"Graphics.Draw":30.677,"Graphics.Draw.draw_and_resource_release":29.067},"trace_dropped":false,"trace":"aps5-trace-36f60df9edb3-12672.json.gz"}
{"commit":"96c7091cd26f","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":2208,"ms":12043.454},"presents":105,"frame_ms":{"p50":109.923,"p90":143.074,"p99":150.546,"max":155.990},"gpu_busy_ms_per_present":92.019,"worker_busy_pct":{"queue worker 0x0":99.348,"queue worker 0x20":99.702},"top_phases_ms_per_frame":{"Driver.Packet":228.196,"Driver.Packet.dispatch":84.498,"Driver.Dispatch":83.324,"Driver.Packet.memory_wait":68.297,"Recorder.WaitSerial":36.124,"Graphics.Draw":31.895,"Graphics.Draw.draw_and_resource_release":30.271,"Driver.Packet.draw":27.516},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-2100.json.gz"}
{"commit":"96c7091cd26f","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":2207,"ms":12027.336},"presents":105,"frame_ms":{"p50":109.894,"p90":143.163,"p99":149.161,"max":156.115},"gpu_busy_ms_per_present":91.941,"worker_busy_pct":{"queue worker 0x0":99.353,"queue worker 0x20":99.650},"top_phases_ms_per_frame":{"Driver.Packet":227.834,"Driver.Packet.dispatch":84.926,"Driver.Dispatch":83.809,"Driver.Packet.memory_wait":68.308,"Recorder.WaitSerial":37.321,"Graphics.Draw":31.875,"Graphics.Draw.draw_and_resource_release":30.273,"Driver.Packet.draw":27.478},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-3980.json.gz"}

Title screen, the switch alone. Same card and screen, the same 96c7091cd build with APS5_NO_WRITER_PRESYNC=1 (off) and without it (on), alternating:

frame p50 (ms) Recorder.Sync under the mutex (ms) Recorder.WaitSerial (ms) queue worker 0x0 Driver.Packet.device_lock (ms)
off 111.692, 111.984, 111.574 1282, 1454, 1375 2261, 2148, 2164 2817, 2842, 2918
on 111.003, 110.797, 111.029 654, 810, 579 3912, 3861, 3912 2199, 2262, 2210

On is faster in 3 of 3 pairs (0.7 % on the mean p50), with the same shift from locked to unlocked waits as against main.

summary lines, the switch alone, off then on
{"commit":"96c7091cd26f","dirty":false,"env":{"APS5_NO_WRITER_PRESYNC":"1","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":2201,"ms":12106.740},"presents":105,"frame_ms":{"p50":111.692,"p90":143.491,"p99":148.558,"max":151.436},"gpu_busy_ms_per_present":91.852,"worker_busy_pct":{"queue worker 0x0":99.370,"queue worker 0x20":99.373},"top_phases_ms_per_frame":{"Driver.Packet":229.044,"Driver.Packet.dispatch":82.791,"Driver.Dispatch":81.808,"Driver.Packet.memory_wait":65.025,"Vulkan.Dispatch":33.352,"Graphics.Draw":31.188,"Vulkan.Dispatch.shader_resources":31.054,"Graphics.Draw.draw_and_resource_release":29.601},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-11716.json.gz"}
{"commit":"96c7091cd26f","dirty":false,"env":{"APS5_NO_WRITER_PRESYNC":"1","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":2196,"ms":12107.583},"presents":104,"frame_ms":{"p50":111.984,"p90":142.824,"p99":147.193,"max":147.296},"gpu_busy_ms_per_present":92.808,"worker_busy_pct":{"queue worker 0x0":99.367,"queue worker 0x20":99.621},"top_phases_ms_per_frame":{"Driver.Packet":231.547,"Driver.Packet.dispatch":83.564,"Driver.Dispatch":82.579,"Driver.Packet.memory_wait":65.722,"Vulkan.Dispatch":34.805,"Vulkan.Dispatch.shader_resources":32.506,"Graphics.Draw":31.620,"Graphics.Draw.draw_and_resource_release":29.969},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-9428.json.gz"}
{"commit":"96c7091cd26f","dirty":false,"env":{"APS5_NO_WRITER_PRESYNC":"1","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":2198,"ms":12108.646},"presents":105,"frame_ms":{"p50":111.574,"p90":142.871,"p99":148.604,"max":149.591},"gpu_busy_ms_per_present":91.948,"worker_busy_pct":{"queue worker 0x0":99.362,"queue worker 0x20":99.605},"top_phases_ms_per_frame":{"Driver.Packet":229.338,"Driver.Packet.dispatch":82.252,"Driver.Dispatch":81.238,"Driver.Packet.memory_wait":64.896,"Vulkan.Dispatch":34.193,"Vulkan.Dispatch.shader_resources":31.900,"Graphics.Draw":31.208,"Driver.Packet.device_lock":29.659},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-2704.json.gz"}
{"commit":"96c7091cd26f","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":2204,"ms":12035.061},"presents":105,"frame_ms":{"p50":111.003,"p90":141.156,"p99":145.323,"max":146.685},"gpu_busy_ms_per_present":92.015,"worker_busy_pct":{"queue worker 0x0":99.355,"queue worker 0x20":99.599},"top_phases_ms_per_frame":{"Driver.Packet":227.917,"Driver.Packet.dispatch":85.920,"Driver.Dispatch":84.974,"Driver.Packet.memory_wait":67.852,"Recorder.WaitSerial":37.257,"Graphics.Draw":32.375,"Graphics.Draw.draw_and_resource_release":30.760,"Driver.Packet.draw":27.780},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-9568.json.gz"}
{"commit":"96c7091cd26f","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":2206,"ms":12079.003},"presents":105,"frame_ms":{"p50":110.797,"p90":143.411,"p99":149.697,"max":151.528},"gpu_busy_ms_per_present":91.848,"worker_busy_pct":{"queue worker 0x0":99.371,"queue worker 0x20":99.475},"top_phases_ms_per_frame":{"Driver.Packet":228.630,"Driver.Packet.dispatch":85.370,"Driver.Dispatch":84.423,"Driver.Packet.memory_wait":66.608,"Recorder.WaitSerial":36.773,"Graphics.Draw":32.555,"Graphics.Draw.draw_and_resource_release":30.970,"Driver.Packet.draw":27.867},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-3508.json.gz"}
{"commit":"96c7091cd26f","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":2202,"ms":12051.484},"presents":105,"frame_ms":{"p50":111.029,"p90":140.597,"p99":149.304,"max":149.315},"gpu_busy_ms_per_present":92.832,"worker_busy_pct":{"queue worker 0x0":99.361,"queue worker 0x20":99.226},"top_phases_ms_per_frame":{"Driver.Packet":227.807,"Driver.Packet.dispatch":85.869,"Driver.Dispatch":84.780,"Driver.Packet.memory_wait":67.887,"Recorder.WaitSerial":37.262,"Graphics.Draw":32.188,"Graphics.Draw.draw_and_resource_release":30.603,"Driver.Packet.draw":27.508},"trace_dropped":false,"trace":"aps5-trace-96c7091cd26f-7908.json.gz"}

Tested

  • On 4d578a4 (this branch, rebased onto main 5d3ab77) and on main 5d3ab77, RTX 4060 (NVIDIA 617.42, Windows 10 19045, WinLibs GCC 15.2.0, Release with BUILD_TESTING=ON): ctest -V -R "agc_driver_(storage|dcc|presync|flush)" with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ANYPS5_NO_SHADER_CACHE=1 ANYPS5_REQUIRE_VULKAN=1 VK_LOADER_DEBUG=error,warn, Vulkan SDK 1.4.363.0. 12 of 12 pass with this change (the 11 on main, which now include agc_driver_storage_write_back_overhang_draw_pipeline, plus agc_driver_storage_presync_writer) and 11 of 11 on main. Neither log has a was not found but was requested by env var VK_INSTANCE_LAYERS line, and both have 0 VUID- lines (each has the same 10 WARNING-VkImageSubresourceRange-layerCount-compatibility lines from agc_driver_storage_write_back_no_window). The same comparison on e5c5329 gave 11 of 11 and 10 of 10.
  • With APS5_NO_WRITER_PRESYNC=1 the new test passes its control case (one locked wait) and then fails with "storage pre-sync writer, writer in the open batch: stage A did not list the storage image of the cached build as a writer range". On main it does not build: the counters it reads are new.
  • agc_driver_graphics passes on 4d578a4.
  • git diff --check, python3 tools/check_test_registration.py build and python3 tools/check_conventions.py --base upstream/main pass on 4d578a4. The rebase onto 5d3ab77 conflicted only in context: in Texture.hpp, main added a waited parameter to FlushPending and StampKeepingNewerResults next to this change's declarations (both kept; waited only feeds PublishShadowsOnly and does not touch the writer wait), and in ARCHITECTURE.md main added its APS5_DRAW_PIPELINE bullet after this change's (kept unchanged). The change's own lines are identical (git range-diff).
  • In game, at 4d578a4, 114c160 and 96c7091cd: the rows above, and 7 of 7 loads on 2026-10-19 without a crash at 96c7091cd. On 114c160 and on main e5c5329, MCD2 stops more often than on 36f60df (a game access violation and the write-watch check above), on both sides.
  • Not checked: other titles, Linux, AMD/RADV, Intel.

Related

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 (none added)
  • No notes, investigation .md files or images added to the repository
  • New third-party code is a submodule built from source (none added)
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 4060 8 GB, NVIDIA 617.42, Windows 10 (tests with validation, gameplay); NVIDIA GeForce RTX 3060 12 GB, NVIDIA 617.42, Windows 10 (title screen captures)
  • AI-assisted: yes

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

Copy link
Copy Markdown
Contributor

@parl0v an overlap note from #8887, which rewrites the same FlushPending block from the other side, so whichever lands second knows what to carry.

What each changes

  • perf(agc): wait for a storage refresh's pending writer before taking the GPU mutex #9400 moves the storage refresh's writer wait for an object from the resource cache into the stage-A pre-sync: it lists each storage image the object binds, the image behind each sampled view and the imported regions as writer-only ranges, waits without the mutex when another image has a pending unit inside the range and recorded work writes or leases it, and the locked FlushPending then finds no writer.
  • perf(agc): wait on a flush only for writers over the image layers it stores #8887 (head 017123e) keeps the wait under the mutex but narrows what it waits for: the 64 KiB blocks of the pending layers the write-back will store (every pending layer when the write-back stores the whole image: a DCC image whose keys are not uncompressed or that has more than one mip, or widened block write-back), checked over their hull above eight runs, plus the heap lease over the range when the flush publishes unit shadows. A writer elsewhere in the flushed range is not waited for. APS5_FLUSH_WAIT_WHOLE_RANGE=1 restores the whole-range wait.

Where the two collide (merge-tree of 02aebc8 against 017123e; #9400 is clean against main 0c6a5bd)

Combined behaviour

Data on offer. In 007 First Light (PPSA11386) on Linux/NVIDIA, the draw committer waits for the GPU mutex behind the async queues' dispatch and indirect holds, with fence waits in FlushPending under StorageTexture::Refresh among them (issuecomment-6312207539 on #7895). I can run #9400 alone and with #8887 there, on main plus the open PRs the title needs (listed with the numbers, title patched as in #6172), with the same input and the [flushwait] and [lock] lines, and post the numbers here.

AI-assisted: yes (Claude Code)

@parl0v

parl0v commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

@SleglJan thanks, that's a precise map of the collision. I agree with the carry: if #8887 lands first, I'll rebase this onto it, wrap your two calls with the counters, and have pendingWriter also report whether the batch it settles on writes a stored range, for CountSync and the FinishUpTo source. Listing your stored-layer ranges in the pre-sync instead of the whole surface also sounds right, and I'll try it as part of that rebase.

Yes please on the 007 First Light runs, #9400 alone and with #8887. A second title is exactly what this PR is missing; MCD2 is the only one I've measured. The [flushwait] and [presync] writer counts next to [lock] would show whether the waits move there as they do at the MCD2 title.

@github-actions

github-actions Bot commented Oct 21, 2026 •

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 862 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1368 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1395 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1896 docs/dev/ENVIRONMENT.md
PR 2434 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4040 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4448 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 4472 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 4847 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5021 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5441 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 5925 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ARCHITECTURE.md
PR 6108 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6146 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6185 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 6186 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 6187 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6192 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6194 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6202 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6209 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6223 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6249 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6280 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6290 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6340 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6412 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ARCHITECTURE.md
PR 6481 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6498 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6501 docs/dev/ENVIRONMENT.md
PR 6539 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6615 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6743 docs/dev/ARCHITECTURE.md
PR 6782 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6804 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6924 docs/dev/ENVIRONMENT.md
PR 6960 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6970 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6971 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6973 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6977 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6987 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6989 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6995 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7002 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7048 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7085 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7201 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7261 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7275 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7310 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7369 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7449 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
docs/dev/ENVIRONMENT.md
PR 7457 docs/dev/ENVIRONMENT.md
PR 7464 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 7484 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 7514 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ENVIRONMENT.md
PR 7604 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ENVIRONMENT.md
PR 7622 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 7642 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ARCHITECTURE.md
docs/dev/ENVIRONMENT.md
PR 7643 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 7684 docs/dev/ARCHITECTURE.md
PR 7689 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7922 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 8004 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 8014 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8077 docs/dev/ENVIRONMENT.md
PR 8105 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8160 core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 8161 core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 8212 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ARCHITECTURE.md
PR 8246 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ENVIRONMENT.md
PR 8484 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ENVIRONMENT.md
PR 8542 docs/dev/ENVIRONMENT.md
PR 8615 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 8707 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8874 core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 8887 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ENVIRONMENT.md
PR 8896 docs/dev/ENVIRONMENT.md
PR 8898 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 8963 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 8998 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9012 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 9050 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9098 docs/dev/ENVIRONMENT.md
PR 9129 docs/dev/ENVIRONMENT.md
PR 9176 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 9193 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9243 docs/dev/ENVIRONMENT.md
PR 9248 docs/dev/ENVIRONMENT.md
PR 9287 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 9289 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 9318 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9345 docs/dev/ENVIRONMENT.md
PR 9346 docs/dev/ENVIRONMENT.md
PR 9356 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ARCHITECTURE.md
docs/dev/ENVIRONMENT.md
PR 9385 docs/dev/ARCHITECTURE.md
docs/dev/ENVIRONMENT.md
PR 9387 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ARCHITECTURE.md
docs/dev/ENVIRONMENT.md
PR 9431 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9432 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9445 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9489 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9508 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ARCHITECTURE.md
docs/dev/ENVIRONMENT.md
PR 9521 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9565 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 9592 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9626 docs/dev/ENVIRONMENT.md
PR 9669 docs/dev/ENVIRONMENT.md
PR 9672 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9673 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9674 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9675 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9676 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ENVIRONMENT.md
PR 9702 docs/dev/ENVIRONMENT.md
PR 9703 docs/dev/ENVIRONMENT.md
PR 9712 core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 9723 docs/dev/ENVIRONMENT.md
PR 9842 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9852 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 9858 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9875 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 9879 docs/dev/ENVIRONMENT.md
PR 9881 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9884 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9891 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9892 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9893 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9895 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9897 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9898 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 9961 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 9978 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9989 docs/dev/ENVIRONMENT.md
PR 9999 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10000 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10026 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10043 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 10049 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10062 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 10064 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10069 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ARCHITECTURE.md
docs/dev/ENVIRONMENT.md
PR 10150 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10159 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10160 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10193 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ARCHITECTURE.md
docs/dev/ENVIRONMENT.md
PR 10194 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ENVIRONMENT.md
PR 10249 core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10256 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10318 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 10351 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10368 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10382 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 10388 docs/dev/ENVIRONMENT.md
PR 10419 docs/dev/ENVIRONMENT.md
PR 10435 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10442 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 10443 docs/dev/ENVIRONMENT.md
PR 10472 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
docs/dev/ENVIRONMENT.md
PR 10487 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 10489 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10492 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10497 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10507 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10513 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10547 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 10551 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10556 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 10652 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10656 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10668 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 10676 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10678 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 10689 docs/dev/ENVIRONMENT.md
PR 10696 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10720 docs/dev/ENVIRONMENT.md
PR 10743 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10750 docs/dev/ENVIRONMENT.md
PR 10757 docs/dev/ENVIRONMENT.md
PR 10773 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10837 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10845 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10846 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/ENVIRONMENT.md
PR 10859 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10867 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10886 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10894 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 10940 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp

@github-actions github-actions Bot added docs agc libSceAgc* labels Oct 22, 2026

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proposed move of storage-writer waits into pre-sync is well motivated and the PR has unusually thorough evidence: paired validation-layer runs on the same RTX 4060 show 10/10 baseline tests and 11/11 on the change with no VUIDs, and the title traces and measurement limits are described clearly. The mock regression also checks the open-batch, in-flight, and no-writer cases. git diff --check passes and the current head merges cleanly with main.

I’m requesting changes for the remaining repository requirements:

  • The latest paired validation runs are on main 0c6a5bd59; current main is 4a17c71757. Please rebase onto current main and rerun the same focused tests on both trees with the required validation-layer settings and VUID comparison. The gameplay and title-screen performance comparisons were measured on older base 36f60df9e; refresh the summaries and traces against current main as well.
  • The current overlap scan identifies open #7307 in the recorder wait/completion path and open #8887 in StorageTexture::FlushPending, which both intersect this PR’s new writer-wait attribution and pre-sync behavior. Please coordinate with their authors on sequencing and integration, and update Depends on: if either needs to land first. The scan also identifies shared texture/header and documentation lines; refresh it after rebasing and manually resolve actual overlaps. #7769 is already merged, so that earlier relationship is now part of main.

No local AGC test or GPU run was possible in this review environment. Hosted eligibility, conventions, intake, labels, and report checks pass; product build/test jobs are skipped. The existing older-base results are strong but do not satisfy current-main validation for this head.

@SleglJan

Copy link
Copy Markdown
Contributor

@parl0v the 007 First Light runs you asked for, #9400 alone and with #8887.

Setup. 007 First Light (PPSA11386, content 01.018.000), Linux 7.2.10 (CachyOS), RTX 3080 10 GB, driver 615.78.08, Ryzen 9 7950X3D, Release builds, 3840x2160, warm shader cache (the same seed cache copied before every run), default VRAM headroom.

11 runs: P1 W1 WR1 P2 W2 WR2 P3 W3 WR3 alternated, then P4 and W4 later the same day (not alternated). P3 and W3 are left out because the storage image cache budget reached its 512 MiB floor at or after present 1400: P3 from present 1567 (its last ~13 presents), W3 from 1452; over its window W3 waited 1,100 ms per present for pipeline room, at a frame p50 of 3,787 ms, and hit the 1,200 s limit at 1573. P3 carries neither PR. Of the runs shown, P2 and W2 ran most of the window with that budget lowered to about 1,000-1,500 MiB, falling to 681 and 685 MiB near the stop; the other seven stayed at 1,757-2,197 MiB, apart from one 876 MiB line in P1 near present 1405. P2 and W2 are their arms' slowest runs.

Per present over the window (sums of the 10 s or longer lines inside the window, divided by its presents; pre-syncs and [flushwait] are deltas of cumulative counters over the window; frame time is the presents-weighted mean of the ~60 s summary windows' p50 lying in the gameplay stretch, 135-193 presents per run, not a percentile over all frames):

P1 P2 P4 W1 W2 W4 WR1 WR2 WR3
frame time p50, ms 1,204 1,328 1,259 1,295 1,429 1,216 1,212 1,508 1,470
queue 0 wait for pipeline room, ms 247 365 243 245 378 374 244 257 267
committer commit, ms 807 932 791 779 935 775 762 841 822
[lock] queue 0x0 waited, ms 40 47 49 44 50 41 40 53 51
pre-syncs waited, ms 26.1 24.9 28.3 27.3 24.2 27.4 31.4 32.9 30.8
[flushwait] all kinds, ms (all threads) - - - 142.5 144.3 138.7 130.0 139.6 141.9

The arms' ranges overlap in every row but the pre-syncs (arm means: frame time 1,264 / 1,313 / 1,397 ms, room wait 285 / 332 / 256 ms). WR's pre-syncs waited 30.8-32.9 ms per present against 24.2-28.3 in P and W, in all three runs.

[presync] and [flushwait], totals over the window:

  • Pre-syncs that waited: P 363 / 453 / 404, W 518 / 613 / 554, WR 498 / 429 / 479. Of them, the ones only a storage refresh's pending writer required: W 120 / 94 / 110, WR 106 / 82 / 102. Writer ranges checked: W 441,819 / 493,606 / 432,330, WR 487,052 / 443,371 / 459,953.
  • [flushwait], count / ms:
open batch, lease only open batch, writes in flight, lease only in flight, writes inside a caller's hold
W1 446 / 2,584 6,397 / 10,443 464 / 2,951 1,168 / 11,240 8,475
W2 499 / 1,841 7,747 / 12,089 511 / 3,097 1,204 / 14,140 9,960
W4 380 / 2,119 6,971 / 9,691 451 / 2,858 1,143 / 10,993 8,945
WR1 556 / 3,251 6,415 / 8,284 571 / 2,712 1,112 / 12,668 8,654
WR2 405 / 2,086 5,775 / 7,905 518 / 3,346 1,046 / 12,205 7,744
WR3 454 / 3,095 7,350 / 9,043 572 / 3,391 1,069 / 12,429 9,444

So in W, 94-120 writer-only pre-syncs per window stand against 8,475-9,961 writer waits in FlushPending, and in every W and WR window all of those but at most one ran with the GPU mutex already held by FlushPending's caller (the last column equals the sum of the four kinds, within one). The counter has no split by caller, and FlushPending has 38 call sites in libSceAgcDriver on this tree, so these numbers don't say how many of the locked waits are the ones your description leaves locked ("work recorded after the pre-sync, and lookups the pre-sync does not list"). A per-call-site count would answer it; I haven't run one.

AI-assisted: yes (Claude Code)

@parl0v
parl0v force-pushed the perf/presync-storage-writer branch from 02aebc8 to 114c160 Compare October 22, 2026 17:07
@parl0v

parl0v commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

@MarcZX10 rebased onto main e5c5329 (114c160, no conflicts: main changed only VulkanDevice.hpp and VulkanDevice.cpp among this change's files, away from its lines) and reran everything on both trees:

  • ctest -V -R "agc_driver_(storage|dcc|presync|flush)" with the validation layer settings from CONTRIBUTING: 11 of 11 on this branch, 10 of 10 on main e5c5329, 0 VUID- lines and no missing-layer line in either log. With APS5_NO_WRITER_PRESYNC=1 the new test fails as before. agc_driver_graphics, git diff --check, test registration and conventions pass.
  • Performance refreshed on the same base, with new traces: title screen +3.0 % in an alternating A/B on the RTX 3060 (10.81 and 10.82 FPS against 10.50, 10.52 and 10.50), and in the captures the GPU mutex wait falls from 32.6 to 19.4 ms per frame. The gameplay capture pair shows 588 against 439 ms frame p50, but the writer pre-sync did not fire in that window, so I don't count it; the body says why. Body updated with the summary lines, comparisons and trace links.
  • Overlaps, against their current heads: feat(agc): add opt-in bounded submission progress #7307 conflicts with this one only in Recorder.cpp, where it adds WaitSerialFor right above FinishUpTo, whose signature this change extends; keeping both resolves it, and neither changes what the other waits for. perf(agc): wait on a flush only for writers over the image layers it stores #8887 needs the carry @SleglJan described. Either order works for both, so Depends on stays none; listed under Related. @Zenodeon, a heads-up in case feat(agc): add opt-in bounded submission progress #7307 lands first: I'll take the adjacent-lines conflict on my side.

@SleglJan thanks for the 007 runs. They match what I see: in your windows the writer-only pre-syncs (94-120) are a small slice of the 8,475-9,961 locked FlushPending writer waits, so on 007 most of the wait stays where it is and the arms overlap. A per-call-site split of [flushwait] would show which of those locked waits a pre-sync could reach; that's a follow-up, not this PR.

@Raghav314

Raghav314 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Data from Astro's Playroom (PPSA01325) with #9400 (114c160) and #8887 (017123e) merged together, in case it helps the review.

Base: #9508's head (5547aa1), APS5_GPU_HEAP=1 APS5_DRAW_PIPELINE=1. RTX 4090, NVIDIA 615.78.08, CachyOS (Linux 7.3.0). Player standing still in the same spot, warm shader cache, APS5_TRACE_SUMMARY_EVERY=10, no profiling.

presents per 10 s frame p50 GPU busy per present
base 171, 166, 167 58.6 ms 30.7 ms
base + #9400 + #8887 176, 172, 174, 175 57.3 ms 29.9 ms

About +3.5%, with the window ranges not overlapping.

A profiled run (APS5_PROFILE_DRAW=1) of the merged build: the longest indirect-dispatch hold of the GPU mutex fell from 35.5 ms to 10.3 ms, and the draw worker's wait for the mutex from 4.3 to 2.4 µs per draw packet. In this scene the [presync] line shows 126,670 writer ranges checked and 0 pre-syncs that only a writer required, and [flushwait] 21 waits / 75 ms (in flight, lease only). I did not A/B the two pull requests separately.

@parl0v

parl0v commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

@Raghav314 thanks for the Astro's Playroom runs. Your [presync] line shows 0 pre-syncs that only a writer required, so in that scene this change never moved a wait out of the lock, and the +3.5 % and the shorter indirect-dispatch hold most likely come from #8887. That fits what I'd expect: this change only acts when a cached dispatch's storage refresh finds another image's pending writer over its range, which happens at the MCD2 title and only rarely in the gameplay windows I traced.

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main moved again (e7f46f5) and the branch now conflicts in Texture.hpp (next to the idle-image reclaim from 3bcd89e) and ARCHITECTURE.md. The logic is untouched; a rebase is needed.

Still open from the CHANGES_REQUESTED review, which is what blocks the merge queue:

  • Validation-layer comparison on current main and on this change: ctest -V -R "agc_driver_(storage|dcc|presync|flush)" with the settings from CONTRIBUTING, the VUID count of both logs, and the missing-layer check. The 10-22 runs are on e5c5329.
  • Title and gameplay summaries refreshed against that same main.

#7307 and #8887 are already sequenced in the thread, so nothing else is needed there. Once the rebased head and the runs are posted, MarcZX10's re-review can clear the CHANGES_REQUESTED.

…the GPU mutex

A cached dispatch's Revalidate refreshes the storage images it binds (StorageTexture::Refresh).
When another image has results pending over one of them, the refresh's FlushPending waits with
the GPU mutex held for the newest batch that writes or leases that memory: an address-based
dispatch's write marks must land before the store chooses the blocks it keeps. At the Minecraft
Dungeons II title this wait held the mutex about 900 ms per 10 s on queue 0x20 (RTX 3060), about
half of it a Sync of the open batch and half a FinishUpTo of a batch in flight.

For an object from the resource cache, PresyncSurfaces now also lists the memory of every storage
image it binds, of the image each of its sampled views reads, and of its imported regions
(PresyncSurface::writerOnly). presync waits for such a range only when another image has a
pending unit inside it (StorageTexture::OthersPendingInside: FlushPending's listing without an
image of exactly that surface, taken without the GPU mutex) and, under the mutex it takes for a
moment, recorded work writes or leases it (PendingWriterSerial, the test FlushPending makes before
it waits). The dispatch reaps that batch before Revalidate, so the locked FlushPending finds no
writer. Work recorded after the pre-sync falls back to the locked wait as before.

APS5_NO_WRITER_PRESYNC=1 leaves the ranges out. The [presync] line counts the writer ranges
checked and the pre-syncs that only a writer required; a [flushwait] line counts FlushPending's
writer waits by open batch or batch in flight and by lease only or write, with their time and how
many ran inside a caller's hold of the mutex. FinishUpTo takes the sync source, so FlushPending's
drain of a batch in flight counts as a pending-write or address-based sync instead of idle. The
test agc_driver_storage_presync_writer covers the locked wait, a writer in the open batch and in
flight, and a pending image without a writer, and skips with the reason check_skips.py expects
when the device has no timeline semaphores.
@parl0v
parl0v force-pushed the perf/presync-storage-writer branch from 114c160 to 4d578a4 Compare October 24, 2026 09:56
@parl0v

parl0v commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

@adriadam10 @MarcZX10 rebased onto main 5d3ab77 (4d578a4). The two conflicts were context only: main's new waited parameter and StampKeepingNewerResults beside this change's declarations in Texture.hpp, and main's new APS5_DRAW_PIPELINE bullet after this change's in ARCHITECTURE.md. git range-diff shows the change's own lines unchanged.

On that main and on this branch, with the CONTRIBUTING validation settings: ctest -V -R "agc_driver_(storage|dcc|presync|flush)" passes 12 of 12 here and 11 of 11 on main, 0 VUID- lines and no missing-layer line in either log. APS5_NO_WRITER_PRESYNC=1 still fails the new test, and agc_driver_graphics, test registration, git diff --check and conventions pass.

Title and gameplay summaries on the same main are in the body, with new traces. Title screen: frame p50 -4.3 % and -2.7 % in two alternating capture pairs. The one gameplay pair favours main this time (324 against 566 ms p50). The writer pre-sync did not fire in that window, and the two rows ran with different storage image cache budgets (1,361 against 899 MiB, 8,450 against 18,700 storage images created), so I've stated it as is and not counted it either way.

@Celegans12

Copy link
Copy Markdown
Contributor

I tried this on Ghost of Yōtei (PPSA26344 v1.008) in the open world, on our own tree rather than main (our tree merged with today's main; RTX 3080 Laptop, driver 610.62, Windows 11). One caveat first: our tree defers some storage-refresh write-backs instead of waiting for their writer (a local experiment, APS5_DEFER_REFRESH_FLUSH=1). So I had to adapt the pre-sync to skip refreshes that would defer, otherwise it would add CPU waits we never take now. These numbers are for that adapted port, not your branch as is.

The 60-frame title check is bit-identical with it, and your tests pass on Windows. I made APS5_NO_WRITER_PRESYNC flippable at run time locally and alternated 60 s phases inside one run (9 pairs). On this tree the pre-sync came out slower: with it off, presents per 10 s were 7.25 against 5.85 with it on (+1.52 ± 0.46 against the neighbouring phases). Two of the nine "on" phases had long stalls (3.3 and 4.0 presents per 10 s). Even leaving those out, "off" stays ahead by roughly half a present per 10 s, and the committer is busier with it on. My guess is that waiting for the writer before taking the GPU mutex costs more here than the mutex hold it saves, because our committer is already the limit. That's only a guess, though; I haven't traced where the stalls sit. I'm keeping it off on our side for now and wanted you to have the data point.

Per-phase means (A = pre-sync on, B = APS5_NO_WRITER_PRESYNC=1)
per phase mean                          A          B        B-A    B/A-1   noise: B vs neighbouring A, mean diff +- SE (SD, n)
presents/10s                         5.85       7.25      +1.40   +23.9%   +1.52 +- 0.46 (SD 1.39, n 9)
frame ms                          1842.03    1405.37    -436.65   -23.7%   -487.41 +- 162.43 (SD 487.30, n 9)
GPU busy ms/frame                  883.25     850.72     -32.53    -3.7%   -18.29 +- 7.21 (SD 21.62, n 9)
GPU idle gaps ms/frame             903.79     535.78    -368.00   -40.7%   -422.70 +- 219.76 (SD 659.27, n 9)
committer us/commit                257.58     235.20     -22.38    -8.7%   -14.42 +- 8.60 (SD 25.79, n 9)
committer % busy                    58.07      65.33      +7.26   +12.5%   +8.10 +- 2.08 (SD 6.25, n 9)
room wait us/draw                   98.94      78.46     -20.48   -20.7%   -15.85 +- 5.80 (SD 17.41, n 9)
drain ms/10s                      1818.22    2074.51    +256.29   +14.1%   +240.25 +- 49.64 (SD 148.93, n 9)
syncwait GPU ms/10s               1401.87    1630.91    +229.04   +16.3%   +184.44 +- 45.19 (SD 135.57, n 9)

@parl0v

parl0v commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

Closing this one. Thanks @Celegans12, @Raghav314 and @SleglJan for running it on titles I can't, and @MarcZX10 and @adriadam10 for the reviews.

What the runs add up to:

  • MCD2 title screen: frame p50 -3 to -4 % in alternating pairs on two cards, the mechanism visible (the GPU mutex wait moves to an unlocked WaitSerial).
  • MCD2 gameplay, Astro's Playroom, 007 First Light: the writer pre-sync fires rarely or never in those windows (0 in Astro, 94-120 against 8,475-9,961 locked waits in 007), so there is nothing to gain there.
  • Ghost of Yōtei (@Celegans12's adapted port): slower with it on, 5.85 against 7.25 presents per 10 s over 9 alternating pairs, with the committer busier. Waiting for the writer on the worker before the lock can cost more than the hold it saves when the committer is the limit.

A few percent on one title screen against a measured regression in an open world isn't a trade I'd ask anyone to merge. If it comes back, it should wait only where the locked wait would otherwise have run under a caller's hold, and @SleglJan's per-call-site split of [flushwait] is the measurement that would show whether such a subset exists.

@parl0v parl0v closed this Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* docs needs rebase Conflicts with main, rebase needed perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants