perf(build): the game is built for the player's own CPU (-march=native), keyed by the CPU clang resolves it to #524
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!524
Loading…
Reference in a new issue
No description provided.
Delete branch "HumanBean/Longshot:perf/native-cpu"
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
The game is compiled on each player's own PC, but always for the x86-64-v3 level (AVX2), so a newer CPU's extra instructions (AVX-512 on Zen 4/5 and some Intel CPUs) and its own tuning go unused. This builds it for the CPU it is built on, as issue 182 asks, without letting a changed CPU reuse objects made for another.
What changed
nx2/build.py, afterCPUandMTUNEare set: a CPU that would getx86-64-v3(and noRX_MARCH) is built with-march=nativeinstead. CPUs without AVX2 keepx86-64-v2/x86-64as before, andRX_MARCHstill decides when it is set.-march=nativenames no CPU, and object keys are made from the flags (flag_text/object_key). On its own it would keep the same keys on another CPU (a new CPU, the disk in another PC, an object store that outlives the CPU) and link objects made for instructions the CPU may lack, which is the no-AVX2 Xeon crash thatnx2/build.pycites as issue 363's crash again. Sonative_cpu()(new,nx2/host_cpu.py) asks clang what native is here (clang -###:-target-cpu,-tune-cpu, the-target-featurelist), and build.py adds-DLONGSHOT_NATIVE_CPU=<cpu>_<tune>_<sha1 of the features>to the flags, e.g.znver4_znver4_…on a Ryzen 9 7900X. Another CPU, or the same model with AVX-512 off, gets other keys and compiles again. The build log names it:build: the game is built for this PC's CPU (…).-tune-cpufollows-target-cpu), so the tuning setting goes:host_mtune()(its only rule wasznver2on a Steam Deck, which native gives the Deck's Zen 2 anyway) andRX_MTUNEare removed, and no-mtuneis passed (it would override native's).x86-64-v3. An explicitRX_MARCH=nativethat clang can't resolve stops the build, so it never produces keys that name no CPU. On Windows the query opens no console (CREATE_NO_WINDOW).x86-64-v3(scripts/linux/appimage.shsetsRX_MARCH), and so doesmake_game.py'scheck_cpu(it readshost_march(), which is unchanged).-ffp-contract=offstays, so float rounding is the same. No code path depends on AVX-512 (the only feature-gated code checks AVX2/FMA, which v3 already has).tests/test_cpu_target.py:test_steamdeck_mtunegoes withhost_mtune(); newNativeCpu: the name from clang's output (CPU, tune, features; feature order doesn't matter), another CPU or another feature set gives another name, no answer givesNone, and build.py's block (native only when the CPU chose v3 and noRX_MARCH, the name inCPU, the stop for an explicit native, no-mtuneleft in build.py).docs/development.md, theRX_MARCHrow (the new default, the key, native's tuning).Flags and settings
RX_MARCHnativeis now the default on a CPU with v3's features, keyed by the CPU clang findsnativeon v3 CPUs (wasx86-64-v3);x86-64-v2/x86-64belowRX_MARCH=x86-64-v3is the way backRX_MTUNEhost_mtune()'s Steam Deck rule: native tunes for the CPU itselfMeasurements
Not measured: the owner chose to open this without a measurement, as it changes only how the game is compiled. The expected gain is small (0-2 %: the lifted code is mostly scalar and at -O1, which clang doesn't vectorize; only the -O2 hot pieces could use AVX-512), and no number backs it yet. Build time should not change (the target level hardly changes clang's work); not measured either.
Testing
Tested: nothing was run on this PC: no build, no game, and no local checks (
tests/run_all.pyis left to CI).clang -march=native -###on this PC's clang (Ryzen 9 7900X, CachyOS) prints-target-cpu znver4and the AVX-512 features, which is the outputnative_cpu()reads.Not tested: a build with this change, so the clang query and the new keys have never run in a build; the game built at native, on any CPU; Windows (llvm-mingw's clang, the
nuldevice for-o); the AppImage's player build (its clang resolving native, the dry run inscripts/linux/check_player_build.sh).Needs other testers:
build: the game is built for this PC's CPU (<cpu>_…)in the log and the game starting (request to open)Screenshots
Nothing on screen.
Risk and rollback
RX_MARCH=x86-64-v3builds as before.x86-64-v3withoutznver2tuning (before: v3 tuned forznver2).Reviewer notes
nx2/build.py's block afterMTUNE, thennative_cpu()innx2/host_cpu.py. The resolved name is put in the flags as a define, not as-march=<cpu>, so the compiler still gets exactly what native gives it (the feature list, not only the CPU's name).Issues
Fixes #182
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above). (not run here: left to CI)third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.mainand passing here.tests/that reads changed source updated in this PR, not weakened.🤖 Generated with Claude Code
7318c149058c4b730864Pushed
8c4b7308: the tuning setting is removed. -march=native tunes for the CPU too (clang's tune CPU follows the target CPU), so host_mtune() (its one rule was znver2 on a Steam Deck, which native gives the Deck's Zen 2 anyway) and RX_MTUNE go, and no -mtune is passed. test_steamdeck_mtune goes with host_mtune(); NativeCpu checks that build.py has no -mtune left. Description updated. Still not built or run here; run_all is left to CI.WIP: perf(build): the game is built for the player's own CPU (-march=native), keyed by the CPU clang resolves it toto perf(build): the game is built for the player's own CPU (-march=native), keyed by the CPU clang resolves it todrcrow referenced this pull request2026-11-14 18:35:10 +00:00
Tested on Windows with a Ryzen 7 9800X3D (Zen 5): it builds, the game starts, and I measure no gain and no loss.
Hardware: Ryzen 7 9800X3D, RTX 5090, NVIDIA 621.24, 64 GB, Windows 11 26200.
Built: nightly-148 @
8b619764(nightly-147 plus #571, a docs change) with that release's Builder (LongshotBuilder.exe --portable --cli), twice from the same game files: as it is, and withRX_MARCH=x86-64-v3.The build. The clang query works with the Builder's llvm-mingw on Windows. The log has
build: the game is built for this PC's CPU (znver5_znver5_7c8212492d), then "compiled in 327s, 0 failed". The native game was started five times (one run of a minute, four of about four minutes): each time it loaded a save and ended by its own quit. No crash, no device lost.The measurement.
In every row the two builds differ by less than the three native runs differ from each other (up to 6% in fps, up to 16% in the 1% low). No frame over 50 ms in any measured segment.
One thing I would not call a loss without more runs: standing in the Market, native was the slower one in each of the three pairs (71.98 against 76.27, 75.04 against 77.20, 76.54 against 77.52 fps), with the gap shrinking each time.
Log lines, from a native run in the Market:
Not measured: with a window (these are the offscreen path's frame intervals), DLSS and frame generation, other areas, v3.0.0-rc.3, and build time (one build each: 327 s native, 296 s x86-64-v3, the second with a warm file cache).
The runs and this text were done with AI assistance (Claude).