mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
wsdbg: make a piped script able to wait, without extra processes
The REPL already reads a piped script over one connection, but there was no way
to wait *inside* it. Anything that needed a pause - let the game run a few
seconds, wait for a breakpoint that isn't the direct answer to the previous
line - had to be split across several wsdbg invocations, each paying for a
process, a TCP connection and a handshake. A polling loop built that way took
minutes per run and was the main reason driving headless felt slow.
Adds four directives that run inside the session:
:sleep <seconds> pause, still draining and printing messages
:wait <event> [timeout] block until that event arrives (e.g. cpu.stepping)
:echo <text> mark up the output
# comment ignored
and --compact, which prints one line per message (`<- event {json}`) instead of
pretty-printed JSON and drops the banner and prompt, so a shell can grep the
output instead of reassembling it. wsdbg now also exits non-zero if a :wait
timed out, so a script can be checked without parsing output at all.
:sleep deliberately keeps reading the socket rather than blocking on a timer -
otherwise broadcasts stop printing and the connection backs up behind them.
Together with cpu.runUntilTime this collapses a repro that needed a shell
driver, a polling loop and a JSON-reassembling filter into one file:
{"event":"broadcast.config.set","disallowed":{"logger":true,"input":true}}
cpu.runUntilTime us=1500000
:wait cpu.stepping 60
cpu.status
cpu.stepInto
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
This commit is contained in:
1 parent
ef426c8f82
commit
a402632445
2 files changed
+193
-16
No files matched your search
@@ -68,3 +68,40 @@ the script forever, so it gives up after `--sync-timeout` seconds (default 30) a
|
||||
echo 'cpu.getAllRegs'
|
||||
) | cargo run -- 12345 --sync
|
||||
```
|
||||
|
||||
### Script directives
|
||||
|
||||
A script often needs to wait for something that isn't a direct response to the line before it.
|
||||
Doing that by splitting the script across several `wsdbg` invocations costs a process, a TCP
|
||||
connection and a handshake per pause, which is slow enough to matter - a polling loop built that
|
||||
way took minutes per run. These run inside the one session instead:
|
||||
|
||||
| Directive | What it does |
|
||||
|---|---|
|
||||
| `:sleep <seconds>` | Wall-clock pause. Keeps draining and printing messages while it waits. |
|
||||
| `:wait <event> [timeout]` | Blocks until a message with that event name arrives. Exits non-zero if it never does. |
|
||||
| `:echo <text>` | Prints text, for marking up a script's output. |
|
||||
| `# comment` | Ignored. |
|
||||
|
||||
`--compact` prints one line per message (`<- event {json}`) instead of pretty-printed JSON, and
|
||||
drops the banner and prompt - much easier for a shell to grep. wsdbg exits non-zero if a `:wait`
|
||||
timed out, so a script can be checked without parsing its output at all.
|
||||
|
||||
A complete repro - boot, get several seconds in, step, inspect - in one file and one connection:
|
||||
|
||||
```
|
||||
# hand this to: wsdbg PORT --sync --compact < script.txt
|
||||
{"event":"broadcast.config.set","disallowed":{"logger":true,"input":true}}
|
||||
:echo === run to 1.5s of emulated time ===
|
||||
cpu.runUntilTime us=1500000
|
||||
:wait cpu.stepping 60
|
||||
cpu.status
|
||||
:echo === step twice ===
|
||||
cpu.stepInto
|
||||
cpu.stepInto
|
||||
:quit
|
||||
```
|
||||
|
||||
`cpu.runUntilTime` (see `docs/WebSocketDebugger.md`) is what makes that reproducible: it stops on
|
||||
the requested emulated microsecond, so the same script reaches the same instruction every run.
|
||||
Polling `cpu.status` in a loop instead lands somewhere different each time.
|
||||
Reference in new issue
Block a user