High resolution timer module
Posted: Sat Sep 10, 2022 11:57 am
Hi all!
Doing some experimenting with a timer module that I want to use in some of my programs.
As it is now, I use prototypes to be able to call the correct function depending on if the target machine has a high resolution timer available or not. The drawback with this approach is that if I forget the parenthesis after the function name, I will not get the time but the address to the chosen procedure.
Feel free to comment on my approach and explain to me if You would think it would be better to use an Interface instead? I'm not very found of Interfaces since it's a lot of extra code just to initialize it, but I might be wrong.
The code is built with a Module for handling the timers (and selecting timer).
There's only two functions to use the Module from the outside:
I wrote some test code to try this out:

Sample output from the test code:
The complete source:
// Moved from "Tricks 'n' Tips" to "Coding Questions" (Kiffi)
Doing some experimenting with a timer module that I want to use in some of my programs.
As it is now, I use prototypes to be able to call the correct function depending on if the target machine has a high resolution timer available or not. The drawback with this approach is that if I forget the parenthesis after the function name, I will not get the time but the address to the chosen procedure.
Feel free to comment on my approach and explain to me if You would think it would be better to use an Interface instead? I'm not very found of Interfaces since it's a lot of extra code just to initialize it, but I might be wrong.

The code is built with a Module for handling the timers (and selecting timer).
There's only two functions to use the Module from the outside:
Code: Select all
Timer::Start() ; Keeps track of a start value for the timer (resets the timer)
Timer::GetNanoSeconds() ; Reads the timer
Sample output from the test code:
Code: Select all
Module Timer is choosing a high resolution timer
Testing HiRes timer with delay 500 ms
5010020000
Testing speed in a loop 1 with size 10000000
1156998000
2317878000
3582612000
4733897000
5888867000
Testing speed in a loop 2 with size 10000000
1172478000
1171137000
1162552000
1165073000
1167249000
Code: Select all
DeclareModule Timer
Prototype protoStart()
Prototype.q protoGetNanoSeconds()
Define Start.protoStart
Define GetNanoSeconds.protoGetNanoSeconds
EndDeclareModule
Module Timer
EnableExplicit
Define *StartTimer, *GetTimerNanoSeconds
Declare.l hiResTimerExists()
Declare useStandardTimer()
Declare useHiResTimer()
Declare StartHiresTimer()
Declare StartStandardTimer()
Declare.q GetHiresTimer()
Declare.q GetStandardTimer()
Global.q frequency, counterStartValue, counter
#debugAlwaysFailHiResTimer = #False
If hiResTimerExists() = #False
useStandardTimer()
Else
useHiResTimer()
EndIf
Start = *StartTimer
GetNanoSeconds = *GetTimerNanoSeconds
Procedure.l hiResTimerExists()
QueryPerformanceFrequency_(@frequency)
CompilerIf #debugAlwaysFailHiResTimer
frequency = 0
CompilerEndIf
If frequency > 0
Debug "Module Timer is choosing a high resolution timer"
ProcedureReturn #True
Else
Debug "Module Timer can't find the high resolution timer, fallback to standard 1ms resolution timer."
ProcedureReturn #False
EndIf
EndProcedure
Procedure useStandardTimer()
Shared *StartTimer, *GetTimerNanoSeconds
*StartTimer = @StartStandardTimer()
*GetTimerNanoSeconds = @GetStandardTimer()
EndProcedure
Procedure useHiResTimer()
Shared *StartTimer, *GetTimerNanoSeconds
*StartTimer = @StartHiresTimer()
*GetTimerNanoSeconds = @GetHiresTimer()
EndProcedure
Procedure StartHiresTimer()
QueryPerformanceCounter_(@counter)
counterStartValue = counter
EndProcedure
Procedure StartStandardTimer()
counterStartValue = ElapsedMilliseconds()
EndProcedure
Procedure.q GetHiresTimer()
QueryPerformanceCounter_(@counter)
ProcedureReturn Abs(counter - counterStartValue) / frequency * 10e9
EndProcedure
Procedure.q GetStandardTimer()
ProcedureReturn (ElapsedMilliseconds() - counterStartValue) * 10e6
EndProcedure
EndModule
#testDelay = 500
#loopSize = 1e7
Declare LetTheGoodLoopRoll()
; ***** Test 1
Timer::Start()
Debug "Testing HiRes timer with delay " + Str(#testDelay) + " ms"
Delay(#testDelay)
Debug Timer::GetNanoSeconds()
; ***** Test 2 - Accumulated timing
Debug " "
Debug "Testing speed in a loop 1 with size " + Str(#loopSize)
Timer::Start()
For j = 1 To 5
LetTheGoodLoopRoll()
Next
; ***** Test 3 - Lap times
Debug " "
Debug "Testing speed in a loop 2 with size " + Str(#loopSize)
For j = 1 To 5
LetTheGoodLoopRoll()
Next
Procedure LetTheGoodLoopRoll()
Timer::Start()
For i = 1 To #loopSize
g = Random(1e6, 1)
Next
Debug Timer::GetNanoSeconds()
EndProcedure
// Moved from "Tricks 'n' Tips" to "Coding Questions" (Kiffi)