Repository navigation
Conversation
A queued store run records each group's plain stores and then its occlusion counter dumps, and any store after a dump starts a new group, so a label the title writes after its dumps lands after them. A title that clears each query slot, dumps into it and then writes a flag after it gets a group per slot that way: a barrier, then three fold dispatches with a barrier before each. The run's writes are now recorded in three parts where that keeps the final bytes: the stores before the first dump and the stores that a later dump overlaps (the clears of the slots), then every dump in one fold, then the other stores in their order. A store after a dump that no later dump overlaps still lands after every dump before it, and those stores keep their order. A clear that only a later dump covers in part must not overlap an earlier dump, and no clear may overlap a store it moves ahead of; otherwise the run keeps its groups. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Thank you for your contribution! Authors with no pull requests merged into |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A queued store run (
Recorder::closeStoreRun) records each group's plain stores and then its occlusion counter dumps.Recorder::QueuedWriteGroupsstarts a new group at every store after a dump, so a label the title writes after its dumps lands after them (#5232).Stray (PPSA02100, Unreal Engine 4) writes three things per query slot:
1just after the slot.The flag is such a label, so every slot became its own group. A run held about 80 writes in about 20 groups, and each group cost a barrier plus a fold of three
SampleDumps.compdispatches with a barrier before each. That came to about 240,000 label-run barriers per 10 s and 17 ms of GPU time per frame (APS5_PROFILE_GPU=1, about 107 runs per frame).Recorder::QueuedWriteOrdernow records a run's writes in three parts:What stays as before:
What changes: a later slot's clear and dumps can now land before an earlier slot's flag. The flag only lands later than it did, after all of the run's dumps.
The run keeps its old groups when the reordering could change the final bytes:
@xXPBSXx asked about the per-slot cost on #5232. @johnmaia, @Tamalero: could you check Epic Mickey: Rebrushed and High on Life with this? I don't have either title.
Tested
Linux (CachyOS, kernel 7.2.10, scx_lavd), Ryzen 9 9950X, RTX 3090 (NVIDIA 615.78.08), GCC 16.2.1, Release, 3840x2160. Stray at the same save, standing at the start of Dead City, stock
engine.ini, one run at a time. Measured at 38a43ec3d onmain676d423; the head is the same change rebased onto 6b8228b (#7489, merged in between, changes the run's leading barrier, not these lines).One run of each with
APS5_PROFILE_GPU=1, last 4 windows of 10 s:main676d423Scored runs,
mainand this change alternating, withAPS5_TRACE_SECONDS=185:20and no otherAPS5_TRACE_*/APS5_PROFILE_*variables:main676d423, scx_lavdmainStray is CPU-bound in this scene (queue worker 0 is 97 to 98 % busy in every run), so the GPU busy time per present falls by about 12 ms while the frame time stays within the spread between runs. Queue worker 0's draw packets took 103-105 ms per frame in these
mainruns and 108-111 ms with the change; runs of one build earlier the same day spread from 102 to 121 ms, andmain676d423 took 112 ms in another run, so I read that as spread too. Left out: onemainrun that hit the #5372 import race (about 1 fps for the whole window). The first run of each build in this batch was a frame-dump run (below).The shape of Stray's runs comes from a local diagnostic (not part of this PR) that logged every 499th run with dumps: in 59 of 67 logged runs, 20 to 21 slots of clear, begin dump, end dump and flag followed each other (about 80 writes in about 20 groups), most of them ending with the next slot's clear and begin dump; the others were shorter runs or a single dump. A sample is on the release.
Frame dumps (
APS5_DUMP_FRAMES=40 APS5_DUMP_FRAMES_EVERY=104, 960x540) ofmain, this change andmainagain. The runs reached the scene at different presents (this change's run later; before that the frames show menus and the loading screen at different moments), so frames 28 to 30 are the ones with all three in the scene. There this change differs from the firstmainrun by 2.4 per 8-bit channel on average and from the second by 5.2, while the twomainruns differ by 5.1 from each other; the differences are the cat's idle pose and TAA edges over the whole frame, and no geometry is missing. Frame 29 with both differences is on the release.agc_queued_write_groupspasses. New cases:The random case also checks that the recorded order keeps the final bytes, and that a store no later dump overlaps never lands before a write ahead of it.
agc_sample_dumpspasses on an RTX 3090 (NVIDIA 615.78.08, Linux).tools/check_conventions.py --base origin/mainpasses;tools/pr_overlap.pyfinds no overlapping functions; of the pull requests it could not compare, the ones touchingRecorder.cpp(perf(agc): reuse cached draw stages when only buffer base addresses moved #5609, fix(agc): copy only the dwords a shader changed back from a GPU-copied buffer #6185, fix(agc): keep CPU stores made after a deferred DCC key store was recorded #6186, perf(agc): draws that only store to a buffer continue one render pass #7340, fix(runtime): isolate host worker MXCSR #7622, feat(agc): look up table images at run time through a device image table on the GPU heap (APS5_GPU_PATH) #7642) don't change these functions.Traces, summaries and digests: https://github.com/teepean/AnyPS5/releases/tag/perf-one-fold-store-runs-20261019 (each scored run's trace,
aps5-summary.jsonlanddigest.md, the[gputime],[barriers]and[samples]lines of the two profiled runs, the store-run sample and frame 29). Thetools/trace_digest.pyoutput for the pair with the same frame p50:`main` 676d423 (run of2b)
seconds 185:20 from present 2892: 120 presents, frame p50 166.6 / p90 203.2 / p99 211.9 / max 243.3 ms, GPU busy 88.6 ms per present
NVIDIA GeForce RTX 3090, NVIDIA 615.78.08, Linux 7.2.10-1-cachyos, 3840x2160, commit 676d423, dropped: yes
{"commit":"676d423968a1","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"185:20"},"gpu":"NVIDIA GeForce RTX 3090","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","resolution":"3840x2160","window":{"spec":"seconds 185:20","first_present":2892,"ms":20033.154},"presents":120,"frame_ms":{"p50":166.581,"p90":203.177,"p99":211.926,"max":243.313},"gpu_busy_ms_per_present":88.622,"worker_busy_pct":{"queue worker 0x0":97.625,"queue worker 0x20":99.318},"top_phases_ms_per_frame":{"Driver.Packet":328.215,"Driver.Packet.memory_wait":165.253,"Driver.Packet.draw":103.127,"Driver.Draw":102.405,"Graphics.Draw":81.429,"Graphics.Draw.draw_and_resource_release":69.855,"Driver.Draw.shader_compile_and_link":67.859,"Shader.DrawStage":59.671},"trace_dropped":true,"trace_dropped_threads":{"queue worker 0x0":{"events_full_after_s":4.517,"events_lost":882067,"totals_full":false},"draw committer":{"events_full_after_s":17.442,"events_lost":38424,"totals_full":false}},"trace":"aps5-trace-676d423968a1-2264195.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 192.5, Driver.Packet.memory_wait 165.2, batch 89.4, Graphics.Draw 46.4, Graphics.Draw.draw_and_resource_release 35.3, Driver.Packet.draw 19.5, Driver.Draw 19.3, Driver.Draw.shader_compile_and_link 10.3, Resources.Complete 6.5, Shader.DrawStage 6.0
Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
this change at 38a43ec3d (run of2o)
seconds 185:20 from present 3253: 122 presents, frame p50 166.6 / p90 195.5 / p99 214.9 / max 232.8 ms, GPU busy 72.9 ms per present
NVIDIA GeForce RTX 3090, NVIDIA 615.78.08, Linux 7.2.10-1-cachyos, 3840x2160, commit 38a43ec3d31e, dropped: yes
{"commit":"38a43ec3d31e","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"185:20"},"gpu":"NVIDIA GeForce RTX 3090","driver":"NVIDIA 615.78.08","os":"Linux 7.2.10-1-cachyos","resolution":"3840x2160","window":{"spec":"seconds 185:20","first_present":3253,"ms":20107.456},"presents":122,"frame_ms":{"p50":166.601,"p90":195.521,"p99":214.892,"max":232.815},"gpu_busy_ms_per_present":72.907,"worker_busy_pct":{"queue worker 0x0":97.601,"queue worker 0x20":99.117},"top_phases_ms_per_frame":{"Driver.Packet":323.552,"Driver.Packet.memory_wait":162.777,"Driver.Packet.draw":110.209,"Driver.Draw":109.465,"Graphics.Draw":87.073,"Graphics.Draw.draw_and_resource_release":74.785,"Driver.Draw.shader_compile_and_link":70.233,"Shader.DrawStage":61.808},"trace_dropped":true,"trace_dropped_threads":{"queue worker 0x0":{"events_full_after_s":4.336,"events_lost":966919,"totals_full":false},"draw committer":{"events_full_after_s":16.551,"events_lost":59325,"totals_full":false}},"trace":"aps5-trace-38a43ec3d31e-2259816.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 187.4, Driver.Packet.memory_wait 162.8, batch 72.3, Graphics.Draw 48.0, Graphics.Draw.draw_and_resource_release 37.0, Driver.Packet.draw 19.3, Driver.Draw 19.1, Driver.Draw.shader_compile_and_link 9.8, Shader.DrawStage 5.8, Resources.Complete 4.3
Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code