Skip to content

perf(libkernel): find free direct-memory ranges in allocation order - #7469

Open
Dripl1x wants to merge 3 commits into
boykopovar:mainfrom
Dripl1x:codex/direct-memory-allocation-order
Open

Dripl1x wants to merge 3 commits into
boykopovar:mainfrom
Dripl1x:codex/direct-memory-allocation-order

Conversation

@Dripl1x

@Dripl1x Dripl1x commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

What

This PR is part of a series of graphics and memory-management performance improvements for AnyPS5, with SuperTuxKart as the main profiling workload. This is item 06/10; the UI Lab startup/cache fix follows as a separate eleventh PR. Each topic's measurements are distinguished from the combined result.

Find first-fit direct-memory space by walking the existing ordered allocation map and skipping occupied ranges. Preserve bounds, alignment and first-fit results without a second free-space index.

Tested

Pinned benchmark base: 6447ed1ed7fd11c7eef60df336e8d66fac271188. Tested topic snapshot: 6da6576d9ceca4122a164fccac59af4e416375b5. Windows 11 Pro build 26300, Ryzen 7 5800H, RTX 3070 Laptop, NVIDIA 617.42. Frozen runtime module hashes and raw traces were verified. No opt-in optimization flags are required.

3/3 targeted cases passed on Windows and native Ubuntu 26.04: MemoryPoolTest, guest_memory and guest_mmap_fixed_anonymous. A 32,768-operation independent naive reference model checks allocation/free, exact first-fit addresses, non-power-of-two alignment, bounds and failures.

SuperTuxKart captures for the bot's before/after requirement: Windows 11 Pro build 26300, Ryzen 7 5800H, RTX 3070 Laptop GPU, NVIDIA 617.42, WinLibs GCC 15.2.0 r7, Release; SuperTuxKart (PPSA69421) tutorial prompt over the main menu, 1920x1080 internal rendering in a maximized 2560x1369 window, warm shader caches, audio muted, no input; APS5_TRACE_SECONDS=20:8 with APS5_TRACE_EVENTS=1048576, console output not redirected, no profiling switches; 2026-10-18, one valid capture of this PR (its second capture lost focus and is excluded) against two of main, order main, PR, main.

Capture Build Commit FPS p50 / p90 / p99 ms
required1018-main-6447 main 6447ed1ed7fd 6447ed1ed7fd 9.584 103.2 / 111.2 / 116.8
required1018-main-6447-awake-r2 main 6447ed1ed7fd 6447ed1ed7fd 9.528 103.9 / 112.2 / 121.1
required1018-7469 this PR 809c0009e3cf 9.635 102.7 / 111.4 / 116.8

The FPS difference is within the run-to-run spread of main; this PR claims no FPS change. What it saves is shown under Where it helps.

Summary lines (main first, then this PR)
{"commit":"6447ed1ed7fd","dirty":false,"env":{"APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":42,"ms":8034.483},"presents":77,"frame_ms":{"p50":103.246,"p90":111.156,"p99":116.826,"max":116.826},"gpu_busy_ms_per_present":5.271,"worker_busy_pct":{"queue worker 0x0":3.148},"top_phases_ms_per_frame":{"Driver.Packet":3.234,"Driver.Packet.draw":2.618,"Driver.Draw":2.562,"Driver.Draw.shader_compile_and_link":1.512,"Driver.Present":0.815,"Shader.DrawStage":0.813,"Driver.Present.queue_present":0.547,"Vulkan.QueuePresent":0.545},"trace_dropped":false,"trace":"aps5-trace-6447ed1ed7fd-21748.json.gz"}
{"commit":"6447ed1ed7fd","dirty":false,"env":{"APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":45,"ms":8081.323},"presents":77,"frame_ms":{"p50":103.882,"p90":112.153,"p99":121.116,"max":121.116},"gpu_busy_ms_per_present":5.214,"worker_busy_pct":{"queue worker 0x0":3.193},"top_phases_ms_per_frame":{"Driver.Packet":3.301,"Driver.Packet.draw":2.672,"Driver.Draw":2.617,"Driver.Draw.shader_compile_and_link":1.540,"Driver.Present":0.839,"Shader.DrawStage":0.828,"Driver.Present.queue_present":0.571,"Vulkan.QueuePresent":0.566},"trace_dropped":false,"trace":"aps5-trace-6447ed1ed7fd-38428.json.gz"}
{"commit":"809c0009e3cf","dirty":false,"env":{"APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":37,"ms":8095.128},"presents":78,"frame_ms":{"p50":102.689,"p90":111.426,"p99":116.817,"max":116.817},"gpu_busy_ms_per_present":5.309,"worker_busy_pct":{"queue worker 0x0":3.221},"top_phases_ms_per_frame":{"Driver.Packet":3.290,"Driver.Packet.draw":2.679,"Driver.Draw":2.618,"Driver.Draw.shader_compile_and_link":1.539,"Driver.Present":0.891,"Shader.DrawStage":0.834,"Driver.Present.queue_present":0.568,"Vulkan.QueuePresent":0.566},"trace_dropped":false,"trace":"aps5-trace-809c0009e3cf-41712.json.gz"}
tools/performance_compare.py (first capture of each side)

