WIP: feat(build): LONGSHOT_OBJ_STORE, one object cache for every work folder #24
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
needs measurements
question
testing wanted
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!24
Loading…
Reference in a new issue
No description provided.
Delete branch "dyst/Longshot:feat/obj-store"
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?
Why
A worktree for a PR compiled the whole game again (about 600 files, most of a 30-minute build on Windows), although another work folder on the same PC had compiled the same sources with the same flags already. With
LONGSHOT_OBJ_STORE=<folder>, every work folder shares one object cache, so each object is compiled once on the PC.What changed
Opt-in: unset, nothing changes (
<work>/objcacheas before).object_cache()innx2/make_game.pypointsbuild.pyat<store>/objects/<toolchain stamp>:object_key), with no work folder's path in it;drop_stale_objects), so the store is split by that stamp (system_headers.txt) instead, one part per toolchain. Without a stamp, the work folder's own cache is used;build.py's runs get the folder (LONGSHOT_OBJ_CACHE, inbuild_envinmain), so the lift's environment, and its key, are unchanged.nx2/build.py'sOBJ_CACHEreads it, else<work>/objcache.cache_put()innx2/build.pyputs an object in whole or not at all: it links or copies the object to a temporary of its own (<key>.o.<pid>-<thread>.tmp), then renames it onto the key. Another build reading the store never finds part of one, a build killed meanwhile leaves no entry, and two builds putting the same object leave one. This also helps without a store: a copy that failed halfway used to leave a partial object in the cache, and raised.prune_object_cache,forget_failed_build, the system-header check) touch only<work>/objcache, never the store.adopt_objects(): the first build with the store puts the work folder's own objects into it, so switching it on compiles nothing again.seed_work()(in place ofmain's copy loop): the git-ignored lists a lift reads (hot_funcs.txt,hot_order.txt,longshot_pieces.prof,longshot.res,image/chunks.txt) come from<store>/seedwhen this checkout'swork/has none, so a new worktree's chunk boundaries and hot pieces match, and so do its objects' keys. The store's copy follows the checkout that has them.tests/test_obj_store.py(no compiler or game);tests/test_compiler_failure.py(the cutcache_put's names:shutil,threading) andtests/test_failed_compile_keeps_objects.py(the pinnedbuild.pyrun now takesbuild_env) updated.Not shared yet: the translation itself. A new worktree still translates the game (about 2:40, below); its C is the same, so its objects come from the store. The store is never pruned; it can be deleted at any time.
Flags and settings
LONGSHOT_OBJ_STORE<folder>: one compiled-object cache shared by every work folder (split by toolchain stamp), plus the lift's seed lists<work>/objcache, as before)LONGSHOT_OBJ_CACHEbuild.pykeeps its compiled objects in;make_game.pysets it forbuild.py's runs only (fromLONGSHOT_OBJ_STORE, else<work>/objcache)build.pyruns alone (<work>/objcache)make_game.py, not by hand)LONGSHOT_OBJtests/test_obj_store.pychecks thatlift_keynames noLONGSHOT_OBJ*variableRX_RELEASEmain()is rewritten as it was)Measurements
Measured on the GitHub version (NotRexed/Hookshot#2974), not yet on Longshot: this PR stays WIP until it is.
Hardware: RTX 3080 (NVIDIA 621.14), Ryzen 9 3900X, 64 GB, Windows 11; the Builder's tools (llvm-mingw), store and worktrees on one NTFS drive.
Method: the
mainfigure is what such a build took before this change, a full build on the same PC, not a run made beside these.Checks: every check that reads the changed files (76), through
run_all.pywith the Builder's tools, Windows: 71 pass.nx2/test_dll.py,test_driver_cache_folder,test_fpx_stickyandtest_linux_updatefail the same way onmainthere.test_dlss_sdk_cachefailed once in the parallel run and passes alone, twice (Defender holds the exe it compiles, now and then).Testing
Tested: the runs under Measurements (on the GitHub version) and the game-free checks this description names. Checked but not measured: the new worktree's game in play (Kokiri Forest, above; no
mainrun beside it).Not tested: Linux (the same code; hard links work there as on NTFS).
Needs other testers:
LONGSHOT_OBJ_STOREset, expecting none of the objects the first compiled compiled again (request to open)Screenshots
Nothing on screen.
Risk and rollback
Unset, nothing changes except
cache_put, which now renames a temporary onto the key: a failed put is skipped where it used to raise. With the store set, every work folder links the store's object for a key, so a bad object there reaches each of them, and a new worktree takes the seed lists another checkout left there; the store is never pruned, so it grows. UnsettingLONGSHOT_OBJ_STOREturns it off (the store folder can be deleted at any time); reverting the commit is enough.Reviewer notes
Carried over from NotRexed/Hookshot#2974 with the move to Longshot: the same change on Longshot's
main, with its rename applied. Its review and discussion are there.The dev-loop proposal's A10 (NotRexed/Hookshot#2636); hckrman101 offered it in the review and is away, so this takes it on.
tests/test_obj_store.pycovers: two work folders over one store compile the same sources throughbuild.py'scompile_onewith a stand-in compiler (the second compiles none, and its objects are the store's, the same file); a changed source compiles alone; a copy that stops halfway leaves no entry and no temporary (main'scache_putfails this); eight threads putting one object leave one; the store's part by stamp, and the fallbacks; adoption, and the seeds both ways; the lift's environment never gets the store's folder.The checks and the in-game runs above were done on the GitHub version; this branch is the same change with the rename applied (the same files and line counts). Forgejo runs no checks, and they were not run again here. Only the checks that read the changed files were run, not the whole
run_all.py.Issues
See NotRexed/Hookshot#2636 (A10).
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above).third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.docs/tested-configurations.mdfor each measured run.MKWVK_API_VERSIONbumped (gpu/vk/vk_api.h'sMkwVkHostorMkwVkRendererchanged).mainand passing here.tests/that reads changed source updated in this PR, not weakened.🤖 Generated with Claude Code
feat(build): LONGSHOT_OBJ_STORE, one object cache for every work folderto WIP: feat(build): LONGSHOT_OBJ_STORE, one object cache for every work folderBack to WIP under #48's process: this was carried over before the new template. Its description will be brought to the template and measured on Longshot (main against this PR, at named commits) when it's wanted for review; ask here if you'd like it sooner.
Description brought to Longshot's PR template (#48). Still WIP: its numbers are from the GitHub version, and it isn't rebased on current main; it gets measured on Longshot (main against this PR, at named commits) before it is marked ready. Also:
7c39708dputs back a space make_game.py's env line had lost.Description moved to the template's Testing section and whole checklist (#72): what was tested, what wasn't, and what needs other testers (their test requests to open while this is WIP).
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.