Skip to content

perf(agc): reuse heap mirror reference buffers between builds - #8874

Draft
JJenkx wants to merge 2 commits into
boykopovar:mainfrom
JJenkx:perf/agc-heap-reference-reuse
Draft

JJenkx wants to merge 2 commits into
boykopovar:mainfrom
JJenkx:perf/agc-heap-reference-reuse

Conversation

@JJenkx

@JJenkx JJenkx commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

GuestBufferMemory::takeHeapReferences copies the served bytes of every written heap-mirror range into a new std::vector on each build, and WriteBack drops it. References are as large as the written heap range (hundreds of MiB in the scene below), so each build faulted in and zeroed fresh anonymous pages and unmapped them again: in a DWARF profile of the scene below (integration base 8a251ef745), takeHeapReferences held 16.6 % of the process samples, 7.9 % of them in anonymous page faults. A profile of an earlier candidate of this change (4165273dc7, same reuse with an allocating store) put it at 5.5 % with no page faults; that profile is of the earlier candidate, not of this commit.

Released reference buffers now go to ReferenceStorage, a store of at most eight idle buffers and 2 GiB, and the next reference takes the smallest one that fits. The bytes copied and compared are unchanged. Take and Return are noexcept and allocate nothing (vector moves only; the byte count changes after the move; evicted storage is destroyed after the lock is released), so the release in ~GuestBufferMemory and WriteBack cannot throw. Storage above the limit, or without capacity, is destroyed as before.

Tested

  • Base main 9f4ddf7; this branch has the change cc53b45601 and a test commit 317d528af7.
  • New agc_reference_storage (CPU): empty store, reuse of the same allocation, smallest fit, eviction of the oldest by byte limit and by slot count (checked against the identities of the retained buffers), oversize storage, and Return/eviction/Take with the allocation-failure countdown armed (still armed afterwards, byte count consistent). A store whose eviction allocates terminates the test with std::bad_alloc.
  • ctest -R 'heap_mirror|sparse_heap|reference_storage|bda|guest_memory_lifetime|sparse' -V on main and on this PR, same machine and GPU, ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation (layer 1.4.363 loaded; neither log reports was not found but was requested): main (9f4ddf7) 28/29, PR (cc53b45601) 29/30 (the extra test is the new one). Both fail agc_driver_guest_memory_lifetime the same way (radv/amdgpu: The CS has been rejected (-14), guest prefix unmap failed), and both logs hold the same validation errors: 2 × VUID-vkCmdCopyBuffer-srcBuffer-00118, 2 × VUID-vkResetFences-pFences-01123. No new VUID-.
  • Diagnostic observations, not controlled performance evidence. Integration build, not unmodified main: Echoes of the End PPSA25636 01.012.000 stops after about 30 s on main, so both sides are main 33a6d6b + fix(shader): preserve read lane dominance across branches #8089 + fix(agc): prefer imported prefixes before sparse heap mirrors #8762 + fix(agc): lower import budgets only on memory exhaustion #8091 + feat(libSceAgcDriver): import scattered direct memory as a dma-buf run list and probe its coherence #4449, without and with this commit. Unattended start to the loading screen, no input, one runtime directory for every run: the shader and pipeline cache directory is shared, so initial cache contents are not matched between runs, and no speedup is claimed from these lines. Ryzen 9 7950X, RX 6650 XT, RADV Mesa 26.2.4, Linux 7.2.9. Order base, PR, PR, base:

Before (integration 8a251ef745):
seconds 40:60 from present 340: 11 presents, frame p50 5867.4 / p90 7221.6 / p99 7377.7 / max 7377.7 ms, GPU busy 543.2 ms per present
seconds 40:60 from present 351: 11 presents, frame p50 5427.9 / p90 6189.5 / p99 7141.4 / max 7141.4 ms, GPU busy 497.8 ms per present

