Skip to main content
gamedev.net
🔒 Locked

QueryPerformanceCounter Question

Started by Chase85 14 replies 3.2k views
Original Post
Chase85
Chase85
Hey guys, wondering if any of you ran into the same situation i am having, and if you have a better result than i am... Basically im Calculating FPS and Frame Time using QueryPerformanceCounter... Only one problem, I call and Save the time before the render, then after and compare the two... But the Count QueryPerformanceCounter returns is exactly the same. Now i know it cant be rendering so fast that QPC hasn't changed yet, so i came up with just Sitting on it till it changes with a while(QPC == lasttime); but im wasting proc. clocks with this fix. :( So i tried switching over to the timeGetTime() method and setting timeBeginPeriod(1); same problem. Returning the same time every cycle :(
_____"C allows you to shoot yourself in the foot, C++ allows you to re-use the Bullet, Assembly allows you to Create the Bullet from Molecules"
krum
krum
Are you trying to convert the value to a double or a float? Neither have enough precision to substract two close-together QPC results.
CrazyCdn
CrazyCdn
Post code, if I recall right QueryPerformanceCounter returns a 64bit int. timeGetTime() is a lot less accurate. You can also search google for QueryPerformanceCounter articles, there's a few timers already written using it for games and other applications. You can even search these forums too.
"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin
Chase85
Chase85
CFrameRate::CFrameRate(void){	uiFrameTimeBufferPos = 0;	QueryPerformanceFrequency((LARGE_INTEGER*)&QPCFreq);}CFrameRate::~CFrameRate(void){	 }void CFrameRate::BeginFrame(void){	__int64 i64Time = 0;	QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);	// Get Current Count	dThisFrame = (long double)i64Time / (long double)QPCFreq;}void CFrameRate::EndFrame(void){	__int64 i64Time = 0;	QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);	//while (((long double)i64Time / (long double)QPCFreq) == dThisFrame)		//QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);	dFrameTime = ((long double)i64Time / (long double)QPCFreq) - dThisFrame;	dFPS = 1.0f/dFrameTime;	dFrameTimeAvgBuffer[uiFrameTimeBufferPos++] = dFrameTime;	if (uiFrameTimeBufferPos == 10) uiFrameTimeBufferPos = 0;}


I have commented out what i want to get rid of... Its really buggin me...
_____"C allows you to shoot yourself in the foot, C++ allows you to re-use the Bullet, Assembly allows you to Create the Bullet from Molecules"
krum
krum
Quote:
Original post by Chase85
CFrameRate::CFrameRate(void){	uiFrameTimeBufferPos = 0;	QueryPerformanceFrequency((LARGE_INTEGER*)&QPCFreq);}CFrameRate::~CFrameRate(void){	 }void CFrameRate::BeginFrame(void){	__int64 i64Time = 0;	QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);	// Get Current Count	dThisFrame = (long double)i64Time / (long double)QPCFreq;}void CFrameRate::EndFrame(void){	__int64 i64Time = 0;	QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);	//while (((long double)i64Time / (long double)QPCFreq) == dThisFrame)		//QueryPerformanceCounter((LARGE_INTEGER*)&i64Time);	dFrameTime = ((long double)i64Time / (long double)QPCFreq) - dThisFrame;	dFPS = 1.0f/dFrameTime;	dFrameTimeAvgBuffer[uiFrameTimeBufferPos++] = dFrameTime;	if (uiFrameTimeBufferPos == 10) uiFrameTimeBufferPos = 0;}


I have commented out what i want to get rid of... Its really buggin me...



So as I mentioned before you can't convert it to a double. :-D It does not have enough precision to store the value. You should subtract the long ints first, then convert that to a double and divide by (double)freq. Also, long double and double should be the same size on win32.

Chase85
Chase85
Okay only 1 tiny little problem, When dividing the Difference in time now by the Frequency, because it's going so fast i get a double that's too small. I wish i could truncate this someway. It runs amazing if i throw a Sleep(1) in the loop cause it slows it down just enough to about 450 fps. It'll run fine once i get more things on the screen but still there's gotta be a way to get that number regardless...
_____"C allows you to shoot yourself in the foot, C++ allows you to re-use the Bullet, Assembly allows you to Create the Bullet from Molecules"
Chase85
Chase85
I went with this for right now

if (dFrameTime < 0.001f) dFrameTime = 0.001f;

