feat(perf): opt-in performance statistics, sent from the launcher to the team's Grafana #206
No reviewers
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!206
Loading…
Reference in a new issue
No description provided.
Delete branch "gab9281/Longshot:feat/perf-metrics"
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
Players report stutter, cutscenes that play badly and uneven frame pacing. The team can't tell which GPUs, drivers, CPUs, systems, renderers or maps these come from. With this PR, a player can tick Send performance statistics in the launcher. It is off by default. The game then counts how its frames went on each map, and the launcher sends the counts to the team's Grafana, where each of those can be filtered on its own.
What changed
gpu/vk/perf_report.handperf_report.cpp. Withsend=1in the game folder'slongshot_perf.ini, for each map the summary holds:perf_pending/every 5 minutes and when the window closes (mkwvk_close_askedinvk_main.cpp, sinceExitProcessis_exiton Linux andatexitnever runs). One is also written, once, on a lost device (vk_replay.cppdevice_lost).vk_fps.cpp: while the summary is on, the FPS counter takes its Breakdown's timings and passes each frame toperf_frame()(add_frame: 6-16 ns). With the tick off, the only cost is one load ofperf_measureper frame.MkwVkHost::perf_info(API 22):hos_main.chos_perf_info;nn_video.ccounts each picture as the game takes it, so a movie still playing at a summary is counted;dav1d_av1.ccounts a decoder that didn't start.nx2/perf_report.py(below). The launchers that were inbuilder/left main in #171 and #181, so the tick itself goes to LongshotLauncher in a separate PR. That PR writessend=1(or deletes the file andperf_pending/when unticked) and, at its start, runs<python> -I nx2/perf_report.py <folder> --sendin a separate process, so Play, which closes the launcher at once, can't cut a send short. Until it lands,send=1inlongshot_perf.initurns it on by hand.perf_report.py:perf_sent/(the newest 48), so a player or a tester can read what went to the team;addresses.ini/addresses.pyhold the relay's address (perf_reports), out of the code.docs/performance-statistics.md(what is sent and never sent, how the parts fit, the cost), a README line, andlongshot_perf.iniindocs/development.md.tests/test_perf_report.cppcovers the summary's functions;tests/test_perf_report.py: the launcher side against a stand-in relay, the detached sender, and the wiring in the game (the pre-map names included);The relay and the Grafana dashboard are in Bean-Ops (
deploy/perf-relay,longshot-performance.json), already merged and deployed:perf_reportsinnx2/addresses.inipoints at it. The dashboard also shows a perf index (average fps, 1% low or smooth frames) by map and graphics card, as a table and in 3D.Flags and settings
longshot_perf.inisend=1(the launcher's Send performance statistics tick)HOS_FPS_MAX=<61-1000>(existing)fps_capis the cap in effect: this flag's when set, the menu's otherwiseMeasurements
main:
fbd42024(2026-11-13)this PR: feat/perf-metrics @
ad4bce73(rebased on that main). Since then: the review's fixes on the launcher's sender (nx2/perf_report.py, run after the game, not during it), and a rebase on main514591a3(#274 afterd9648863: docs only) that changed none of this PR's code. Main's 9 commits sincefbd42024change the renderer for both sides alike (#234, #260, #247); this PR's per-frame work is the same, so the comparison above still holdsHardware: NVIDIA GeForce RTX 3060 Laptop GPU (6 GB), NVIDIA 620.70.06, AMD Ryzen 7 6800H, 15 GB, CachyOS (Linux 7.3.3), KDE Wayland
Scene: the game's start, the intro and title (no save on this PC), 1920x1080, upscaler Off, no frame generation,
HOS_FPS_MAX=1000(uncapped)Method: 75 s per run, started as the launcher starts it (through CachyOS's
game-performance), withRX_VK_FRAME_LOG, ended with the control bridge's quit (the window's close path). Frames from 20 s on. Main, then this PR with the tick off, then on, repeated 3 times (interleaved). Each value is the median of the 3 runs.How to reproduce: two game folders built from the same game files, one at each commit;
HOS_FPS_MAX=1000;longshot_perf.iniwithsend=1for "on"; quit withpython -I scripts/longshot_ctl.py quit.fbd42024ad4bce73, tick offad4bce73, tick onReading: main itself spread from 148.6 to 153.9 fps across the rounds, and every run of this PR is inside that spread. Round by round, though, the tick off was behind main each time (0.17, 0.04 and 0.05 ms a frame; 1.5 to 3.5 fps), so a cost of about 1% with the tick off can't be ruled out on this PC; on a laptop a 1% gap is the size of the drift between rounds. The tick on was about the same as the tick off (5.75 against 5.73 ms; faster in round 3). The earlier set at
88404d20on main36a12f6f, same method, gave main 148.4, off 150.4, on 149.8 fps: there the tick off was ahead of main. A bigger PC (test requests below) can settle the 1%.Capped at 60 (the default cap, 3 rounds, same commits): all three were at 59.8-60.0 fps, with 1% lows of 41.6-42.1 (main), 41.5-44.2 (off) and 42.1-43.5 (on).
Testing
Tested:
RX_CPM=<the CPM cache> python -I -B tests/run_all.pyat65c63546(main @d9648863;b271368dis the same code on514591a3, docs only): 518 passed, 1 failed, 15 skipped (Windows only). The failure,tests/test_menu_i18n.py(a pt_BR text of a menu line main changed), fails on maind9648863too. Atad4bce73on mainfbd42024: 515 passed, 0 failed.ecfc377f), a run on the title: the summary's map is "Title and intro" (53.2 s).nx2/perf_report.pysent a real summary from these runs to a local copy of Bean-Ops' relay, which took it. Its/metricsshowed:NVIDIA 620.70, CPU,CachyOS, kernel7.3, upscalerOff, cap, map;perf_reports(as unofficial builds), were all taken, and show in Prometheus and on the Grafana dashboard.Not tested:
source=yet, so every summary is "not a release" for now, as in the crash report.Needs other testers:
send=1in the game folder'slongshot_perf.ini, play 10 minutes, close the game, then runpython -I nx2/perf_report.py <folder> --send. Expectperf_pending\to empty, and the same summaries inperf_sent\(what was sent: check thegpu,driver,cpu,osand the maps). Request T-ULGD (waiting for thetesting wantedlabel).perf_pending/every 5 minutes, each with the maps played since the one before, and after--sendthe same summaries inperf_sent/and the maps on the dashboard's map × graphics card panels. Request T-AAC7 (waiting for thetesting wantedlabel).gpuanddrivername the card and its driver (for exampleradv Mesa 25.2). Request T-WNBH (waiting for thetesting wantedlabel).Screenshots
None: the game shows nothing new, and the tick is in LongshotLauncher's PR.
Risk and rollback
add_frame(). See Measurements.docs/performance-statistics.mdlists what is sent. Unticking deletes what is waiting, and a game already running stops at its next summary.perf_reportsfromnx2/addresses.ini.Reviewer notes
gpu/vk/perf_report.cpp(what runs per frame and per summary), thennx2/perf_report.py(what leaves the PC).deploy/perf-relay/perf_relay.py).nx2/addresses.iniis also added by #141, with itscrash_*keys. Whichever merges second has an add/add conflict to resolve by keeping both sections' keys./code-review(high) on 36a12f6f..76bea1d7 found 10 issues. All are fixed (9abd14d5after the rebase; see that commit's message). The most important were a send cut short by Play, and the summary missing at a window close on Linux. A second/code-review(high) on the rebased branch (0c74253d..6702528f) found 10 more, all fixed in2c952130(its message lists them). The most important were hitches blamed on translation done by the jobs behind the game, the title's time counted on the last map, and a summary's version replaced by the folder's at sending. A third/code-review(high) on the copy of each sent summary (9d8d6cfa..ad4bce73) found 8, all fixed inedda0942(its message lists them).tests/test_perf_report.cpp: the main ones were a copy kept after the player unticked during a send, a copy cut short taken for what was sent, and pruning by the summaries' names (a wrong clock kept the wrong ones).Issues
None.
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.ad4bce73for the measurements, Windows with llvm-mingw atedda0942.)🤖 Generated with Claude Code
https://claude.ai/code/session_015KgSKoUqUvce5UXG89NBgi
88404d20bb6702528faf910b654999ac41919db9ac41919db92c952130619e6c4c61ffedda0942aeWIP: feat(perf): opt-in performance statistics, sent from the launcher to the team's Grafanato feat(perf): opt-in performance statistics, sent from the launcher to the team's Grafanaedda0942ae65c63546ca65c63546cab271368d0bView command line instructions
Checkout
From your project repository, check out a new branch and test the changes.