Performance comparison

Capture Commit Trace Presents Window (ms)
baseline 6447ed1 aps5-trace-6447ed1ed7fd-21748.json.gz 77 8034.483
candidate 809c000 aps5-trace-809c0009e3cf-41712.json.gz 78 8095.128
  • Compare captures from the same machine, title and scene; summaries do not record the CPU, title or scene.
  • Changes are candidate minus baseline. A negative frame-time change means a shorter frame interval.
  • A missing top phase is unreported, not zero; its change is unavailable.
  • Recorded configuration differs; these measurements do not isolate the code change.

Configuration differences

Setting Baseline Candidate
window.first_present 42 37

Frame and GPU times (ms)

Metric Baseline Candidate Change Change (%)
frame_ms.p50 103.246 102.689 -0.557 -0.539
frame_ms.p90 111.156 111.426 +0.270 +0.243
frame_ms.p99 116.826 116.817 -0.009 -0.008
frame_ms.max 116.826 116.817 -0.009 -0.008
mean_frame_ms 104.344 103.784 -0.560 -0.537
gpu_busy_ms_per_present 5.271 5.309 +0.038 +0.721

Top phases (ms per frame)

Metric Baseline Candidate Change Change (%)
Driver.Draw 2.562 2.618 +0.056 +2.186
Driver.Draw.shader_compile_and_link 1.512 1.539 +0.027 +1.786
Driver.Packet 3.234 3.290 +0.056 +1.732
Driver.Packet.draw 2.618 2.679 +0.061 +2.330
Driver.Present 0.815 0.891 +0.076 +9.325
Driver.Present.queue_present 0.547 0.568 +0.021 +3.839
Shader.DrawStage 0.813 0.834 +0.021 +2.583
Vulkan.QueuePresent 0.545 0.566 +0.021 +3.853
tools/trace_digest.py output (first capture of each side; all digests are in the evidence archive)

required1018-main-6447

seconds 20:8 from present 42: 77 presents, frame p50 103.2 / p90 111.2 / p99 116.8 / max 116.8 ms, GPU busy 5.3 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 1920x1080, commit 6447ed1, dropped: no

