perf(build): a first build in under 10 minutes: what was measured, and a proposal (a clang-free cold tier) #362
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
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/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot#362
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
A player's first build (Build click to title) takes about 41 minutes on a Ryzen 5 5600 with 16 GB under Windows. Most of it is clang compiling the lifted C: 6,478 compiler-seconds, about 27 minutes at 4 compilers. Over the last day I measured what can take it down. All of this was on that PC, in local experiments; nothing has been pushed apart from the PRs linked below.
1. A clang-free cold tier (the big one)
Clang compiles only the hot list (the functions play actually runs). Every other function becomes threaded code: a list of calls to small helpers, one helper per statement form the lift emits, generated by the lifter and compiled on the player's PC. So nothing made from the game ships.
What it would take:
2. More compilers, smaller pieces (#31)
mem_needcounts a 4 MB piece at about 2.4 times its real peak, so with ~5 GB free the gate starts only about 5. Across 70 measured compiles,40 + 72 × MB of C + 550 × MB of the largest functionnever under-counted, and starts 8 with about 2.5 GB to spare.3. Splitting the giant functions
The giant cluster, code_023-025, is one function per file at up to 6 MB of C. Split at its labels into 8 KB pieces with a dispatcher, it compiles 1,462 → 559 compiler-seconds (0.38x), with its peak memory down from 2.26 to 0.59 GB. Equivalence: 1,200 random states on made-up functions in the lifter's shapes, and 160 states recorded in play for each of the two hottest giants, all with no differences. On those real states the split code is 2-3% faster per call. Seven 300 s game runs, split and unsplit alternated, showed no fps difference. This overlaps #38's fast float regions, which change the same emitter: the splitter would need to learn their shape.
4. Lighter compiler passes
Without -O1's module passes, ordinary chunks compile 21-34% faster for 3-5% more code; the inliner barely inlines lifted code anyway. On the giants, Machine LICM off saves 16-18%. Runtime speed with these isn't measured yet.
Already up as PRs
A lifter bug found on the way
#361: SDIV of the most negative number by -1 kills the game on x86 (found by the equivalence harness of section 1).
Happy to share any of the harnesses or numbers.
How big the hot list needs to be: one 100-minute play session
To size section 1's hot list, I recorded which lifted functions run in a real session: nightly-130 (
0caf0618) on Windows (Ryzen 5 5600, RX 6700 XT), played by a person for 100 minutes from boot, about 2 minutes to reach play. A small DLL marks each function the first time it runs. It's the coverage tool on the local branch bold/cover, not pushed. Compile costs use the build's own model (nx2/chunks.py, size + size²/350000), scaled to the 6,478 -O1 compiler-seconds of nightly-34's first build. The C sizes are from a recent main lift, not nightly-130's own.What it says:
The limits: one player, one route, one session. Later play and other routes will reach code this didn't. A shipped hot list would want several sessions merged, from boot to a few areas in.