diff --git a/runtime/src/gpu_gl_renderer.c b/runtime/src/gpu_gl_renderer.c index ff7bfe3a..6e3c3741 100644 --- a/runtime/src/gpu_gl_renderer.c +++ b/runtime/src/gpu_gl_renderer.c @@ -68,6 +68,7 @@ #include "gpu_sw_renderer.h" #include "gpu_gl_renderer.h" #include "host_osd.h" +#include "host_time.h" #include "latency_ring.h" #include "psx_sdl.h" @@ -3808,7 +3809,7 @@ static int interp_thread_main(void *opaque) { uint64_t remain = deadline - now; uint32_t ms = (uint32_t)((remain * 1000u) / (freq ? freq : 1u)); - if (ms > 1) SDL_Delay(ms - 1); + if (ms > 1) psx_host_sleep_ms(ms - 1); } while (SDL_GetPerformanceCounter() < deadline) {} now = SDL_GetPerformanceCounter(); @@ -3832,7 +3833,7 @@ static int interp_thread_main(void *opaque) { diag_swaps = s_interp_swaps; } SDL_UnlockMutex(s_interp_mutex); - if (uncapped && !presented) SDL_Delay(1); + if (uncapped && !presented) psx_host_sleep_ms(1); } p_glBindVertexArray(0); SDL_GL_MakeCurrent(s_win, NULL); diff --git a/runtime/src/psx_lobby_client.c b/runtime/src/psx_lobby_client.c index 9b4e208f..83cbfad7 100644 --- a/runtime/src/psx_lobby_client.c +++ b/runtime/src/psx_lobby_client.c @@ -106,11 +106,12 @@ void psx_lobby_clear_launch_pending(void) {} #include "recomp_net/ice_rtt.h" #include "recomp_net/lan_beacon.h" #include "recomp_net/rtt_probe.h" +#include "host_time.h" #if defined(_WIN32) #include #include -#include /* GetTickCount64 for lobby_mono_ms */ +#include #define close closesocket #else #include @@ -203,16 +204,8 @@ enum { static uint64_t lobby_mono_ms(void) { - /* Win32 first: MinGW's CLOCK_MONOTONIC needs winpthread at link time. */ -#if defined(_WIN32) - return (uint64_t)GetTickCount64(); -#elif defined(CLOCK_MONOTONIC) - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - return (uint64_t)ts.tv_sec * 1000ull + - (uint64_t)ts.tv_nsec / 1000000ull; -#endif - return (uint64_t)time(NULL) * 1000ull; + /* QPC / CLOCK_MONOTONIC — not GetTickCount64 (coarse Win↔Linux lobby RTT). */ + return psx_host_mono_ms(); } /* Defined later; used by waiting-room RTT signal handling. */ diff --git a/runtime/src/psx_netplay_sched.c b/runtime/src/psx_netplay_sched.c index 019c6f12..753b7f72 100644 --- a/runtime/src/psx_netplay_sched.c +++ b/runtime/src/psx_netplay_sched.c @@ -910,6 +910,85 @@ static void np_admit_maybe_log_stats(uint32_t now) fflush(stderr); } +/* BattleShip-style Win↔Linux cadence triage. PSX_NETPLAY_CROSS_OS_PACING_DIAG=1 */ +static int np_cross_os_diag_enabled(void) +{ + static int s = -1; + if (s < 0) { + const char *e = getenv("PSX_NETPLAY_CROSS_OS_PACING_DIAG"); + s = (e && e[0] == '1' && e[1] == '\0') ? 1 : 0; + } + return s; +} + +static const char *np_cross_os_platform(void) +{ +#if defined(_WIN32) + return "windows"; +#elif defined(__APPLE__) + return "darwin"; +#elif defined(__linux__) + return "linux"; +#else + return "other"; +#endif +} + +static void np_cross_os_maybe_log(uint32_t now, uint32_t sim, + const RNetSessionStats *st) +{ + static uint32_t s_last_ms; + static uint32_t s_gap1_0; + static uint32_t s_gap2_0; + static uint32_t s_gap3_0; + static uint32_t s_grace_0; + static uint32_t s_tip_stale_0; + static uint32_t s_runway_0; + static uint32_t s_cushion_wait_0; + static uint32_t s_debt_added_0; + const char *stall; + uint32_t tip_age; + + if (!np_cross_os_diag_enabled() || !st) + return; + if (s_last_ms != 0u && (uint32_t)(now - s_last_ms) < 1000u) + return; + s_last_ms = now ? now : 1u; + stall = np_sched_admit_stall_tag(); + tip_age = np_tip_age_ms(); + fprintf(stderr, + "psxrecomp: cross_os_pacing platform=%s slot=%d sim=%u " + "hr=%u remote_lead=%d D=%d P=%d tip_ema=%u tip_age=%u " + "debt_ms=%u d_debt_added=%u " + "d_invent_gap1=%u gap2=%u gap3+=%u grace=%u tip_stale=%u " + "runway=%u cushion_wait=%u stall=%s freeze=%d cushion=%d\n", + np_cross_os_platform(), sched_local_slot(), (unsigned)sim, + (unsigned)st->highest_remote_wire, st->remote_lead, sched_delay(), + g_sb.input_prediction ? *g_sb.input_prediction : 0, + (unsigned)g_tip_arrival_ema_ms, + tip_age == 0xffffffffu ? 0u : (unsigned)tip_age, + (unsigned)g_ts_debt_ms, + (unsigned)(g_ts_debt_added_ms - s_debt_added_0), + (unsigned)(g_admit_invent_gap1 - s_gap1_0), + (unsigned)(g_admit_invent_gap2 - s_gap2_0), + (unsigned)(g_admit_invent_gap3p - s_gap3_0), + (unsigned)(g_admit_gap1_grace - s_grace_0), + (unsigned)(g_admit_invent_tip_stale - s_tip_stale_0), + (unsigned)(g_admit_invent_runway_empty - s_runway_0), + (unsigned)(g_admit_cushion_wait - s_cushion_wait_0), + (stall && stall[0]) ? stall : "-", g_pcap_frozen, + g_cushion_rebuild); + fflush(stderr); + s_gap1_0 = g_admit_invent_gap1; + s_gap2_0 = g_admit_invent_gap2; + s_gap3_0 = g_admit_invent_gap3p; + s_grace_0 = g_admit_gap1_grace; + s_tip_stale_0 = g_admit_invent_tip_stale; + s_runway_0 = g_admit_invent_runway_empty; + s_cushion_wait_0 = g_admit_cushion_wait; + s_debt_added_0 = g_ts_debt_added_ms; +} + /* ------------------------------------------------------------------ */ /* §56 equilibrium scorecard (per-window deltas, ~30 s) */ /* */ @@ -1446,6 +1525,7 @@ int np_sched_pre_admit(uint32_t sim, uint32_t wire, const RNetSessionStats *st) * source). Never engages during episodes/lockstep — only live admits. */ if (!psx_netplay_rb_active() && np_timesync_throttle(wire)) { np_sched_set_admit_stall("timesync_pace"); + np_cross_os_maybe_log(sched_mono_ms(), sim, st); return 1; } @@ -1454,6 +1534,7 @@ int np_sched_pre_admit(uint32_t sim, uint32_t wire, const RNetSessionStats *st) np_admit_log_runway(now, sim, wire, st->highest_remote_wire, st->remote_lead); np_phase_ctrl_maybe_log(now, sim, st->remote_lead); + np_cross_os_maybe_log(now, sim, st); np_auto_delay_tick(now); np_scorecard_sample(now, sim, wire, st); @@ -1778,9 +1859,20 @@ int np_sched_on_remote_miss(int slot, uint32_t sim, uint32_t wire, void np_sched_post_admit(int any_invent) { + RNetSession *s; + RNetSessionStats st; + uint32_t now; + np_sched_clear_admit_stall(); /* Remote caught up or we invented inside P — leave freeze if armed. */ np_pcap_freeze_exit(); + now = sched_mono_ms(); if (any_invent) - np_admit_maybe_log_stats(sched_mono_ms()); + np_admit_maybe_log_stats(now); + s = sched_session(); + if (s) { + memset(&st, 0, sizeof(st)); + rnet_session_get_stats(s, &st); + np_cross_os_maybe_log(now, st.sim_tick, &st); + } }