{"commit":"6447ed1ed7fd","dirty":false,"env":{"APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":42,"ms":8034.483},"presents":77,"frame_ms":{"p50":103.246,"p90":111.156,"p99":116.826,"max":116.826},"gpu_busy_ms_per_present":5.271,"worker_busy_pct":{"queue worker 0x0":3.148},"top_phases_ms_per_frame":{"Driver.Packet":3.234,"Driver.Packet.draw":2.618,"Driver.Draw":2.562,"Driver.Draw.shader_compile_and_link":1.512,"Driver.Present":0.815,"Shader.DrawStage":0.813,"Driver.Present.queue_present":0.547,"Vulkan.QueuePresent":0.545},"trace_dropped":false,"trace":"aps5-trace-6447ed1ed7fd-21748.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 67: 116.8 ms at 2551 ms: Driver.WorkerWait (queue worker 0x0) 111.9, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 111.8, batch (gpu) 5.3, Driver.Packet (queue worker 0x0) 3.6
  • present 68: 115.8 ms at 2668 ms: Driver.WorkerWait (queue worker 0x0) 110.8, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 110.6, batch (gpu) 5.3, Driver.Packet (queue worker 0x0) 3.7
  • present 97: 112.3 ms at 5756 ms: Driver.WorkerWait (queue worker 0x0) 107.7, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 107.6, batch (gpu) 5.2, Driver.Packet (queue worker 0x0) 3.3

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 2.6 (2 %) 100.7 (97 %) 1.0 3.9 Driver.Packet 2.6, Driver.EndSubmission 0.0
presenter 0.8 (1 %) 0.0 (0 %) 103.5 0.1 Driver.Present 0.8
gpu 5.3 (5 %) 0.0 (0 %) 99.1 0.0 batch 5.3

required1018-7469

seconds 20:8 from present 37: 78 presents, frame p50 102.7 / p90 111.4 / p99 116.8 / max 116.8 ms, GPU busy 5.3 ms per present
NVIDIA GeForce RTX 3070 Laptop GPU, NVIDIA 617.42, Windows 10.0.26300, 1920x1080, commit 809c000, dropped: no

{"commit":"809c0009e3cf","dirty":false,"env":{"APS5_TRACE_SECONDS":"20:8"},"gpu":"NVIDIA GeForce RTX 3070 Laptop GPU","driver":"NVIDIA 617.42","os":"Windows 10.0.26300","resolution":"1920x1080","window":{"spec":"seconds 20:8","first_present":37,"ms":8095.128},"presents":78,"frame_ms":{"p50":102.689,"p90":111.426,"p99":116.817,"max":116.817},"gpu_busy_ms_per_present":5.309,"worker_busy_pct":{"queue worker 0x0":3.221},"top_phases_ms_per_frame":{"Driver.Packet":3.29,"Driver.Packet.draw":2.679,"Driver.Draw":2.618,"Driver.Draw.shader_compile_and_link":1.539,"Driver.Present":0.891,"Shader.DrawStage":0.834,"Driver.Present.queue_present":0.568,"Vulkan.QueuePresent":0.566},"trace_dropped":false,"trace":"aps5-trace-809c0009e3cf-41712.json.gz"}

Slowest frames (largest slices inside each, inclusive)

  • present 52: 116.8 ms at 1533 ms: Driver.WorkerWait (queue worker 0x0) 111.8, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 111.7, batch (gpu) 5.3, Driver.Packet (queue worker 0x0) 3.7
  • present 51: 116.8 ms at 1417 ms: Driver.WorkerWait (queue worker 0x0) 111.9, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 111.8, batch (gpu) 5.3, Driver.Packet (queue worker 0x0) 3.6
  • present 72: 114.1 ms at 3671 ms: Driver.WorkerWait (queue worker 0x0) 109.2, Driver.WorkerWait.idle_and_completion_poll (queue worker 0x0) 109.1, batch (gpu) 5.3, Driver.Packet (queue worker 0x0) 3.6

Threads (ms per frame)

thread busy wait untraced in slices < 20 us largest
queue worker 0x0 2.7 (3 %) 100.1 (96 %) 1.0 3.9 Driver.Packet 2.7, Driver.EndSubmission 0.0
presenter 0.8 (1 %) 0.1 (0 %) 102.9 0.1 Driver.Present 0.9
gpu 5.3 (5 %) 0.0 (0 %) 98.5 0.0 batch 5.3

Metadata-only search probe, same C++ implementation with stub backing, ABBA order and medians of five trials per process (2,000 alloc/free cycles per trial): empty pool 0.0752 -> 0.0786 us/cycle; one 64-MiB allocation 1.8810 -> 0.0881; one 512-MiB allocation 14.5025 -> 0.0872; one 4-GiB allocation 115.8989 -> 0.0888. With 2,048 adjacent 64-KiB allocations, 3.7746 -> 8.3561 us/cycle (about 2.2x slower). This trades page scans for allocation-node scans; the contiguous-prefix win does not cover all fragmentation patterns and is not whole-frame timing.

Where it helps

About 48 sceKernelAllocateDirectMemory calls per frame search the physical pool for a free range.

Measured main 2185dbf92e main + series
PhysicalMemoryPool::Alloc calls per frame 48.6 47.9
PhysicalMemoryPool::Alloc µs per call 47.54 6.62
PhysicalMemoryPool::Alloc ms per frame 2.31 0.32
sceKernelAllocateDirectMemory calls per frame 48.6 47.9
sceKernelAllocateDirectMemory µs per call 47.77 6.77
sceKernelAllocateDirectMemory ms per frame 2.32 0.32

Counters come from a local probe build that is not part of this PR (review-probe.patch in the evidence archive): the same counters and timers were inserted into main 2185dbf92e and into main with all eleven series PRs merged (#7464 in its rebased form), anchored on function definitions present in both trees. Runs were in the mirrored order main, series with #7464 reduced to its wake only, series, series, reduced series, main, in the scene above with APS5_PROFILE_DRAW=1; values are medians of two runs over the same 8-second window as the trace, starting 20 s after the first flip, per flip. These runs carry profiling overhead and are not used for FPS. Each optimised function below is changed by this PR only; counters show where the work goes, not an isolated FPS gain.

Other homebrew checks

Workload Control FPS This topic FPS Scope
vkQuake N/A N/A Earlier compatibility capture; no matched FPS claim here
Syobon Action N/A N/A Earlier compatibility capture; no matched FPS claim here
Middle Ages Ping Pong N/A N/A Earlier compatibility capture; no matched FPS claim here

UI Lab: the 21 default concepts were rendered and visually reviewed in a navigation cycle for this topic. Artwork was present; this covers default navigation, not all themes or every widget interaction.

Known baseline rendering issue: vkQuake still has intermittent flickering and an intermittently black floor on main and the tested performance branches. These changes do not fix it. Yamagi Quake II gameplay stops at unsupported last-provoking-vertex flat interpolation, and UZDoom at unsupported clip/cull-distance handling on the baseline; neither supplies a valid gameplay FPS comparison.

Dependencies, series and overlap

#6044 relocates the test files. Its MemoryPoolTest change is a relocation, not this allocator algorithm; whichever lands later must retain the model test at the current path.

The project overlap scan compared the local topics against 785 open PRs and checked merges into main e5c2b3c325e485ba7fd417c47c46f48aa2c89115. This topic merges cleanly in that snapshot. Some other PRs already conflict with main, so the tool cannot compare all their shared-file hunks; the full report is retained with the common series evidence package. No exact duplicate was identified in the inspected implementations. This is not a certification that every conflicting foreign branch is composition-tested.

Conventions and whitespace checks passed for the tested topic range. The benchmark base remains pinned for comparability; this is not a fresh-current-main build/test claim. Measurements and focused tests refer to the pinned source revisions above; no full-suite CI run is claimed.

Re-checked on 2026-10-21: this head still merges cleanly into main 2185dbf92e. #6658, which the earlier combined runs carried, merged into main on 2026-10-20.

Combined series result

Re-measured on 2026-10-21 on current main 2185dbf92e (Windows 11 Pro build 26300, Ryzen 7 5800H, RTX 3070 Laptop GPU, NVIDIA 617.42, WinLibs GCC 15.2.0 r7, Release; SuperTuxKart (PPSA69421) tutorial prompt over the main menu, 1920x1080 internal rendering in a maximized 2560x1369 window, warm shader caches, audio muted, no input; APS5_TRACE_SECONDS=20:8 with APS5_TRACE_EVENTS=1048576, console output not redirected, no profiling switches). Runs in the order A-B-C-D-D-C-B-A, two per configuration; FPS is presents over the 8-s window.

Configuration FPS, run 1 / run 2
main 2185dbf92e 9.18 / 9.03
main + #7464 + #7465 20.85 / 22.02
main + all eleven PRs of the series 29.01 / 28.70

#7464 and #7465 make the largest step together: the title's per-frame host imports disappear (see their PRs). With #7464 reduced to its CPU-label wake only, the whole series measured 10.07 / 9.01 FPS against main 9.24 / 9.30 in a separate block of the same session. Combined numbers are not the gain of any single PR. The combined builds are local merges of the published (#7465-#7470, #7472, #7474) and rebased (#7464, #7471, #7473) heads into main 2185dbf92e; the commits in their summary lines are those merges, not pushed. Summary lines, traces and digests: series-evidence.zip.

Checklist

  • Based on pinned main 6447ed1ed7fd; merges cleanly into current main 2185dbf92e (git merge-tree, 2026-10-21); related overlaps are listed above
  • 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: n/a (library-only change; game test hardware above)
  • AI-assisted: yes

The current head includes the review correction and validation recorded below.

Series index

These are the ten performance topics from the same profiling effort, followed by a separate UI Lab cache-preservation fix. Membership in the series does not imply a dependency.

Item Pull request Required dependency
01 #7464: perf(agc): keep unimported label stores on the CPU #6658
02 #7465: perf(agc): defer small host imports until first GPU use none
03 #7466: perf(agc): validate host imports through their registered owner none
04 #7467: perf(libc): avoid repeated Windows path component scans none
05 #7468: perf(libkernel): find direct-memory aliases through the physical index none
06 #7469: perf(libkernel): find free direct-memory ranges in allocation order none
07 #7470: perf(libc): release exact resident mappings without repeated queries none
08 #7471: perf(libc): collect resident writes directly into the output buffer none
09 #7472: perf(libc): reuse saved direct-memory buffers when unreferenced none
10 #7473: perf(libc): skip write-watch queries for proven clean resident ranges #7471
11 #7474: fix(agc): preserve pipeline caches on immediate guest exit none

Reproduction evidence

Series traces, summary lines, module hashes, focused-test logs and UI contact sheets. Game measurements use the pinned base and source revisions described above; assets contain no game binaries.

Update of 2026-10-21: 7469-evidence.zip (traces, summary lines, trace_digest.py and performance_compare.py output, loaded-module hashes), counters where.json and the probe review-probe.patch with probe_window.py.

Review correction (2026-10-18)

Thanks for testing the allocation semantics and measuring the page-granular case. Fixed in 809c0009e3cf: after eight allocation-node probes the search falls back to the previous reverse-page search from the current candidate. On this machine the 16,384 one-page prefix goes from 92.16 us in the old PR to 7.50 us after the correction (7.43 us in the pinned main); the one-4-GiB-block case remains 0.085 us. These are metadata-only medians over five 2,000-cycle trials, not FPS. All 17 MemoryPoolTest cases pass on Windows and native Linux, including the 32,768-operation independent first-fit model and a new 16,384-block bounds/alignment case.

The three corrections (#7467, #7469 and #7470) were also checked together against the previous series in a same-scene SuperTuxKart A-B-B-A repeat: 32.680 -> 32.722 FPS (1920x1080 internal rendering, maximized 2560x1369 client, warm caches, trace seconds 20-28, RTX 3070 Laptop/NVIDIA 617.42). Focus and loaded-module hashes were verified. This combined check does not assign a separate FPS gain to this PR. #7473 is being validated separately.

Complete the publication checklist and series cross-links for boykopovar#7469.
No source or test changes.
@github-actions

github-actions Bot commented Oct 18, 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 6044 core/libs/tests/MemoryPoolTest.cpp
PR 7105 core/libs/prx/libkernel/DirectMemory/MemoryPool.cpp

@wachi35676

Copy link
Copy Markdown
Contributor

I compiled the old and new MemoryPool.cpp side by side. 1.5M random operations (Alloc with odd alignments and bounds, Free, CheckedFree, Retype splits, Find) give identical results and addresses. MemoryPoolTest passes on Windows and Linux.

One addition to the fragmentation note in the description:

Pool state main this PR
16,384 adjacent 16-KiB (one-page) allocations ahead of the free space, 64-KiB alloc+free 6.2 µs 108 µs (17x slower)
One large block in front 105 µs 0.095 µs

The old cost is O(pages/len) per probe; the new cost is O(blocks before the first fit). Whether this is a net win depends on the title's allocation pattern. A SuperTuxKart A-B-B-A result of +1.95% doesn't cover page-granular allocators.

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

@Dripl1x

Dripl1x commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

@wachi35676 Thanks for testing the allocation semantics and measuring the page-granular case. Fixed in 809c0009e3cf: after eight allocation-node probes the search falls back to the previous reverse-page search from the current candidate. On this machine the 16,384 one-page prefix goes from 92.16 us in the old PR to 7.50 us after the correction (7.43 us in the pinned main); the one-4-GiB-block case remains 0.085 us. These are metadata-only medians over five 2,000-cycle trials, not FPS. All 17 MemoryPoolTest cases pass on Windows and native Linux, including the 32,768-operation independent first-fit model and a new 16,384-block bounds/alignment case.

The three corrections (#7467, #7469 and #7470) were also checked together against the previous series in a same-scene SuperTuxKart A-B-B-A repeat: 32.680 -> 32.722 FPS (1920x1080 internal rendering, maximized 2560x1369 client, warm caches, trace seconds 20-28, RTX 3070 Laptop/NVIDIA 617.42). Focus and loaded-module hashes were verified. This combined check does not assign a separate FPS gain to this PR. #7473 is being validated separately.

@github-actions github-actions Bot added perf Performance change perf numbers missing perf pull request without a before and after summary line labels Oct 18, 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.

@JJenkx

JJenkx commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Additional current-main Linux check of the corrected PR (809c0009e3cf), using Record of Lodoss War: Deedlit in Wonder Labyrinth / PPSA05347, stationary opening forest/tutorial scene.

Control: 585075cb7ed3467889745d0a4b2e8285318b019d. Candidate: control plus this PR's two source/test commits (6da6576d9cec, 809c0009e3cf), locally applied as bb114f70d3560fff9901ce7d0478fdf7703cbaf8. No other local changes.

Ryzen 9 7950X, Radeon RX 6650 XT, RADV Mesa 26.2.4-arch1.1, Linux 7.2.9-arch1-1. Same scripted inputs, identical initial warm-cache clones (SHA-256 manifests attached), pipelined draws and DMA enabled in both. Official APS5_TRACE_SECONDS=200:30 captures; no perf sampling during these runs.

FPS p50 ms p90 ms p99 ms
Main 27.437 35.644 42.066 48.886
Main + corrected PR 27.199 35.629 43.156 53.196

This single ordered pair shows no gain in this scene (throughput −0.87%); it is not replicated evidence of a regression or a general conclusion about other titles. Both runs exited zero, restored configuration and the kernel limit, and left no native process. The 240-second screenshots show the same scene, HP 100/100 and readable tutorial text with no obvious visual regression.

MemoryPoolTest, guest_memory, and guest_mmap_fixed_anonymous pass on both revisions. The candidate runs all 17 allocator cases, including the randomized first-fit model and page-granular-prefix correction.

Raw traces, trace digests, exact commands, cache hashes, screenshots and test logs.

Official trace summary lines
{"commit":"585075cb7ed3","dirty":false,"env":{"APS5_DRAW_CACHE_ENTRIES":"4096","APS5_HOST_IMPORT_MIB":"16384","APS5_PAD_INPUT_FILE":"<path>","APS5_PIPELINED_DRAWS":"1","APS5_PIPELINE_DMA":"1","APS5_SPIRV_OPT":"full","APS5_TRACE_SECONDS":"200:30"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","resolution":"3840x2160","window":{"spec":"seconds 200:30","first_present":9729,"ms":30031.926},"presents":824,"frame_ms":{"p50":35.644,"p90":42.066,"p99":48.886,"max":55.291},"gpu_busy_ms_per_present":2.162,"worker_busy_pct":{"queue worker 0x0":26.296},"top_phases_ms_per_frame":{"Driver.Packet":9.573,"Graphics.Draw":4.414,"Graphics.Draw.validate":2.852,"VideoOut.Flip":1.744,"VideoOut.Flip.present":1.711,"Driver.Present":1.711,"Driver.Present.render_fence_wait":1.553,"Vulkan.Retire":1.553},"trace_dropped":false,"trace":"aps5-trace-585075cb7ed3-3566494.json.gz"}
{"commit":"bb114f70d356","dirty":false,"env":{"APS5_DRAW_CACHE_ENTRIES":"4096","APS5_HOST_IMPORT_MIB":"16384","APS5_PAD_INPUT_FILE":"<path>","APS5_PIPELINED_DRAWS":"1","APS5_PIPELINE_DMA":"1","APS5_SPIRV_OPT":"full","APS5_TRACE_SECONDS":"200:30"},"gpu":"AMD Radeon RX 6650 XT (RADV NAVI23)","driver":"radv Mesa 26.2.4-arch1.1","os":"Linux 7.2.9-arch1-1","resolution":"3840x2160","window":{"spec":"seconds 200:30","first_present":9824,"ms":30000.814},"presents":816,"frame_ms":{"p50":35.629,"p90":43.156,"p99":53.196,"max":65.631},"gpu_busy_ms_per_present":2.185,"worker_busy_pct":{"queue worker 0x0":28.054},"top_phases_ms_per_frame":{"Driver.Packet":10.304,"Graphics.Draw":4.798,"Graphics.Draw.validate":3.28,"VideoOut.Flip":1.74,"Driver.Present":1.711,"VideoOut.Flip.present":1.711,"Recorder.Sync":1.659,"Vulkan.Retire":1.552},"trace_dropped":false,"trace":"aps5-trace-bb114f70d356-3673174.json.gz"}

AI-assisted: yes.

@oneandonlydean oneandonlydean self-assigned this Oct 20, 2026
@github-actions github-actions Bot removed the perf numbers missing perf pull request without a before and after summary line label Oct 20, 2026
@Dripl1x

Dripl1x commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

@JJenkx, thanks for the Lodoss run. It matches what I see: no FPS claim for this PR. To show where it does work, I counted the allocator in SuperTuxKart's menu scene on current main: about 49 sceKernelAllocateDirectMemory calls per frame, 47.5 µs per pool search on main against 6.6 µs with this PR. Fresh before/after summary lines of the published head and its base are in the description.

AI-assisted: yes (Claude Code)

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

libkernel perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants