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", "1", "use SDL_GetTicks() timer"};
214 #if HAVE_QUERYPERFORMANCECOUNTER
215 cvar_t sys_usequeryperformancecounter = {CVAR_SAVE, "sys_usequeryperformancecounter", "1", "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)"};
217 #if HAVE_CLOCKGETTIME
218 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)"};
221 static unsigned long benchmark_time;
223 void Sys_Init_Commands (void)
225 Cvar_RegisterVariable(&sys_debugsleep);
226 Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
227 #if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
228 if(sys_supportsdlgetticks)
229 Cvar_RegisterVariable(&sys_usesdlgetticks);
231 #if HAVE_QUERYPERFORMANCECOUNTER
232 Cvar_RegisterVariable(&sys_usetimegettime);
234 #if HAVE_CLOCKGETTIME
235 Cvar_RegisterVariable(&sys_useclockgettime);
239 double Sys_DoubleTime(void)
241 static int first = true;
242 static double oldtime = 0.0, curtime = 0.0;
244 if(sys_usenoclockbutbenchmark.integer)
247 return ((double) benchmark_time) / 1e6;
250 // first all the OPTIONAL timers
252 #if HAVE_QUERYPERFORMANCECOUNTER
253 else if (sys_usequeryperformancecounter.integer)
255 // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
256 // QueryPerformanceCounter
258 // Windows 95/98/ME/NT/2000/XP
260 // very accurate (CPU cycles)
262 // does not necessarily match realtime too well (tends to get faster and faster in win98)
263 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
265 LARGE_INTEGER PerformanceFreq;
266 LARGE_INTEGER PerformanceCount;
268 if (!QueryPerformanceFrequency (&PerformanceFreq))
270 Con_Printf ("No hardware timer available\n");
271 // fall back to timeGetTime
272 Cvar_SetValueQuick(&sys_usetimegettime, true);
273 return Sys_DoubleTime();
275 QueryPerformanceCounter (&PerformanceCount);
278 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
279 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
281 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
282 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
287 #if HAVE_CLOCKGETTIME
288 else if (sys_useclockgettime.integer)
291 # ifdef CLOCK_MONOTONIC
293 clock_gettime(CLOCK_MONOTONIC, &ts);
296 clock_gettime(CLOCK_HIGHRES, &ts);
298 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
302 // now all the FALLBACK timers
303 else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
305 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
310 static int firsttimegettime = true;
313 // Windows 95/98/ME/NT/2000/XP
315 // reasonable accuracy (millisecond)
317 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
319 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
320 if (firsttimegettime)
323 firsttimegettime = false;
326 newtime = (double) timeGetTime () / 1000.0;
328 #elif HAVE_GETTIMEOFDAY
332 gettimeofday(&tp, NULL);
333 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
336 // fallback for using the SDL timer if no other timer is available
339 newtime = (double) Sys_SDL_GetTicks() / 1000.0;
340 // this calls Sys_Error() if not linking against SDL
350 if (newtime < oldtime)
352 // warn if it's significant
353 if (newtime - oldtime < -0.01)
354 Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
356 else if (newtime > oldtime + 1800)
358 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
361 curtime += newtime - oldtime;
367 void Sys_Sleep(int microseconds)
370 if(sys_usenoclockbutbenchmark.integer)
372 benchmark_time += microseconds;
375 if(sys_debugsleep.integer)
377 t = Sys_DoubleTime();
382 tv.tv_sec = microseconds / 1000000;
383 tv.tv_usec = microseconds % 1000000;
384 select(0, NULL, NULL, NULL, &tv);
387 usleep(microseconds);
389 Sleep(microseconds / 1000);
391 Sys_SDL_Delay(microseconds / 1000);
393 if(sys_debugsleep.integer)
395 t = Sys_DoubleTime() - t;
396 printf("%d %f # debugsleep\n", microseconds, t);