From 96514b5077f2d7bef1f87e427d833993bbc9e8c3 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 25 Feb 2005 08:38:05 +0000 Subject: [PATCH] New simplified timer implementation. --- include/osg/Timer | 231 ++------------------------------------- src/osg/Timer.cpp | 270 ++++------------------------------------------ 2 files changed, 30 insertions(+), 471 deletions(-) diff --git a/include/osg/Timer b/include/osg/Timer index fbae34b01..a952d4ffc 100644 --- a/include/osg/Timer +++ b/include/osg/Timer @@ -16,37 +16,15 @@ #include - -#if defined(_MSC_VER) - namespace osg { - typedef __int64 Timer_t; - } -#elif defined(__linux) || defined(__FreeBSD__) || defined(__CYGWIN__)|| defined(__MINGW32__) - namespace osg { - typedef unsigned long long Timer_t; - } -#elif defined(__sgi) - namespace osg { - typedef unsigned long long Timer_t; - } -#elif defined(unix) - namespace osg { - typedef unsigned long long Timer_t; - } -#elif defined __APPLE__ || defined macintosh - namespace osg { - typedef double Timer_t; - } -#else - #include - namespace osg { - typedef std::clock_t Timer_t; - } -#endif - namespace osg { -/** A high resolution, low latency time stamper. */ +#if defined(_MSC_VER) + typedef __int64 Timer_t; +#else + typedef unsigned long long Timer_t; +#endif + +/** Time stamper. */ class SG_EXPORT Timer { public: @@ -56,7 +34,7 @@ class SG_EXPORT Timer { static const Timer* instance(); - inline Timer_t tick() const; + Timer_t tick() const; inline double delta_s( Timer_t t1, Timer_t t2 ) const { return (double)(t2 - t1)*_secsPerTick; } inline double delta_m( Timer_t t1, Timer_t t2 ) const { return delta_s(t1,t2)*1e3; } @@ -67,198 +45,9 @@ class SG_EXPORT Timer { protected : - double _secsPerTick; - bool _useStandardClock; - -# ifdef __sgi - unsigned long* _clockAddress_32; - unsigned long long* _clockAddress_64; - int _cycleCntrSize; - // for SGI machines with 32 bit clocks. - mutable unsigned long _lastClockValue; - mutable unsigned long long _rollOver; -# endif - + double _secsPerTick; + }; } - -#if defined(_MSC_VER) - - #include - #pragma optimize("",off) - - namespace osg{ - - inline Timer_t Timer::tick( void ) const - { - if (_useStandardClock) return clock(); - - volatile Timer_t ts; - volatile unsigned int HighPart; - volatile unsigned int LowPart; - _asm - { - xor eax, eax // Used when QueryPerformanceCounter() - xor edx, edx // not supported or minimal overhead - _emit 0x0f // desired - _emit 0x31 // - mov HighPart,edx - mov LowPart,eax - } - //ts = LowPart | HighPart >> 32; - *((unsigned int*)&ts) = LowPart; - *((unsigned int*)&ts+1) = HighPart; - return ts; - } - - } - #pragma optimize("",on) - -#elif defined(__MINGW32__) - - #include - - #define CLK(x) __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)) - namespace osg{ - - inline Timer_t Timer::tick() const - { - if (_useStandardClock) - return clock(); - else - { - Timer_t x;CLK(x);return x; - } - } - - } - -#elif defined(__linux) || defined(__FreeBSD__) || defined(__CYGWIN__) - - #include - -# if defined(__powerpc) -# ifndef __HAVE_POWERPC_GET_TBL -# define __HAVE_POWERPC_GET_TBL 1 -static inline unsigned long get_tbl(void) -{ - unsigned long tbl; - asm volatile ("mftb %0":"=r" (tbl)); - return tbl; -} -# endif - -# define CLK(x)\ -{ \ - unsigned long tb, tblu; \ - do { \ - tb = get_tbl(); \ - __asm__ __volatile__ ("mftbu %0":"=r" (tblu)); \ - } while (tb != get_tbl()); \ - x = (((Timer_t) tblu) << 32) | (Timer_t) tb; \ -} - -# elif defined(__i386) - #define CLK(x) __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)) - -# endif - - namespace osg{ - - inline Timer_t Timer::tick() const - { -# ifdef CLK - if (_useStandardClock) - { - struct timeval tv; - gettimeofday(&tv, NULL); - return ((osg::Timer_t)tv.tv_sec)*1000000+(osg::Timer_t)tv.tv_usec; - } - else - { - Timer_t x;CLK(x);return x; - } -# else // CLK - struct timeval tv; - gettimeofday(&tv, NULL); - return ((osg::Timer_t)tv.tv_sec)*1000000+(osg::Timer_t)tv.tv_usec; -# endif // CLK - } - - } - -#elif defined(__sgi) - - #include - #include - - namespace osg{ - - inline Timer_t Timer::tick() const - { - if (_useStandardClock) - { - struct timeval tv; - gettimeofday(&tv, NULL); - return ((osg::Timer_t)tv.tv_sec)*1000000+(osg::Timer_t)tv.tv_usec; - } - else - { - if ( _clockAddress_64 ) - return *_clockAddress_64; - else - { - unsigned long clockValue = *_clockAddress_32; - if( _lastClockValue > clockValue ) - { - # ifdef __GNUC__ - _rollOver += 0x100000000LL; - #else - _rollOver += 0x100000000L; - #endif - } - _lastClockValue = clockValue; - return _rollOver + clockValue; - } - } - } - } - -#elif defined (__APPLE__) || defined (macintosh) - - #include - - namespace osg{ - inline Timer_t Timer::tick() const - { - // Always uses std::clock() - struct timeval tv; - gettimeofday(&tv, NULL); - return ((osg::Timer_t)tv.tv_sec)*1000000+(osg::Timer_t)tv.tv_usec; - } - } -#elif defined(unix) - - #include - - namespace osg{ - inline Timer_t Timer::tick() const - { - struct timeval tv; - gettimeofday(&tv, NULL); - return ((osg::Timer_t)tv.tv_sec)*1000000+(osg::Timer_t)tv.tv_usec; - } - } - -#else - - // no choice, always use std::clock() - namespace osg{ - - inline Timer_t Timer::tick( void ) const { return std::clock(); } - } - -#endif - #endif diff --git a/src/osg/Timer.cpp b/src/osg/Timer.cpp index aac28ee01..5d7ea7165 100644 --- a/src/osg/Timer.cpp +++ b/src/osg/Timer.cpp @@ -15,6 +15,7 @@ #include #include +#include using namespace osg; @@ -39,279 +40,48 @@ const Timer* Timer::instance() #include Timer::Timer() { - //_useStandardClock = false; - _useStandardClock = true; - - if (_useStandardClock) + LARGE_INTEGER frequency; + if(QueryPerformanceFrequency(&frequency)) { - #if defined(__CYGWIN__) - _secsPerTick = 1e-6; // gettimeofday()'s precision. - #else - _secsPerTick = (1.0 / (double) CLOCKS_PER_SEC); - #endif + _secsPerTick = 1.0/(double)frequency.QuadPart; } else { - // use a static here to ensure that the time to determine - // the cpu frequency is not incurred more than once - // per app execution. - static double _tempSecsPerClick=0.0; - if (_tempSecsPerClick==0.0) - { - // QueryPerformanceCounter under Windows 2000 Service Pack 3 - // two 2.4 GHz cpus was timed to take about 70 times longer - // than the RDTSC assembly instruction sequence, but if - // that counter is available we use it to quickly determine - // the Time Stamp Counter rate, quickly as in 240 microseconds - LARGE_INTEGER frequency; - if(QueryPerformanceFrequency(&frequency)) - { - //#define DEBUG_TIME_OUTPUT 1 - LARGE_INTEGER QPCstart, QPCstop, - QPCstartAfter, QPCstopAfter; - Timer_t TSCstart, TSCstop; - double QPCSecsPerClock = 1.0/frequency.QuadPart; - double elapsed, last, current, bound; - - QueryPerformanceCounter(&QPCstart); - TSCstart=tick(); - QueryPerformanceCounter(&QPCstartAfter); - - current = 0; - do - { - // store the seconds per clock - last = current; - // read the clocks - QueryPerformanceCounter(&QPCstop); - TSCstop=tick(); - QueryPerformanceCounter(&QPCstopAfter); - // average before and after to approximate reading - // both clocks at the same time - elapsed = ((QPCstop.QuadPart+QPCstopAfter.QuadPart) - -(QPCstart.QuadPart+QPCstartAfter.QuadPart))/2.0 - *QPCSecsPerClock; - // TSC seconds per clock - current = elapsed / (TSCstop-TSCstart); - // calculate a bound to check against - bound = current/1000000; - // break if current-boundlast - }while(current-bound>last || current+bound - #include - #include - #include - #include - Timer::Timer() + Timer_t Timer::tick() const { - _useStandardClock = false; - - if (_useStandardClock) + LARGE_INTEGER qpc; + if (QueryPerformanceCounter(&qpc)) { - _secsPerTick = 1e-6; // gettimeofday()'s precision. + return qpc.QuadPart; } else { - int cpuspeed; - size_t len; - - len = sizeof(cpuspeed); - if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &len, NULL, NULL) == -1) - { - _useStandardClock = true; - perror("sysctlbyname(machdep.tsc_freq)"); - return; - } - - _secsPerTick = 1.0/cpuspeed; + notify(NOTICE)<<"Error: Timer::Timer() unable to use QueryPerformanceCounter, "< - #include - #include - #include - - Timer::Timer() - { -#if defined(__ia64) || defined(__x86_64__) || defined(__powerpc) - _useStandardClock = true; // set to true to avoid problems with variable CPU speeds #else - _useStandardClock = true; // set to true to avoid problems with variable CPU speeds -#endif - if (_useStandardClock) - { - _secsPerTick = 1e-6; // gettimeofday()'s precision. - } - else - { - char buff[128]; - FILE *fp = fopen( "/proc/cpuinfo", "r" ); - - double cpu_mhz=0.0f; - - while( fgets( buff, sizeof( buff ), fp ) > 0 ) - { - if( !strncmp( buff, "cpu MHz", strlen( "cpu MHz" ))) - { - char *ptr = buff; - - while( ptr && *ptr != ':' ) ptr++; - if( ptr ) - { - ptr++; - sscanf( ptr, "%lf", &cpu_mhz ); - } - break; - } - } - fclose( fp ); - - if (cpu_mhz==0.0f) - { - // error - no cpu_mhz found. - Timer_t start_time = tick(); - sleep (1); - Timer_t end_time = tick(); - _secsPerTick = 1.0/(double)(end_time-start_time); - } - else - { - _secsPerTick = 1e-6/cpu_mhz; - } - } - } - -#elif defined(__sgi) - - #include - #include - #include - #include - #include + #include Timer::Timer( void ) { - _useStandardClock = false; // default to false. - - if (!_useStandardClock) - { - __psunsigned_t phys_addr, raddr; - unsigned int cycleval; - volatile unsigned long long *iotimer_addr; - int fd, poffmask; - - poffmask = getpagesize() - 1; - phys_addr = syssgi( SGI_QUERY_CYCLECNTR, &cycleval ); - raddr = phys_addr & ~poffmask; - - _clockAddress_32 = 0; - _clockAddress_64 = 0; - _rollOver = 0; - _lastClockValue = 0; - - if( (fd = open( "/dev/mmem", O_RDONLY )) < 0 ) - { - perror( "/dev/mmem" ); - _useStandardClock=true; - return; - } - - iotimer_addr = (volatile unsigned long long *)mmap( - (void *)0L, - (size_t)poffmask, - (int)PROT_READ, - (int)MAP_PRIVATE, fd, (off_t)raddr); - - iotimer_addr = (unsigned long long *)( - (__psunsigned_t)iotimer_addr + (phys_addr & poffmask) - ); - - _cycleCntrSize = syssgi( SGI_CYCLECNTR_SIZE ); - - // Warning: this casts away the volatile; not good - if( _cycleCntrSize > 32 ) - _clockAddress_32 = 0, - _clockAddress_64 = (unsigned long long *) iotimer_addr; - else - _clockAddress_32 = (unsigned long *) iotimer_addr, - _clockAddress_64 = 0; - - _secsPerTick = (double)(cycleval)* 1e-12; - -#if 0 // Obsolete - // this is to force the use of the standard clock in - // instances which the realtime clock is of such a small - // size that it will loop too rapidly for proper realtime work. - // this happens on the O2 for instance. - if (_cycleCntrSize<=32) _useStandardClock=true; -#endif // Obsolete - - } - - if (_useStandardClock) - { - _secsPerTick = 1e-6; // gettimeofday()'s precision. - } - + _secsPerTick = (1.0 / (double) 1000000); } -#elif defined (__APPLE__) || defined (macintosh) - - Timer::Timer() + Timer_t Timer::tick() const { - _useStandardClock = true; - _secsPerTick = 1e-6; // gettimeofday()'s precision. - } - -#elif defined(unix) - - Timer::Timer( void ) - { - _useStandardClock = true; - _secsPerTick = 1e-6; // gettimeofday()'s precision. - } - -#else - - // handle the rest of the OS world by just using the std::clock, - - Timer::Timer( void ) - { - _useStandardClock = true; - _secsPerTick = (1.0 / (double) CLOCKS_PER_SEC); + struct timeval tv; + gettimeofday(&tv, NULL); + return ((osg::Timer_t)tv.tv_sec)*1000000+(osg::Timer_t)tv.tv_usec; } #endif