15 static char sys_timestring[128];
16 char *Sys_TimeString(const char *timeformat)
18 time_t mytime = time(NULL);
21 localtime_s(&mytm, &mytime);
22 strftime(sys_timestring, sizeof(sys_timestring), timeformat, &mytm);
24 strftime(sys_timestring, sizeof(sys_timestring), timeformat, localtime(&mytime));
26 return sys_timestring;
30 extern qboolean host_shuttingdown;
31 void Sys_Quit (int returnvalue)
33 if (COM_CheckParm("-profilegameonly"))
34 Sys_AllowProfiling(false);
35 host_shuttingdown = true;
40 #if defined(__linux__) || defined(__FreeBSD__)
47 void Sys_AllowProfiling(qboolean enable)
49 #if defined(__linux__) || defined(__FreeBSD__)
56 ===============================================================================
60 ===============================================================================
63 qboolean Sys_LoadLibrary (const char** dllnames, dllhandle_t* handle, const dllfunction_t *fcts)
66 const dllfunction_t *func;
67 dllhandle_t dllhandle = 0;
75 dllhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
78 for (func = fcts; func && func->name != NULL; func++)
79 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
84 Con_DPrintf ("All of %s's functions were already linked in! Not loading dynamically...\n", dllnames[0]);
93 for (func = fcts; func && func->name != NULL; func++)
94 *func->funcvariable = NULL;
96 // Try every possible name
97 Con_DPrintf ("Trying to load library...");
98 for (i = 0; dllnames[i] != NULL; i++)
100 Con_DPrintf (" \"%s\"", dllnames[i]);
102 dllhandle = LoadLibrary (dllnames[i]);
104 dllhandle = dlopen (dllnames[i], RTLD_LAZY | RTLD_GLOBAL);
110 // see if the names can be loaded relative to the executable path
111 // (this is for Mac OSX which does not check next to the executable)
112 if (!dllhandle && strrchr(com_argv[0], '/'))
114 char path[MAX_OSPATH];
115 strlcpy(path, com_argv[0], sizeof(path));
116 strrchr(path, '/')[1] = 0;
117 for (i = 0; dllnames[i] != NULL; i++)
119 char temp[MAX_OSPATH];
120 strlcpy(temp, path, sizeof(temp));
121 strlcat(temp, dllnames[i], sizeof(temp));
122 Con_DPrintf (" \"%s\"", temp);
124 dllhandle = LoadLibrary (temp);
126 dllhandle = dlopen (temp, RTLD_LAZY | RTLD_GLOBAL);
136 Con_DPrintf(" - failed.\n");
140 Con_DPrintf(" - loaded.\n");
142 // Get the function adresses
143 for (func = fcts; func && func->name != NULL; func++)
144 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (dllhandle, func->name)))
146 Con_DPrintf ("Missing function \"%s\" - broken library!\n", func->name);
147 Sys_UnloadLibrary (&dllhandle);
158 void Sys_UnloadLibrary (dllhandle_t* handle)
161 if (handle == NULL || *handle == NULL)
165 FreeLibrary (*handle);
174 void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
178 return (void *)GetProcAddress (handle, name);
180 return (void *)dlsym (handle, name);
188 # define HAVE_TIMEGETTIME 1
189 # define HAVE_QUERYPERFORMANCECOUNTER 1
190 # define HAVE_Sleep 1
193 #if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
194 # define HAVE_CLOCKGETTIME 1
198 // FIXME improve this check, manpage hints to DST_NONE
199 # define HAVE_GETTIMEOFDAY 1
203 # define HAVE_SELECT 1
207 // FIXME improve this check
208 # define HAVE_USLEEP 1
211 cvar_t sys_debugsleep = {0, "sys_debugsleep", "0", "write requested and attained sleep times to standard output, to be used with gnuplot"};
212 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."};
213 cvar_t sys_usesdlgetticks = {CVAR_SAVE, "sys_usesdlgetticks", "0", "use SDL_GetTicks() timer (less accurate, for debugging)"};
214 cvar_t sys_usesdldelay = {CVAR_SAVE, "sys_usesdldelay", "0", "use SDL_Delay() (less accurate, for debugging)"};
215 #if HAVE_QUERYPERFORMANCECOUNTER
216 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)"};
218 #if HAVE_CLOCKGETTIME
219 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)"};
222 static unsigned long benchmark_time;
224 void Sys_Init_Commands (void)
226 Cvar_RegisterVariable(&sys_debugsleep);
227 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
228 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
229 if(sys_supportsdlgetticks)
231 Cvar_RegisterVariable(&sys_usesdlgetticks);
232 Cvar_RegisterVariable(&sys_usesdldelay);
235 #if HAVE_QUERYPERFORMANCECOUNTER
236 Cvar_RegisterVariable(&sys_usetimegettime);
238 #if HAVE_CLOCKGETTIME
239 Cvar_RegisterVariable(&sys_useclockgettime);
243 double Sys_DoubleTime(void)
245 static int first = true;
246 static double oldtime = 0.0, curtime = 0.0;
248 if(sys_usenoclockbutbenchmark.integer)
251 return ((double) benchmark_time) / 1e6;
254 // first all the OPTIONAL timers
256 #if HAVE_QUERYPERFORMANCECOUNTER
257 else if (sys_usequeryperformancecounter.integer)
259 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
260 // QueryPerformanceCounter
262 // Windows 95/98/ME/NT/2000/XP
264 // very accurate (CPU cycles)
266 // does not necessarily match realtime too well (tends to get faster and faster in win98)
267 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
269 LARGE_INTEGER PerformanceFreq;
270 LARGE_INTEGER PerformanceCount;
272 if (!QueryPerformanceFrequency (&PerformanceFreq))
274 Con_Printf ("No hardware timer available\n");
275 // fall back to timeGetTime
276 Cvar_SetValueQuick(&sys_usetimegettime, true);
277 return Sys_DoubleTime();
279 QueryPerformanceCounter (&PerformanceCount);
282 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
283 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
285 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
286 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
291 #if HAVE_CLOCKGETTIME
292 else if (sys_useclockgettime.integer)
295 # ifdef CLOCK_MONOTONIC
297 clock_gettime(CLOCK_MONOTONIC, &ts);
300 clock_gettime(CLOCK_HIGHRES, &ts);
302 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
306 // now all the FALLBACK timers
307 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
309 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
311 #if HAVE_GETTIMEOFDAY
315 gettimeofday(&tp, NULL);
316 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
318 #elif HAVE_TIMEGETTIME
321 static int firsttimegettime = true;
324 // Windows 95/98/ME/NT/2000/XP
326 // reasonable accuracy (millisecond)
328 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
330 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
331 if (firsttimegettime)
334 firsttimegettime = false;
337 newtime = (double) timeGetTime () / 1000.0;
340 // fallback for using the SDL timer if no other timer is available
343 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
344 // this calls Sys_Error() if not linking against SDL
354 if (newtime < oldtime)
356 // warn if it's significant
357 if (newtime - oldtime < -0.01)
358 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
360 else if (newtime > oldtime + 1800)
362 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
365 curtime += newtime - oldtime;
371 void Sys_Sleep(int microseconds)
374 if(sys_usenoclockbutbenchmark.integer)
376 benchmark_time += microseconds;
379 if(sys_debugsleep.integer)
381 t = Sys_DoubleTime();
383 if(sys_supportsdlgetticks && sys_usesdldelay.integer)
385 Sys_SDL_Delay(microseconds / 1000);
391 tv.tv_sec = microseconds / 1000000;
392 tv.tv_usec = microseconds % 1000000;
393 select(0, NULL, NULL, NULL, &tv);
398 usleep(microseconds);
403 Sleep(microseconds / 1000);
408 Sys_SDL_Delay(microseconds / 1000);
411 if(sys_debugsleep.integer)
413 t = Sys_DoubleTime() - t;
414 printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));