perf(vk): ask the start's cache first for stage libraries in play #1961
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!1961
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/play-cache-library-asks"
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?
Changes
A follow-up to #1772. With it, a stage library asked without compiling goes to the play generation first and to pcache second. The generation starts empty, so on NVIDIA every library ask in play was answered from the driver's own disk cache and copied in, though #1586's warm pass had already put the library in pcache. That is the slow path: on the route below, stage library links in play took 0.6 s before #1772 and 7.3 s after, about 2.2 ms a pipeline.
The comment on #1772 said the libraries would still go to the start's cache, where the warm pass put them. This makes the code do that: in
create_cached, a library asked without compiling now goes to pcache first, then the generation, and is never compiled there. A dispatch's compute ask keeps #1772's order, so pcache does not grow from those.RX_VK_PLAY_ASK_START_FIRST=0puts the libraries back on the old order.The second part is the save. pcache still grows a little in play, and
pipeline_cache_savewrites it whole whenever its size differs from the last write. On the route below that was 25 writes of the 2.4 GB file for 9 MB of growth. In play it is now written once it has grown 64 MB. The window's close does not write it (it saves the play generation only), so growth under 64 MB is written only by a forced save, Restart now or the prepare; the next start can still get those libraries from the driver's own cache. A run prints how much it grew, up to four times.RX_VK_PLAY_SAVE_START_MB=<n>sets the threshold, and 0 writes on any change as before.The play cache and cache save tests are updated for the new order and the threshold.
Testing
RTX 4070 Ti SUPER, driver 621.14, Windows 11, Ryzen 7 9800X3D.
Build: the Windows DLL builds on
fc375e9with this change.test_pipeline_cache_save,test_pipeline_play_cacheandtest_gpl_library_cachepass on Linux.Route: the scripted 10-minute first visit through five areas, from the same prepared folder each time (stage libraries warmed by the prepare), one run each. The runs were on
51de681with #1858's lines. Nothing increate_cachedorpipeline_cache_savehas changed on main since.51de681RX_VK_PLAY_CACHE=0The play files' own counts show the libraries landing in pcache: 4105 pipelines "from the start's cache" against 543 on
51de681, and 1120 "from the driver's cache" against 4711. The "compiled" count is the same in both (2222, 2226).Not tested: AMD and Intel, and a folder prepared before the warm pass.
Thanks, the numbers make a good case, and the library ask order looks right to me. A cold library ask now goes to pcache, then the generation, and is never compiled. A dispatch's compute ask and a worker's compiling ask keep #1772's order. The counters match the play file log, and the new checks in
pipeline_play_cache_test.cppcover each branch (pcache hit, a driver copy into pcache, generation-only, nowhere).One thing doesn't match the code. The description, the two new comments and the new log line all say pcache "is written at the close if it changed at all". The window's close doesn't do that.
mkwvk_close_askedcallspipeline_cache_close(), and that only runsplay_cache_save()(the generation). It never callspipeline_cache_save(true). vk_menu.cpp says so too: "as the window's own close does not force the pipeline cache". Only Restart now, the menu's restart path and the prepare force it. So in a normal session, pcache's in-play growth under 64 MB is never written. Thein-playtest passes because it callspipeline_cache_save(true)itself, as if that were the close.The cost is probably small. What pcache picks up in play is mostly libraries NVIDIA's own disk cache answered, and the next start can still get those from there. A folder prepared before the warm pass should get re-warmed through the warmed stamp anyway. Still, it's a change from
51de681: the old order put those driver copies into the generation, and from there into a play file. Either way works for me:CI: Linux, the Windows back-end build and actionlint pass. Windows Python fails
test_log_batch(a timing bound) andtest_recorder_sync, neither of which touches this code. Main's latest run has other unrelated failures. No conflicts with main increate_cachedorpipeline_cache_save, even though the branch is 54 commits behind.Nits: a negative
RX_VK_PLAY_SAVE_START_MBwraps to a huge threshold (never written in play). That's harmless, butstd::max(0LL, ...)would make it obvious. Also, AGENTS.md asks the description to open with why the PR is needed. Yours gets there in its second and third sentences, so it's close enough.@ -8197,12 +8219,26 @@ void pipeline_cache_save(bool force) {while (busy.load()) Sleep(1); // (the one under way, then this one)The window's close doesn't reach this.
mkwvk_close_asked→pipeline_cache_close()runs onlyplay_cache_save(), so nothing forces this save at the close. Only Restart now, the menu's restart and the prepare callpipeline_cache_save(true). Either add the write topipeline_cache_close()(if a full pcache write at the close is acceptable) or drop the "at the close" part here, at line 873 and in the log line below.Same here: "written at the close" isn't true for a normal window close (see above), so this line will mislead whoever reads the log.
Thanks. I kept the behaviour and fixed the wording, since a 2.4 GB write at every close is what the threshold was meant to avoid.
d67f855corrects the comments at 873 and 8230, the log line ("written once it is N MB larger, or by a forced save"), and the comments in both tests, and the description now says the close does not write pcache. I also took the nit:std::max(0LL, ...)onRX_VK_PLAY_SAVE_START_MB.test_pipeline_cache_save,test_pipeline_play_cacheandtest_gpl_library_cachepass, and the Windows DLL builds.Linux run with NVIDIA's driver: no regression, but on this route the play generation is never asked. RTX 4090, NVIDIA 615.78.08, i9-13900K, Arch Linux. I merged
d67f8558onto mainbdfe09c(it merges cleanly). Headless,RX_VK_GPL=1in all runs.Both builds started from a fresh folder: the pipeline caches and the driver's shader cache deleted, then
--prepare-shaderswithRX_VK_GPL=1(the warm pass loggedwarmed 86974 stage libraries). Then a scripted first visit: Kokiri Forest from a save, then the debug teleports to Hyrule Field, Kakariko, the Market, the Lost Woods and Death Mountain Trail, about 22 s each with a camera turn. Load average 1-6.bdfe09c(three runs)After the warm pass this route needs no library link worth counting, so the new ask order and the 64 MB threshold have nothing to act on here. The frame counts are within what two runs of main gave each other.
Not tested: Windows (where your numbers come from), AMD, Intel, a folder prepared before the warm pass, or a longer route.
Thanks for
d67f855. The wording is fixed everywhere I pointed at: the comments at 873 and 8230, the log line ("written once it is N MB larger, or by a forced save"), both tests' comments and the description now say the close doesn't write pcache. Keeping the behaviour is fine with me, for the reason you gave. Both earlier inline threads are resolved.One new problem, from the nit fix.
std::max(0LL, ...)breakstest_pipeline_cache_saveon Windows: the test builds withwindows.hin scope, and itsmaxmacro eatsstd::max(. CI (Windows part 2/2):pipeline_cache_save.inc:22:97: error: expected unqualified-id ... expanded from macro 'max'. That test passed on0e25963. The DLL build itself is fine (the Windows back-end job passes), but the check fails.std::max<long long>(0, ...)or(std::max)(0LL, ...)avoids the macro, the same way thestd::min<size_t>in the log line below already does. Sorry, that nit cost more than it saved.mooki000's Linux run (RTX 4090, after the warm pass) shows no regression, though the route never reaches a library link, so it doesn't test the new order either. Your Windows numbers are still the evidence for the gain.
Other CI: Linux Python fails
test_finish_outputandtest_linux_update(aNameErrorin the tests themselves), Windows part 1 fails those plustest_recorder_sync, and actionlint flags a shellcheck info inlinux-appimage.yml. None of those touch this PR's files. No conflicts with main.With the
maxfixed, I'd approve.@ -8197,12 +8219,26 @@ void pipeline_cache_save(bool force) {while (busy.load()) Sleep(1); // (the one under way, then this one)On Windows the test build has
windows.h'smaxmacro in scope, so this fails to compile intest_pipeline_cache_save(CI Windows part 2/2).std::max<long long>(0, atoll(...))or(std::max)(0LL, ...)avoids the macro.Fixed in
39d5d05withstd::max<long long>(0, ...). I checked that form compiles with a function-likemaxmacro defined after<algorithm>, the waywindows.hdefines it, and that the oldstd::max(0LL, ...)fails the same way as CI did.tests/test_pipeline_cache_save.pypasses on Linux.The blocker is fixed:
std::max<long long>(0, atoll(...))in39d5d05no longer goes through windows.h'smaxmacro, and the Windows Vulkan back end job passes. That commit is the only change sinced67f855.The red Python source checks fail in
tests/test_vcore_video_acquire.py(env_onundeclared in its fixture), a file this PR doesn't touch, so I don't hold it against the PR. The appimage failure is a runner/apt problem in the system packages step. Both look unrelated, but worth a re-run before merging.mooki000's NVIDIA/Linux report (play generation not asked on that route) is a separate finding about route coverage, not a regression from this change; it's for the author and maintainer to weigh. Nothing else from me.
github-sync referenced this pull request2026-11-12 06:22:54 +00:00