Accuracy of Millisecs()

BlitzMax Forums/BlitzMax Programming/Accuracy of Millisecs()

Grey Alien(Posted 2006) [#1]
As far as you know, is Millisecs() accurate on *all* PCs? I appreciate that when you read it, it's rounded to the nearest millisec (wonder if it uses bankers rounding, normal rounding, or Floor or Ceil?). Anyway, I wondered if sometimes it can return values that are out by quite a few milliseconds on some PCs, perhaps if other tasks are interfereing. Anyone see anything like this posted before? I remember seeing someone say something about the accuracy of Millisecs() and wondered what they meant.


GfK(Posted 2006) [#2]
Its the same on everyone's PC.

I appreciate that when you read it, it's rounded to the nearest millisec (wonder if it uses bankers rounding, normal rounding, or Floor or Ceil?).
Who cares? Its 1/1000th of a second. You can't comprehend such a small amount of time.


TartanTangerine (was Indiepath)(Posted 2006) [#3]
Time is time after all unless your name is DR Who.

Today, typical CPUs run in excess of 3GHz, so you'd think that 1ns accuracy shouldn't be that big a deal - it's three clock cycles right? But remember that CPU pipelines tend to run pretty deep these days. So while your processor might be able to execute instructions at a rate of several per nanosecond, that doesn't mean that any individual instruction necessarily executes in under a nanosecond.
http://www.interact-sw.co.uk/iangblog/2005/03/31/nanoperf

A better path is to use Win32's special high-resolution timers that span a pair of functions: QueryPerformanceCount() and QueryPerformanceFrequency(). On Intel-based systems the functions rely on a counter built into Pentium chips since the Pentium II generation. When an Intel-based system is started up, a 64-bit register keeps track of elapsed clock ticks. This counter provides an extremely high-resolution timing device.
http://www.devx.com/SummitDays/Article/16293/1411/pdo/29FD2B1375EBAC824CE7A420FAC318F4:3835


Grey Alien(Posted 2006) [#4]
Hmm that hi-res thing sounds interesting, but really it would need to work on Celerons and AMDs as well...


TartanTangerine (was Indiepath)(Posted 2006) [#5]
Umn, try it?


Grey Alien(Posted 2006) [#6]
I don't have non Pentiums. Seems that to use it properly you have to get a totally accurate figure for the speed of the chip first.


FlameDuck(Posted 2006) [#7]
Millisecs is accurate down to the millisecond, for any crystal or square pulse generator running close to 10 KHz (10 pulses per millisecond). I don't care how long your CPU pipeline is, it's not going to interfere with millisecond accuracy.


Dreamora(Posted 2006) [#8]
you have to get a totally accurate figure for the speed of the chip first.


And as even EA and other are not capable of that, I would not try it ... (Sims 2 and any other game having issues with HT / dualcore suffers exactly of this problem because "speed" is relative when you have Cool'n'Quiet / SpeedStep technology)


Jake L.(Posted 2006) [#9]
I've written a Profiler-module (based on some code I found in the code archives) using QueryPerformanceCount. It runs well on my system (Athlon XP). It's not in the archives yet(no time to really finish it and check for bugs), but feel free to use it or copy code from it:




ImaginaryHuman(Posted 2006) [#10]
At the instant that you call Millisecs() it should be accurate. That said, bare in mind that you can execute a fair amount of code WITHIN 1 millisecond. If you just read the value, and are only going to get updates from it ever millisecond, it's possible that it also just changed to the next millisecond the instant after you read it. Your code is not synchronized with the timer. So at the most you might be up to 1 millisecond off. It's not so much the accuracy of the timer which is always to the millisecond, but moreso the accuracy of your checking of the timer and catching it exactly when it changes.

I thought about this too when I was trying to measure the amount of remaining time left in a frame. Ideally each frame was going to last 16 milliseconds. Thing was, since it's possible to read a value just before it changes, I sort of had to reduce the number of available millisecs per frame by 1 to compensate, which reduced the amount of processing time available in the frame. If I didn't do this, the flip may possibly have not occured within the frame time and would've waited for the next vertical blank, wasting a whole frame and making things jerky.

So you only really need worry about having not checked the millisecs recently enough and the possibility that there is some delay between your checking it and your using it. The closer your code use of it is to the reading of it the better. That said, if you just read the value just *after* it changed, and you're waiting for a given future change, then you may end up with potentially up to a whole millisecond extra time, based on when you read it the first time and when you read it the second time. ie your code's execution resolution is higher than the resolution of the timer.


Grey Alien(Posted 2006) [#11]
Thanks Jake.L and others for feedback.

AngelDaniel: Exactly, when you read the timer it could be at the start of a millisec or the end of one, and your code might think a millisec has passed by the next loop when really 0.01 of a millisec has passed.

"bare in mind" Freudian ;-)


ImaginaryHuman(Posted 2006) [#12]
Hmm. You could check for a millisecond value, then rapidly check until 2 millisecs have passed, because that'll probably mean 1.02 millisecs have passed. ;-)


*(Posted 2006) [#13]
why dont you wait for a millisecond to pass (the millisec value changing) before reading, that way you will test from the beginning of a millisecond and that will give you an 'accurate' result.


Grey Alien(Posted 2006) [#14]
EdzUp: Yes that's true. It's not really actually an issue for me, I was just interested in if it's inaccurate by BIG amounts on some systems, perhaps when interrupted by other tasks.


ImaginaryHuman(Posted 2006) [#15]
The timer value itself should be accurate despite anything else that is going on because presumably the timer HAS to at some level be generated by the hardware itself which surely would be always processed internally regardless of any software running.


Grey Alien(Posted 2006) [#16]
that's what I thought, but was just interested if ever say a request to the time could return duff values due to other threads interfering. I guess not.


TartanTangerine (was Indiepath)(Posted 2006) [#17]
Sub Nano Second timing, this is actually time in cpu cycles, you'll need to do a little math to calibrate it to time.

__int64 GetMachineCycleCount()
{      
   __int64 cycles;
   _asm rdtsc; // won't work on 486 or below - only pentium or above
   _asm lea ebx,cycles;
   _asm mov [ebx],eax;
   _asm mov [ebx+4],edx;
   return cycles;
}



Grey Alien(Posted 2006) [#18]
groovy choovy, unfortunately to work out the time, you need to know the accurate CPU speed but it seems that getting that accurate ain't so easy...


TartanTangerine (was Indiepath)(Posted 2006) [#19]
Wrong, calculating the number of cycles per millisecond is easy:
int64 timethen = GetMachineCycleCount();
Sleep(1);
int64 timenow = GetMachineCycleCount();
int64 one_millisecond = timenow - timethen;
float one_nanosecond =  (float)((float)one_millisecond / (float)1000); // It's gonna be 1 cycle for 1 GHz



Grey Alien(Posted 2006) [#20]
Of course, good one Tim!


Grey Alien(Posted 2006) [#21]
question is, how does Sleep(1) determine when a millisec is up? If it just reads a value and waits until it's 1 higher, this could be only a fraction of a millisecond, or anything up to a whole millisecond. How does Delay(1) ensure that it stops for one millisec? Maybe delay 10 would be more accurate as the delay could be 9-10ms.


bradford6(Posted 2006) [#22]
The closer to the speed of light your PC gets, the longer each millisec becomes.

you can simulate this by attaching your PC to a 12 meter rope and spinning it with the rotational velocity of 1,034,456.

I would try again but my rope broke.


TartanTangerine (was Indiepath)(Posted 2006) [#23]
Yeah I'm using Sleep(1) as a baseline, In the real world you might want to do it for 100ms to account for any small errors.


Robert Cummings(Posted 2006) [#24]
I assume this is to prevent any stuttering when msn etc pops up??


Yan(Posted 2006) [#25]
float one_microsecond =  (float)((float)one_millisecond / (float)1000); // It's gonna be 1 cycle for 1 GHz



TartanTangerine (was Indiepath)(Posted 2006) [#26]
Silly me, 1 nano second is one cycle - 1 microsecond is 1000 cycles on a 1ghz machine


Yan(Posted 2006) [#27]
I forgot to change the comment. :o)


Grey Alien(Posted 2006) [#28]
I assume this is to prevent any stuttering when msn etc pops up??
nah, sorry. See the thread priority thread for info about that.