Repository navigation
perf(agc): dispatch-cache recipe hits as ordered commit items - #1747
Conversation
|
@MichonGoddijn231849 here are the Demon's Souls numbers for Setup: Nobara 44 x86-64, RTX 5070 Ti (driver 595.91.07), Ryzen 5 7600X, Demon's Souls PPSA01341 v1.07, tutorial level (Outpost Passage) through the debug start menu. Base is main Method: one build, the switch unset vs
* Run 345 lost three windows to unrelated CPU load on the box (16, 8 and 14 presents). Run 350's first window was the tail of the level load (12). No new errors: 0/6 fatal, no GPU hangs or timeouts, and both sides show the same boot-time notes (missing debug-menu concommands, one ALSA underrun). Why it doesn't help here: only about 2.5k of the ~85k queue-0 direct dispatches per 10 s are dispatch-cache hits. The rest miss by-value validation because the captured data differs every frame, so they never get a recipe and drain as before (~2k items per 10 s against ~82k "no recipe"). The pre-lookup scan of the cache entry runs for every candidate, which probably accounts for most of the +2 us per dispatch. The drain wait isn't where the time goes either. Dispatches here mostly come back to back, so the pipeline is already empty for all but ~1.7k of them per 10 s, and the cost is capture plus the device call on the worker. One suggestion: split "no recipe" into "validation miss" and "hit without a recipe". On this title those are very different numbers. AI-assisted: yes. |
|
Parked as a draft with the rest of the pipelined stack while it is ported onto #639. @fisherjoey thanks for the Demon's Souls numbers: if the dispatch cache rather than the pipelining is what limits that title, that is where I'll look after the port. |
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
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.
|
c7cc7b7 to
da1833f
Compare
|
Rebased onto current
@fisherjoey, your Demon's Souls numbers pointed at the dispatch cache rather than the pipelining. On this base the queue-0 resolve-ahead skip is a new trade, so a before/after on that title would show whether the items or |
…IPELINE_DISPATCH) With pipelined draws, a DISPATCH_DIRECT on queue 0 whose dispatch-cache entry hits with a recipe runs as an ordered commit item instead of draining the pipeline first. Misses, reads that overlap writes still pending in the pipeline, verified data hits and writes that cannot be ranged still drain. A dispatch that is resolved ahead (or adopted from a group resolved ahead) and copy kernels keep the drained path; with the switch on, queue 0 does not resolve dispatch groups ahead, since that drains the pipeline at every group. Off by default. agc_driver_pipelined_dispatch counts drains per opcode (each dispatch drains with the switch off); agc_driver_pipelined_dispatch_item checks that repeated dispatches do not drain, and that a dispatch whose descriptor table a pending fill retargets drains and reads the new buffer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
da1833f to
89333e0
Compare
|
Checked on this branch merged onto current Added on your branch as our own commits:
Merging once CI is green. |
What
With pipelined draws (#1201, on by default since #1202), every compute dispatch on queue 0 still drains the pipeline before it runs, so the committer goes idle and the worker waits. Titles with many dispatches between draws pay that on each one: Demon's Souls issues about 3,800 queue-0 dispatches per frame in its tutorial level, most of them one chain of small ones (measured by @fisherjoey on #1202).
APS5_PIPELINE_DISPATCH=1(off by default; needs pipelined draws) makes aDISPATCH_DIRECTwhose dispatch-cache entry hits with a recipe an ordered commit item, like the draws around it. The capture and the cache lookup run on the worker; the recording runs on the committer in order. A dispatch still drains, as today, when:DrawPipeline::DrainRequestsByOpcodecounts drains per opcode andDrawPipeline::QueuedItemsreports the queue size, both for the tests.DispatchWriteRangesgives the commit item the dispatch's write ranges, so later draws that read them wait for it.Tests (
tests/execution/PipelinedDispatch.cpp):agc_driver_pipelined_dispatch(switch off): a dispatch after an immediate fill of its input, in one DCB, over several rounds; each dispatch drains once and reads the fill.agc_driver_pipelined_dispatch_item(switch on): repeated dispatches that read nothing pending do not drain; a round whose descriptor table a pending fill retargets drains and reads the new buffer. That round holds the committer behind a gate item, waits until the fills are queued, and only then submits the dispatch, so the order is exact rather than timed. With the read-side check removed it reads the buffer the table named before the fill (0x6a6a0002 for 0x6b6b0003), every run; with the commit-item path removed, the first round fails ("a dispatch that reads nothing pending drained the pipeline").Tested
Windows 11 Pro, AMD Ryzen 5 7600, NVIDIA GeForce RTX 5080 (driver 32.0.16.1074), 32 GB, MinGW-w64 GCC 15.2.0.
agc_tests pass with the switch off and on.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)main)🤖 Generated with Claude Code