It's lying to itself... I wish i could be completely accurate with nothing on the screen... if (dFrameTime < 0.001f) dFrameTime = 0.001f; brings the FPS to lock at 999.99
_____"C allows you to shoot yourself in the foot, C++ allows you to re-use the Bullet, Assembly allows you to Create the Bullet from Molecules"
darkelf2k5
darkelf2k5
DOUBLE dxutStaticTimer(){	static BOOL bQPCSupported = TRUE;	static LARGE_INTEGER liCurrentTime = { (LONGLONG)0 };;	static LARGE_INTEGER liFrequency = { (LONGLONG)0 };	static LARGE_INTEGER liLastTime = { (LONGLONG)0 };;	static DOUBLE dTimeFactor = 1.0f;	if ( liFrequency.QuadPart != (LONGLONG)0 )	{		// QueryPerformanceCounter(...) supported and set, use high precision timer		::QueryPerformanceCounter( &liCurrentTime );		LARGE_INTEGER liElapsed;		liElapsed.QuadPart = liCurrentTime.QuadPart - liLastTime.QuadPart;		liLastTime.QuadPart = liCurrentTime.QuadPart;		return liElapsed.QuadPart * dTimeFactor;	}	if ( bQPCSupported != TRUE )	{		// QueryPerformanceCounter(...) not supported, use low precision timer		liCurrentTime.QuadPart = ::timeGetTime();		LARGE_INTEGER liElapsed;		liElapsed.QuadPart = liCurrentTime.QuadPart - liLastTime.QuadPart;		liLastTime.QuadPart = liCurrentTime.QuadPart;		return liElapsed.QuadPart * 0.001f;	}	if ( bQPCSupported && liFrequency.QuadPart == (LONGLONG)0 )	{		// QueryPerformanceCounter(...) not supported or not yet initialized		::QueryPerformanceFrequency( &liFrequency );		if ( !liFrequency.QuadPart )		{			bQPCSupported = FALSE;			liLastTime.QuadPart = ::timeGetTime();		}		else		{			dTimeFactor /= liFrequency.QuadPart;			::QueryPerformanceCounter( &liLastTime );		}		return 0.0f;	}	return 0.0f;}


This works fine for me, and it even should revert back to timeGetTime() in case QPC is not supported.

Edit: it returns the time elapsed since last call( 0 at first call naturally) and in seconds
Every time you implement a singleton, God kills a kitten. Please, think of the kittens!
krum
krum
I usually show my frame times in fractions of milliseconds:

AvgFrameTime: 5.87 ms (170.31 FPS) | Memory: 5.3 MB | Objects: 149
AvgFrameTime: 6.53 ms (153.04 FPS) | Memory: 4.9 MB | Objects: 480
AvgFrameTime: 18.17 ms ( 55.04 FPS) | Memory: 5.2 MB | Objects: 750
AvgFrameTime: 20.73 ms ( 48.23 FPS) | Memory: 3.8 MB | Objects: 750
AvgFrameTime: 20.41 ms ( 49.00 FPS) | Memory: 4.4 MB | Objects: 750
AvgFrameTime: 20.20 ms ( 49.49 FPS) | Memory: 5.0 MB | Objects: 750
AvgFrameTime: 20.47 ms ( 48.85 FPS) | Memory: 3.6 MB | Objects: 750
AvgFrameTime: 20.25 ms ( 49.38 FPS) | Memory: 4.1 MB | Objects: 750
AvgFrameTime: 20.28 ms ( 49.31 FPS) | Memory: 4.8 MB | Objects: 750
AvgFrameTime: 20.33 ms ( 49.18 FPS) | Memory: 3.4 MB | Objects: 750
AvgFrameTime: 20.30 ms ( 49.26 FPS) | Memory: 4.0 MB | Objects: 750
AvgFrameTime: 20.25 ms ( 49.37 FPS) | Memory: 4.6 MB | Objects: 750
AvgFrameTime: 20.26 ms ( 49.36 FPS) | Memory: 5.2 MB | Objects: 750
AvgFrameTime: 20.50 ms ( 48.79 FPS) | Memory: 3.8 MB | Objects: 750
AvgFrameTime: 20.28 ms ( 49.32 FPS) | Memory: 4.3 MB | Objects: 750
AvgFrameTime: 20.42 ms ( 48.98 FPS) | Memory: 4.9 MB | Objects: 750
Chase85
Chase85
Tsk Tsk, im stupid i found my problem :( I was calculating Frames Before Calling Begin Scene and testing if it actually worked, So sometimes BeginScene would return false, and id be calculating a bogus frame thus the 999.999 fps, Now it only Runs when frames are rendered, and i apologize. Thx a ton those guys...
_____"C allows you to shoot yourself in the foot, C++ allows you to re-use the Bullet, Assembly allows you to Create the Bullet from Molecules"
Specchum
Specchum
On a related note, I came across this interesting para while reading the documetnation of the timer class in boost libraries:

"... Tests showed that while the precision of these timers was high, the latency was sometimes very much higher than for the std::clock() function, and that is very bad. Furthermore, results using the Win32 API were very dependent on both the compiler (Microsoft and Borland were tested) and the operating system version (Windows NT, Windows 95, etc.) Thus the std::clock() function was much more reliable, and so was retained even on this platform with its own timer API."

Can anyone shed some light by what it means by "higher latency is very bad"? I thought QueryPerformanceCounter was recommended over the standard clock because of it's greater precision and that was that, so is this latency issue something a game developer should be worried about?
"There is no dark side of the moon." - Pink Floyd
Specchum
Specchum
:) I'm aware of that doc, but I'd like to know why the timer in boost implementation puts down the QPC for reasons cited above. Or are they just talking thru their collective hat(s)? ;)
"There is no dark side of the moon." - Pink Floyd
Chase85
Chase85
What it means is Precision doesn't necesaraly mean accuracy. Although the number 1.2 is more percise than 1, if the latency was too high sending you that number, the existing number could already be at 2. So you could be sitting here with a precise number of 1.2 but it doesn't necesaraly mean it is correct. What you want is the most Accurate Percise number. I havent had an issue with QPC ever being inaccurate so im happy with it.
_____"C allows you to shoot yourself in the foot, C++ allows you to re-use the Bullet, Assembly allows you to Create the Bullet from Molecules"

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.