PDA

View Full Version : High precision/resolution time, multicore issues



z42
01-14-2008, 07:39 PM
Is there any functionality in ClanLib to retrieve a high-precision/resolution time value like it is available with the Windows API ::QueryPerformanceCounter()?

I searched the docs, forum and the code but couldn't find anything besides CL_System::get_time(). This functions implementation uses ::QueryPerformanceCounter() which makes good precision but limits the resolution by returning ms units only.

Furthermore CL_System::get_time() seems to have a multicore-issue that occassionally results in discontinuous movement of objects if you base the timing in your games frame loop on it. "Occassionally" means e.g. once every ~30s, some times more often and very noticable.
I could work around this by calling ::SetProcessAffinityMask( ::GetCurrentProcess(), 1 ) at the start of my game, but would loose platform-independence.
(See also:
http://msdn2.microsoft.com/en-us/library/bb173458(VS.85).aspx
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323 )

Last, I suggest increasing the precision of CL_System::sleep() which has a default precision of only ~10ms under Windows by calling Windows-API ::timeBeginPeriod( 1 ) at process start and ::timeEndPeriod( 1 ) at process end. Or at least provide an option to do so.

sphair
01-14-2008, 08:39 PM
ClanLib team accept patches if you see a solution for this :)

rombust
01-15-2008, 08:15 AM
Have you seen this happen in a ClanLib project?

Since ClanLib reduces the timer accuracy to ms, i would have thought that the muticore timer problem would not happen, or be extremely rare?

z42
01-15-2008, 09:55 AM
Have you seen this happen in a ClanLib project?

Since ClanLib reduces the timer accuracy to ms, i would have thought that the muticore timer problem would not happen, or be extremely rare?

Yes, indeed. I used CL_System::get_time() in a game I'm developing to achieve a fixed frame rate.
Something like this:

while( ! quit )
{
unsigned startTime = CL_System::get_time();
DrawScreen();
unsigned drawTime = CL_System::get_time() - startTime;
CL_System::sleep( DESIRED_FRAME_TIME - drawTime );
}

There definitely were noticable time glitches until I called ::SetProcessAffinityMask( ::GetCurrentProcess(), 1 );
My System is a WinXP SP2 on a dual core CPU at ~1.8 GHz.

I'm now avoiding CL_System::get_time() completely by calling ::QueryPerformanceCounter() directly since I need more precision in the timing.

I will think about contributing a platform-independent patch for ClanLib later since my game is in a very early phase of developement where this doesn't have a high priority ;)

ephemeron
03-17-2008, 07:34 PM
Hmm, in no ways I am an expert, but sleeping for a calculated amount of time does not look good for me.
This is what I am using:


LONGLONG PerfCountFreq;
LONGLONG CurrentTime;
LONGLONG NextUpdate;
const LONGLONG FPS=60;
LONGLONG UpdateStep;
int Counter=0;

QueryPerformanceFrequency( (LARGE_INTEGER*) &PerfCountFreq);

UpdateStep=PerfCountFreq/FPS;
QueryPerformanceCounter( (LARGE_INTEGER*) &CurrentTime);
NextUpdate=CurrentTime;
while (!quit) { // well yes
if (CurrentTime >= NextUpdate) {
NextUpdate+=UpdateStep;
cout << ++Counter << endl;
QueryPerformanceCounter( (LARGE_INTEGER*) &CurrentTime);
} else {
Sleep(1);
QueryPerformanceCounter( (LARGE_INTEGER*) &CurrentTime);
}
}

This is a "catch-up" style loop, as when the computer lags heavily, it will make up for the delay by accelerating to maximum speed as long as it is needed. (I dunno', but it is like Warcraft3's speedups? )