Sign in to follow this  

QueryPerformanceCounter woes.

This topic is 4694 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Having lost all my source code in a recent hard disk format I dont have my good ole performance timer that I've used in previous little games, so I'm back on the web looking it all up and rebuilding the functions. Anyways, I have the following basic code to record time differences, but near the beginning it sometimes gives negative numbers, why?
LARGE_INTEGER lastTime;
LARGE_INTEGER tickFreq;
int ready = 0;

//QueryPerformanceCounter(&time);
//QueryPerformanceFrequency(&rate);
//double calc = (double) time.QuadPart / (double)rate.QuadPart;

void timerPrep(void)
{
	QueryPerformanceFrequency(&tickFreq);
	QueryPerformanceCounter(&lastTime);
	ready = 1;
}

double timerTick(void)
{
	if(ready == 0) {return 0;}

	LARGE_INTEGER thisTime;
	double theDifference;

	QueryPerformanceCounter(&thisTime);
	theDifference = ((double)thisTime.QuadPart - (double)lastTime.QuadPart) * tickFreq.QuadPart;

	lastTime = thisTime;

	return theDifference;	
}
I have written this basic console app to do some rough testing
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

LARGE_INTEGER lastTime;
LARGE_INTEGER tickFreq;
int ready = 0;

//QueryPerformanceCounter(&time);
//QueryPerformanceFrequency(&rate);
//double calc = (double) time.QuadPart / (double)rate.QuadPart;

void timerPrep(void)
{
	QueryPerformanceFrequency(&tickFreq);
	QueryPerformanceCounter(&lastTime);
	ready = 1;
}

double timerTick(void)
{
	if(ready == 0) {return 0;}

	LARGE_INTEGER thisTime;
	double theDifference;

	QueryPerformanceCounter(&thisTime);
	theDifference = ((double)thisTime.QuadPart - (double)lastTime.QuadPart) * tickFreq.QuadPart;

	lastTime = thisTime;

	return theDifference;	
}


int main(int argc, char *argv[])
{

  timerPrep();
  
  /*int i = 0;
  for (i = 0; i < 1000; ++i)
  {
    int lala = 4009;
    int boo = i / lala;
  }*/

  system("PAUSE");

  printf("Took %i\n", timerTick());

  printf("laaaa\n");
  system("PAUSE");
  return 0;
}
Resources on the web on how to use these functions seem rather vague ... does anyone know what I'm doing wrong at a glance?

Share this post


Link to post
Share on other sites
I had this problem a while ago...turnde out I was just using the low 32 bits which is obviously VERY wrong ;o) you're not though so lets move on.

It looks to me (without looking at my code as Im at work) like you should be dividing by the frequency...not multiplying by it...to get the time difference? you're mul'ing a 64bit number by another probably large 64 bit number...so Im guessing you're just overflowing and "theDifference" is wrapping to negative

? Could be wrong...I've not tested the theory.

Also perhaps you can save on a cast?

theDifference = (double)(thisTime.QuadPart - lastTime.QuadPart)\tickFreq.QuadPart;

again not tested and I can never decide if that sorta thing will work without plugging in the code... =op

good luck!

Share this post


Link to post
Share on other sites
Quote:
Original post by xyuri
Having lost all my source code in a recent hard disk format I dont have my good ole performance timer that I've used in previous little games, so I'm back on the web looking it all up and rebuilding the functions.

Anyways, I have the following basic code to record time differences, but near the beginning it sometimes gives negative numbers, why?

<code snip>

I have written this basic console app to do some rough testing

*** Source Snippet Removed ***

Resources on the web on how to use these functions seem rather vague ... does anyone know what I'm doing wrong at a glance?



double timerTick(void)
...
printf("Took %i\n", timerTick());


Are you sure? %i is an integer you know :) (use %f).

This was the first error. But the more important is that you must divide by the time freq, not multiply by it. It is a frequency, not a period.

Hence:


theDifference = ((double)thisTime.QuadPart - (double)lastTime.QuadPart) / double(tickFreq.QuadPart);


And then it seems to works...

HTH,

Share this post


Link to post
Share on other sites
As far as I can see, you are casting DWORDs into double's where you shouldnt.

theDifference = ((double)thisTime.QuadPart - (double)lastTime.QuadPart) * tickFreq.QuadPart;

should be:

