From 52afb9a677c0dd937fdf4f40b02be1611ea0bbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 20 Oct 2026 11:01:47 +0200 Subject: [PATCH] Headless: Count --timeout-emulated from when --state has loaded The game boots until the queued state is read, decompressed and applied, which takes a varying amount of host time, and those boot frames counted towards the timeout. So the same state ended on different frames depending on the host, for example while texture replacements competed for the IO threads. After the load the emulation is identical: syscall traces of Fate/Extra CCC with no texture pack, and with one loading slowly or instantly, are byte for byte the same. Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/debugging.md | 4 +++- headless/Headless.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/debugging.md b/docs/debugging.md index 67af0b05fe..c9c6f20fea 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -55,7 +55,9 @@ A working invocation, and the traps around it: - **The timeouts apply to the whole session**, not per test. `--timeout-wall=N` is real seconds and `--timeout-emulated=N` is emulated ones; both default to infinity, both can be set at once, and whichever - is reached first ends the run (`TIMEOUT` or `TIMEOUT (emulated)`). `--timeout` is the old name for + is reached first ends the run (`TIMEOUT` or `TIMEOUT (emulated)`). With `--state=`, emulated time counts + from when the state has loaded: until then the game boots for however long the load takes on the host, so + counting from boot made runs end on different frames. `--timeout` is the old name for `--timeout-wall`. As soon as you pass one it applies to your whole interactive debugging session too, so pass something huge (`--timeout-wall=100000`) or the process exits out from under you mid-session. The wall-clock check is skipped while `IsDebuggerPresent()`; the emulated one doesn't need that escape hatch, diff --git a/headless/Headless.cpp b/headless/Headless.cpp index 85c028e454..46bee0dd8b 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -547,7 +547,9 @@ static bool RunAutoTest(GraphicsContext *graphicsContext, CoreParameter &corePar const double emulatedNow = CoreTiming::GetGlobalTimeUs() / 1000000.0; const double emulatedStep = emulatedNow - lastEmulatedTime; lastEmulatedTime = emulatedNow; - if (emulatedStep > 0.0 && emulatedStep < emulatedStepLimit) { + // With --state, count from when the state lands. Until then the game boots, for however long + // reading and decompressing the state takes on the host, which made runs end on different frames. + if (emulatedStep > 0.0 && emulatedStep < emulatedStepLimit && !g_stateLoadPending) { emulatedElapsed += emulatedStep; }