This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  RDTSC Timer Class
  Submitted by



Hi, here is a timer class I came up with that uses RDTSC, It fallbacks on TimeGetTime if RDTSC is unavailable. It would be nice to get some constructive criticism on the code. Paul Hope.

Download Associated File: timer.cpp (5,321 bytes)

const uint32 ticksPerSecond = 1000;

class cTimer { private:

bool isClassInit;

uint32 framesPerSecond; float32 hzPerSecondTicks; uint64 hzPerSecondRdtsc;

static uint64 rdtscPerMillesecond; static uint64 rdtscPerSecond; static bool usePerformanceCounter; uint64 startTimeKeyRdtsc; ulong32 startTimeKeyTicks; uint64 startTimeKeyRdtscFPS; ulong32 startTimeKeyTicksFPS; uint64 startTimeKeyFPS; float32 frameCount; float32 timeElapsed; uint64 timeKeyRdtsc; ulong32 timeKeyTicks; uint64 timeDifferenceRdtsc; float32 timeDifferenceTicks; uint64 timeRdtsc; ulong32 timeTicks;

public: cTimer( ) { isClassInit = false; } ~cTimer( ) { }

void TimerInit( uint32 ); const float32& TimerFPS( ); bool TimerAlarm( ); void TimerElapsedTime( ulong32* , uint64* = NULL ); };

_INLINE bool cTimer::TimerAlarm( ) { if( !isClassInit ) { //ASSERTPRINT( isClassInit != false ); return false; }

if( framesPerSecond ) { if( usePerformanceCounter ) { TimerElapsedTime( NULL, &timeKeyRdtsc ); timeDifferenceRdtsc = timeKeyRdtsc - startTimeKeyRdtsc;

if( timeDifferenceRdtsc >= hzPerSecondRdtsc ) { startTimeKeyRdtsc = timeKeyRdtsc; return true; } else return false; } else { TimerElapsedTime( &timeKeyTicks ); if( timeKeyTicks < startTimeKeyTicks ) startTimeKeyTicks = 0; timeDifferenceTicks = (float32)(timeKeyTicks - startTimeKeyTicks);

if( timeDifferenceTicks >= hzPerSecondTicks ) { startTimeKeyTicks = timeKeyTicks; return true; } else return false; } } else return true; }

_INLINE const float32& cTimer::TimerFPS( ) { if( !isClassInit ) { //ASSERTPRINT( isClassInit != false ); return frameCount; }

if( usePerformanceCounter ) { TimerElapsedTime( NULL, &timeKeyRdtsc ); timeDifferenceRdtsc = timeKeyRdtsc - startTimeKeyRdtscFPS;

if( timeDifferenceRdtsc == 0 ) { //ASSERTPRINT( timeDifferenceRdtsc == 0 ); timeDifferenceRdtsc = 1; }

frameCount = (float32)( rdtscPerSecond / timeDifferenceRdtsc );

startTimeKeyRdtscFPS = timeKeyRdtsc; } else { TimerElapsedTime( &timeKeyTicks ); if( timeKeyTicks < startTimeKeyTicksFPS ) startTimeKeyTicksFPS = 0; timeDifferenceTicks = (float32)( timeKeyTicks - startTimeKeyTicksFPS ); if( timeDifferenceTicks < FLOAT32_EPSILON ) { //ASSERTPRINT( timeDifferenceTicks >= FLOAT32_EPSILON ); timeDifferenceTicks = FLOAT32_EPSILON; }

frameCount = (float32)ticksPerSecond / timeDifferenceTicks;

startTimeKeyTicksFPS = timeKeyTicks; } return frameCount; }

_INLINE void cTimer::TimerElapsedTime( ulong32* timeTicks, uint64* timeRdtsc ) { if( !isClassInit ) { //ASSERTPRINT( isClassInit != false ); return; }

if( timeRdtsc && usePerformanceCounter ) { ulong32 dwLow, dwHigh; __asm { rdtsc mov dwLow, eax mov dwHigh, edx } *timeRdtsc = ( (uint64)dwHigh << 32 ) | (uint64)dwLow; } if( timeTicks ) { timeBeginPeriod( 1 ); *timeTicks = timeGetTime( ); timeEndPeriod( 1 ); } }

uint64 cTimer::rdtscPerMillesecond = 0; uint64 cTimer::rdtscPerSecond = 0; bool cTimer::usePerformanceCounter = false;

void cTimer::TimerInit( uint32 fps ) { if( isClassInit ) { //ASSERTPRINT( isClassInit != true ); return; } isClassInit = true;

static bool isInit = false; if( !isInit ) { __try { ulong32 dwLow1, dwHigh1; ulong32 dwLow2, dwHigh2; uint64 time; uint64 time2; __asm { rdtsc mov dwLow1, eax mov dwHigh1, edx } Sleep( 50 );

__asm { rdtsc mov dwLow2, eax mov dwHigh2, edx }

time = ( (unsigned __int64)dwHigh1 << 32 ) | (unsigned __int64)dwLow1; time2 = ( (unsigned __int64)dwHigh2 << 32 ) | (unsigned __int64)dwLow2; time2 -= time;

rdtscPerSecond = time2; __asm { rdtsc mov dwLow1, eax mov dwHigh1, edx } Sleep( 50 );

__asm { rdtsc mov dwLow2, eax mov dwHigh2, edx }

time = ( (unsigned __int64)dwHigh1 << 32 ) | (unsigned __int64)dwLow1; time2 = ( (unsigned __int64)dwHigh2 << 32 ) | (unsigned __int64)dwLow2; time2 -= time; rdtscPerSecond += time2; rdtscPerSecond *= 10; rdtscPerMillesecond = rdtscPerSecond / (uint64)ticksPerSecond; usePerformanceCounter = true; DebugMsg( "Accurate rdtsc Timer Activated" ); LogEntry( "Accurate rdtsc Timer Activated\n\n");

} __except( EXCEPTION_EXECUTE_HANDLER ) { usePerformanceCounter = false; DebugMsg( "TimeGetTime Timer Activated" ); LogEntry( "TimeGetTime Timer Activated\n\n"); } isInit = true; } framesPerSecond = fps;

if( framesPerSecond ) { hzPerSecondTicks = (float32)ticksPerSecond/(float32)framesPerSecond;

if( usePerformanceCounter ) hzPerSecondRdtsc = rdtscPerSecond / framesPerSecond; }

TimerElapsedTime( &startTimeKeyTicks, &startTimeKeyRdtsc ); startTimeKeyTicksFPS = startTimeKeyTicks; startTimeKeyRdtscFPS = startTimeKeyRdtsc; }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.