7 # include <mmsystem.h> // timeGetTime
8 # include <time.h> // localtime
10 #pragma comment(lib, "winmm.lib")
15 # include <sys/time.h>
22 static char sys_timestring[128];
23 char *Sys_TimeString(const char *timeformat)
25 time_t mytime = time(NULL);
28 localtime_s(&mytm, &mytime);
29 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
31 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
33 return sys_timestring;
37 extern qboolean host_shuttingdown;
38 void Sys_Quit (int returnvalue)
40 if (COM_CheckParm("-profilegameonly"))
41 Sys_AllowProfiling(false);
42 host_shuttingdown = true;
47 #if defined(__linux__) || defined(__FreeBSD__)
54 void Sys_AllowProfiling(qboolean enable)
56 #if defined(__linux__) || defined(__FreeBSD__)
63 ===============================================================================
67 ===============================================================================
70 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
73 const dllfunction_t *func;
74 dllhandle_t dllhandle = 0;
82 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
85 for (func = fcts; func && func->name != NULL; func++)
86 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
91 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
100 for (func = fcts; func && func->name != NULL; func++)
101 *func->funcvariable = NULL;
103 // Try every possible name
104 Con_DPrintf ("Trying to load library...");
105 for (i = 0; dllnames[i] != NULL; i++)
107 Con_DPrintf (" \"%s\"", dllnames[i]);
109 dllhandle = LoadLibrary (dllnames[i]);
111 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
117 // see if the names can be loaded relative to the executable path
118 // (this is for Mac OSX which does not check next to the executable)
119 if (!dllhandle && strrchr(com_argv[0], '/'))
121 char path[MAX_OSPATH];
122 strlcpy(path, com_argv[0], sizeof(path));
123 strrchr(path, '/')[1] = 0;
124 for (i = 0; dllnames[i] != NULL; i++)
126 char temp[MAX_OSPATH];
127 strlcpy(temp, path, sizeof(temp));
128 strlcat(temp, dllnames[i], sizeof(temp));
129 Con_DPrintf (" \"%s\"", temp);
131 dllhandle = LoadLibrary (temp);
133 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
143 Con_DPrintf(" - failed.\n");
147 Con_DPrintf(" - loaded.\n");
149 // Get the function adresses
150 for (func = fcts; func && func->name != NULL; func++)
151 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
153 Con_DPrintf ("Missing function \"%s\" - broken library!\n", func->name);
154 Sys_UnloadLibrary (&dllhandle);
165 void Sys_UnloadLibrary (dllhandle_t* handle)
168 if (handle == NULL || *handle == NULL)
172 FreeLibrary (*handle);
181 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
185 return (void *)GetProcAddress (handle, name);
187 return (void *)dlsym (handle, name);
195 # define HAVE_TIMEGETTIME 1
196 # define HAVE_QUERYPERFORMANCECOUNTER 1
197 # define HAVE_Sleep 1
200 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
201 # define HAVE_CLOCKGETTIME 1
205 // FIXME improve this check, manpage hints to DST_NONE
206 # define HAVE_GETTIMEOFDAY 1
210 # define HAVE_SELECT 1
214 // FIXME improve this check
215 # define HAVE_USLEEP 1
218 // this one is referenced elsewhere
219 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."};
222 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
223 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
224 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
225 #if HAVE_QUERYPERFORMANCECOUNTER
226 static 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)"};
228 #if HAVE_CLOCKGETTIME
229 static 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)"};
232 static unsigned long benchmark_time;
234 void Sys_Init_Commands (void)
236 Cvar_RegisterVariable(&sys_debugsleep);
237 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
238 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
239 if(sys_supportsdlgetticks)
241 Cvar_RegisterVariable(&sys_usesdlgetticks);
242 Cvar_RegisterVariable(&sys_usesdldelay);
245 #if HAVE_QUERYPERFORMANCECOUNTER
246 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
248 #if HAVE_CLOCKGETTIME
249 Cvar_RegisterVariable(&sys_useclockgettime);
253 double Sys_DoubleTime(void)
255 static int first = true;
256 static double oldtime = 0.0, curtime = 0.0;
258 if(sys_usenoclockbutbenchmark.integer)
261 return ((double) benchmark_time) / 1e6;
264 // first all the OPTIONAL timers
266 #if HAVE_QUERYPERFORMANCECOUNTER
267 else if (sys_usequeryperformancecounter.integer)
269 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
270 // QueryPerformanceCounter
272 // Windows 95/98/ME/NT/2000/XP
274 // very accurate (CPU cycles)
276 // does not necessarily match realtime too well (tends to get faster and faster in win98)
277 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
279 LARGE_INTEGER PerformanceFreq;
280 LARGE_INTEGER PerformanceCount;
282 if (!QueryPerformanceFrequency (&PerformanceFreq))
284 Con_Printf ("No hardware timer available\n");
285 // fall back to timeGetTime
286 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
287 return Sys_DoubleTime();
289 QueryPerformanceCounter (&PerformanceCount);
292 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
293 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
295 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
296 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
301 #if HAVE_CLOCKGETTIME
302 else if (sys_useclockgettime.integer)
305 # ifdef CLOCK_MONOTONIC
307 clock_gettime(CLOCK_MONOTONIC, &ts);
310 clock_gettime(CLOCK_HIGHRES, &ts);
312 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
316 // now all the FALLBACK timers
317 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
319 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
321 #if HAVE_GETTIMEOFDAY
325 gettimeofday(&tp, NULL);
326 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
328 #elif HAVE_TIMEGETTIME
331 static int firsttimegettime = true;
334 // Windows 95/98/ME/NT/2000/XP
336 // reasonable accuracy (millisecond)
338 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
340 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
341 if (firsttimegettime)
344 firsttimegettime = false;
347 newtime = (double) timeGetTime () / 1000.0;
350 // fallback for using the SDL timer if no other timer is available
353 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
354 // this calls Sys_Error() if not linking against SDL
364 if (newtime < oldtime)
366 // warn if it's significant
367 if (newtime - oldtime < -0.01)
368 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
370 else if (newtime > oldtime + 1800)
372 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
375 curtime += newtime - oldtime;
381 void Sys_Sleep(int microseconds)
384 if(sys_usenoclockbutbenchmark.integer)
386 benchmark_time += microseconds;
389 if(sys_debugsleep.integer)
391 t = Sys_DoubleTime();
393 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
395 Sys_SDL_Delay(microseconds / 1000);
401 tv.tv_sec = microseconds / 1000000;
402 tv.tv_usec = microseconds % 1000000;
403 select(0, NULL, NULL, NULL, &tv);
408 usleep(microseconds);
413 Sleep(microseconds / 1000);
418 Sys_SDL_Delay(microseconds / 1000);
421 if(sys_debugsleep.integer)
423 t = Sys_DoubleTime() - t;
424 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
428 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
430 const char *p = PATH;
434 while((q = strchr(p, ':')))
436 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
437 if(FS_SysFileExists(buf))
441 if(!q) // none found - try the last item
443 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
444 if(FS_SysFileExists(buf))
451 const char *Sys_FindExecutableName(void)
456 static char exenamebuf[MAX_OSPATH+1];
458 #if defined(__FreeBSD__)
459 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
460 #elif defined(__linux__)
461 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
463 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
468 if(strchr(com_argv[0], '/'))
469 return com_argv[0]; // possibly a relative path
471 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
475 void Sys_ProvideSelfFD(void)
479 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);