perf(build): an update with nothing changed copies no unchanged exe into the game folder, and the finish says where its time went #631
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/tooling
area/upscaling
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
risk
high
risk
low
risk
medium
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!631
Loading…
Reference in a new issue
No description provided.
Delete branch "HumanBean/Longshot:perf/finish-skip-unchanged"
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, i7-9700K lab (btrfs, SATA SSD) · Needs: Windows: a no-change update's finish
Why
Every update copies the game's exe (about 490 MB) and image.bin into the game folder and swaps them in, even when the link produced the same bytes. The link is deterministic, so on an update with nothing changed this is pure waste: 4-8 s of the finish on the lab, and more on Windows, where the copy is a real write and an antivirus scans each new exe. The finish's time also showed as one number, so a player's record couldn't say where 70 s went.
What changed
The finish skips a file the last finish installed when it is still the installed one and the new file has the same bytes. It also times each of its parts, so the build-times table and
build_times.jsonshow where the finish's time goes.build:
installed_already()innx2/make_game.pydrops a file from staging when all of these hold:.longshot_installed.json(INSTALLED_NOTE) records it;The installed file is never read: comparing it with
filecmptook 10 s for the exe on a cold cache, slower than the copy. Hashing the freshly linked source takes about 0.4 s.build:
note_installed()writes the note after the swap, only for the files actually copied. A changed file is still staged as.newand swapped, every file is staged before any swap, andend_stale_gamesstill runs on Windows. A leftover<dst>.newof a skipped file is removed. If the note is missing or broken, the files are copied as before.build:
PhaseClock.part()splits the finish into copying, swap and runtimes, shader list, button prompts, pipeline lists/icon/stamps, build files deleted, and object store.docs:
docs/development.md, Build times: the parts and the note.tests:
tests/test_finish_output.py: five new checks:.newis removed, and a changed image is still copied;Also
tests/test_build_times.py:part().The button prompts, the largest part left (14-18 s on every packaged build), are left to #314, which keeps unchanged prompts in packaged builds. The two don't overlap.
Measurements
Verdict: Helps on every update with nothing changed: the copy and swap go from 4-8 s to about 0.5-1.5 s of hashing on the lab's btrfs (two interleaved runs each way). The finish total went 26 → 20 s and 19 → 15 s, with the button prompts' 14-18 s left unchanged. Windows should save more and is not measured.
Hardware: Linux, i7-9700K, btrfs on a SATA SSD (the copy is a clone there)
Scene: none (the build)
Method:
make_game.py --updatewith nothing changed, as a packaged builder (LONGSHOT_TOOLSset, game inbin/),--no-prepare-shaders. Interleaved B/A/B/A in one locked job after a warm-up that wrote the note. "Before" forces the copy path back on with a lab-only switch (it also wrote the note, +0.5 s, which main doesn't). The parts come from the new per-part timing.How to reproduce: two
--updateruns in a row with nothing changed; the second's "where the time went" table2b1d38c6(copy forced)6d053652, rebased)Two more runs on main with only the timing added: finish 24 s and 30 s, copy 3 s, swap 3 s and 8 s. The exe had the same hash over three no-change runs.
Where a no-change update's finish goes on main (lab):
Flags and settings
None
Testing
Tested: on the lab (Linux): the runs above.
tests/test_finish_output.py(18 OK, 3 Windows-only skipped),tests/test_build_times.py(20 OK) andtests/test_prompt_skip.py(41 OK, it reads the finish's source) pass. Nothing was run on the author's PC.Not tested: Windows; the full
tests/run_all.py.Must be tested:
Risks
.longshot_installed.json, sits in the game folder.Compatibility: saves,
longshot_options.ini, the shader and pipeline caches, the vk ABI and the builder's tools are untouched. The game folder gains.longshot_installed.json; a folder without it (every one before this PR) has all its files copied once more, as before.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). (not run: left to CI)third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
Assisted-by:/Co-Authored-By:trailers.tests/that reads changed source updated in this PR, not weakened.🤖 Generated with Claude Code
https://claude.ai/code/session_017vw8e3MfaADZobPGhWJk77
6d053652f8ddd371233dRebased on main @
dec8aa67(nowddd37123). One conflict innx2/make_game.py: main's removal of an oldwgpu_native.dll(#577) and this PR'snote_installedcall were added at the same spot; both kept,note_installedfirst. Added the Compatibility line under Risks.WIP: perf(build): an update with nothing changed copies no unchanged exe into the game folder, and the finish says where its time wentto perf(build): an update with nothing changed copies no unchanged exe into the game folder, and the finish says where its time went