perf(vk): the staging arenas a load used a moment ago are kept, not made again every second frame #568
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
beanstalk: approved @ 1697603
beanstalk: approved @ 2c5a62e
beanstalk: approved @ 4fd82b7
beanstalk: approved @ 64d6d09
beanstalk: approved @ 6f91fae
beanstalk: approved @ 70a78f9
beanstalk: approved @ 8d361dc
beanstalk: approved @ 9d8356e
beanstalk: approved @ abf2227
beanstalk: approved @ d82f202
beanstalk: approved @ e5f1e40
beanstalk: approved @ ee8ab5f
ci: approved
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!568
Loading…
Reference in a new issue
No description provided.
Delete branch "p0lux/Longshot:perf/staging-burst-keep"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type: perf · Risk: low · Tested on: Linux (SteamOS), Steam Deck OLED (RADV VANGOGH) · Needs: a desktop card of 6 GB or less, Windows or Linux
Why
On a card of 6.5 GB or less, a load that uploads textures in frames that follow each other makes a new 64 MB staging arena about every second frame and frees it a frame later: 14 to 17 arenas an arrival on a Steam Deck, about 13 ms of the replay thread each. The arenas are needed again at once; freeing them between two frames of the same load buys nothing. See #395.
What changed
An idle staging arena that a load staged into in the last 2 seconds is kept, up to 256 MB of them, instead of being freed between two frames of the same load. Two seconds after the load's last upload the old 64 MB rule holds again; cards that already keep 256 MB see no change.
texture_framelearns at the next present, after the next frame has already staged. So frames that stage in a row need two arenas taking turns. Where 64 MB of idle arenas is kept (one arena: cards of 6.5 GB or less since the 64 MB rule), the idle one of the two went at every second present, and the frame after made a 64 MB arena again.texture_frame,gpu/vk/vk_texture.cpp): an idle arena that was staged into in the last 2 s stays, up to 256 MB of them. 256 MB is what a card over 6.5 GB keeps anyway, so nothing changes there. Two seconds after a load's last upload the 64 MB rule holds again, and the 30 s rule after it. Arenas over 64 MB still go as soon as the GPU is done with them.RX_VK_STAGING_BURST_Sindocs/development.md; one run file indocs/tested/.tests/test_staging_burst.py(new) cutsstaging()and the give-back loop out ofvk_texture.cppand runs frames through them on a clock of its own.Measurements
Verdict: it removes the churn it targets: 16 arenas made an arrival become 4 in Hyrule Field and 15 become 5 in Kokiri Forest on a Steam Deck OLED, 120 to 170 ms of the replay thread less in the load's slow frames. The arrival as a whole is not measurably shorter, and GPU memory at the end of the run is the same. No frame rate gain is claimed. Passed.
Hardware: SteamOS 3.9.5 (kernel 7.2.7-valve2), Steam Deck OLED: AMD Custom APU 0932, RADV VANGOGH, Mesa 26.2.0-devel, 16 GB shared with the GPU; the GPU's clock fixed at 1600 MHz
Scene: the arrival in an area: a save in Hyrule Field and one in Kokiri Forest loaded by script; no screen (headless), handheld profile, Minimum preset, the game's own upscaler, no frame generation, no cap
Method: the game and host built from main
9c9d69ed; the back end built alone from each commit (clang, same flags) and swapped in that game folder. Each run starts the game and loads the save, withRX_VK_FRAME_TRACE=1. Arenas made are the log'sa staging arena of 64 MB took ... ms to makelines over the whole run (the log stops at 24, never reached). Frame times are the trace's, over the 600 presents after the load's transition frame (the first frame over 600 ms that uploads over 60 MB). GPU memory isdrm-memory-gttfrom/proc/<pid>/fdinfoat the end of the run. Main, this PR, and a third renderer (another pull request's), alternated, 3 runs a scene; the median of 3How to reproduce:
RX_VK_FRAME_TRACE=1, load a save, thengrep "staging arena of" logs/longshot_log.txt | wc -l;RX_VK_STAGING_BURST_S=0for the old rulethis PR: perf/staging-burst-keep @ d3004735 (this PR's code commit on main
9c9d69ed; on the fork asmeasured/staging-burst-keep-d3004735). The branch is now on main9e6f231d(be132765and a docs commit):git range-diffshows the same patch. Main has changedtexture_framein between (#735: the texture budget is set by the card, and an integrated GPU's line for the driver's count), but notstaging()nor the loop that gives idle arenas back, which is all this PR touches; so the numbers hold. Not measured again on this main.Medians; each run in brackets, in the order run:
9c9d69ed9c9d69ed15 such lines in each Kokiri Forest run on main, 5 with this PR.
Read with care. The change removes ten to twelve arena creations an arrival and the 120 to 170 ms they cost, spread over the load's slow frames. It does not make the arrival measurably shorter on this machine: 3.0 s against 3.0 s in slow frames in Hyrule Field, and in Kokiri Forest main's own three runs go from 6.0 to 9.1 s. What it costs is under Risks.
Flags and settings
One new switch, on by default at 2 seconds.
RX_VK_STAGING_BURST_S=<seconds>=0is the behaviour beforeTesting
Tested:
python -I -B tests/run_all.pyon macOS with the Vulkan headers given, on the rebased head: 507 passed, 48 failed, 39 skipped. The 48 fail the same way on main9e6f231don that machine (no/proc, noposix_fallocate, Python 3.9, the Linux launch scripts and the like). The suite ran beside four others and 11 more checks timed out in that run (on main too, 10); each passes when run alone.tests/test_staging_burst.py(new), on macOS (clang) and Linux (g++ 14): 20 frames that stage in a row make 2 arenas and give none back (the old rule makes 11 and gives 9 back, which is how it fails on main); the 256 MB cap after a frame that needs six arenas; an arena over 64 MB still goes; back to 64 MB 2 s after the last upload and to none after 30 s; with 256 MB kept nothing changes;RX_VK_STAGING_BURST_S=0gives the old behaviour in each case.tests/test_staging_arena_fallback.pyandtests/test_texture_staging_publication.py, which cut the same code, needed no change and pass.ef080109; clang, x86-64-v3, on the Steam Deck): 0 failed. Windows:longshot_vk.dllcross-builds from the same head with llvm-mingw 20261104 on Linux: 0 failed. Not run on Windows.Not tested:
Must be tested:
RX_VK_STAGING_BURST_S=0against unset on one build of this PR)Risks
What could break: memory on a small card during a load. Where 64 MB of idle arenas was kept, up to 256 MB now stay while a load is uploading and for 2 s after its last upload: up to 192 MB more, VRAM on a desktop card with resizable BAR, system memory on an APU. It is memory the load was making and freeing in turn, not new memory, and a card over 6.5 GB keeps that much all the time. On the Deck the GPU memory at the end of the run is the same.
Turning it off:
RX_VK_STAGING_BURST_S=0is the old rule; reverting the commit removes the change.Compatibility: Nothing changes: saves and
longshot_options.iniare untouched, no shader or pipeline cache is rebuilt (no stamped file is touched),MKWVK_API_VERSIONis as it was.Reviewer notes
RX_VK_STAGING_KEEP_MB=256(existing) also stops the churn, by keeping 256 MB for good, which is what the 64 MB rule was made to avoid on small cards.Issues
See #395
Checklist
Everyone
type(scope): description) of the status line's type.main.python -I -B tests/run_all.pypasses (any failure that also fails onmainis named).third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
Assisted-by:/Co-Authored-By:trailers.docs/tested/for each new measured run (format indocs/tested-configurations.md).mainand passing here.WIP: perf(vk): the staging arenas a load used a moment ago are kept, not made again every second frameto perf(vk): the staging arenas a load used a moment ago are kept, not made again every second frame341ca45298ef080109f4Rebased onto main
9e6f231d(headef080109): no conflict;git range-diffshows the same patch. Main changedtexture_framein between (#735, the texture budget), notstaging()nor the loop that gives idle arenas back. The numbers are the ones measured before; the description says why they still hold.The description now follows the new template: the status line, a summary under What changed, the verdict, Flags and settings under Measurements, Must be tested, and Risks with Compatibility.
On the rebased head:
python -I -B tests/run_all.pyon macOS gives 507 passed, 48 failed, 39 skipped, the 48 failing the same way on main9e6f231don that machine; the back end builds for Linux (clang, on a Steam Deck) and for Windows (llvm-mingw 20261104, cross-built), 0 failed.View command line instructions
Manual merge helper
Use this merge commit message when completing the merge manually.
Checkout
From your project repository, check out a new branch and test the changes.