Repository navigation
perf(agc): note an address space's in-place reads by reference - #4978
Conversation
|
Windows test (MinGW GCC 15.2, Release, Windows 10, RTX 4080 SUPER). Built on main
Not tested: no game run. The batch was built once, not per PR; nothing failed, so no bisect was needed. AI-assisted (Claude Code). |
|
Measured on a game: The Pathless (PPSA01825, 02.000.000) at the main menu, Windows 11, RTX 5070 Ti, WinLibs GCC 15.2.0 Release. Base is
About 159 draws per frame on both sides, so -14.8 ms per frame (+17 % FPS), with #4428 already on |
|
Thank you @winstrex, that's a great independent number: −14.8 ms per frame (+17 % FPS) on The Pathless, a different title from the one I measured, with #4428 already on main. A rebase onto current main is on its way. The conflicts are test registration only ( |
000aa39 to
a6970f1
Compare
|
Rebased onto current main. The only conflicts were in test registration ( |
|
Reviewed the diff: the shared The only conflict with |
a6970f1 to
57758d2
Compare
|
|
57758d2 to
ccf399d
Compare
Every address-based build copied the cached address space's imported ranges (about 9000 in Sword of the Sea gameplay) into its batch as pending reads, only for the copy HLE's reader check to scan them. The space now builds that list once, and a build that took the space whole notes it by reference (Recorder::NotePendingReadList); its own ranges follow as before. The space is immutable while its serial lives, the list equals the space's part of InPlaceReads in its order, and the batch scans plain reads and lists in note order, a list by bisection, so every PendingReadOverlaps and DescribePendingRead answer and reader kind stay the same. A capture trace or APS5_FLIP_READ_CHECK expands the list as before. Tests: lists noted by reference answer like the same ranges noted one by one (open and in-flight scans, kinds, a list noted twice, empty and null lists); the space's list is shared while the registry stands and rebuilt when a range is added or removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
ccf399d to
48cdce9
Compare
What
An address-based build now notes the cached address space's in-place reads by reference instead of copying them into its batch.
GuestBufferMemory::AddressSpacebuildsdirectReadsonce when the space is published: the ranges its imports serve in place, sorted and disjoint. It is shared by every build that takes the space and dies with it, so it follows the registry generation, the import epoch and the device exactly as the space does.GuestBufferMemory::SplitInPlaceReads()returns that list plus the build's own in-place ranges. Their concatenation isInPlaceReads(); a build that does not hold the space (or is committed) returns nothing and keeps the old path.Recorder::NotePendingReadList()notes a shared list on the open batch in O(1).readOverlapwalks plain reads and lists in note order (a list by bisection), soPendingReadOverlapsandDescribePendingReadanswer and report the reader kind exactly as the ranges noted one by one. The same list noted again in a batch is dropped, because an earlier note is always found first. A capture trace orAPS5_FLIP_READ_CHECKnotes the ranges one by one as before, so trace lines and the submit-time collect do not change.ShaderResources::MarkGpuWritesnotes the space's list, then the build's own ranges.No environment switch: the path is always on and exact.
Why
Every address-based build copied the space's imported ranges (about 9000 in Sword of the Sea gameplay) into its batch, roughly 44 million range notes per 10 s, only for the copy HLE's reader check to scan them. On a lab line (a fork of this code with the same hooks) the change, together with the BDA table memo that is not part of this PR, measured:
record: marksfell from 15-19 us to 3-6 us per dispatch.InPlaceReads()on sampled notes and compared found 0 mismatches in 517 comparisons.These numbers come from the lab line, not from
main, and I did not capture the Performance report summary lines ofmainagainst this branch, so treat them as the motivation and not as the report the protocol asks for.Tested
tests/Recorder.cppreadListTests, own ctestagc_recorder_read_list: random lists noted by reference answer everyPendingReadOverlapsandDescribePendingReadquery like the same ranges noted one by one, for the open batch and for the batch in flight, with plain reads of other kinds before, between and after the lists, the same list noted twice, and empty and null lists. It also checks that the queries cover several reader kinds, so the comparison is not vacuous, and that the noted-read counter adds the list's size.tests/BdaResources.cppspaceReadListTests(inagc_driver_graphics): the space's list is shared by builds while the registry stands, rebuilt when a range is added or removed, is valid (sorted, disjoint), andspace + own == InPlaceReads(); a committed build and a build without the space offer no split.tools/check_conventions.py --base origin/main: passed.build.yml): Linux and Windows green, 0 failures (https://github.com/AlxcBTW/AnyPS5/actions/runs/38358855402); the newagc_recorder_read_listpassed on Linux (lavapipe) and is skipped on Windows, which has no Vulkan on the runner. Run on the commit before a rebase onto amainthat only addedtests/ShaderMemory.cppChecklist
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