More accurate alternative to millisecs()
BlitzMax Forums/BlitzMax Programming/More accurate alternative to millisecs()
| ||
I was going to request it, but in the meantime came up with this (only works on OS X): I found that millisecs wasn't accurate enough for me, so I present the following. Add this bit to your Blitz source: Import "GetTime.c" Extern Function getTime:Double() End Extern And place this in a text file named "GetTime.c" in the same folder as your Blitz project: #include <Carbon/Carbon.h> double getTime() { double t; t=(double)GetCurrentEventTime(); return t; } This returns the time in seconds since System startup. I have no idea how to do this on Windows, but I'm sure someone else does. |
| ||
I dont own BlitzMax Umm, doesnt millisecs (at least in the other Blitz's) return the milliseconds since system startup? |
| ||
Maybe so, but this is accurate to more than 1/1000th of a second, which is what I needed. |
| ||
So how accurate is it? I did a quick check with google and didn't find anything specific. There were some suggestions that the resolution is better than one millisecond. But how much better? |
| ||
Since you can measure 1.3 and 1.4 microseconds while running a testprogram, its 1/10000000 second. I'm on windows - so I cannot test it myself and must rely on what I read at iDevGames: I have exactly what you want... #include <CoreServices/CoreServices.h> double GetUpTime(void) { AbsoluteTime atime = UpTime(); Nanoseconds nsecs = AbsoluteToNanoseconds(atime); double time = UnsignedWideToUInt64(nsecs); return time*1.0E-9; }; This function returns the uptime of the machine in seconds, and on my machine (G4/400) two successive calls measure a delay of 1.3-1.4 microseconds. |
| ||
On win32 I recommend QueryPerformanceCounter to get the time and QueryPerformanceFrequency to get the resolution of the timer. |
| ||
QueryPerfomanceCounter is the highest resolution on Windows. So yes, tickcount() aint as accurate. |
| ||
Doesn't QueryPerformanceCounter mess up with Intel's SpeedStep and, in the future, AMD's Cool & Quiet? |
| ||
You are right Michael, I never thought of that. However, Intel mention something called an Enhanced Timer which make use the QueryPerformance functions but deals with SpeedStep and such. But I don't know if it could be used in Bmax or not. |
| ||
This thread on another forum might be of use to you lot. |
| ||
It is more precise than millisecs to be sure. I was finding it difficult to get accurate fps readings when I could only get the time to the 1000th of a second, since my project runs between 300 and 750 fps. |
| ||
It is more precise than millisecs to be sure. I was finding it difficult to get accurate fps readings when I could only get the time to the 1000th of a second, since my project runs between 300 and 750 fps. Don't count millisecs between frames, count frames per second (or half second, etc). I'll dig up my FPS code: Const fpsUpdate# = 0.5 Global fpsCount, fpsLastUpdated, fpsLastCount Function FPS( ) If ( Millisecs( ) - fpsLastUpdated ) > Int( fpsUpdate# * 1000.0 ) fpsLastCount = Float( fpsCount / fpsUpdate# ) fpsCount = 1 fpsLastUpdated = MilliSecs( ) Else fpsCount = fpsCount + 1 EndIf Return fpsLastCount End Function With fpsUpdate as default, it counts the number of frames every half second and multiplies by two. This is good because it gives you a precise, to the nearest frame number - it also means the fps counter is MUCH more stable and easier to read than updating every frame. |
| ||
Here is some examples of using QueryPerformanceCounter in Windows - wrapped in a little class (on GHz machines, this is nanosecond accuracy):Framework brl.retro ' initialize the timer internals TCodeTimer.Initialise() Print "Timing 1..." Local myarray:Int[1000] Local dummy:Int timer:TCodeTimer = TCodeTimer.Create() timer.StartWatch() While timer.WatchTime() < 1000 timer.StartTimer() Local ma_len:Int = myarray.length - 1 For counter = 0 To ma_len dummy = myarray[counter] Next timer.StopTimer() Wend Print "Using length in local variable" Print "Iterations: " + timer._iterations Print "Total Time: " + timer._totaltime Print "Average time: " + timer._totaltime / Double(timer._iterations) Print "***************************" Print timer.ResetTimer() Print "Timing 2..." timer.StartWatch() While timer.WatchTime() < 1000 timer.StartTimer() For counter = 0 Until myarray.length dummy = myarray[counter] Next timer.StopTimer() Wend Print "Using length in For/Until" Print "Iterations: " + timer._iterations Print "Total Time: " + timer._totaltime Print "Average time: " + timer._totaltime / Double(timer._iterations) Print "***************************" Print timer.ResetTimer() Print "Timing 3..." timer.StartWatch() While timer.WatchTime() < 1000 timer.StartTimer() For value=EachIn myarray Next timer.StopTimer() Wend Print "Using length in For/Until" Print "Iterations: " + timer._iterations Print "Total Time: " + timer._totaltime Print "Average time: " + timer._totaltime / Double(timer._iterations) Print "***************************" Print ' classes Extern "win32" Function QueryPerformanceCounter(count:Long Var) Function QueryPerformanceFrequency(freq:Long Var) End Extern Type TCodeTimer Field _start:Long Field _stop:Long Field _iterations:Int Field _totaltime:Double Method ResetTimer() _start = 0 _stop = 0 _iterations = 0 _totaltime = 0 End Method Method StartTimer() QueryPerformanceCounter(_start) End Method Method StopTimer() QueryPerformanceCounter(_stop) _totaltime :+ (Double(_stop - _start) / Double(_freq)) _iterations :+ 1 End Method ''' Stopwatch functions Field _watchstart:Double Method StartWatch() self._watchstart = QueryCounter() End Method ''' returns the number of milliseconds since calling StartWatch() Method WatchTime:Double() Return QueryCounter() - _watchstart End Method ''' Globals ''' Initialize should be called before first use, to determine timer class overhead Global _overhead:Double Global _freq:Long Function Create:TCodeTimer() Return New TCodeTimer End Function Function Initialise() QueryPerformanceFrequency(_freq) _freq :/ 1000 End Function Function QueryCounter:Double() Local counter:Long QueryPerformanceCounter(counter) Return Double(counter) / _freq End Function End Type |