mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 09:39:33 +01:00
Docs: Finding stalls with the frame profiler, and driving the app or a phone
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a935279cc4
commit
1b92700e54
3 files changed
+53
-1
No files matched your search
@@ -14,7 +14,7 @@ for it:
|
||||
| [docs/building.md](docs/building.md) | Build commands for every target (VS/MSBuild, CMake, UWP, legacy Android NDK, libretro), unit tests, pspautotests |
|
||||
| [docs/android-device-testing.md](docs/android-device-testing.md) | Running a build on a real Android device or a Quest over adb: installing the build you think you are, forcing activity recreates, measuring retained activities, VR, running the C++ unit tests on a device (`Tools/android_unittest.py`), starting the app with options (`Tools/android_run.py`), and the storage tests that exercise content URIs in the app (`Tools/android_storage_test.py`) |
|
||||
| [docs/android-todo.md](docs/android-todo.md) | Known Android Java issues found in reviews and not fixed yet - check before reviewing or changing that code |
|
||||
| [docs/debugging.md](docs/debugging.md) | Driving the WebSocket debugger and PPSSPPHeadless from a script, measuring a commercial game with headless, comparing binaries' speed (`Tools/headless_bench.py`), finding a game's hot JIT blocks (`--jit-profile`), breakpoint reliability per CPU backend, debugging a game that works on hardware, finding and hashing a game function (like its own `memcpy`) for `ReplaceTables` when hardware backends miss CPU writes to VRAM |
|
||||
| [docs/debugging.md](docs/debugging.md) | Driving the WebSocket debugger and PPSSPPHeadless from a script, measuring a commercial game with headless, comparing binaries' speed (`Tools/headless_bench.py`), finding a game's hot JIT blocks (`--jit-profile`), finding what makes frames stall (`--profile-log`, `Tools/profile_report.py`), breakpoint reliability per CPU backend, debugging a game that works on hardware, finding and hashing a game function (like its own `memcpy`) for `ReplaceTables` when hardware backends miss CPU writes to VRAM |
|
||||
| [docs/DebuggerThreading.md](docs/DebuggerThreading.md) | `Core_RunOnCPUThread` / `g_frameMutex` / shutdown-lock rules - required reading before touching debugger code |
|
||||
| [docs/HLEModules.md](docs/HLEModules.md) | Adding an HLE module or function, and the seven build files a new source file goes in |
|
||||
| [docs/translations.md](docs/translations.md) | Translating UI strings with Tools/langtool |
|
||||
|
||||
@@ -73,6 +73,32 @@ with `crop SHOT.png X,Y,W,H OUT.png` from a screenshot of the screen you want, a
|
||||
script: paths in a script are relative to it. A title screen left alone too long may start an attract
|
||||
demo, so don't wait for one without pressing.
|
||||
|
||||
A screen that only shows on some runs (a profile menu that needs a save, say) takes a branch: `until`
|
||||
also stops on any `--or REF@X,Y`, and a line `if REF --box X,Y : COMMAND ; COMMAND` runs the commands
|
||||
only when the screen shows the reference right then:
|
||||
|
||||
```
|
||||
until select_profile.png --box 100,14 --or create_profile.png@100,14 --press start --every 4
|
||||
if select_profile.png --box 100,14 : press cross
|
||||
if create_profile.png --box 100,14 : press cross ; wait 2 ; press cross
|
||||
```
|
||||
|
||||
### Driving the app, or a phone
|
||||
|
||||
`attach` makes a session of one PPSSPP that's already running with `--debugger=PORT` (default 45678),
|
||||
and the other commands then drive it. With `--adb`, that's the app on an Android device: the port is
|
||||
forwarded, and screenshots come from `screencap`, cut to the game's image (`--rect X,Y,W,H` in the
|
||||
device's pixels; `0,249,1080,612` on a Galaxy S8 in portrait) and scaled to 480x272, so a script and its
|
||||
references work the same on a phone as headless. `screencap` doesn't pause emulation, unlike the
|
||||
debugger's screenshot, which matters when the run is being profiled
|
||||
([debugging.md](debugging.md#finding-stalls-with-the-frame-profiler)).
|
||||
|
||||
```bash
|
||||
python Tools/android_run.py -- --debugger=45678 /sdcard/PSP/GAME.iso
|
||||
python3 Tools/adhoc_session.py attach --adb --rect 0,249,1080,612
|
||||
python3 Tools/adhoc_session.py run game_ingame.txt
|
||||
```
|
||||
|
||||
To see what a game does, `log sceNet debug` turns a log channel up, and `watch SECONDS NAME` collects
|
||||
each instance's log messages meanwhile into `NAME_N.log` (the debugger only sends log messages to
|
||||
clients that are connected). That works without `--log`, which slows the instances down enough to
|
||||
|
||||
@@ -295,6 +295,32 @@ shows as emitter and IR pass functions; profile 20 emulated seconds or more to s
|
||||
To compare two builds by where the time goes, profile one game at a time: several at once wait on each
|
||||
other's GPU work, which moves the shares.
|
||||
|
||||
### Finding stalls with the frame profiler
|
||||
|
||||
The frame profiler (`Common/Profiler/Profiler.h`) is compiled into everything but Android release
|
||||
builds, iOS, UWP and libretro, and off until something turns it on. `--profile-log=FILE` (app and
|
||||
headless) does, and writes a JSON line per frame with each thread's time per scope category, plus, for
|
||||
each slow frame, every scope of at least `--profile-span-ms` (default 1) that ended in it, with its
|
||||
label: which syscall, CoreTiming event, module file or pipeline. A frame is slow when it takes at least
|
||||
`--profile-hitch-ms` (default 25) and 1.5 times the median of the frames before it; each one also gets a
|
||||
`Profiler: Frame` line in the log naming its longest scopes.
|
||||
|
||||
```bash
|
||||
python Tools/profile_report.py profile.jsonl # summary, causes, the worst frames' scopes
|
||||
python Tools/profile_report.py profile.jsonl --frame 1234 # one frame
|
||||
```
|
||||
|
||||
The report only counts a slow frame as a stall if it fell behind the emulated time it covered (each
|
||||
vblank in it is 16.7 ms on a PSP): a game that doesn't flip for ten vblanks while loading shows a 167 ms
|
||||
frame on hardware too. It sums the stalls' time by thread and category from the exact per-frame totals,
|
||||
for the emulator thread and the render thread (a worker's time matters where something waits for it,
|
||||
which shows as `wait_*`), and lists the labelled scopes.
|
||||
|
||||
To find the stalls a player sees, measure a cold first run: `--shader-cache=false`, and 1x rendering
|
||||
resolution so the GPU matters less. Getting into the game from boot takes a script (see "Driving the
|
||||
app, or a phone" in [adhoc-multiplayer-testing.md](adhoc-multiplayer-testing.md)): pressing buttons at
|
||||
random gets stuck in profile and save menus.
|
||||
|
||||
## Debugging and breakpoint considerations
|
||||
|
||||
It might be worth trying the interpreter - all types of breakpoints are the most reliable with this CPU backend.
|
||||
|
||||
Reference in new issue
Block a user