Repository navigation
perf(libSceAgcDriver): keep storage surfaces tracked around unwatching host imports - #4448
Mouad-Scriptz-0 wants to merge 3 commits into
Conversation
|
Windows/007 cross-test planning: the import-window and storage-import changes look relevant to the comparison hot spot. Before carrying the frame-scoped memo, could you add a regression for an unwatched surface changed by the CPU between two synchronized uses in the same frame (no flip)? A completed first draw/dispatch, CPU store, then a second draw is ordered, so it need not race the console; a frame serial alone cannot validate the old snapshot there. The new stamp also retains only ForgetSerial parity, so a completed forget/remap within that frame deserves an invalidation check. I have not built this head or reproduced a failure yet; these are source-review concerns, not measured Windows results. Preparing a focused comparison fixture while my current heap-corruption repro runs. AI-assisted: yes (Codex). |
|
Focused Windows regression now available: Scramblrrrr@c4981fb (fixture only, older integration base with #3991). After a completed write-back, Refresh + a readback submitted and waited populate/observe the untracked snapshot; a CPU memset follows; another Refresh + waited readback must see 0xabababab. No flip and no concurrent GPU use. Existing policy passes (0.36s); replacing only compareUntracked's stamp/cacheable expressions with your new policy, using constant frame serial1 because this fixture never flips, fails: |
|
Reviewed updated headbc616d758e740d0e6b3febee5d0936508a3afff8: the unsafe frame-scoped stamp is removed and the original comparison stamp restored, addressing the isolated policy regression I reported. The idle-unwatching import retirement/capture-on-unwatch approach needs its own lifetime and invalidation cross-test; not claiming the new full head tested or a Windows FPS gain. Currently running the 007 hull-v1 cross-test, so will keep this out until that completes. Thanks for retaining detection of ordered CPU stores. AI-assisted: yes (Codex). |
bc616d7 to
f82f49d
Compare
f82f49d to
1b6c33d
Compare
|
Both points are right, and the fixture shows it well. The frame-scoped memo was a heuristic: for an unwatched range nothing can see a CPU store, so a comparison at every use is the only correct policy, and I had argued a race where an ordered store (completed use, store, second use) is legal. The existing Commit 1b6c33d drops the memo and restores the original stamp, and attacks the cost from the other side instead: an unwatched import that no lookup used for two frames is retired at the flip and its range goes back under the write watch, with its blocks stamped as possibly CPU-written so a surface there compares once and is tracked from then on ( Your fixture passes unchanged under this policy, since the compare path is the original one. One more hole closed on the way: a watched surface created without a guest copy had nothing to compare against once a buffer import of its allocation unwatched it, so the import now reports the range and such surfaces take their copy at once ( I'd welcome the cross-test on the RTX 5070 Ti; the retirement should be inert there (host imports keep their watch on NVIDIA by the probe), so the interesting check is that nothing else moved. |
|
On Windows Three more things:
|
1b6c33d to
9b0e9c5
Compare
|
Status on the requested rebase — I attempted it and got partway, but I'm not posting a handoff branch because the result isn't correct yet. Details so the next attempt (mine or yours) starts from the real map: Commit 1 (storage surfaces around unwatching) merges cleanly in spirit: main's newer guards kept, this PR's Commit 2 (retire idle imports instead of memoizing) is the hard part: it restructures If it's useful I can push my work-in-progress branch for inspection, or take another run at it with the author's input on the hit-path semantics. |
…g host imports On a device whose host imports resolve the guest write watch (Intel's i915 userptr, by the start-up probe), an import spanned the whole run of adjacent allocations inside the 8 MiB window, so one buffer's import unwatched every texture allocated next to it; a storage surface imported its own range for GPU-direct paths, unwatching itself; and a surface in an unwatched range compared its whole guest copy at every draw because its memo was keyed on tracker-wide counters that change at every draw. Such a device now imports one allocation at a time, a storage surface does not import a range the watch still covers, the comparison runs once per presented frame or after a GPU write note, and the import refresh re-unwatches only ranges the watch covers again. Minecraft (PPSA17221) spent its render thread in those comparisons. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…zing the untracked compare The frame-scoped comparison memo missed an ordered CPU store between two uses in one frame and a completed forget inside it; nothing but the comparison can see a store to an unwatched range, so the original stamp is back. The cost goes the other way: on a device whose imports unwatch their range, an import that no lookup used for sixty frames retires at the flip and its range returns to the write watch with its blocks stamped as possibly written, like the import window stamps them, so a surface there compares once and is tracked from then on. When an import takes a range off the watch, the storage surfaces over it without a guest copy take one at once, outside the import lock. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Second rebase attempt — two of the three failures root-caused and fixed, one remains, branch pushed for inspection. Following the hint that the retire-idle commit needs to fit Fixed 1 — Fixed 2 — Remaining — Current state on the branch: builds, conventions pass, 1284/1287 — |
|
The second pass fixes |
…e staged upload The staged upload marked the guest snapshot valid for every surface; the direct path marks it valid only when the surface is not write-watched. With StorageImportFor a watched surface on a device whose imports unwatch takes the staged path, so its pending results kept saved guest bytes while watched, which agc_driver_store_over_untracked rejects. The rebase had also kept the superseded debt entry next to the current one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Taken. The PR head is now @blawesom's
One failure remains in the same test, on this machine too (Fedora 44, Intel Arc Meteor Lake, Mesa 26.2, where the probe reports that imports resolve the write watch). The three single-surface leave-the-watch cases print "not run, the surface is not write-watched", since the write-back's
So the path this PR newly takes on such a device, a watched surface uploaded staged and written back through an import created at the write-back, does not land its bytes before the CPU read. I have not yet read the write-back's segment copy and shadow publish to say where they go. @oneandonlydean, before I do: is the leave-the-watch group meant to run on a device whose imports unwatch, when the surface's own write-back imports it anyway? If the answer is that the write-back should use The branch still sits on blawesom's base ( |
9b0e9c5 to
924aaa4
Compare
|
@Mouad-Scriptz-0 Thanks for the trace, it made this quick to answer. Yes, the leave-the-watch group is meant to run on a device whose imports unwatch, and the write-back should use When you make that change, please cover all the places that can create an import for a storage surface, not only the one in your trace:
With no existing import, a watched surface then takes the readback write-back ( On the remaining failure: please merge current The merge is real work. It conflicts in 7 files (both GuestMemory files, VulkanDevice.hpp, PacketExecution.cpp, both GuestBufferMemory files, and the debt doc). Two points to watch:
After you push the merged head with the write-back change, we'll review it and run full CI. |
What
On Intel's i915 a
VK_EXT_external_memory_hostimport resolves the guest write watch of its pages (the start-up probe reports "host imports resolve write protection: yes"), so the driver stops trusting the watch for every imported range and a storage surface in such a range compares its whole guest copy with its snapshot at every use. Minecraft (PPSA17221) keeps about 250 such surfaces, atlases of 4 MiB among them, and its render thread ran at 89 % CPU with every stack sample inStorageTexture::Refresh→compareUntracked→memcmp, with the GPU idle. Three causes stacked up:shrinkImportWindow, 64 KiB): a buffer's import leaves its neighbours watched. The existing window test keeps the 8 MiB behaviour for other devices;agc_driver_bda_resourcesgainsunwatchedImportWindowTests: afterSetImportWatch(Unwatch)an import covers the allocation it serves, a view across two allocations is refused, and the import is reused.StorageImportForuses an existing import but does not make one for a range the watch still covers on such a device (ExistingHostImport,HostImportsUnwatch); the staged paths serve the upload and clear sites. A refresh with a pending alias, a copy source and a write-back still import: the device path needs the import, and the staged upload's CPU read would flush the alias's results instead of borrowing them.RetireIdleImports,GuestMemory::Rewatch); a surface without a guest copy under a range an import unwatches takes one at once (StorageTexture::NoteRangeUnwatched). Minecraft imports a texture's allocation only while its compute uploader writes it through a buffer binding; two frames later the range is tracked again and the comparisons end. A range the GPU writes every frame stays imported and compared. The retirement runs only on devices whose imports unwatch their range.agc_driver_graphicsgainsidleImportRetireTests.refreshImportsre-unwatched every unwatched import at every registry generation change (200,000Unwatchcalls in about a minute of Minecraft); it now checksGuestMemory::Watchedfirst.Tested
Fedora 44 (kernel 7.2.8, GCC 16.2.1, Ninja, Release,
BUILD_TESTING=ON, Intel Arc Meteor Lake, Mesa 26.2.3), worktree onmain33ae282:agc_driver_bda_resourcespasses with the new case;tools/check_conventions.py --base origin/mainandgit diff --checkpass. Minecraft (PPSA17221): the render thread no longer spends its time in the untracked comparisons (the 250 surfaces were in the neighbours of imported buffers); the home screen runs at the same frame rate as before the PR once an unrelated in-place vertex input sync is out of the way (separate PR), 60 fps on this device. Not tested on Windows, where imports are compared by design and the window change does not apply unless the probe says so.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)🤖 Generated with Claude Code