Jump to content
  • Advertisement
Sign in to follow this  
Wixner

[Win32] QueryPerformance Anomalities

This topic is 4257 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

For the past two days, I've seen pink-spotted elephingos flying around throwing pumpkins at kids because this weird behaviour of QueryPerformanceCounter and QueryPerformanceFrequency.
[source lang = "cpp"]

//////
// my objects constructor
//////
if( !QueryPerformanceFrequency( &m_frequency ) )
 throw "QueryPerformanceFrequency failed";

//////
// my objects update-function
//////
LARGE_INTEGER start;
if( !QueryPerformanceCounter( &start ) )
 throw "QueryPerformanceCounter@start failed";

// do some computations, time-space-continuum disruptions and coffe...

LARGE_INTEGER end;
if( !QueryPerformanceCounter( &end ) )
 throw "QueryPerformanceCounter@end failed";

// calculate the time between start and end
double time = static_cast < double >( ( end.QuadPart - start.QuadPart ) / static_cast < double >( m_frequency.QuadPart ) );

// keep track of time
static double counter = 0;
counter += time;

// average computations per second
double computations = 1.0 / time;

// run the app for approximately 1 second
if( counter >= 1.0 )
 return computations;




Unless my keen (yeah, right) eye got this wrong, the code seems valid, but the results are not. When my function returns after what's supposed to be 1 second, the application has in fact been active for 10 seconds. It seems that my "time" is 10 times less than what it should be. I've tried this on my two computers; one with and AMD64 and one AMD AthlonXP cpu, but the same behaviour exist on both. edit: i forgot to typecast the frequency to double, but the problem is still there [Edited by - Wixner on October 22, 2006 5:01:55 PM]

Share this post


Link to post
Share on other sites
Advertisement
Consider yourself lucky... I occasionally get a negative number (like 1 out of 20 times). I don't think it's very reliable?

btw, you have a static_cast<double>(LONGLONG / double) above... I'm not sure what the result of a LONGLONG / double would be, but maybe that's the source of your problem?

Hey, this link seems to have some more info...

Share this post


Link to post
Share on other sites
I looked through the link and that problem currently only occurs on dual-core Amd64 cpu's. The most annoying thing is that I know I've used this code earlier (a month or two ago).

I've just tested the code on a new fresh project, and the anomaly is still there:

[source lang = "cpp"]
#include <windows.h>
#include <iostream>

int main( int argc, char** argv )
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency( &frequency );
double _frequency = static_cast < double >( frequency.QuadPart );

double counter = 0;
while( counter < 10 )
{
LARGE_INTEGER start = { 0 };
QueryPerformanceCounter( &start );
double _start = static_cast < double >( start.QuadPart );

// seems correct
// Sleep( 10 );

// seems incorrect
// Sleep( 1 );

// the more work we throw to our cpu, the more it seems to differ
// for( int i = 0; i < 100000; ++i )
// float a = i * 3.1415192f;


LARGE_INTEGER end = { 0 };
QueryPerformanceCounter( &end );
double _end = static_cast < double >( end.QuadPart );

double time = ( _end - _start ) / _frequency;
counter += time;
std::cout << counter;

// my knowledge in console programming is.. limitied ;P
for( int i = 0; i < 1000; ++i )
std::cout << "\b";
}
}




If you guys got the time, could you please check this out and see if the counter (supposed to count on a second-basis) seems correct?

Share this post


Link to post
Share on other sites
Yeah duel core screws it up. You will get negative times in some cases, but don't worry, I got the solution right here for ya [smile] QueryPerformanceCounter is as accurate as you are gonna get on windows btw!

Anyways, I'm gonna just throw code at you, please excuse my language in my comments.. To make it work on a duel core system the easiest way is to set the thread affinity - basically lock it to run on one core:


/**************************************************************************
*
* File: cTime.cpp
* Author: Neil Richardson
* Ver/Date:
* Description:
*
*
*
*
*
**************************************************************************/


#include "cDebug.h"
#include "cTime.h"

using namespace core;
/////////////////////////////////////////////////
// Ctor & Dtor
/////////////////////////////////////////////////
cTime::cTime():
MilliSeconds_ ( 0.0f ),
Seconds_ ( 0.0f )
{
#ifdef WIN32_DUAL_CORE_TIMING
// Set our threads affinity to first CPU to stop jittering
if ( SetThreadAffinityMask( GetCurrentThread(), 1 ) == 0 )
{
DBG_FAIL( "Invalid affinity! Do you have a CPU at all?\n" );
}
#endif

#ifdef WIN32_PERFORMANCE_TIMER
// Get the frequency
if ( QueryPerformanceFrequency(&Freq_) == 0 )
{
DBG_FAIL( "QueryPerformanceFrequency is shit\n" );
}

// Get first tick
QueryPerformanceCounter(&FirstTick_);

#else // GetShitCount()

// Get first tick
FirstTick_ = GetTickCount();

#endif
}

cTime::~cTime()
{

}

/////////////////////////////////////////
// update
/////////////////////////////////////////
void cTime::update()
{
#ifdef WIN32_PERFORMANCE_TIMER
// Get the tick
QueryPerformanceCounter(&Tick_);

// Compensate
Seconds_ = (cReal)(Tick_.QuadPart - FirstTick_.QuadPart) / (cReal)Freq_.QuadPart;
MilliSeconds_ = Seconds_ * 1000.0f;

#else // GetShitCount()
MilliSeconds_ = (cReal)(GetTickCount() - FirstTick_);
Seconds_ = MilliSeconds_ * 0.001f;
#endif
}




Share this post


Link to post
Share on other sites
Odd, I will say I've never experienced that problem before. I mean try locking the thread affinity - see if that works, I mean do any other games give you any trouble? Another time - Could use the multimedia time - timeGetTime.

Share this post


Link to post
Share on other sites
No other application depending on QueryPerformanceTimer gives me any problems (not that I know of ofcourse )

Setting the thread's affinity does not change anything - it would be strange if it did in the first place though :)

timeGetTime() seems to work with my initial tests, but we all know we should avoid timeGetTime() like the plague ;)

Ah well, I suppose i need to wait for my fever to go down before I wrestle this beast any more :(

Edit:
Added the information about thread affinity

Share this post


Link to post
Share on other sites
Quote:

// seems correct
// Sleep( 10 );

// seems incorrect
// Sleep( 1 );


This is a BAD way to test timer code. Sleep(1) tells the OS that you need a minimum of 1ms downtime.
So your app probably wont be reactivated for 10-15ms. That would explain the
difference in timing there

Quote:

// for( int i = 0; i < 100000; ++i )
// float a = i * 3.1415192f;


If you are going to use loops like this to test your code make sure that you have optimizations turned completely off
or that loop will probably get removed from the output code.


Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!