/* -*-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. */ //#include #include #include #include using namespace osg; // follows are the constructors of the Timer class, once version // for each OS combination. The order is WIN32, FreeBSD, Linux, IRIX, // and the rest of the world. // // all the rest of the timer methods are implemented within the header. const Timer* Timer::instance() { static Timer s_timer; return &s_timer; } #ifdef WIN32 #include #include #include #include Timer::Timer() { _useStandardClock = false; if (_useStandardClock) { _secsPerTick = (1.0 / (double) CLOCKS_PER_SEC); } 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() { _useStandardClock = false; if (_useStandardClock) { _secsPerTick = 1e-6; // gettimeofday()'s precision. } 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; } } #elif defined(__linux) #include #include #include #include Timer::Timer() { #if defined(__ia64) || defined(__x86_64__) || defined(__powerpc) _useStandardClock = true; #else _useStandardClock = true; #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 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. } } #elif defined (__APPLE__) || defined (macintosh) Timer::Timer() { _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); } #endif