10 # include <sys/time.h>
17 static char sys_timestring[128];
18 char *Sys_TimeString(const char *timeformat)
20 time_t mytime = time(NULL);
23 localtime_s(&mytm, &mytime);
24 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
26 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
28 return sys_timestring;
32 extern qboolean host_shuttingdown;
33 void Sys_Quit (int returnvalue)
35 if (COM_CheckParm("-profilegameonly"))
36 Sys_AllowProfiling(false);
37 host_shuttingdown = true;
42 #if defined(__linux__) || defined(__FreeBSD__)
49 void Sys_AllowProfiling(qboolean enable)
51 #if defined(__linux__) || defined(__FreeBSD__)
58 ===============================================================================
62 ===============================================================================
65 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
68 const dllfunction_t *func;
69 dllhandle_t dllhandle = 0;
77 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
80 for (func = fcts; func && func->name != NULL; func++)
81 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
86 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
95 for (func = fcts; func && func->name != NULL; func++)
96 *func->funcvariable = NULL;
98 // Try every possible name
99 Con_DPrintf ("Trying to load library...");
100 for (i = 0; dllnames[i] != NULL; i++)
102 Con_DPrintf (" \"%s\"", dllnames[i]);
104 dllhandle = LoadLibrary (dllnames[i]);
106 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
112 // see if the names can be loaded relative to the executable path
113 // (this is for Mac OSX which does not check next to the executable)
114 if (!dllhandle && strrchr(com_argv[0], '/'))
116 char path[MAX_OSPATH];
117 strlcpy(path, com_argv[0], sizeof(path));
118 strrchr(path, '/')[1] = 0;
119 for (i = 0; dllnames[i] != NULL; i++)
121 char temp[MAX_OSPATH];
122 strlcpy(temp, path, sizeof(temp));
123 strlcat(temp, dllnames[i], sizeof(temp));
124 Con_DPrintf (" \"%s\"", temp);
126 dllhandle = LoadLibrary (temp);
128 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
138 Con_DPrintf(" - failed.\n");
142 Con_DPrintf(" - loaded.\n");
144 // Get the function adresses
145 for (func = fcts; func && func->name != NULL; func++)
146 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
148 Con_DPrintf ("Missing function \"%s\" - broken library!\n", func->name);
149 Sys_UnloadLibrary (&dllhandle);
160 void Sys_UnloadLibrary (dllhandle_t* handle)
163 if (handle == NULL || *handle == NULL)
167 FreeLibrary (*handle);
176 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
180 return (void *)GetProcAddress (handle, name);
182 return (void *)dlsym (handle, name);
190 # define HAVE_TIMEGETTIME 1
191 # define HAVE_QUERYPERFORMANCECOUNTER 1
192 # define HAVE_Sleep 1
195 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
196 # define HAVE_CLOCKGETTIME 1
200 // FIXME improve this check, manpage hints to DST_NONE
201 # define HAVE_GETTIMEOFDAY 1
205 # define HAVE_SELECT 1
209 // FIXME improve this check
210 # define HAVE_USLEEP 1
213 cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
214 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."};
215 cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
216 cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
217 #if HAVE_QUERYPERFORMANCECOUNTER
218 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)"};
220 #if HAVE_CLOCKGETTIME
221 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)"};
224 static unsigned long benchmark_time;
226 void Sys_Init_Commands (void)
228 Cvar_RegisterVariable(&sys_debugsleep);
229 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
230 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
231 if(sys_supportsdlgetticks)
233 Cvar_RegisterVariable(&sys_usesdlgetticks);
234 Cvar_RegisterVariable(&sys_usesdldelay);
237 #if HAVE_QUERYPERFORMANCECOUNTER
238 Cvar_RegisterVariable(&sys_usequeryperformancecounter);
240 #if HAVE_CLOCKGETTIME
241 Cvar_RegisterVariable(&sys_useclockgettime);
245 double Sys_DoubleTime(void)
247 static int first = true;
248 static double oldtime = 0.0, curtime = 0.0;
250 if(sys_usenoclockbutbenchmark.integer)
253 return ((double) benchmark_time) / 1e6;
256 // first all the OPTIONAL timers
258 #if HAVE_QUERYPERFORMANCECOUNTER
259 else if (sys_usequeryperformancecounter.integer)
261 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
262 // QueryPerformanceCounter
264 // Windows 95/98/ME/NT/2000/XP
266 // very accurate (CPU cycles)
268 // does not necessarily match realtime too well (tends to get faster and faster in win98)
269 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
271 LARGE_INTEGER PerformanceFreq;
272 LARGE_INTEGER PerformanceCount;
274 if (!QueryPerformanceFrequency (&PerformanceFreq))
276 Con_Printf ("No hardware timer available\n");
277 // fall back to timeGetTime
278 Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
279 return Sys_DoubleTime();
281 QueryPerformanceCounter (&PerformanceCount);
284 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
285 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
287 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
288 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
293 #if HAVE_CLOCKGETTIME
294 else if (sys_useclockgettime.integer)
297 # ifdef CLOCK_MONOTONIC
299 clock_gettime(CLOCK_MONOTONIC, &ts);
302 clock_gettime(CLOCK_HIGHRES, &ts);
304 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
308 // now all the FALLBACK timers
309 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
311 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
313 #if HAVE_GETTIMEOFDAY
317 gettimeofday(&tp, NULL);
318 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
320 #elif HAVE_TIMEGETTIME
323 static int firsttimegettime = true;
326 // Windows 95/98/ME/NT/2000/XP
328 // reasonable accuracy (millisecond)
330 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
332 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
333 if (firsttimegettime)
336 firsttimegettime = false;
339 newtime = (double) timeGetTime () / 1000.0;
342 // fallback for using the SDL timer if no other timer is available
345 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
346 // this calls Sys_Error() if not linking against SDL
356 if (newtime < oldtime)
358 // warn if it's significant
359 if (newtime - oldtime < -0.01)
360 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
362 else if (newtime > oldtime + 1800)
364 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
367 curtime += newtime - oldtime;
373 void Sys_Sleep(int microseconds)
376 if(sys_usenoclockbutbenchmark.integer)
378 benchmark_time += microseconds;
381 if(sys_debugsleep.integer)
383 t = Sys_DoubleTime();
385 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
387 Sys_SDL_Delay(microseconds / 1000);
393 tv.tv_sec = microseconds / 1000000;
394 tv.tv_usec = microseconds % 1000000;
395 select(0, NULL, NULL, NULL, &tv);
400 usleep(microseconds);
405 Sleep(microseconds / 1000);
410 Sys_SDL_Delay(microseconds / 1000);
413 if(sys_debugsleep.integer)
415 t = Sys_DoubleTime() - t;
416 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));