theDifference = thisTime.QuadPart - lastTime.QuadPart;

where theDifference is a DWORD as well, divide by the total ticks per second and you should have your double there (typecast it when converting to seconds, not before), remember the quadparts are DWORD's

Good luck :)

p.s. it might work anyway, but it seems like a waste

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
don't use LARGE_INTEGER, you can use __int64s with those functions. then take difference between __int64s and convert to double, then divide by the frequency.

Share this post


Link to post
Share on other sites
// link with winmm.lib

unsigned long GetTime(void) // returns the time in milliseconds
{
unsigned __int64 frequency;
unsigned __int64 count;

if (QueryPerformanceFrequency((ULARGE_INTEGER *)&frequency))
{
QueryPerformanceCounter((ULARGE_INTEGER *)&count);

return (unsigned long)(count * 1000 / frequency);

}

return timeGetTime();

}

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
don't use LARGE_INTEGER, you can use __int64s with those functions. then take difference between __int64s and convert to double, then divide by the frequency.


Well, LARGE_INTEGER is the type which is used by QPC and QFF. Since this is a type abstraction (we don't have to worry about the underlying data type), I believe we should still use them.


QueryPerformanceCounter((LARGE_INTEGER *)&my_i64_var);


Is probably more dangerous, and I'm not sure it is really needed.

Regards,

Share this post


Link to post
Share on other sites
Quote:
Original post by Emmanuel Deloget
Quote:
Original post by Anonymous Poster
don't use LARGE_INTEGER, you can use __int64s with those functions. then take difference between __int64s and convert to double, then divide by the frequency.


Well, LARGE_INTEGER is the type which is used by QPC and QFF. Since this is a type abstraction (we don't have to worry about the underlying data type), I believe we should still use them.


QueryPerformanceCounter((LARGE_INTEGER *)&my_i64_var);


Is probably more dangerous, and I'm not sure it is really needed.

Regards,


Taken from the windows header files



typedef __int64 LONGLONG;

#if defined(MIDL_PASS)
typedef struct _LARGE_INTEGER {
#else // MIDL_PASS
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
};
struct {
DWORD LowPart;
LONG HighPart;
} u;
#endif //MIDL_PASS
LONGLONG QuadPart;
} LARGE_INTEGER;





as you can see __int64 is the same as LARGE_INTEGER.

so

why use __int64 ?

-> because MSVC++ 7 has built in support for __int64

what does this mean ?

-> it means we can multiply and divide it safely in the function I detailed above

what if I dont have MSVC++ 7

-> then it is not necessary to use __int64, but you will have to implement the division and multiplication yourself

Share this post


Link to post
Share on other sites
Quote:
Original post by ZedFx
Taken from the windows header files

*** Source Snippet Removed ***

as you can see __int64 is the same as LARGE_INTEGER


Yes. I didn't say it was wrong. Hum. Well. As for today, it is true. But if I have a look to a particular implementation of the STL I'll have überl33t hints to find new way to use my vector. Is it a good idea ?

When an API gives you an abstracted data type to use, it is actually better to use it. Moreover, I think it is actually a very bad idea to tell a beginner to use what I might call "a hack". I don't call it a hack because it is bad, I call it like this because it assumes the knowledge of the internals of the API you are using (in this case, you had to search though the windows header to find it. It is not documented anywhere. A LARGE_INTEGER resolves to a LONGLONG or to a struct, not to a __int64).

Plus, you had to add those casts everwhere to enable everything to compile. Will they work if they go to __int128 when they'll release longhorn?

Quote:
Original post by ZedFx
so why use __int64 ?
-> because MSVC++ 7 has built in support for __int64
what does this mean ?
-> it means we can multiply and divide it safely in the function I detailed above
what if I dont have MSVC++ 7
-> then it is not necessary to use __int64, but you will have to implement the division and multiplication yourself


I hope their is support for LONGLONG as well :) More seriously, No offense but this cannot be an argument. Because VC7 supports __int64, I have to use it instead of an abstracted type? If I use gcc then LONGLONG is a typedef to long long. Should I change all my code? Should I make two version of my code to compile on both compiler? Just because they have support for a particular, non standard buitin type?

Hope you get my point, regards,

Share this post


