Repository navigation
Conversation
…k buffer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This pull request is labeled |
XairRrR
left a comment
There was a problem hiding this comment.
Reviewed — changes requested
The code change is correct, merges cleanly, builds, and the focused resident heap mirror tests pass with validation on. The block is on evidence only: this is a perf PR, and its description does not yet carry the same-scene main/change summary lines that CONTRIBUTING.md requires.
What I ran
- Head:
c12a20f45da55cd45da092e937ee196416cc2f72 main:ba5b5330b37724bca4b99f30faab504653635a04(the head's parent, so the PR is on currentmain)- Machine: Arch Linux 7.2.11-zen, GCC 16.2.1, Intel Core i9-14900KF, NVIDIA GeForce RTX 4070 Ti SUPER (driver 615.78.08). Release build, Ninja,
BUILD_TESTING=ON, in a clean worktree withmainmerged with the PR head (--no-ff).
git diff --check origin/main...refs/review/12827
python3 tools/check_conventions.py --base origin/main
cmake --build build -j10
VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ANYPS5_NO_SHADER_CACHE=1 ANYPS5_REQUIRE_VULKAN=1 VK_LOADER_DEBUG=error,warn,layer \
ctest --test-dir build -R 'agc_driver_resident_heap_mirror|heap_mirror|resident' -V -j4 --output-on-failure
# the same build and ctest command on origin/main
# coverage check: gdb breakpoints with backtraces on ResidentBuffer::RecordReadback, ::ReadDevice and ::Store
gdb -batch -x count.gdb build/tests/agc_driver_resident_heap_mirror_tests
# perf label gate on the PR description
python3 -c "import pr_labels; print(pr_labels.has_numbers(body))"Results
| Check | Result |
|---|---|
Merge into main |
Clean |
git diff --check |
Clean |
check_conventions.py |
All conventions checks passed. |
Build (merged tree and main) |
OK |
| Focused tests, merged tree | 14/14 passed, 0 VUID- lines |
Focused tests, main |
14/14 passed, 0 VUID- lines |
| Validation layer loaded | Yes: Inserted device layer "VK_LAYER_KHRONOS_validation" in 6 Vulkan tests in each log; no was not found but was requested by env var VK_INSTANCE_LAYERS |
| Changed branch exercised | Yes: agc_driver_resident_heap_mirror_tests records 16 readbacks (RecordCopyBacks) and calls ResidentBuffer::Store 8 times from GuestBufferMemory::WriteBack; ReadDevice is never called |
| Test durations | All under 1 s |
tools/pr_labels.py has_numbers on the description |
False |
ctest, merged tree
1/14 Test #1304: agc_driver_partially_resident_snapshot .......... Passed 0.40 sec
2/14 Test #1548: agc_driver_partially_resident_pending_stores .... Passed 0.14 sec
3/14 Test #1583: agc_heap_mirror_unwatch ......................... Passed 0.01 sec
4/14 Test #1584: agc_heap_mirror_unwatch_no_space_cache .......... Passed 0.01 sec
5/14 Test #1585: agc_sparse_heap_mirror_unwatch .................. Passed 0.00 sec
6/14 Test #1586: agc_sparse_heap_mirror_unwatch_no_space_cache ... Passed 0.00 sec
7/14 Test #1587: agc_sparse_heap_mirror_budget ................... Passed 0.01 sec
8/14 Test #1588: agc_heap_mirror_run_unwatch ..................... Passed 0.01 sec
9/14 Test #1589: agc_heap_mirror_run_unwatch_no_space_cache ...... Passed 0.00 sec
10/14 Test #1590: agc_heap_mirror_unwatched_import ................ Passed 0.00 sec
11/14 Test #829: agc_resident_present ............................ Passed 0.61 sec
12/14 Test #1257: agc_driver_linear_target_resident ............... Passed 0.63 sec
13/14 Test #1368: agc_driver_resident_heap_mirror ................. Passed 0.74 sec
14/14 Test #1626: agc_driver_uint8x4_color_target_no_resident ..... Passed 0.37 sec
100% tests passed out of 14
1368: resident heap mirror tests passed
gdb call counts, agc_driver_resident_heap_mirror_tests (merged tree)
16 HIT RecordReadback (callers: ShaderResources::MarkGpuWrites -> GuestBufferMemory::RecordCopyBacks)
8 HIT Store (caller: GuestBufferMemory::WriteBack)
0 HIT ReadDevice
resident heap mirror tests passed
Negative control
None. The PR adds or changes no tests, and the change is meant to store the same bytes as before, so no existing test should fail when it is reverted. The gdb run above shows that the existing agc_driver_resident_heap_mirror test does reach the changed recorded-readback branch and checks guest memory after it.
Findings
Blocking
-
The
perfevidence required by CONTRIBUTING.md is not in the description. CONTRIBUTING.md:71 requires aperf(...)PR to show the summary lines ofmainand of the change, from the same machine and scene. It keepsperf numbers missingon the PR until the description holds two valid summary lines with different commits. Two things are missing:- The four lines in the description are shortened with
..., so they are not JSON.tools/pr_labels.pyhas_numbersreturnsFalseon the current description, which is why the label is still set. The full lines are only in the external release. - By the description's own account, the base and change windows cover different scenes: logo and fade frames on the base side, the loading screen on the change side. So the lines cannot support or refute a speed change. "Reached the loading scene earlier in 2 of 2 runs" is suggestive, but it is not the same-scene comparison the rule asks for.
Using
main+ #4449/#8089/#11873/#6867 as the base, because the title does not boot onmainalone, is well explained. Whether that is an acceptable stand-in formainis for the maintainers to decide. - The four lines in the description are shortened with
Non-blocking
None about the code. What I checked:
- Lifetime.
currentnow points into the readbackBuffermapping. That buffer is owned byheapReadbacks(and byrecorder.Keep) from GuestBufferMemory.cpp:5876-5877 untilheapReadbacks.clear()after the loop. Nothing inResidentBuffer::Store,storeSparseorstoreChangedmodifiesheapReadbacks, so the span stays valid across GuestBufferMemory.cpp:6291-6303. - Same bytes, same visibility. The old
memcpyread the same mapping at the same point.ResidentBuffer::Store'sGuestBytesZerocheck scans host pointers, so passing the mapping instead of a vector does not change its meaning. - Memory type. The readback
Bufferuses the defaultHOST_VISIBLE | HOST_COHERENTflags, andContext::BufferMemoryTypeprefers aHOST_CACHEDtype for those flags. So the extra reads of the mapping (byStore, then bystoreChanged/storeSparse) are cached reads wherever the driver exposes such a type. The description'sResidentBuffer::Store42 → 78 ms is consistent with that.
Not verified
- Any frame-time or per-write-back timing. I did not launch a title, and I did not measure the copy removal on this NVIDIA machine.
- The
ReadDevicefallback branch (no recorded readback). No focused test reaches it. Its behaviour is unchanged apart from moving the vector intoread. - The private attribution counters in the description's table.
To get this to a good state
- Paste the full, unshortened
aps5-summary.jsonllines (one base, one change) into the description, so that theperf numbers missinggate can parse them. - Provide a pair whose trace windows cover the same scene on both sides. For example, use a window that starts after both builds have reached the in-world loading screen, with runs long enough for the base to get there too. Attach the
tools/trace_digest.pyoutput for that pair as before.
|
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.
|
✅ NVIDIA GPU test: passedPR head
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (3, not counted against this PR)Validation IDs already present on main (13 IDs in 549 tests)Skipped (49)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
|
@XairRrR thanks for the check and the NVIDIA run. Agreed: the pair in the description lands on different scenes, so it is not a qualifying same-scene I'm rerunning it now. Echoes needs four open PRs to boot on
I'll post the summary lines, traces and digests here. If the scenes still differ, I'll say so rather than claim a speed change. AI-assisted: yes (Claude Code). |
adriadam10
left a comment
There was a problem hiding this comment.
The code change itself checks out: the readback span in GuestBufferMemory.cpp:6295 stays alive in heapReadbacks until it is cleared after the write-back loop, Store/storeSparse/storeChanged only read it, and the size is checked against the write-back length. The NVIDIA CI run is clean (0 new failures, 0 new validation IDs).
What blocks it is evidence, as the perf label bot and @XairRrR's review say:
- Paste the
aps5-summary.jsonlline ofmainand of the change from the same title, scene and machine, plus thetools/trace_digest.pyoutput. The pair in the description lands on different scenes (the description says so itself), so it does not qualify. - If the same-scene rerun you announced still can't be matched, drop the speed framing and state only the per-write-back attribution, which is already clearly labelled as such.
Happy to merge once the report is in and the review request is cleared.
|
@XairRrR @adriadam10 the same-scene rerun is done. One of its two pairs is on the same scene in both windows and shows a frame-time drop. The other pair is also on matching scenes but shows no clear difference. Both are below. Setup
Pair 1: in-game loading screen in both windows. Screenshots at 1440 s and 1795 s show the same "Loading..." screen (cathedral with the blue crystal) in both runs.
Pair 2: in-world scene in both windows. At 1440 s and 1795 s both runs show the same in-world scene: two characters at a ruined archway.
Caveats
Release https://github.com/JJenkx/AnyPS5/releases/tag/heap-writeback-readback-samescene-20261029 has the four 🤖 Generated with Claude Code |
|
@XairRrR @adriadam10 please re-check the evidence follow-up at #12827 (comment) and the current description against the two remaining evidence requests. The description now contains the full valid summary JSON lines and the matching-scene trace/digest pairs; the earlier different-scene pair is not presented as qualifying evidence. The limitations remain explicit: the base contains the same four open prerequisites on both sides; one matched pair improves frame time and the second is inconclusive. This is not a claim of a repeatable plain-main or general FPS gain. Please assess whether that scoped report satisfies the request, or whether to retain only the per-write-back attribution framing you suggested. The code is unchanged; this follow-up requests re-review of the completed report rather than claiming new measurements. AI-assisted: yes. |
XairRrR
left a comment
There was a problem hiding this comment.
Re-checked — approved
The code is the same commit (c12a20f). The description now holds the full aps5-summary.jsonl lines of two same-scene base/change pairs, with trace digests, so the one blocking finding of my last review is resolved.
What changed since my last review
- No new commits. delta.patch shows
c12a20f45d = c12a20f45d. - The description was rewritten:
- the earlier different-scene pair is gone and is marked as not evidence;
- two pairs of full, unshortened summary lines from 1800 s runs (window
1500:240) were added, with scene screenshots at 1440 s and 1795 s; - the
tools/trace_digest.pyoutput for all four traces is now in the description.
- Comments from the author on 2026-10-29 and 2026-11-02 ask for a re-check of that report.
What I ran
Head c12a20f45da55cd45da092e937ee196416cc2f72, main 096c45570f516de76a43bbe1b97781381c84f55f, merged tree deea710d7d1c33842a4cb6ce865061c3f49a9daa. Debian 13 VM (Xeon Gold 6136), GCC 14.2.0, lavapipe (Mesa 26.1.6). Release, Ninja, BUILD_TESTING=ON.
git diff --check 096c45570f516de76a43bbe1b97781381c84f55f...c12a20f45da55cd45da092e937ee196416cc2f72
python3 tools/check_conventions.py --base 096c45570f516de76a43bbe1b97781381c84f55f
# perf gate on the pair-1 base and change lines, copied verbatim from the description
python3 -I -c "import sys; sys.path.insert(0,'tools'); import pr_labels; print(pr_labels.has_numbers(sys.argv[1]+chr(10)+sys.argv[2]))" '<base line>' '<change line>'
VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ANYPS5_NO_SHADER_CACHE=1 ANYPS5_REQUIRE_VULKAN=1 VK_LOADER_DEBUG=error,warn,layer \
ctest --test-dir build -j8 --test-load 32 -V -R "heap_mirror|resident"The script also built the merged tree and ran the selected tests and the validation comparison against main.
| Check | Result |
|---|---|
Merge into main |
Clean |
git diff --check |
Clean |
check_conventions.py |
All conventions checks passed. |
Build and libs |
OK |
| Selected tests (2031 run) | 0 new failures, 0 timeouts. 7 known failures also fail on main. |
Validation vs main (757 tests) |
Layer loaded in 756 and missing in none; 0 tests with new VUID- |
Focused heap_mirror|resident tests (16), with validation |
16/16 passed; 0 VUID- lines; no was not found line; the layer was inserted in 6 tests; resident heap mirror tests passed printed, longest test 2.08 s |
pr_labels.has_numbers on the pair-1 lines |
True |
Previous findings
- Blocking: the
perfevidence required by CONTRIBUTING.md:73 was missing. Resolved.- The lines now parse. The four summary lines are full JSON inside fenced blocks. On the pair-1 base (
27db71c581b4) and change (3e83ee94776d) lines,has_numbersreturnsTrue, so theperf numbers missinggate is satisfied. - Same scene on both sides. Pair 1 has the in-game "Loading..." screen in both windows, confirmed by screenshots at 1440 s and 1795 s (author-reported). Same title, machine, resolution, seed cache and window. Frame p50 goes from 1621.1 to 704.9 ms.
- The second pair is reported honestly. Pair 2 (in-world) is called inconclusive, and the caveats state one run per side and that per-phase totals are partial (
trace_dropped). - The screenshots and traces are in the author's release, which I did not open.
- The base is
main+ #4449/#8089/#11873/#6867 on both sides. As I said before, the maintainers decide whether that stands in formain. The description is clear that this is not a bare-mainresult.
- The lines now parse. The four summary lines are full JSON inside fenced blocks. On the pair-1 base (
New findings
Blocking
None.
Non-blocking
None. I re-checked the span lifetime on the merged tree:
heapReadbacksis filled inRecordCopyBacks.- It is cleared only in
releaseHeapReferences(GuestBufferMemory.cpp:6652-6656). That function is called fromtakeHeapReferencesbefore the build and at the end ofWriteBack(GuestBufferMemory.cpp:6781), after the loop. - So the span assigned at
GuestBufferMemory.cpp:6720stays valid throughStore/storeSparse/storeChanged(GuestBufferMemory.cpp:6726-6728).
This agrees with adriadam10's review.
Not verified
- Any frame-time or per-write-back timing. I launched no title and opened neither the external release nor its screenshots and traces. The scene match is author-reported.
- The
ReadDevicefallback branch (no recorded readback). No focused test reaches it; it only moved into thereadvector. - Negative control: none. No tests were added or changed, and the change stores the same bytes.
|
@adriadam10 both conditions from your 10-29 review are now met on the same head |
|
On the order with #12840 (BDA stores into writable heap mirrors), which conflicts with this PR in #12840's checklist will say |
|
Data: plain PPSA22408, first race, Trees:
Run setup:
What happens on
Trace:
trace_digest.py: A (main b11c7bf), during the loadtrace_digest.py: B (this head), during the loadSummary records: the window nearest Select Vehicle +400 s of each run (A1, B1, A2, B2)PPSA28416 (Star Wars Galactic Racer, UE5), first race of the campaign. This is attribution, not a The tree: What happens there: resident heap-mirror write-backs of about 575 MiB each, about 220 GB per run. Runs: two pairs, alternating, holding 180 s in the race. The second pair ran in reversed order.
There were no exceptions. AI-assisted. |
|
Queue maintenance follow-up: the remaining older change request has no formal re-review request. The completed report and XairRrR's re-check/approval are already present, and the description now also links mrfelek's November 4 plain-main title measurements with their source/configuration limits. I attempted to re-request the outstanding review through GitHub. REST returned 404; GraphQL explicitly returned |
|
A second title where this helps: Mortal Shell II (PPSA34008), title key art. Linux 7.2.11, Ryzen 9 7950X, RX 6650 XT (RADV Mesa 26.2.6), Release. Why this title. Its key art runs compute dispatches that write a resident heap mirror of several hundred MiB. Each write-back reads the written range back, and on How I measured. The key art alternates between slow phases (about 0.1 to 0.6 FPS) and fast ones (about 5 to 10 FPS), so a mean over a fixed window mostly reflects where the fast phase falls. I report, per run, the time of the first fast phase (the first sample above 3 FPS after 20 s) and the median FPS of the slow-phase samples (below 2 FPS) from 20 to 120 s.
Earlier Limits: one title, one machine, 2+2 runs. Per-sample FPS, 20 to 120 s, every runAI-assisted: yes |
Additional title measurements supplied by @mrfelek, 2026-11-04: full route, source pins, summaries and trace digests. On PPSA22408 (Hot Wheels Infinite Rush), RTX3080Ti/NVIDIA615.71.09, Ryzen5950X/Linux7.3, 3840×2160, warm shader caches and identical import/staging/shadow settings, their alternating A/B/A/B route compares plain main
b11c7bf84fwith that main plus this PR'sc12a20f45dtopic (5fcf8be8a4). The post-load flyover improves from 0.30/0.30 to 0.62/0.63 presents/s, with median frame p50 moving from3.94/4.10s to1.82/1.86s. This remains very slow gameplay.The race-load window has no established improvement; the attached 330:10s trace windows land in loading and do not measure that post-load gain. The comment separately provides the post-load summary records. Later magenta/green artifacts also occur on their longer main control, and no exceptions occurred. These are the contributor's measurements, not locally reproduced title results. Their PPSA28416 multi-PR-tree switch pairs are attribution-only, not plain-main performance evidence. All measurements retain these historical source/configuration pins and do not qualify later heads.
Previous implementation report and contribution template:
What
GuestBufferMemory::WriteBackstores a resident heap mirror's write-back from its recorded readback buffer. It used to copy the readback into a newstd::vector<std::byte>of the written range and store from that copy.ResidentBuffer::StoreandstoreChanged/storeSparsetake astd::span<const std::byte>, and the readback buffer stays alive inheapReadbacksfor the whole write-back, so the copy is dropped. A write-back without a recorded readback (ResidentBuffer::ReadDevice) still reads into a vector, as before. The bytes stored in the resident shadow and in guest memory are the same.Why
In Echoes of the End (PPSA25636), a compute dispatch with atomic writes into a resident sparse heap mirror completes about once per second. Each completion writes back the dispatch's whole written range, about 540 MiB. A later build that reads the same heap waits for that write-back in
CompletePendingCpuWrites(UploadFinish). Allocating, zeroing and filling the 540 MiB vector took most of each write-back.The attribution below comes from a private integration tree (older
mainplus open PRs) with private counters (APS5_PROFILE_DRAWplus diagnostics). It is attribution, not a speed claim: 4 interleaved 900 s runs of the same build, with a private switch restoring the copy.ResidentBuffer::StorestoreChanged)CompletePendingCpuWritessync per copied-writer overlapResidentBuffer::Storereads the host-visible readback mapping directly now, so it got slower. The total per write-back still falls from about 419 ms to about 115 ms.Tested
Arch Linux 7.2.9-arch1-1, AMD Radeon RX 6650 XT, RADV Mesa 26.2.4, Ryzen 9 7950X.
Focused tests on
mainand on the change (ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ctest -V -j1 -R 'agc_driver_resident_heap_mirror|heap_mirror'; 9 tests):main4c7d275: 9/9 passed, 0VUID-.VUID-.was not found but was requested by env var VK_INSTANCE_LAYERS.agc_driver_resident_heap_mirrorran its resident tests on this device (the device has sparse residency; the log printsresident heap mirror tests passed, not the skip message). They dispatch stores into a resident heap mirror and check guest memory after the write-back.Echoes of the End: same-scene
main/change pairs on one machine (also posted with screenshots in #12827 (comment)). Echoes does not boot onmainalone:-1000072003) and it segfaults at 32 s.ShaderRecompiler::Recompile: value IR instruction definition does not dominate its use(recompiler: ReadLaneEliminator rewrites a spilled lane read to a value stored inside a branch, which does not dominate the read; fix branch ready #8050).Both sides therefore use the same private base:
main899ae3d + #4449 + #8089 + #11873 + #6867, commit 27db71c581b. The change side is that base + this PR's commit, 3e83ee94776; itsgit patch-idequalsc12a20f45da's. These runs therefore compare this PR on that private stack, not on baremain.Runs:
6a3bbca6eb39b28b),APS5_TRACE_SECONDS=1500:240, no otherAPS5_TRACE_*/APS5_PROFILE_*switch set.Pair 1: in-game "Loading..." screen (cathedral with the blue crystal) in both windows. Base, then change:
Resources.Completeon queue worker 0x20 (the copied-writer write-back) took 7.4 s on base and 3.5 s on the change.Recorder.Syncon that worker took 1.6 s and 0.8 s.Pair 2: in-world scene (two characters at a ruined archway) in both windows. Base, then change:
Caveats:
trace_dropped: true; the digests list the times). The frame times come from presents and are complete; only the per-phase totals are partial.An earlier pair in this description (900 s runs,
APS5_TRACE_SECONDS=600:240) landed on different scenes, so it is removed and is not evidence.tools/trace_digest.pyoutput for the four traces:Pair 1 base (27db71c581b4)
seconds 1500:240 from present 803: 125 presents, frame p50 1621.1 / p90 2233.2 / p99 8046.2 / max 8428.7 ms, GPU busy 816.4 ms per present
AMD Radeon RX 6650 XT (RADV NAVI23), radv Mesa 26.2.4-arch1.1, Linux 7.2.9-arch1-1, 3840x2160, commit 27db71c581b4, dropped: yes
{"commit":"27db71c581b4","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"1500:240"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","cpu":"AMD Ryzen 9 7950X 16-Core Processor","cpu_threads":32,"memory_mib":127901,"title_id":"PPSA25636","title":"Echoes of the End","content_version":"01.012.000","resolution":"3840x2160","window":{"spec":"seconds 1500:240","first_present":803,"ms":240007.014},"presents":125,"frame_ms":{"p50":1621.105,"p90":2233.242,"p99":8046.195,"max":8428.698},"gpu_busy_ms_per_present":816.406,"worker_busy_pct":{"queue worker 0x0":99.503,"queue worker 0x20":98.191},"top_phases_ms_per_frame":{"Driver.Packet":3760.159,"Driver.Packet.dispatch":2070.479,"Driver.Dispatch":1796.986,"Driver.Packet.memory_wait":1211.455,"Vulkan.Dispatch":1111.888,"Resources.Complete":1068.127,"Vulkan.Dispatch.shader_resources":1033.539,"Graphics.Draw":286.697},"trace_dropped":true,"trace_dropped_threads":{"queue worker 0x0":{"events_full_after_s":64.295,"events_lost":646426,"totals_full":false},"queue worker 0x20":{"events_full_after_s":217.5,"events_lost":27431,"totals_full":false}},"trace":"aps5-trace-27db71c581b4-196709.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 2191.6, Driver.Packet.dispatch 1045.8, Driver.Packet.memory_wait 991.9, Driver.Dispatch 930.1, batch 817.7, Resources.Complete 639.5, Vulkan.Dispatch 621.0, Vulkan.Dispatch.shader_resources 552.2, Graphics.Draw 269.5, Graphics.Draw.draw_and_resource_release 259.3
Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
Pair 1 change (3e83ee94776d)
seconds 1500:240 from present 1452: 341 presents, frame p50 704.9 / p90 877.5 / p99 1018.8 / max 1114.2 ms, GPU busy 335.1 ms per present
AMD Radeon RX 6650 XT (RADV NAVI23), radv Mesa 26.2.4-arch1.1, Linux 7.2.9-arch1-1, 3840x2160, commit 3e83ee94776d, dropped: yes
{"commit":"3e83ee94776d","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"1500:240"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","cpu":"AMD Ryzen 9 7950X 16-Core Processor","cpu_threads":32,"memory_mib":127901,"title_id":"PPSA25636","title":"Echoes of the End","content_version":"01.012.000","resolution":"3840x2160","window":{"spec":"seconds 1500:240","first_present":1452,"ms":240019.614},"presents":341,"frame_ms":{"p50":704.873,"p90":877.547,"p99":1018.779,"max":1114.243},"gpu_busy_ms_per_present":335.082,"worker_busy_pct":{"queue worker 0x0":98.756,"queue worker 0x20":97.053},"top_phases_ms_per_frame":{"Driver.Packet":1357.357,"Driver.Packet.dispatch":671.973,"Driver.Dispatch":595.953,"Driver.Packet.memory_wait":456.245,"Vulkan.Dispatch":245.115,"Vulkan.Dispatch.shader_resources":233.316,"Resources.Complete":188.105,"Graphics.Draw":126.533},"trace_dropped":true,"trace_dropped_threads":{"queue worker 0x0":{"events_full_after_s":28.328,"events_lost":2033306,"totals_full":false},"queue worker 0x20":{"events_full_after_s":94.147,"events_lost":460849,"totals_full":false}},"trace":"aps5-trace-3e83ee94776d-824611.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 342.5, batch 335.0, Driver.Packet.memory_wait 168.9, Driver.Packet.dispatch 142.4, Driver.Dispatch 130.2, Graphics.Draw 119.0, Graphics.Draw.draw_and_resource_release 114.0, Recorder.Submit 88.1, Resources.Complete 70.1, Vulkan.Dispatch 61.7
Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
Pair 2 base (27db71c581b4)
seconds 1500:240 from present 1054: 220 presents, frame p50 1084.5 / p90 1276.9 / p99 1413.1 / max 1538.9 ms, GPU busy 563.6 ms per present
AMD Radeon RX 6650 XT (RADV NAVI23), radv Mesa 26.2.4-arch1.1, Linux 7.2.9-arch1-1, 3840x2160, commit 27db71c581b4, dropped: yes
{"commit":"27db71c581b4","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"1500:240"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","cpu":"AMD Ryzen 9 7950X 16-Core Processor","cpu_threads":32,"memory_mib":127901,"title_id":"PPSA25636","title":"Echoes of the End","content_version":"01.012.000","resolution":"3840x2160","window":{"spec":"seconds 1500:240","first_present":1054,"ms":240025.444},"presents":220,"frame_ms":{"p50":1084.471,"p90":1276.934,"p99":1413.076,"max":1538.887},"gpu_busy_ms_per_present":563.648,"worker_busy_pct":{"queue worker 0x0":99.116,"queue worker 0x20":97.803},"top_phases_ms_per_frame":{"Driver.Packet":2123.795,"Driver.Packet.dispatch":1102.659,"Driver.Dispatch":997.477,"Driver.Packet.memory_wait":748.864,"Vulkan.Dispatch":540.299,"Vulkan.Dispatch.shader_resources":527.13,"Resources.Complete":476.271,"GpuMutex.wait.indirect":155.197},"trace_dropped":true,"trace_dropped_threads":{"queue worker 0x0":{"events_full_after_s":39.845,"events_lost":1294831,"totals_full":false},"queue worker 0x20":{"events_full_after_s":127.742,"events_lost":221256,"totals_full":false}},"trace":"aps5-trace-27db71c581b4-1422189.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 733.8, batch 563.6, Driver.Packet.memory_wait 392.9, Driver.Packet.dispatch 287.7, Driver.Dispatch 253.6, Resources.Complete 152.3, Graphics.Draw 139.3, Graphics.Draw.draw_and_resource_release 132.6, Vulkan.Dispatch 130.4, Vulkan.Dispatch.shader_resources 127.2
Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
Pair 2 change (3e83ee94776d)
seconds 1500:240 from present 1305: 239 presents, frame p50 1018.3 / p90 1212.9 / p99 1379.8 / max 1666.4 ms, GPU busy 515.5 ms per present
AMD Radeon RX 6650 XT (RADV NAVI23), radv Mesa 26.2.4-arch1.1, Linux 7.2.9-arch1-1, 3840x2160, commit 3e83ee94776d, dropped: yes
{"commit":"3e83ee94776d","dirty":false,"env":{"APS5_PAD_INPUT_FILE":"<path>","APS5_TRACE_DIR":"<path>","APS5_TRACE_SECONDS":"1500:240"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","cpu":"AMD Ryzen 9 7950X 16-Core Processor","cpu_threads":32,"memory_mib":127901,"title_id":"PPSA25636","title":"Echoes of the End","content_version":"01.012.000","resolution":"3840x2160","window":{"spec":"seconds 1500:240","first_present":1305,"ms":240957.123},"presents":239,"frame_ms":{"p50":1018.347,"p90":1212.909,"p99":1379.782,"max":1666.358},"gpu_busy_ms_per_present":515.481,"worker_busy_pct":{"queue worker 0x0":99.162,"queue worker 0x20":97.691},"top_phases_ms_per_frame":{"Driver.Packet":1961.533,"Driver.Packet.dispatch":1018.941,"Driver.Dispatch":918.054,"Driver.Packet.memory_wait":701.249,"Vulkan.Dispatch":484.835,"Vulkan.Dispatch.shader_resources":472.343,"Resources.Complete":425.887,"Graphics.Draw":145.052},"trace_dropped":true,"trace_dropped_threads":{"queue worker 0x0":{"events_full_after_s":40.275,"events_lost":1403009,"totals_full":false},"queue worker 0x20":{"events_full_after_s":125.406,"events_lost":258029,"totals_full":false}},"trace":"aps5-trace-3e83ee94776d-787378.json.gz"}Slowest frames (largest slices inside each, inclusive)
Threads (ms per frame)
Largest slices (ms per frame, inclusive, all threads): Driver.Packet 668.7, batch 514.3, Driver.Packet.memory_wait 361.7, Driver.Packet.dispatch 261.5, Driver.Dispatch 238.7, Resources.Complete 150.2, Graphics.Draw 133.5, Graphics.Draw.draw_and_resource_release 127.1, Vulkan.Dispatch 127.1, Vulkan.Dispatch.shader_resources 124.1
Longest waits
Largest GPU batches (GPU ranges inside, and the CPU slices that recorded each, inclusive)
Attached in the release https://github.com/JJenkx/AnyPS5/releases/tag/heap-writeback-readback-samescene-20261029: the four traces, the four summary lines, their digests, the 1440 s and 1795 s screenshots and the seed manifest. The earlier release https://github.com/JJenkx/AnyPS5/releases/tag/heap-writeback-readback-evidence holds the focused-test VVL logs.
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