/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSG_TIMER #define OSG_TIMER 1 #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. */ class SG_EXPORT Timer { public: Timer(); ~Timer() {} static const Timer* instance(); inline 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; } inline double delta_u( Timer_t t1, Timer_t t2 ) const { return delta_s(t1,t2)*1e6; } inline double delta_n( Timer_t t1, Timer_t t2 ) const { return delta_s(t1,t2)*1e9; } inline double getSecondsPerTick() const { return _secsPerTick; } 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 }; } #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