/* timer.h - Cross-platform timer library - Public Domain - 2011 Mattias Jansson / Rampant Pixels * * This library provides a cross-platform interface to measure * elapsed time with (at least) millisecond accuracy. * * This library is put in the public domain; you can redistribute * it and/or modify it without any restrictions. * */ #include "timer.h" #define TIMER_PLATFORM_WINDOWS 0 #define TIMER_PLATFORM_APPLE 0 #define TIMER_PLATFORM_POSIX 0 #if defined( _WIN32 ) || defined( _WIN64 ) # undef TIMER_PLATFORM_WINDOWS # define TIMER_PLATFORM_WINDOWS 1 # define WIN32_LEAN_AND_MEAN # include #elif defined( __APPLE__ ) # undef TIMER_PLATFORM_APPLE # define TIMER_PLATFORM_APPLE 1 # include # include static mach_timebase_info_data_t timerlib_info; static void absolutetime_to_nanoseconds (uint64_t mach_time, uint64_t* clock ) { *clock = mach_time * timerlib_info.numer / timerlib_info.denom; } #else # undef TIMER_PLATFORM_POSIX # define TIMER_PLATFORM_POSIX 1 # include # include # include #endif static tick_t timerlib_freq = 0; static double timerlib_oofreq = 0; int timer_lib_initialize( void ) { #if TIMER_PLATFORM_WINDOWS tick_t unused; if( !QueryPerformanceFrequency( (LARGE_INTEGER*)&timerlib_freq ) || !QueryPerformanceCounter( (LARGE_INTEGER*)&unused ) ) return -1; #elif TIMER_PLATFORM_APPLE if( mach_timebase_info( &timerlib_info ) ) return -1; timerlib_freq = 1000000000ULL; #elif TIMER_PLATFORM_POSIX struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; if( clock_gettime( CLOCK_MONOTONIC, &ts ) ) return -1; timerlib_freq = 1000000000ULL; #endif timerlib_oofreq = 1.0 / (double)timerlib_freq; return 0; } void timer_lib_shutdown( void ) { } tick_t timer_current( void ) { #if TIMER_PLATFORM_WINDOWS tick_t curclock; QueryPerformanceCounter( (LARGE_INTEGER*)&curclock ); return curclock; #elif TIMER_PLATFORM_APPLE tick_t curclock = 0; absolutetime_to_nanoseconds( mach_absolute_time(), &curclock ); return curclock; #elif TIMER_PLATFORM_POSIX struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; clock_gettime( CLOCK_MONOTONIC, &ts ); return ( (uint64_t)ts.tv_sec * 1000000000ULL ) + ts.tv_nsec; #endif } tick_t timer_ticks_per_second( void ) { return timerlib_freq; } deltatime_t timer_elapsed( const tick_t t ) { return (deltatime_t)( (double)timer_elapsed_ticks( t ) * timerlib_oofreq ); } tick_t timer_elapsed_ticks( const tick_t t ) { tick_t dt = 0; #if TIMER_PLATFORM_WINDOWS tick_t curclock = t; QueryPerformanceCounter( (LARGE_INTEGER*)&curclock ); dt = curclock - t; #elif TIMER_PLATFORM_APPLE tick_t curclock = t; absolutetime_to_nanoseconds( mach_absolute_time(), &curclock ); dt = curclock - t; #elif TIMER_PLATFORM_POSIX tick_t curclock; struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; clock_gettime( CLOCK_MONOTONIC, &ts ); curclock = ( (tick_t)ts.tv_sec * 1000000000ULL ) + ts.tv_nsec; dt = curclock - t; #endif return dt; } deltatime_t timer_ticks_to_seconds( const tick_t dt ) { return (deltatime_t)( (double)dt * timerlib_oofreq ); } #if TIMER_PLATFORM_WINDOWS struct __timeb64 { __time64_t time; unsigned short millitm; short timezone; short dstflag; }; _CRTIMP errno_t __cdecl _ftime64_s(_Out_ struct __timeb64 * _Time); #endif tick_t timer_system( void ) { #if TIMER_PLATFORM_WINDOWS struct __timeb64 tb; _ftime64_s( &tb ); return ( (tick_t)tb.time * 1000ULL ) + (tick_t)tb.millitm; #elif TIMER_PLATFORM_APPLE tick_t curclock = 0; absolutetime_to_nanoseconds( mach_absolute_time(), &curclock ); return ( curclock / 1000000ULL ); #elif TIMER_PLATFORM_POSIX struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; clock_gettime( CLOCK_REALTIME, &ts ); return ( (uint64_t)ts.tv_sec * 1000ULL ) + ( ts.tv_nsec / 1000000ULL ); #endif }