7 # include <mmsystem.h> // timeGetTime
8 # include <time.h> // localtime
12 # include <sys/time.h>
19 static char sys_timestring[128];
20 char *Sys_TimeString(const char *timeformat)
22 time_t mytime = time(NULL);
25 localtime_s(&mytm, &mytime);
26 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
28 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
30 return sys_timestring;
34 extern qboolean host_shuttingdown;
35 void Sys_Quit (int returnvalue)
37 if (COM_CheckParm("-profilegameonly"))
38 Sys_AllowProfiling(false);
39 host_shuttingdown = true;
44 #if defined(__linux__) || defined(__FreeBSD__)
51 void Sys_AllowProfiling(qboolean enable)
53 #if defined(__linux__) || defined(__FreeBSD__)
60 ===============================================================================
64 ===============================================================================
67 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
70 const dllfunction_t *func;
71 dllhandle_t dllhandle = 0;
79 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
82 for (func = fcts; func && func->name != NULL; func++)
83 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
88 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
97 for (func = fcts; func && func->name != NULL; func++)
98 *func->funcvariable = NULL;
100 // Try every possible name
101 Con_DPrintf ("Trying to load library...");
102 for (i = 0; dllnames[i] != NULL; i++)
104 Con_DPrintf (" \"%s\"", dllnames[i]);
106 dllhandle = LoadLibrary (dllnames[i]);
108 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
114 // see if the names can be loaded relative to the executable path
115 // (this is for Mac OSX which does not check next to the executable)
116 if (!dllhandle && strrchr(com_argv[0], '/'))
118 char path[MAX_OSPATH];
119 strlcpy(path, com_argv[0], sizeof(path));
120 strrchr(path, '/')[1] = 0;
121 for (i = 0; dllnames[i] != NULL; i++)
123 char temp[MAX_OSPATH];
124 strlcpy(temp, path, sizeof(temp));
125 strlcat(temp, dllnames[i], sizeof(temp));
126 Con_DPrintf (" \"%s\"", temp);
128 dllhandle = LoadLibrary (temp);
130 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
140 Con_DPrintf(" - failed.\n");
144 Con_DPrintf(" - loaded.\n");
146 // Get the function adresses
147 for (func = fcts; func && func->name != NULL; func++)
148 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
150 Con_DPrintf ("Missing function \"%s\" - broken library!\n", func->name);
151 Sys_UnloadLibrary (&dllhandle);
162 void Sys_UnloadLibrary (dllhandle_t* handle)
165 if (handle == NULL || *handle == NULL)
169 FreeLibrary (*handle);
178 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
182 return (void *)GetProcAddress (handle, name);
184 return (void *)dlsym (handle, name);
192 # define HAVE_TIMEGETTIME 1
193 # define HAVE_QUERYPERFORMANCECOUNTER 1
194 # define HAVE_Sleep 1
197 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
198 # define HAVE_CLOCKGETTIME 1
202 // FIXME improve this check, manpage hints to DST_NONE
203 # define HAVE_GETTIMEOFDAY 1
207 # define HAVE_SELECT 1
211 // FIXME improve this check
212 # define HAVE_USLEEP 1
215 // this one is referenced elsewhere
216 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."};
219 static cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
220 static cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
221 static cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
222 #if HAVE_QUERYPERFORMANCECOUNTER
223 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)"};
225 #if HAVE_CLOCKGETTIME
226 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)"};
229 static unsigned long benchmark_time;
231 void Sys_Init_Commands (void)
233 Cvar_RegisterVariable(&sys_debugsleep);
234 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
235 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
236 if(sys_supportsdlgetticks)
238 Cvar_RegisterVariable(&sys_usesdlgetticks);
239 Cvar_RegisterVariable(&sys_usesdldelay);
242 #if HAVE_QUERYPERFORMANCECOUNTER
243 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
245 #if HAVE_CLOCKGETTIME
246 Cvar_RegisterVariable(&sys_useclockgettime);
250 double Sys_DoubleTime(void)
252 static int first = true;
253 static double oldtime = 0.0, curtime = 0.0;
255 if(sys_usenoclockbutbenchmark.integer)
258 return ((double) benchmark_time) / 1e6;
261 // first all the OPTIONAL timers
263 #if HAVE_QUERYPERFORMANCECOUNTER
264 else if (sys_usequeryperformancecounter.integer)
266 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
267 // QueryPerformanceCounter
269 // Windows 95/98/ME/NT/2000/XP
271 // very accurate (CPU cycles)
273 // does not necessarily match realtime too well (tends to get faster and faster in win98)
274 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
276 LARGE_INTEGER PerformanceFreq;
277 LARGE_INTEGER PerformanceCount;
279 if (!QueryPerformanceFrequency (&PerformanceFreq))
281 Con_Printf ("No hardware timer available\n");
282 // fall back to timeGetTime
283 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
284 return Sys_DoubleTime();
286 QueryPerformanceCounter (&PerformanceCount);
289 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
290 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
292 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
293 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
298 #if HAVE_CLOCKGETTIME
299 else if (sys_useclockgettime.integer)
302 # ifdef CLOCK_MONOTONIC
304 clock_gettime(CLOCK_MONOTONIC, &ts);
307 clock_gettime(CLOCK_HIGHRES, &ts);
309 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
313 // now all the FALLBACK timers
314 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
316 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
318 #if HAVE_GETTIMEOFDAY
322 gettimeofday(&tp, NULL);
323 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
325 #elif HAVE_TIMEGETTIME
328 static int firsttimegettime = true;
331 // Windows 95/98/ME/NT/2000/XP
333 // reasonable accuracy (millisecond)
335 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
337 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
338 if (firsttimegettime)
341 firsttimegettime = false;
344 newtime = (double) timeGetTime () / 1000.0;
347 // fallback for using the SDL timer if no other timer is available
350 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
351 // this calls Sys_Error() if not linking against SDL
361 if (newtime < oldtime)
363 // warn if it's significant
364 if (newtime - oldtime < -0.01)
365 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
367 else if (newtime > oldtime + 1800)
369 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
372 curtime += newtime - oldtime;
378 void Sys_Sleep(int microseconds)
381 if(sys_usenoclockbutbenchmark.integer)
383 benchmark_time += microseconds;
386 if(sys_debugsleep.integer)
388 t = Sys_DoubleTime();
390 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
392 Sys_SDL_Delay(microseconds / 1000);
398 tv.tv_sec = microseconds / 1000000;
399 tv.tv_usec = microseconds % 1000000;
400 select(0, NULL, NULL, NULL, &tv);
405 usleep(microseconds);
410 Sleep(microseconds / 1000);
415 Sys_SDL_Delay(microseconds / 1000);
418 if(sys_debugsleep.integer)
420 t = Sys_DoubleTime() - t;
421 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
425 const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
427 const char *p = PATH;
431 while((q = strchr(p, ':')))
433 dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
434 if(FS_SysFileExists(buf))
438 if(!q) // none found - try the last item
440 dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
441 if(FS_SysFileExists(buf))
448 const char *Sys_FindExecutableName(void)
453 static char exenamebuf[MAX_OSPATH+1];
455 #if defined(__FreeBSD__)
456 n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
457 #elif defined(__linux__)
458 n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
460 if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
465 if(strchr(com_argv[0], '/'))
466 return com_argv[0]; // possibly a relative path
468 return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
472 void Sys_ProvideSelfFD(void)
476 com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);