WIP: feat(profile): HOS_HLE_STATS=1 counts HLE, host-call and NVN export calls #153
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/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!153
Loading…
Reference in a new issue
No description provided.
Delete branch "klimovich008/Longshot:feat/hle-call-counters"
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?
Port of NotRexed/Hookshot#2580 (draft there). It went through five gpt-6.1-sol review rounds, as that PR's description says. Each round's findings were fixed, and the last round found none. It has no GitHub reviews. The commits are the same, rebased onto Longshot
main, plus one that gives the test Longshot's file names.Why
The CPU profile's calls column came from a local patch that nobody else could rebuild. With this PR, anyone can count how often each HLE function, host call and NVN export runs, behind a switch that is off by default.
What changed
host/hos.h: theHLE(sym)macro counts entries in a tail-called arm (hos_hle_counted). With counting off, an entry pays one flag test and a branch.host/hos_hostcall.c: logshle:blocks about every 5 s, each stamped with the monotonic clock times it covers (begin_ns,end_ns). Host calls are counted ina64_call_missanda64_lookup_host. The host-call table is read under its lock and the counters are published atomically. If the report thread can't start, counting stays off.host/hos_main.c: turns counting on before the game starts.host/nvn_native.c: counts SDK export calls innvn2_dispatch.scripts/cpu_report.py(--calls):HOS_SAMPLE_ALLstacks;scripts/crit.py: names an HLE body that wasn't inlined after itsimp_<sym>entry.docs/development.md,docs/cpu-profile.md: the switch and how to collect a counting run. The profile's existing calls and per-call columns predate the clock-checked joins, so they are marked for regeneration. This PR does not recompute them.tests/test_hle_stats.py,tests/test_cpu_report.py: switching on and off, NVN exports, 32-bit wrap, concurrent callers with the reporter running, a failed thread start, the complete-block and window checks, and nine broken variants that must be caught.Flags and settings
HOS_HLE_STATS=1hle:call counts about every 5 s, with clock boundaries, forcpu_report.py --callsMeasurements
These are the measurements from the Hookshot PR, taken before the move to Longshot. They were not repeated on Longshot
main.Baseline: Hookshot
main@46780503. "This PR" is the same base with this PR's commits on top (the Hookshot branch). It was not remeasured on Longshotmain, which has changed since that base. The figures use the old 32:9 standard test and are not comparable with 16:9 numbers.main: Hookshot
46780503this PR: Hookshot
feat/hle-call-counterson46780503(the same commits as here)Hardware: AMD RX 9070 XT (Adrenalin 26.10.2), Ryzen 7 5700X3D, 64 GB, Windows 11
Scene: Hyrule Field, fast camera turn; 32:9 (
HOS_WINDOW_SIZE=2560x720,HOS_ASPECT=3.5556),HOS_FPS_MAX=240,HOS_FPS_LOG=1, no upscaler or frame generationMethod:
HOS_HLE_STATSunset in both arms.host/hos.h, but its code and data match the base byte for byte, apart from the version string.How to reproduce: the standard test with
HOS_HLE_STATSunset, alternating main and this PR.46780503feat/hle-call-counters, counting offThe per-pair difference in CPU ms a frame (this PR minus main) ranges from -4.5 to +2.4 ms. The mean is -0.31 and the median +0.10, and this PR is lower in 4 of the 8 pairs. No measurable cost.
One run with counting on (
HOS_HLE_STATS=1, same base and hardware) checked the reporting end to end, not the cost:hle:blocks were complete and timed, with no gaps between them.LockMutexandUnlockMutexcame out within 0.1% of each other, at about 12,930 calls a frame each.Testing
Tested:
main@39647e1a. The branch was then rebased onto6b7fa356, whose only change since (#148) is to the release script, its test and the README, none of which this PR touches:tests/test_hle_stats.pypasses with llvm-mingw clang++ and with g++ (MSYS2 UCRT64), andtests/test_cpu_report.pypasses.python -I -B tests/run_all.py(Windows, llvm-mingw 20261104): 466 passed, 4 failed, 69 skipped. The 4 also fail onmainon this PC:nx2/test_nup_paths.py,tests/test_check_third_party.py,tests/test_setup_runtime.py,tests/test_release.py.host/*.csyntax-compiles with llvm-mingw, except five that need third-party headers not installed here (dav1d, zstd, opus, ffmpeg). None of the five use the counters.Not tested:
cpu_report.py --callsreported the estimates as unavailable instead of guessing, which is the intended behaviour. The estimate path is covered by the test fixtures only.Needs other testers:
HOS_HLE_STATS=1logshle:blocks and the game runs normally, with no change when the switch is off (request to open).Screenshots
Nothing on screen.
Risk and rollback
The
HLE(sym)macro is on every HLE entry's path. With counting off, the only change is one flag test, and the measurement above shows no cost. With it on, an extra thread wakes about every 5 s and every counted call does an atomic increment. Reverting the commits removes it all.Reviewer notes
Start with
hos.h(the macro) andhos_hostcall.c(the counters and the report thread). The calls and per-call columns already indocs/cpu-profile.mdare left for a regenerated profile. This PR only marks them.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.🤖 Generated with Claude Code
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.