From b80ff7f40c5f7d7907b066fa93b56103a5d8b875 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Mon, 12 Feb 2018 18:12:48 +0100 Subject: [PATCH] Implement a 'busywait' cvar to force the client and server to busy wait. Sleeping with Sys_Nanosleep() is fair enough but has the problem that we may get scheduled away and the hosts power management inteferes with our interal timings. While this wasn't a big issue on FreeBSD and Linux it let to serious timing issues in Windows. There're several reports in the net, apperently everything below 5ms is very inaccurate on Windows: * https://stackoverflow.com/questions/7827062/ \ is-there-a-windows-equivalent-of-nanosleep/7827446#7827446 * https://lists.gnu.org/archive/html/bug-gnulib/2010-04/msg00045.html --- src/common/frame.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/common/frame.c b/src/common/frame.c index 297c3bf8..f780c8ca 100644 --- a/src/common/frame.c +++ b/src/common/frame.c @@ -34,6 +34,7 @@ cvar_t *timescale; cvar_t *fixedtime; cvar_t *cl_maxfps; cvar_t *dedicated; +cvar_t *busywait; extern cvar_t *logfile_active; extern jmp_buf abortframe; /* an ERR_DROP occured, exit the entire frame */ @@ -129,6 +130,12 @@ Qcommon_Buildstring(void) printf("Architecture: %s\n", YQ2ARCH); } +#ifndef DEDICATED_ONLY +#define FRAMEDELAY 5 +#else +#define FRAMEDELAY 850 +#endif + void Qcommon_Mainloop(void) { @@ -139,12 +146,32 @@ Qcommon_Mainloop(void) while (1) { // Throttle the game a little bit. -#ifdef DEDICATED_ONLY - Sys_Nanosleep(850000); -#else - Sys_Nanosleep(5000); + if (busywait->value) + { + long long spintime = Sys_Microseconds(); + + while (1) + { +#if defined (__GNUC__) && (__i386 || __x86_64__) + /* Give the CPU a hint that this is a very tight + spinloop. One PAUSE instruction each loop is + enough to reduce power consumption and head + dispersion a lot, it's 95°C against 67°C on + a Kaby Lake laptop. */ + asm("pause"); #endif + if (Sys_Microseconds() - spintime >= FRAMEDELAY) + { + break; + } + } + } + else + { + Sys_Nanosleep(FRAMEDELAY * 1000); + } + newtime = Sys_Microseconds(); Qcommon_Frame(newtime - oldtime); oldtime = newtime; @@ -226,6 +253,7 @@ Qcommon_Init(int argc, char **argv) host_speeds = Cvar_Get("host_speeds", "0", 0); log_stats = Cvar_Get("log_stats", "0", 0); showtrace = Cvar_Get("showtrace", "0", 0); + busywait = Cvar_Get("busywait", "1", CVAR_ARCHIVE); #else dedicated = Cvar_Get("dedicated", "1", CVAR_NOSET); #endif