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.