High resolution Timer class (especially Windows)


#1

The implementation of the Timer class uses “Time::getMillisecondCounter()”. This counter is in windows a very low resolution timer (about 16 milliseconds). In some applications I need timed events with a better resolution (near 10 or 12 millseconds), that are exactly timed.

Would it be possible to have another Timer class (or an option to the Timer class), that uses the high resolution “Time::getMillisecondCounterHiRes()”?


#2

Well, no, there’d be no point - the Timer class uses event-based callbacks, so it’s inherently inaccurate.

But I’m not sure where you’re getting your information from - in my experience, the millisecond counter works very well, getting an accuracy of about 1ms.


#3

Using this test class for the timer functionality:

class TimerTest: public Timer
{
public:
	TimerTest(int milliSeconds):
		lastCounterHiRes(0)
	{
		printf("TimerTest: milliseconds = %d\n", milliSeconds);
		startTimer(milliSeconds);
	}
	~TimerTest()
	{
		stopTimer();
	}

	void timerCallback()
	{
		int64 counterHiRes = (int64)Time::getMillisecondCounterHiRes();
		printf("counter = %lld, difference = %lld\n", counterHiRes, counterHiRes-lastCounterHiRes);
		lastCounterHiRes = counterHiRes;
	}

private:
	int64 lastCounterHiRes;
};

I get the following output when testing on Windows XP SP2 on a HP xw4300 workstation for variuos values of milliseconds:

Testing the same with Linux on the same workstation gives:

Which is not 100% perfect, but much more accurate and as precise as I need it.

For testing I changed the implementation of “InternalTimerThread::run” to use “Time::getMillisecondCounterHiRes()” instead of “Time::getMillisecondCounter()” and that gives the following results on windows

Also not perfect, but within the accurateness I need.

To my opinion this is because “Time::getMillisecondCounter()” is based on the Windows function “GetTickCount” and that is this inaccurate.


#4

Just an additional remark: When testing this, I found that obviously the “Time::getMillisecondCounterHiRes” on Linux returns the milliseconds since epoch and not since system startup as in Windows and as stated in the documentation.


#5

…but like I said above, that test is completely meaningless, because the Timer class uses the event-loop. All the callbacks are completely at the mercy of other events, like repaints, button clicks, mouse-moves, other timers, etc, so they could be several seconds late, not just milliseconds.

If you ran a loop that just printed the value of Time::getMilliseconds, you’d see that the resolution is actually very good. But the Timer class is absolutely not designed for time-critical events.


#6

Do you really mean “Time::getMillisconds”? This method returns the milliseconds part of a Time object and it’s resolution depends how you initialised the Time object.
I am talking of “Time::getMillisecondCounter” which is used internally by the Timer class.
I created this very simple test program:

int main(int argc, char** argv)
{
	initialiseJuce_NonGUI();

	for (int i=0; i<100000; i++)
	{
		printf("Time::getMillisecondCounter(): %u\n", Time::getMillisecondCounter());
	}

	shutdownJuce_NonGUI();
	return 0;
}

The output on my windows machine is the following:

and so on. On Linux it really switches every millisecond.

I understand that the Timer class is not designed for time-critical events, but I do not understand that my test is completely meaningless, when it shows, that it could be much better in Windows, if “Time::getMillisecondCounter” is replaced with “Time::getMillisecondCounterHiRes” in the implementation of the Timer class.

The behaviour of the Timer class is sufficient for my applications on Linux and could be sufficient on Windows, if it would use the HiRes counter. But the default behaviour (at least on my test machines) on Windows is not good enough.

Do you have any other explanation, why “Time::getMillisecondCounter()” behaves in this way on my machines on Windows. Is there a mistake that I can make when building and linking Juce applications??


#7

Hi,

I tend to support Andreas.
Another timing source with better accuracy on the Windows platform is the timeGetTime() function from the Multimedia API.
You have a discussion about this very problem here, where Paul di Lascia comment about a remark I made :
http://msdn.microsoft.com/en-us/magazine/cc163931.aspx

Robert


#8

Well, if you need a hi-res timer, use Time::getMillisecondCounterHiRes()… that’s why it’s there. And if you just need a plain old, not-too-fussy counter, use Time::getMillisecondCounter().

On a side-note, I used to use timeGetTime(), but changed it to GetTickCount(). Can’t actually remember why I changed that…