After (integration + this PR, 6e0a219cbe):
seconds 40:60 from present 343: 15 presents, frame p50 4069.4 / p90 5171.4 / p99 5460.5 / max 5460.5 ms, GPU busy 497.8 ms per present
seconds 40:60 from present 348: 16 presents, frame p50 4004.1 / p90 4933.0 / p99 5394.2 / max 5394.2 ms, GPU busy 479.7 ms per present

The title still loads at well under 1 FPS on both sides. The captures ran on an integration with the earlier base 33a6d6bbfb; the PR commit was cherry-picked onto it (6e0a219cbe). Traces, logs, screenshots, profiles and validation logs: evidence archive (SHA-256 00bbfd328cc0ecbed29aedd3925217dc6e39a9a018170bd941549b5146af27be).

  • Second title, neutral observation, no improvement claimed: Mortal Shell II PPSA34008, measured by another worker on the same machine and scene, APS5_TRACE_SECONDS=150:30, one run each, separate relinked runtimes, initial shader/pipeline cache state not reported as matched. Base main e0e57a3270 + fix(libSceVideodec2): answer the generic picture query for VP9 pictures #8839 (641fce5c84), change = base + this PR (91d0f400ba):

Before: seconds 150:30 from present 26: 6 presents, frame p50 4885.1 / p90 7341.3 / p99 7341.3 / max 7341.3 ms, GPU busy 186.3 ms per present
After: seconds 150:30 from present 40: 6 presents, frame p50 5074.1 / p90 5685.3 / p99 5685.3 / max 5685.3 ms, GPU busy 178.7 ms per present

Resources.Complete 5.29 vs 5.14 ms per dispatch: no measurable change in that title, where the per-dispatch cost is the copy and the WriteChanged compare that this PR keeps. Traces (SHA-256 4412bd6c74fc8493e765d3d33b970a6b947ef900e09e6a38384d0ebc4f659c25).

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
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: AMD Radeon RX 6650 XT, RADV Mesa 26.2.4, Arch Linux 7.2.9-arch1-1
  • AI-assisted: yes

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added perf Performance change perf numbers missing perf pull request without a before and after summary line labels Oct 21, 2026
@github-actions

Copy link
Copy Markdown

This pull request is labeled perf, so it needs the summary line of a capture on main and one with the change, from the same title, scene and machine, as the Performance report form asks. Please paste both aps5-summary.jsonl lines, attach the two traces and add the output of tools/trace_digest.py.

if (begin >= served) continue;
const auto bytes = mirror.buffer->Bytes().subspan(static_cast<std::size_t>(begin - mirror.base), static_cast<std::size_t>(served - begin));
heapReferences.emplace_back(begin, std::vector<std::byte>(bytes.begin(), bytes.end()));
auto storage = ReferenceStorage::Shared().Take(bytes.size());

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.

When Take() reuses a previously larger vector, assign() updates its contents but does not reduce its size. WriteBack() later requires reference->second.size() == length for each merged heap range, so a smaller subsequent range can hit heap mirror write-back has no reference even though the begin address matches. Could this resize the vector to bytes.size() after ensuring capacity (or resize before copying), and add a regression that returns a larger buffer then takes it for a smaller reference and exercises the size invariant?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for checking this. The size does follow the new reference: std::vector::assign(first, last) replaces the whole contents, so size() becomes last - first while the larger capacity is kept ([sequence.reqmts]). The vector is not resized to its capacity anywhere on this path, so WriteBack's size() == length check holds.

317d528 adds checks for it on the production path:

  • agc_heap_mirror_reference_size (--heap-mirror-reference-size, Linux and Windows) makes writable heap-mirror builds of 8 KiB, then 2 KiB, then 8 KiB through AddWritable / Upload / WriteBack, with a GPU store in each, and checks that every store reaches guest memory. The 2 KiB reference takes the 8 KiB storage the first write-back returned.
  • agc_reference_storage gains LargerStorageTakesTheReferenceSize: a smaller assign into larger reused storage keeps the same allocation, has the smaller size and holds the reference's bytes.

