7 # include <mmsystem.h> // timeGetTime
11 # include <sys/time.h>
18 static char sys_timestring[128];
19 char *Sys_TimeString(const char *timeformat)
21 time_t mytime = time(NULL);
24 localtime_s(&mytm, &mytime);
25 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
27 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
29 return sys_timestring;
33 extern qboolean host_shuttingdown;
34 void Sys_Quit (int returnvalue)
36 if (COM_CheckParm("-profilegameonly"))
37 Sys_AllowProfiling(false);
38 host_shuttingdown = true;
43 #if defined(__linux__) || defined(__FreeBSD__)
50 void Sys_AllowProfiling(qboolean enable)
52 #if defined(__linux__) || defined(__FreeBSD__)
59 ===============================================================================
63 ===============================================================================
66 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
69 const dllfunction_t *func;
70 dllhandle_t dllhandle = 0;
78 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
81 for (func = fcts; func && func->name != NULL; func++)
82 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
87 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
96 for (func = fcts; func && func->name != NULL; func++)
97 *func->funcvariable = NULL;
99 // Try every possible name
100 Con_DPrintf ("Trying to load library...");
101 for (i = 0; dllnames[i] != NULL; i++)
103 Con_DPrintf (" \"%s\"", dllnames[i]);
105 dllhandle = LoadLibrary (dllnames[i]);
107 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
113 // see if the names can be loaded relative to the executable path
114 // (this is for Mac OSX which does not check next to the executable)
115 if (!dllhandle && strrchr(com_argv[0], '/'))
117 char path[MAX_OSPATH];
118 strlcpy(path, com_argv[0], sizeof(path));
119 strrchr(path, '/')[1] = 0;
120 for (i = 0; dllnames[i] != NULL; i++)
122 char temp[MAX_OSPATH];
123 strlcpy(temp, path, sizeof(temp));
124 strlcat(temp, dllnames[i], sizeof(temp));
125 Con_DPrintf (" \"%s\"", temp);
127 dllhandle = LoadLibrary (temp);
129 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
139 Con_DPrintf(" - failed.\n");
143 Con_DPrintf(" - loaded.\n");
145 // Get the function adresses
146 for (func = fcts; func && func->name != NULL; func++)
147 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
149 Con_DPrintf ("Missing function \"%s\" - broken library!\n", func->name);
150 Sys_UnloadLibrary (&dllhandle);
161 void Sys_UnloadLibrary (dllhandle_t* handle)
164 if (handle == NULL || *handle == NULL)
168 FreeLibrary (*handle);
177 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
181 return (void *)GetProcAddress (handle, name);
183 return (void *)dlsym (handle, name);
191 # define HAVE_TIMEGETTIME 1
192 # define HAVE_QUERYPERFORMANCECOUNTER 1
193 # define HAVE_Sleep 1
196 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
197 # define HAVE_CLOCKGETTIME 1
201 // FIXME improve this check, manpage hints to DST_NONE
202 # define HAVE_GETTIMEOFDAY 1
206 # define HAVE_SELECT 1
210 // FIXME improve this check
211 # define HAVE_USLEEP 1
214 cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
215 cvar_t sys_usenoclockbutbenchmark = {CVAR_SAVE, "sys_usenoclockbutbenchmark", "0", "don't use ANY real timing, and simulate a clock (for benchmarking); the game then runs as fast as possible. Run a QC mod with bots that does some stuff, then does a quit at the end, to benchmark a server. NEVER do this on a public server."};
216 cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
217 cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
218 #if HAVE_QUERYPERFORMANCECOUNTER
219 cvar_t sys_usequeryperformancecounter = {CVAR_SAVE, "sys_usequeryperformancecounter", "0", "use windows QueryPerformanceCounter timer (which has issues on multicore/multiprocessor machines and processors which are designed to conserve power) for timing rather than timeGetTime function (which has issues on some motherboards)"};
221 #if HAVE_CLOCKGETTIME
222 cvar_t sys_useclockgettime = {CVAR_SAVE, "sys_useclockgettime", "0", "use POSIX clock_gettime function (which has issues if the system clock speed is far off, as it can't get fixed by NTP) for timing rather than gettimeofday (which has issues if the system time is stepped by ntpdate, or apparently on some Xen installations)"};
225 static unsigned long benchmark_time;
227 void Sys_Init_Commands (void)
229 Cvar_RegisterVariable(&sys_debugsleep);
230 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
231 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
232 if(sys_supportsdlgetticks)
234 Cvar_RegisterVariable(&sys_usesdlgetticks);
235 Cvar_RegisterVariable(&sys_usesdldelay);
238 #if HAVE_QUERYPERFORMANCECOUNTER
239 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
241 #if HAVE_CLOCKGETTIME
242 Cvar_RegisterVariable(&sys_useclockgettime);
246 double Sys_DoubleTime(void)
248 static int first = true;
249 static double oldtime = 0.0, curtime = 0.0;
251 if(sys_usenoclockbutbenchmark.integer)
254 return ((double) benchmark_time) / 1e6;
257 // first all the OPTIONAL timers
259 #if HAVE_QUERYPERFORMANCECOUNTER
260 else if (sys_usequeryperformancecounter.integer)
262 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
263 // QueryPerformanceCounter
265 // Windows 95/98/ME/NT/2000/XP
267 // very accurate (CPU cycles)
269 // does not necessarily match realtime too well (tends to get faster and faster in win98)
270 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
272 LARGE_INTEGER PerformanceFreq;
273 LARGE_INTEGER PerformanceCount;
275 if (!QueryPerformanceFrequency (&PerformanceFreq))
277 Con_Printf ("No hardware timer available\n");
278 // fall back to timeGetTime
279 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
280 return Sys_DoubleTime();
282 QueryPerformanceCounter (&PerformanceCount);
285 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
286 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
288 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
289 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
294 #if HAVE_CLOCKGETTIME
295 else if (sys_useclockgettime.integer)
298 # ifdef CLOCK_MONOTONIC
300 clock_gettime(CLOCK_MONOTONIC, &ts);
303 clock_gettime(CLOCK_HIGHRES, &ts);
305 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
309 // now all the FALLBACK timers
310 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
312 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
314 #if HAVE_GETTIMEOFDAY
318 gettimeofday(&tp, NULL);
319 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
321 #elif HAVE_TIMEGETTIME
324 static int firsttimegettime = true;
327 // Windows 95/98/ME/NT/2000/XP
329 // reasonable accuracy (millisecond)
331 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
333 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
334 if (firsttimegettime)
337 firsttimegettime = false;
340 newtime = (double) timeGetTime () / 1000.0;
343 // fallback for using the SDL timer if no other timer is available
346 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
347 // this calls Sys_Error() if not linking against SDL
357 if (newtime < oldtime)
359 // warn if it's significant
360 if (newtime - oldtime < -0.01)
361 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
363 else if (newtime > oldtime + 1800)
365 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
368 curtime += newtime - oldtime;
374 void Sys_Sleep(int microseconds)
377 if(sys_usenoclockbutbenchmark.integer)
379 benchmark_time += microseconds;
382 if(sys_debugsleep.integer)
384 t = Sys_DoubleTime();
386 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
388 Sys_SDL_Delay(microseconds / 1000);
394 tv.tv_sec = microseconds / 1000000;
395 tv.tv_usec = microseconds % 1000000;
396 select(0, NULL, NULL, NULL, &tv);
401 usleep(microseconds);
406 Sleep(microseconds / 1000);
411 Sys_SDL_Delay(microseconds / 1000);
414 if(sys_debugsleep.integer)
416 t = Sys_DoubleTime() - t;
417 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));