From 5025b7cdf88e91dbba6ca0f8b3334bade41b2a55 Mon Sep 17 00:00:00 2001 From: Shokunin <30949000+tetrisgm@users.noreply.github.com> Date: Wed, 21 Oct 2026 08:39:22 -0700 Subject: [PATCH] Retain the completion clock in bounded production replay --- runtime/src/main.cpp | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index 687daeaa..55dbacd5 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -4811,29 +4811,44 @@ static uint64_t g_frame_report_wait_ticks = 0; /* offline pacer waits */ /* Explicit, file-driven production benchmark. No debug server, sampler or * per-instruction tracing is needed. Capture outside the measured interval; * export the existing frame ring before requesting the normal quit path. */ +struct ReplayWorkSample { uint64_t frame, guest, pacer, queue, completed; }; +static std::vector g_replay_work; +static void input_replay_frame_completed(uint64_t frame) { + if (g_replay_work.empty()) return; + auto &sample = g_replay_work[frame % HOST_FRAME_STAMP_CAP]; + if (sample.frame == frame) sample.completed = host_clock_us(); +} static void input_replay_frontend_tick(uint64_t frame) { uint64_t relative = input_replay_frame(frame); if (relative == UINT64_MAX) return; - static uint64_t stop = 0; + static uint64_t stop = 0, seconds = 0, deadline_us = 0; static const char *report = nullptr, *shots = nullptr; static bool initialized = false, finished = false; - struct WorkSample { uint64_t frame, guest, pacer, queue; }; - static std::vector work; + auto &work = g_replay_work; if (!initialized) { if (const char *e = std::getenv("PSX_INPUT_REPLAY_STOP")) stop = std::strtoull(e, nullptr, 10); + if (const char *e = std::getenv("PSX_INPUT_REPLAY_SECONDS")) { + char *end = nullptr; + seconds = std::strtoull(e, &end, 10); + if (!seconds || seconds > 60 || !end || *end || stop) + throw std::runtime_error("replay seconds must be 1..60, without replay stop"); + } report = std::getenv("PSX_INPUT_REPLAY_REPORT"); shots = std::getenv("PSX_INPUT_REPLAY_SHOTS"); if (report && *report) work.resize(HOST_FRAME_STAMP_CAP); initialized = true; } if (finished) return; + if (seconds && relative >= 900 && !deadline_us) + deadline_us = host_clock_us() + seconds * 1000000; + if (deadline_us && !stop && host_clock_us() >= deadline_us) stop = relative; if (report && *report) { RtStats rs{}; rt_get_stats(&rs); const uint64_t hz = SDL_GetPerformanceFrequency(); work[frame % HOST_FRAME_STAMP_CAP] = {frame, g_runtime_perf.guest_work_ticks * 1000000 / hz, g_runtime_perf.pacer_ticks * 1000000 / hz, - (rs.backpressure_ns + rs.ring_full_ns + rs.acquire_ns) / 1000}; + (rs.backpressure_ns + rs.ring_full_ns + rs.acquire_ns) / 1000, 0}; } if (shots && (relative == 800 || (stop > 0 && relative == stop+2))) { char path[512]; @@ -4845,7 +4860,7 @@ static void input_replay_frontend_tick(uint64_t frame) { if (report && *report) { FILE *f = std::fopen(report, "w"); if (!f) throw std::runtime_error("cannot write input replay frame report"); - std::fputs("frame,relative,us,interp,checks,faults,io_kb,guest_us,pacer_us,queue_us\n", f); + std::fputs("frame,relative,us,interp,checks,faults,io_kb,guest_us,pacer_us,queue_us,completed_us\n", f); uint64_t total = host_frame_stamp_total(); uint64_t first = total > HOST_FRAME_STAMP_CAP ? total-HOST_FRAME_STAMP_CAP : 0; for (uint64_t i=first; i