Negative control: with takeHeapReferences changed to keep the storage at its capacity (resize(capacity()) plus a copy instead of assign), agc_heap_mirror_reference_size fails with AGC graphics: heap mirror write-back has no reference, which is the failure you describe. With the PR's assign it passes, as do agc_driver_graphics and agc_reference_storage (Linux 7.2.9, GCC, Release).

@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 1191 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 1368 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 1896 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 4040 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 4448 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 4449 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5372 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 5426 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5431 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5441 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6044 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6146 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6169 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6182 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6185 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6186 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6187 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6188 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6192 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6194 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6235 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6249 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6280 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6412 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 6481 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6501 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6548 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6565 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6612 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6628 core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 6642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6741 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6747 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6788 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6804 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6820 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6868 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6905 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6918 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 6921 core/libs/prx/libSceAgcDriver/tests/BdaTests.hpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6970 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6973 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6987 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6989 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6995 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7002 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7085 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7201 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 7223 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7243 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7256 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7261 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7275 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7292 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 7307 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7310 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7410 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7446 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7457 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7464 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 7465 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 7508 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7535 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7618 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7622 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 7644 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7668 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7677 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7705 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7717 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7800 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7803 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7833 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7844 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7893 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8014 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8016 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8089 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8105 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8121 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8126 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8139 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8160 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8161 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8180 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8212 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8246 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8279 core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 8283 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8365 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8380 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 8395 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8484 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8527 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8542 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8552 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8563 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8564 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8592 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8608 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8622 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 8658 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8672 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8707 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8740 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8887 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8895 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8896 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8926 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 8939 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8963 core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 8999 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9007 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9012 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9013 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9020 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9050 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9098 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9159 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9176 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9188 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9193 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9243 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9248 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9287 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9289 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9305 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9335 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9348 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9356 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9387 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9396 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9401 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9402 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9412 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9424 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9436 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9443 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9445 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9450 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9457 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9489 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9495 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9508 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 9514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
core/libs/prx/libSceAgcDriver/tests/BdaTests.hpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9521 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9533 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9564 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9565 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9597 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9604 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9626 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9633 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9671 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9675 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9685 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9694 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9696 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9700 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9702 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9703 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9712 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9717 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9721 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9723 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9737 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9742 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9748 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9749 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9779 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9789 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9790 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9852 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9875 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9879 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 9884 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9890 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9892 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9897 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9898 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9899 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9907 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9913 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9915 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9940 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9941 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 9969 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9988 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 9989 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10000 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10025 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 10026 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10043 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10046 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 10049 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 10062 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10064 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10141 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 10159 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10164 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10193 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
PR 10194 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JJenkx

JJenkx commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

A matched-seed capture pair on a real title. It does not show a measurable gain from this change, so the PR stays in draft.

Setup

Summary lines

  • without: seconds 290:120 from present 461: 88 presents, frame p50 1112.6 / p90 2018.2 / p99 4388.6 / max 4388.6 ms, GPU busy 635.5 ms per present
  • with: seconds 290:120 from present 442: 90 presents, frame p50 1042.2 / p90 2157.3 / p99 5609.5 / max 5609.5 ms, GPU busy 453.3 ms per present

tools/performance_compare.py, candidate minus baseline:

  • mean frame -3.1 %, p50 -6.3 %, p90 +6.9 %, p99 +27.8 %;
  • Driver.Dispatch +0.1 %, Driver.Packet -3.6 %.

Reading

  • The windows start at different presents (461 and 442), and one pair has no repeat, so these differences are within run-to-run variance.
  • The GPU busy drop is not attributable to a change in CPU-side reference buffers.
  • This title's frame time is dominated by GPU-side storage image churn and by CPU copies of a large sparse buffer, not by the allocations this PR removes.
  • Both captures report dropped trace events.