Link to post
Share on other sites
w00000t ! :-) Thanks very much fellas. Yes, it appears that dividing by the frequency can be wuite useful! I really love the friendliness of everyone on these boards :-) Thanks again.

Just so all can see, here is my updated timer class:

LARGE_INTEGER timerLast;
LARGE_INTEGER timerThis;
LARGE_INTEGER timerFreq;
int timerReady = 0;

void timerPrep(void)
{
QueryPerformanceFrequency(&timerFreq);
QueryPerformanceCounter(&timerThis);
timerReady = 1;
}

double timerTick(void)
{
// If timerPrep function hasnt been run then return 0
if(timerReady == 0) {return 0;}
// LAST = THIS so that THIS can be updated and the difference returned
timerLast = timerThis;
// Update THIS
QueryPerformanceCounter(&timerThis);
// Return the Difference
return (double)(timerThis.QuadPart - timerLast.QuadPart) / (double)timerFreq.QuadPart;
}


[Edited by - xyuri on February 9, 2005 5:22:23 PM]

Share this post


Link to post
Share on other sites
Why does this crash??

LARGE_INTEGER* timerLast = 0;
LARGE_INTEGER* timerThis = 0;
LARGE_INTEGER* timerFreq = 0;
//int timerReady = 0;

void timerPrep(void)
{
QueryPerformanceFrequency(timerFreq);
QueryPerformanceCounter(timerThis);
//timerReady = 1;
}

double timerTick(void)
{
// If timerPrep function hasnt been run then return 0
//if(timerReady == 0) {return 0;}
// LAST = THIS so that THIS can be updated and the difference returned
*timerLast = *timerThis;
// Update THIS
QueryPerformanceCounter(timerThis);
// Return the Difference
return (double)(timerThis->QuadPart - timerLast->QuadPart) / (double)timerFreq->QuadPart;
}
??

Share this post


Link to post
Share on other sites
Because you created the pointers but they don't point to a valid block of memory - they instead point to 0. timerPrep() tries to write to a non valid block and then crash.

You should do:

LARGE_INTEGER timerLast = 0;
LARGE_INTEGER timerThis = 0;
LARGE_INTEGER timerFreq = 0;
int timerReady = 0;

void timerPrep(void) // you don't need the void, unless you are using pure C
{
QueryPerformanceFrequency(&timerFreq); // use &
QueryPerformanceCounter(&timerThis); // use &
timerReady = 1;
}

double timerTick(void)
{
// If timerPrep function hasnt been run then return 0
if(timerReady == 0) {return 0;}
// LAST = THIS so that THIS can be updated and the difference returned
timerLast = timerThis;

// Update THIS
QueryPerformanceCounter(&timerThis); // use &

// Return the Difference
return (double)(timerThis.QuadPart - timerLast.QuadPart) / (double)timerFreq.QuadPart;
}

You don't have to make your life more complex with those nasty pointers here.

HTH,

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
**I don't mean to highjack the thread, but on a related note...

Are there any known issues with QueryPerformanceCounter and "clock throttling" schemes found commonly on notebook CPU's?

Share this post


Link to post
Share on other sites
Quote:
Original post by Emmanuel Deloget
I don't call it a hack because it is bad, I call it like this because it assumes the knowledge of the internals of the API you are using (in this case, you had to search though the windows header to find it. It is not documented anywhere. A LARGE_INTEGER resolves to a LONGLONG or to a struct, not to a __int64).


Actually it is documented in the MSDN docs:

The LARGE_INTEGER structure is used to represent a 64-bit signed integer value.

Note Your C compiler may support 64-bit integers natively. For example, Microsoft® Visual C++® supports the __int64 sized integer type. For more information, see the documentation included with your C compiler.


and later:


Remarks

The LARGE_INTEGER structure is actually a union. If your compiler has built-in support for 64-bit integers, use the QuadPart member to store the 64-bit integer. Otherwise, use the LowPart and HighPart members to store the 64-bit integer.


I think in this case using the QuadPart member of LARGE_INTEGER on compilers that support a 64 bit int type can be considered standard usage and not a hack. However it may make your code less portable since you obviously won't be able to compile it on a compiler that does not support __int64. The LowPart and HighPart members are there to provide support for these compilers.

In general I agree that it is a good idea to not depend on undocumented "features" as they have a tendency to change or disapear.

Share this post


Link to post
Share on other sites

This topic is 4694 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this