perf(build): a host header edit compiles the files that read it, not the whole host #673
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!673
Loading…
Reference in a new issue
No description provided.
Delete branch "dyst/Longshot:perf/host-depfiles"
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: medium · Tested on: Windows 11, game-free checks · Needs: a timed build after a host header edit (Windows and Linux, any GPU)
Why
Every host object shares one header key, so an edit to any
host/*.hcompiles all ~55 host files again, even a comment in a header two of them include. The same key also leaves out gpu headers the host does read: it names onlyvk_api.h,dlss_math.handlongshot_env.hfromgpu/, whilehost/nn_libc.c,nvn_layout.candnvn_native.cincludegpu/render/rx_nvn.h(and through itnvn_api.h), andhost/display.cincludesgpu/render/rx.h. An edit to one of those keeps the host objects built with the old header.Builds on #37 (the renderer's half of the same change): review that first. This PR's own commit is the top one,
301586e8. It is the dev-loop proposal's A6 for the host (https://github.com/NotRexed/Hookshot/pull/2636). No Longshot issue fits (the tracker searched).What changed
The host's files are keyed the way #37 keys the renderer's own files: each is compiled with
-MD, and the next build names its object by the headers its depfile lists, so a host header edit compiles only the files that include it. A file with no depfile yet falls back to a wider key than before, one that now covers every header undergpu/the host could read.nx2/build.pymain(): the host jobs get-MD, an entry inDEPFILE_JOBS, andrenderer_deps(host_blob, host_roots, obj)as their headers.host_rootsishost/, the lifted headers (gen,rt64),gpu/, opus's include folder and zstd's.host_blob, for a file with no depfile, is the lifted headers, every header underhost/(withhost/posixon both systems), and every header undergpu/but eden's, sirit's andgpu/third_party's. FFmpeg's version, dav1d'sversion.hand zstd's API forprompts.candhos_zstd.cstay in the key as before.rekey_depfiles(jobs)in place ofrekey_depfiles(vk_jobs), after the compile and before the object store's share:jobsholds the back end's jobs too, and only the objects inDEPFILE_JOBSare keyed again.docs/development.md, Building, "What a build compiles again": the host's files are named by their depfiles too, and what the fallback covers for each.tests/test_host_depfiles.py(new): a host header compiles only its readers; a gpu header (rx_nvn.h) or a lifted header a file reads changes its key; the blob coversgpu/'s own headers andhost/posix's but not eden's, sirit's orgpu/third_party's; no depfile keeps the blob; and the wiring inmain().tests/test_renderer_depfiles.pyfollows the rekey overjobs.Measurements
Verdict: game-free: with this PR a host header edit changes the key of only the files that read it, and a gpu header a host file reads changes that file's key, where on #37's tree (and main) one key covers every host file and leaves those gpu headers out. The build times are not taken yet: they will be added here when the build under Must be tested is run, by me or by anyone who runs it first.
Hardware: Windows 11 Pro, Ryzen 9 3900X, 64 GB (the key needs no GPU)
Scene: none (a build change, game-free, no dump)
Method:
tests/test_host_depfiles.pyon a made-uphost/andgpu/tree (two host files with clang-style depfiles: one readshos.h,gpu/render/rx_nvn.hand a lifted header, the otherother.h), each edit against the key before it; main's and #37's host key read innx2/build.pymain()(host_deps). A key is the same or not, so there is nothing to take a median ofHow to reproduce:
python -I -B tests/test_host_depfiles.py; for the Before column,host_depsinnx2/build.pyat main @53f96d7853f96d78301586e8host/*.hone file readsgpu/render/rx_nvn.hnn_libc.c,nvn_layout.c,nvn_native.c)host/, the lifted ones andgpu/'s ownAgainst #37's
build.py(this PR's parent,6631b629) the wiring case fails: the host's jobs have no-MD, noDEPFILE_JOBSentry and norenderer_deps.Flags and settings
None: no switch, menu row, ini key or build flag changes for players (
-MDwrites a depfile beside each host object and changes nothing in it;flag_textleaves it out of the key, as #37 does).Testing
Tested:
tests/test_host_depfiles.py(6 cases) andtests/test_renderer_depfiles.py(11) pass, Windows 11.python -I -B tests/run_all.pyon this branch and on main @53f96d78, with the Builder's llvm-mingw clang (12 at once): this branch 542 passed, 18 failed, 35 skipped; main 539 passed, 19 failed, 35 skipped; the 18 fail on both (test_appimage_player_build, test_cpm_discovery, test_cpp_preflight, test_crash_dialog, test_env_on, test_fpx_sticky, test_lift_cleanup_error, test_linux_preflight, test_make_game_cache, test_make_game_prepare, test_missing_nup, test_oot_state_tap, test_readback_late, test_spawn_emit, test_tested_configurations, test_vk_pgo, test_vram_budget_row, test_walk_key), and main's nineteenth was test_dlss_sdk_cache, which fails on this PC only some of the time.tests/test_third_party_objects.py(#629) passes here too.Not tested: a real build: that clang writes the host's depfiles where
renderer_depsreads them (it does for the back end's, #37) and that the second build compiles only the includers; Linux; a build after one of the host's object-store fetches (an object from the store has no depfile, so it keeps the blob until it is compiled in that folder, as #37's do).Must be tested:
host/*.hfew files include and build again, expecting the build's@@file ... newlines to name only that header's includers,host/hos_main.candgpu/vk/vk_menu.cpp(both carry the version), where main compiles every host file; then editgpu/render/rx_nvn.hand build, expectingnn_libc.c,nvn_layout.c,nvn_native.c,hos_main.cand the renderer files that read it compiled again, where main compiles no host file. Then start the game once from a save, expecting it to reach play.host/posixfiles read their own headers too).Risks
What could break: a host file that reads a header outside
host_rootsand outside the extras (a header the build adds to its include path that neither the depfile's folders nor the old key covered) would keep an old object after that header changes. The roots cover every folder our host code includes from (host/, the lifted headers,gpu/, opus, zstd), the extras keep FFmpeg's and dav1d's version, and the system's headers are covered by the flags and the system headers' stamp, as for every object. An include added to a source changes the source, so its key changes anyway, and an object keyed by an old depfile is compiled again before it is trusted (DEPFILE_PENDING, #37).Turning it off: revert the commit (the host goes back to one key).
Compatibility: the host objects' keys change once (the blob is wider, and once a file has a depfile its key comes from it), so the next build compiles the host's ~55 files again: a minute or two, no translation. Saves, the options file, the shader and pipeline caches and the vk ABI are unchanged.
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.mainand passing here.tests/that reads changed source updated in this PR, not weakened.🤖 Generated with Claude Code
Ready for review and independent testing now: the measurement here is game-free (Measurements), and the timed builds under Must be tested are not run yet. I will run them and edit this description with the numbers when they are done; anyone with a build tree and their own game files is welcome to run them first and post the results here. Stacked on #37: its commits are the first four here, this PR's own is the top one,
64bd6b97.WIP: perf(build): a host header edit compiles the files that read it, not the whole hostto perf(build): a host header edit compiles the files that read it, not the whole host64bd6b9789301586e8d1Moved onto #37's rebase (main
53f96d78); this PR's own commit is now301586e8, unchanged. The full suite on this branch and on main again: no failure main doesn't have (Testing).View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.