So: no regression and no demonstrated improvement on this title. The PR needs a capture from a title where heap-mirror reference allocation shows up in the profile before it can leave draft.

@JJenkx

JJenkx commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Third title, with a matched comparison: Code Violet (PPSA26528) on Linux/RADV. Shader-resource time is about 14% lower with this PR on the menu scene.

Setup

  • Linux 7.2.9, Ryzen 9 7950X, RX 6650 XT, RADV (Mesa 26.2.4); PPSA26528 01.000.028.
  • This is an integration-relative comparison, not plain main. Plain main cannot render this title on RADV (Code Violet (PPSA26528) #6256). Both sides are main a6dcea9 + feat(libSceAgcDriver): import scattered direct memory as a dma-buf run list and probe its coherence #4449 (with a local descriptor guard) + fix(agc): keep the write-back ready barrier while hole copies are pending #8908: control 4e68e5f738, and control + this PR (head 317d528, clean merge) 4b55032e92.
  • One persistent runtime for every run, with no per-run restore of shader-cache or save seeds (corrected; see my follow-up below). The AnyPS5 shader cache (12,796 files, ~5.0 GB, warm from earlier runs) had no file written during this batch. The Mesa cache and the title's save state were not reset or checked. 240 s per run with Cross at 100, 140 and 170 s, and APS5_TRACE_SECONDS=200:30. Every trace reports dirty false and dropped false. Screenshots at 230 s show the same difficulty/start menu in all four runs.
  • Run order: control, PR, PR, control. The first second-control run segfaulted during startup before the trace window (the title's occasional startup crash, seen on both sides before), so I replaced it with one more control run.

Why this title. A DWARF profile of the control at 200–220 s puts ShaderResources::Complete at 52% of process samples (inclusive). GuestBufferMemory::takeHeapReferences accounts for 25%, mostly memcpy, plus do_anonymous_page at 12% and page zeroing at 5%. That matches the per-build allocation this PR removes.

Run presents frame p50 / p90 / p99 ms GPU busy ms/present Resources.Complete ms per frame (digest's largest-slices line)
control 12 2836.5 / 4137.9 / 4503.1 754.6 1944.5
PR 14 2304.5 / 2712.7 / 2840.4 765.9 1655.8
PR 14 2457.4 / 2631.1 / 2769.9 826.4 1682.2
control 12 2885.0 / 4282.5 / 4293.5 746.5 1950.0
  • Resources.Complete drops from about 1945–1950 to about 1656–1682 ms per frame, and frame p90 from about 4.1–4.3 s to 2.6–2.7 s. The control pair and the PR pair are each tight.
  • This menu is still well under 1 FPS, held up by the rest of ShaderResources::Complete. So this is a smaller per-frame CPU cost on one scene, not a playable-rate claim.

AI-assisted: yes (Claude Code); results above were run on this machine.

@JJenkx

JJenkx commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Draft status, per the current readiness rule: this stays a draft for one specific evidence blocker, not for queue reasons.

It is a perf change, and no capture so far supports a speed claim:

  • Echoes of the End (PPSA25636): one matched-seed pair, posted above. It shows no measurable difference.
  • Code Violet (PPSA26528): four runs in the batch posted above, with the setup corrected in this comment. Every arm ran in one persistent runtime. The shader-cache and save seeds were not restored before each run, and the Mesa shader cache and the title's save state were neither reset nor checked. These four runs are observations only; they do not meet the matched-seed performance gate, so this PR makes no claim from them.

It becomes ready once a present-matched pair, from a title whose profile shows heap mirror reference allocation (takeHeapReferences), shows a measurable gain. Each arm of that pair needs the shader-cache, Mesa-cache and save seeds restored before it runs. If none turns up, I'll close the PR rather than keep it parked.

@JJenkx

JJenkx commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Correction to my Code Violet comment above: its setup said the runs used "identical shader-cache and save seeds". That was wrong. I have edited the comment.

  • The Code Violet batch ran every arm in one persistent runtime and did not restore shader-cache or save seeds before each run. (My Lodoss harness does restore them; I carried that wording over.)
  • What I can show: the AnyPS5 shader cache, warm from earlier runs, had no file written during this batch (12,796 files, ~5.0 GB).
  • Not reset or checked: the Mesa shader cache and the title's save state.

The measured numbers are unchanged. The Resources.Complete figures are from tools/trace_digest.py's largest-slices line, which differs by a few ms per frame from a per-frame reduction of the same traces.

AI-assisted: yes (Claude Code); results above were run on this machine.

@JJenkx

JJenkx commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Protocol note on my measurement above (comment 6332826974): it does not meet the performance-report protocol's "do not redirect the log" rule. The game's stdout and stderr were redirected to game.log by the run wrapper. The results stay as diagnostic observations, but I am withdrawing any claim of measured speed impact or direction from them until a terminal-attached rerun. The counts, logs and traces themselves are unaffected.

AI-assisted: yes (Claude Code)

@JJenkx

JJenkx commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Controlled AMD/Linux run on Code Violet (PPSA26528). It replaces my earlier, unconstrained Code Violet numbers above, which remain observations only.

Scope: integration-relative, not main. On RADV, plain main does not render this title (#6256), so both sides carry the PRs it needs:

Protocol

  • Machine: Ryzen 9 7950X, RX 6650 XT 8 GiB, Linux 7.2.9, mesa/vulkan-radeon 26.2.4-1, no VK_* layer variables, on-disk shader cache enabled.
  • Seeds restored before every arm and hash-checked: the AnyPS5 shader cache (17,054 files, 6.32 GB), the Mesa cache (1,891 files) and the title's writable download0; no _sd. The seeds came from one warm-up run of the control. Both caches were pointed at per-arm copies through ANYPS5_SHADER_CACHE_DIR and MESA_SHADER_CACHE_DIR.
  • Each arm ran in a terminal; the game's stdout/stderr were that terminal (asserted isatty), not redirected to a file.
  • 300 s per arm, no input; scene = title screen. APS5_TRACE_SECONDS=240:30, APS5_TRACE_EVENTS=4194304. The game window was set once to 1024x576 and checked for later size changes; there were none.
  • Order: control, PR, PR, control, PR, control, control, PR. Every arm's screenshots at 235 s and 270 s show the title with START. All 8 traces report dirty false, dropped false and 3840x2160.
arm build presents frame p50 / p90 ms GPU busy ms/present Resources.Complete ms/frame Driver.Packet.memory_wait ms/frame
0 control 10 3992 / 5427 745 2417 1878
1 PR 15 1757 / 2985 683 1526 1302
2 PR 17 1900 / 2236 675 1283 1254
3 control 11 2962 / 4728 656 2506 1552
4 PR 12 2408 / 3490 684 1985 1505
5 control 12 3310 / 4205 632 2038 1379
6 control 11 2036 / 4246 811 2214 1452
7 PR 15 2022 / 2605 718 1579 1308
  • Resources.Complete: control 2038–2506 vs PR 1283–1985 ms per frame, no overlap; medians 2316 vs 1552.
  • Frame p90: control 4205–5427 vs PR 2236–3490 ms, no overlap.
  • Presents in the 30 s window: control 10–12 vs PR 12–17.
  • Frame p50 overlaps (control 2036–3992, PR 1757–2408), so I don't claim a median frame-time change.
  • The title is still well under 1 FPS on both sides.

Resources.Complete is read from tools/trace_digest.py's largest-slices line.

AI-assisted: yes (Claude Code); results above were run on this machine.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 23, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* build needs rebase Conflicts with main, rebase needed perf numbers missing perf pull request without a before and after summary line perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants