FreeBasic's Timer
-
- Posts: 4158
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
An observation.
If we use timeBeginPeriod in both delay() and regulate() to use a threshold of 3ms to keep the CPU load down, then we don't need to make adjustments for Timer being reset at midnight because that will not happen; being on Windows.
If we cannot use timeBeginPeriod, then we will have to use a threshold of 32ms because of Sleep's association with the system clock. Staying with 3ms is a disaster. I reckon we can go down to 24ms, but the CPU load is still horrendously high.
What I know about Linux can be put on the back of a postage stamp, and I have no idea what it does with using Timer in our code. Is Timer, or whatever is used, reset at midnight? The manual does not mention this.
Linux's system clock has a frequency of 100Hz as opposed to Windows 64Hz, so that will help, and perhaps we can get way with a threshold of 15ms. That is still poor compared with 3ms.
We need a Linux expert to come in here because I cannot help.
If we use timeBeginPeriod in both delay() and regulate() to use a threshold of 3ms to keep the CPU load down, then we don't need to make adjustments for Timer being reset at midnight because that will not happen; being on Windows.
If we cannot use timeBeginPeriod, then we will have to use a threshold of 32ms because of Sleep's association with the system clock. Staying with 3ms is a disaster. I reckon we can go down to 24ms, but the CPU load is still horrendously high.
What I know about Linux can be put on the back of a postage stamp, and I have no idea what it does with using Timer in our code. Is Timer, or whatever is used, reset at midnight? The manual does not mention this.
Linux's system clock has a frequency of 100Hz as opposed to Windows 64Hz, so that will help, and perhaps we can get way with a threshold of 15ms. That is still poor compared with 3ms.
We need a Linux expert to come in here because I cannot help.
Re: FreeBasic's Timer
Fine-grain procedure for waiting and loop's procedure for FPS control
For now, I do not know yet where to put this (procedures + examples) in the documentation (in Programmer's Guide - Technical Articles, or in Community Tutorials - ???, or in ...).
I plan to start with a version that does not take into account the type of platform used (Windows, Linus, ...), but putting in a second optional parameter the switching threshold between SLEEP and DO...LOOP, with 32 ms as default value (the basic value for a Windows platform).
Usable procedures (draft)
Examples (draft)
For now, I do not know yet where to put this (procedures + examples) in the documentation (in Programmer's Guide - Technical Articles, or in Community Tutorials - ???, or in ...).
I plan to start with a version that does not take into account the type of platform used (Windows, Linus, ...), but putting in a second optional parameter the switching threshold between SLEEP and DO...LOOP, with 32 ms as default value (the basic value for a Windows platform).
Usable procedures (draft)
- - 'delay()':
- 'regulate()':
Code: Select all
Sub delay(Byval amount As Single, Byval threshold As Single = 32) '' 'amount' : requested temporisation to apply, in milliseconds '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds Dim As Double t1 = Timer Dim As Double t2 Dim As Double t3 = t1 + amount / 1000 If amount > threshold Then Sleep amount - threshold, 1 Do t2 = Timer If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60 Loop Until t2 >= t3 End Sub
- 'framerate()':Code: Select all
Function regulate(Byval MyFps As Ulong, Byval threshold As Single = 32) As Double '' 'MyFps' : requested FPS value, in frames per second '' function return : applied delay (for debug), in milliseconds '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds Static As Double t1 Dim As Single tf = 1 / MyFps Dim As Double t3 = t1 + tf Dim As Double t2 = Timer If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60 Dim As Single dt = (tf - (t2 - t1)) * 1000 If dt >= threshold Then Sleep dt - threshold, 1 Do t2 = Timer If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60 Loop Until t2 >= t3 t1 = Timer Return dt End Function
Code: Select all
Function framerate() As Ulong '' function return : measured FPS value (for debug), in frames per second Static As Double t1 Dim As Double t2 = Timer If t2 < t1 Then t1 -= 24 * 60 * 60 Dim As Ulong tf = 1 / (t2 - t1) t1 = t2 Return tf End Function
Examples (draft)
- - Using 'delay()':
- Using 'regulate()' and 'framerate()':
Code: Select all
Sub delay(Byval amount As Single, Byval threshold As Single = 32) '' 'amount' : requested temporisation to apply, in milliseconds '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds Dim As Double t1 = Timer Dim As Double t2 Dim As Double t3 = t1 + amount / 1000 If amount > threshold Then Sleep amount - threshold, 1 Do t2 = Timer If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60 Loop Until t2 >= t3 End Sub '------------------------------------------------------------------------------ Dim As Double t Dim As Single t0 = 100 For N As Integer = 1 To 4 Print "Requesred delay :"; t0; " ms" For I As Integer = 1 To 4 t = Timer delay(t0) Print Using" Measured delay : ###.### ms"; (Timer - t) * 1000 Next I Print t0 /= 10 Next N Sleep
Code: Select all
Function regulate(Byval MyFps As Ulong, Byval threshold As Single = 32) As Double '' 'MyFps' : requested FPS value, in frames per second '' function return : applied delay (for debug), in milliseconds '' 'thresold' : fixing threshold for fine-grain temporisation (by waiting loop), in milliseconds Static As Double t1 Dim As Single tf = 1 / MyFps Dim As Double t3 = t1 + tf Dim As Double t2 = Timer If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60 Dim As Single dt = (tf - (t2 - t1)) * 1000 If dt >= threshold Then Sleep dt - threshold, 1 Do t2 = Timer If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60 Loop Until t2 >= t3 t1 = Timer Return dt End Function Function framerate() As Ulong '' function return : measured FPS value (for debug), in frames per second Static As Double t1 Dim As Double t2 = Timer If t2 < t1 Then t1 -= 24 * 60 * 60 Dim As Ulong tf = 1 / (t2 - t1) t1 = t2 Return tf End Function '------------------------------------------------------------------------------ Screen 12 Dim As Ulong FPS = 60 Do Static As Ulongint l Static As Single dt Screenlock Cls Color 11 Print Using "Requested FPS : ###"; FPS Print Print Using "Applied delay : ###.### ms"; dt Print Using "Measured FPS : ###"; framerate() Print Print Print Color 14 Print "<+> : Increase FPS" Print "<-> : Decrease FPS" Print "<Escape> : Quit" Line (0, 80)-(639, 96), 7, B Line (0, 80)-(l, 96), 7, BF Screenunlock l = (l + 1) Mod 640 Dim As String s = Inkey Select Case s Case "+" If FPS < 999 Then FPS += 1 Case "-" If FPS > 1 Then FPS -= 1 Case Chr(27) Exit Do End Select dt = regulate(FPS) Loop
-
- Posts: 4158
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
Please note that we need
if we pass 3 in the second parameter of delay() and regulate() with Windows.
I played around with 24ms rather than 32ms, without _setTimer, but the benefit was only marginal.
Code: Select all
Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(Byval As Ulong = 1) As Long
_setTimer()
I played around with 24ms rather than 32ms, without _setTimer, but the benefit was only marginal.
Perhaps some comments from members would be helpful. Stand aside to avoid being crushed.For now, I do not know yet where to put…

Re: FreeBasic's Timer
Yes I know.deltarho[1859] wrote: ↑May 27, 2023 7:43 Please note that we needif we pass 3 in the second parameter of delay() and regulate() with Windows.Code: Select all
Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(Byval As Ulong = 1) As Long _setTimer()
For now, I will rather put this in a note at the end of the article:
- Why adjust the threshold balue and how to do it?
- Example with Windows.
- .....
-
- Posts: 4158
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
See what I mean? At PowerBASIC quite a few members would have responded by now.Yours truly wrote:Perhaps some comments from members would be helpful. Stand aside to avoid being crushed.
FWIW I reckon:
regulate(): Programmer's Guide>Graphics
delay(): Miscellaneous
Re: FreeBasic's Timer
But you also have a difficult subject!
This program is started without parameters and calls a second instance of itself.
Firefox sets the timer resolution to 10ms, VirtualBox sets it to 1ms.
Therefore, all programs that are not required should be closed.
I tested frame.bas (Using 'regulate()' and 'framerate()) with the Task-Manager and with this program.
The specified CPU usage values vary and are not specified exactly.
timerresolution.bas:

This program is started without parameters and calls a second instance of itself.
Firefox sets the timer resolution to 10ms, VirtualBox sets it to 1ms.
Therefore, all programs that are not required should be closed.
I tested frame.bas (Using 'regulate()' and 'framerate()) with the Task-Manager and with this program.
The specified CPU usage values vary and are not specified exactly.
timerresolution.bas:
Code: Select all
Declare Function NtQueryTimerResolution Lib "ntdll" Alias "NtQueryTimerResolution"(_
Byref MinimumResolution As Ulong,_
Byref MaximumResolution As Ulong,_
Byref CurrentResolution As Ulong) As Ulong
Declare Function NtSetTimerResolution Lib "ntdll" Alias "NtSetTimerResolution"(_
Byval DesiredResolution As Ulong,_
Byval SetResolution As Boolean,_
Byref CurrentResolution As Ulong) As Ulong
''The program has to be started without command line parameter.
''Then do this:
If Len(Command(1)) = 0 Then
''Start a new instance with parameter "1"
Dim As String commandline =_
"Start" & Chr(32,34) & "SetTimerResolution" & Chr(34,32,34) & Command(0) & Chr(34,32) & "1"
Shell commandline
''Print CurrentResolution in a loop:
Dim As Ulong minRes,maxRes,curRes
Do
NtQueryTimerResolution(minRes,maxRes,curRes)
Print "CurrentResolution:";curRes/10000;" ms"
Sleep 500
Cls
Loop
End If
''If command line parameter = "1" then do this:
If Command(1) = "1" Then
Dim As Ulong minRes,maxRes,curRes,res
Do
NtQueryTimerResolution(minRes,maxRes,curRes)
Print "MinimumResolution:";minRes/10000;" ms"
Print "MaximumResolution:";maxRes/10000;" ms"
'Print "CurrentResolution:";curRes/10000;" ms"
Input "DesiredResolution: ",res
Print String(29,"-")
res = res*10000
NtSetTimerResolution(res,True,0)
Loop
End If
Code: Select all
CurrentResolution [ms]| CPU Usage [%]
15.6 | 49 Measured FPS is flickering
10 | 49.5
5 | 50
2.5 | 52
1.25 | 55
1 | 56
0.5 | 58
Re: FreeBasic's Timer
deltarho[1859] wrote: ↑May 27, 2023 19:28 FWIW I reckon:
regulate(): Programmer's Guide>Graphics
delay(): Miscellaneous
Perhaps each in the Programmer's Guide as follows:
Graphics
- .....
Controlling FPS by using an in-loop regulating procedure
Other Topics
- .....
Improving SLEEP by using a fine-grain waiting procedure
-
- Posts: 4158
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
@hhr
Maybe I need another coffee because I don't understand what you are getting at.
Are you on Win10/Win11 or earlier?
@fxm
Yep, looks good.
Maybe I need another coffee because I don't understand what you are getting at.
Are you on Win10/Win11 or earlier?
@fxm
Yep, looks good.

Re: FreeBasic's Timer
@deltarho
I understood that graphics programs should run stably and at the same time the CPU load should be minimized.
I am on Windows 7.
I understood that graphics programs should run stably and at the same time the CPU load should be minimized.
I am on Windows 7.
Re: FreeBasic's Timer
@hhr,
If you want to reduce the CPU load by using higher resolutions for the OS cycle time, you must also adjust the optional second parameter of 'regulate()':
For each different resolution of the OS cycle time, set this second parameter with a value (in ms) comprise between two times and three times the OS cycle time.
This interval corresponds to a tradeoff between CPU load and delay accuracy:
- two times -> promote CPU load (decreasing)
- three times -> promote delay accuracy (increasing)
Examples:
OS cycle time resolution / 2nd parameter of 'regulate()'
16 ms / 32 ms (default value)
10 ms / 20 ms
5 ms / 15 ms
2.5 ms / 7.5 ms
1.25 ms / 3.75 ms
1 ms / 3 ms
0.5 ms / 1.5 ms
If you want to reduce the CPU load by using higher resolutions for the OS cycle time, you must also adjust the optional second parameter of 'regulate()':
For each different resolution of the OS cycle time, set this second parameter with a value (in ms) comprise between two times and three times the OS cycle time.
This interval corresponds to a tradeoff between CPU load and delay accuracy:
- two times -> promote CPU load (decreasing)
- three times -> promote delay accuracy (increasing)
Examples:
OS cycle time resolution / 2nd parameter of 'regulate()'
16 ms / 32 ms (default value)
10 ms / 20 ms
5 ms / 15 ms
2.5 ms / 7.5 ms
1.25 ms / 3.75 ms
1 ms / 3 ms
0.5 ms / 1.5 ms
-
- Posts: 4158
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
I was just responding to deltarho's objections regarding involvement. As I said before, you are dealing with a difficult subject. I can't follow. I can only recommend paying attention to user-friendliness. I have to say goodbye to this topic.
-
- Posts: 4158
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
I am confident that fxm will do a good job at explaining things when he introduces delay() and regulate() to the manual.
Re: FreeBasic's Timer
I think so too, I consider you both to be experts, but I shouldn't interfere here anymore.
-
- Posts: 4158
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
@hhr
I am not an expert. You may think that I am, but you have probably only seen me post in threads where I have some idea of what I am talking about.
If ever you pop into a graphics thread where UEZ or dodicat, for example, are posting, you will never find me there. I read their code and am amazed at their results, but I couldn't write a graphics program to save my life. For some reason, I haven't ventured into graphics coding.
Not many people could have written your NtSetTimerResolution code above. It just so happens I could because I wrote a GUI application to do the same thing a few years ago at PowerBASIC. It is called TimerInterval(Win10). It might work on Win7 – I don't know. If you right-click on the title bar and select 'Set' you can choose a resolution.
Your binary is 67KiB and mine is 64.5KiB.
Give it a try: TimerInterval(Win10)
I am not an expert. You may think that I am, but you have probably only seen me post in threads where I have some idea of what I am talking about.
If ever you pop into a graphics thread where UEZ or dodicat, for example, are posting, you will never find me there. I read their code and am amazed at their results, but I couldn't write a graphics program to save my life. For some reason, I haven't ventured into graphics coding.
Not many people could have written your NtSetTimerResolution code above. It just so happens I could because I wrote a GUI application to do the same thing a few years ago at PowerBASIC. It is called TimerInterval(Win10). It might work on Win7 – I don't know. If you right-click on the title bar and select 'Set' you can choose a resolution.
Your binary is 67KiB and mine is 64.5KiB.
Give it a try: TimerInterval(Win10)