Advertisement

High resolution timer

Started by November 11, 2007 05:19 AM
16 comments, last by Jan Wassenberg 17 years ago
I need a high resolution timer class that works for both Linux and Windows (by using #ifdefs etc, since I know that the platform independent C++ standard library time functions are too inaccurate). A. is there any good public domain implementation of this already, that you would recommend? or B. if I need to write it myself: 1. in Windows, which of the many possible implementations should I use? QueryPerformanceCounter() Windows timers (events, I think) GetTickCount() (someone said this one was inaccurate) timeGetTime() etc. etc. If possible, I would like one with at least millisecond resolution, and available on as much hardware as possible released since around year 2000. 2. in Linux, which of the many possible implementations should I use? gettimeofday() time() gethrtime() gethrvtime() As with the windows timer, I'm looking for as good hardware compatibility as possible, and millisecond resolution. It should also not be available only on a small number of Linux distributions, but is part of the standard so I can expect it to work on all of the major distributions.
clock_gettime is posix I think.

The down-side is that it's pretty much up to the kernel what to do.

clock_gettime on linux 2.6.21+ should(meaning I never tested it) use this mm-timer or what it's called (10mhz+ resolution). Maybe someone can share his windows-experience to this.
Advertisement
This is what i am using: http://rafb.net/p/g3v1v524.html
However i'm using SDL, but i guess you could just check how SDL implements SDL_GetTicks() to see how you should do it on linux.
Thanks a lot, that's exactly what I need!
Quote: Original post by lexs
This is what i am using: http://rafb.net/p/g3v1v524.html
However i'm using SDL, but i guess you could just check how SDL implements SDL_GetTicks() to see how you should do it on linux.


That really offers no advantages over using SDL's timer directly - especially since the Windows implementation there is broken (doesn't check for jumps in the performance timer), while SDL's works fine.

As to your original question:
All *nix variants (Linux, Mac OS X, etc.): gettimeofday() is the best way to do this. It uses the highest performance timer available, and exists on every *nix platform.
Windows: Here you need to use QueryPerformanceCounter(), but because it often skips/jumps, you need to compare it with the lower resolution GetTickCount(), and correct the performance counter when it jumps.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Quote: Original post by swiftcoder
Quote: Original post by lexs
This is what i am using: http://rafb.net/p/g3v1v524.html
However i'm using SDL, but i guess you could just check how SDL implements SDL_GetTicks() to see how you should do it on linux.


That really offers no advantages over using SDL's timer directly - especially since the Windows implementation there is broken (doesn't check for jumps in the performance timer), while SDL's works fine.


I had problems with my game running out of sync badly and i guessed it was a timer issue, so i hacked together this class (its not perfect by any means) and it worked again. It didnt run out of sync on every computer but some and with this class it worked on them all. :)

EDIT: I just checked the SDL source and it uses QueryPerformanceCounter() but only when USE_GETTICKCOUNT is defined, maybe it isnt defined in the regular win32 build?
Oh, seems like the whole QPC part has been commented out and hires_timer_available set to false. That explains it.

Maybe someone could be nice and write a proper crossplatform timer wrapper class? :)
Advertisement
Quote: Original post by swiftcoder
Windows: Here you need to use QueryPerformanceCounter(), but because it often skips/jumps, you need to compare it with the lower resolution GetTickCount(), and correct the performance counter when it jumps.

Hm, I'm not sure I understand what is skipped. Do you mean that QPC occasionally skips doing a new hardware check and just reads off the same old value from some memory location, so that the result equals the last result read? So, should the comparison be as follows (pseudo code)?
NewQPCResult = QueryPerformanceCounter();while (NewQPCResult - OldQPCResult == 0 && newGetTickCountResult - oldGetTickCountResult > 0) {  NewQPCResult = QueryPerformanceCounter();}

Or how should the comparison be made?

Quote: Original post by lexs
Maybe someone could be nice and write a proper crossplatform timer wrapper class? :)

I can post mine here when it's ready and tested for windows :), but I won't be able to test it on Linux until in a few days.

Edit: here's a temporary timer, but it doesn't use QPC, but instead uses timeGetTime. It's probably accurate, but the resolution isn't too high.

#ifdef WIN32	#define WIN32_LEAN_AND_MEAN	#include <windows.h>	#include <mmsystem.h>#endif#include <SDL/SDL.h>inline unsigned long myGetTicks() {#ifdef WIN32	return timeGetTime();#else	return SDL_GetTicks();#endif}


[Edited by - all_names_taken on November 11, 2007 11:08:18 AM]
Quote: Original post by all_names_taken
Quote: Original post by swiftcoder
Windows: Here you need to use QueryPerformanceCounter(), but because it often skips/jumps, you need to compare it with the lower resolution GetTickCount(), and correct the performance counter when it jumps.

Hm, I'm not sure I understand what is skipped. Do you mean that QPC occasionally skips doing a new hardware check and just reads off the same old value from some memory location, so that the result equals the last result read? So, should the comparison be as follows (pseudo code)?
NewQPCResult = QueryPerformanceCounter();while (NewQPCResult - OldQPCResult == 0 && newGetTickCountResult - oldGetTickCountResult > 0) {  NewQPCResult = QueryPerformanceCounter();}

Or how should the comparison be made?


Take a look here: Microsoft KB: 274323

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Here's a writeup on the topic: Timing Pitfalls and Solutions

HTH+HAND
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3
Quote: Original post by Jan Wassenberg
Here's a writeup on the topic: Timing Pitfalls and Solutions

HTH+HAND


Nice, I hadn't seen a thorough analysis of this before.

It also might be worth talking to the guys at OGRE - they are using GetTickCount() to stabilise QueryPerformanceCounter(), it seems with much success.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement