QueryPerformanceCounter problems

Started by
5 comments, last by vbuser1338 18 years, 11 months ago
I'm sorry to post this but after looking on google I just can't get QueryPerformanceCounter to give me the number of seconds past. I need it for my pac-man game and using clock() for timebased movement does not work too well. I have a bit of code which does not work. I want to be able to multiple the seconds by a number of how many pixels to move a second so thats what they move by. So if it is 50 pixels a second and .1 seconds elapsed move 5 pixels. But I can't get this to work. Here is my code

#include <windows.h>
#include <ctime>
#include <cstdlib>
#include <stdio.h>
#include <iostream>

LARGE_INTEGER GetElapsedTime(LARGE_INTEGER start)
{
    LARGE_INTEGER ticspersecond;				//The cpu speed, needed to work out how many tics/sec
	LARGE_INTEGER time1, time2;				//The 1st and 2nd time to work out the difference between the 2
	float tics;						//A more convinent place to store ticspersecond
	float difference;					//The ticks between the 1st and 2nd time
	float seconds;						//The time in seconds between the 1st and 2nd time
	
	QueryPerformanceFrequency (&ticspersecond);		//WINAPI funciton, Gets the ticks per second
	tics = ticspersecond.QuadPart;				//A more convinent place to store ticspersecond, optional
	QueryPerformanceCounter (&start);			//WINAPI funciton, Gets the 1st time
    start.QuadPart = (ticspersecond.QuadPart *  start.QuadPart);
    return start;
}

int main()
{
    LARGE_INTEGER LastUpdate = GetElapsedTime(LastUpdate);
    LARGE_INTEGER CurrentTime = GetElapsedTime(CurrentTime);
    
	char answer = 'y';
	while(answer == 'y')
	{
        CurrentTime = GetElapsedTime(CurrentTime);   // Update counter
        std::cout << (CurrentTime.QuadPart - LastUpdate.QuadPart)<< std::endl;
        std::cin >> answer;
        LastUpdate = GetElapsedTime(LastUpdate);   // Update counter
    }
	return 0;
}

Can someone point out what I am doing wrong please? Thanks vbuser
Advertisement
Try something like this:

1. You need to get the resolution of your motherboards high performance counter and check one actually exists (should do on most new systems). The code below should give you starting time:

LARGE_INTEGER startTime;
LARGE_INTEGER lastTime;
LARGE_INTEGER currentTime;


if (QueryPerformanceCounter((LARGE_INTEGER *)&startTime))
{
QueryPerformanceFrequency((LARGE_INTEGER *)&frequency);
}
else
{
printf("ERROR: QueryPerformanceCounter not available on this machine \n");
}

startTick = GetTickCount();

//Get the current Performance Counter value
QueryPerformanceCounter((LARGE_INTEGER *)&currentTime);

elapsedTimeError = 0.0;

// Store last time and tick
lastTime.QuadPart = startTime.QuadPart;
lastTick = startTick;

firstTime = true;


2. To get the elapsed time:

// Get QUERYCount method
double previousError;
DWORD deltaPerformanceCounter;
DWORD deltaTickCount;

//Store the last tick count
lastTick = currentTick;

//get the current tick count
currentTick = GetTickCount();


//Store the elapsed tick count from the startTick
elapsedTick = currentTick - startTick;

//Store the last Time
lastTime.QuadPart = currentTime.QuadPart ;

//Get the current Performance Counter value
QueryPerformanceCounter((LARGE_INTEGER *)&currentTime);

// Calculate the elapsed time in secs from the start time
elapsedTime = ((double)(currentTime.QuadPart - startTime.QuadPart)/(frequency.QuadPart)) - elapsedTimeError;
//printf("Elapsed Time %f\n",elapsedTime) ;

// First time do not check for jumps as there will be a big jump!
if (!firstTime)
{
deltaPerformanceCounter = (DWORD)(((currentTime.QuadPart - lastTime.QuadPart) * 1000.0) / (double)frequency.QuadPart);
deltaTickCount = currentTick - lastTick;
previousError = elapsedTimeError ;

// if differnce between performance counter and tick count methods
// is greater than 500 ms then Counter has jumped
if ( abs( deltaPerformanceCounter - deltaTickCount ) > 500)
{
// printf("Timer jump\n");
elapsedTimeError = elapsedTimeError + (double)( (deltaPerformanceCounter/1000.0) - (deltaTickCount/1000.0) );
elapsedTime = elapsedTime - elapsedTimeError + previousError;
}
}
firstTime=false;

3. The elapsedTime should contain the number of seconds that have passed to however many decimal places your timer supports:


I hope this helps. If not, let me know and I'll try to explain it a bit better.


Mr. Creamy.

BTW: Just in case you are not aware, LARGE_INTEGER is defined somewhere in one of the headers window.h references.
I'm not exactly sure what you're trying to do in GetElapsedTime().

Some ideas:

You probably just want to call QueryPerformanceFrequency() once in your program.

The QPFrequency should be a divisor, not a multiplier.

I don't see any place where you subtract time2 from time1. In fact a lot of your variables and headers go unused, but you're definately going to need to subtract two tick counts at some point. That part of the logic is essential.

Finally, I've got a CTimer class that uses QPC if available, and if not, uses timGetTime(). I can post that code if you want - it's only about a hundred lines in total (header plus source).

Hope that helps.
1. seconds = ticks / ticks_per_second.

2. You can't use floats when converting to seconds. floats don't have enough precision to hold the values returned by QPC and QPF. Furthermore, you have to be careful because doubles don't have enough precision to hold values values returned by QPC. You should do it like this:
    double elapsed_seconds = double( current_time - old_time ) / double( ticks_per_second );
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Ok I got this code working I'm pretty sure right. But I would be interested at looking at your timer class if you didn't mind. Well here is what I have
#include <windows.h>#include <iostream>int main(){    LARGE_INTEGER startTime;    LARGE_INTEGER lastTime;    LARGE_INTEGER currentTime; 	LARGE_INTEGER frequency;	LARGE_INTEGER elaspedTime;	    if (QueryPerformanceCounter((LARGE_INTEGER *)&startTime))    {        QueryPerformanceFrequency((LARGE_INTEGER *)&frequency);    }    else    {        std::cout << "ERROR: QueryPerformanceCounter not available on this machine \n";    }    QueryPerformanceCounter(&currentTime);        //Get the current Performance Counter value    QueryPerformanceCounter(&startTime);	char answer = 'y';	while(answer == 'y')	{        QueryPerformanceCounter(&currentTime);        double timedif = double(((currentTime.QuadPart - lastTime.QuadPart) * 1000) / frequency.QuadPart) / 1000;        QueryPerformanceCounter(&lastTime);                std::cout << timedif << std::endl;        std::cin >> answer;    }	return 0;}


Thanks for the help with this.
vbuser
The "* 1000" and "/ 1000" will result in a 1 ms resolution, which is ok. But if you use a floating-point divide (with doubles) you will get the full resolution.
    double timedif = double(currentTime.QuadPart - lastTime.QuadPart) / double(frequency.QuadPart); 
Also, instead of querying the time twice, you can simply copy it ("lastTime = currentTime;"). Not only is this faster, but when you query the time twice, your elapsed time is slightly off.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Thanks. I fixed those two things now I just have to add a few more things and some levels and it will be done. Hopefully it won't take me too long.
Cya later,
vbuser

This topic is closed to new replies.

Advertisement