FreeBasic's Timer

General FreeBASIC programming questions.
Post Reply
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

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.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

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)
  • - 'delay()':

    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
    
    - 'regulate()':

    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
    
    - 'framerate()':

    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()':

    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
    
    - Using 'regulate()' and '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
    
    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
    
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

Please note that we need

Code: Select all

Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(Byval As Ulong = 1) As Long
_setTimer()
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.
For now, I do not know yet where to put…
Perhaps some comments from members would be helpful. Stand aside to avoid being crushed. :lol:
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

deltarho[1859] wrote: May 27, 2023 7:43 Please note that we need

Code: Select all

Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(Byval As Ulong = 1) As Long
_setTimer()
if we pass 3 in the second parameter of delay() and regulate() with Windows.
Yes I know.
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.
- .....
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

Yours truly wrote:Perhaps some comments from members would be helpful. Stand aside to avoid being crushed. :lol:
See what I mean? At PowerBASIC quite a few members would have responded by now.

FWIW I reckon:
regulate(): Programmer's Guide>Graphics
delay(): Miscellaneous
hhr
Posts: 208
Joined: Nov 29, 2019 10:41

Re: FreeBasic's Timer

Post by hhr »

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:

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
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

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
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

@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. :)
hhr
Posts: 208
Joined: Nov 29, 2019 10:41

Re: FreeBasic's Timer

Post by hhr »

@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.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

@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
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

@hhr

Win7 and Win10 behave differently.

Check this out: timeBeginPeriod function
hhr
Posts: 208
Joined: Nov 29, 2019 10:41

Re: FreeBasic's Timer

Post by hhr »

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.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

I am confident that fxm will do a good job at explaining things when he introduces delay() and regulate() to the manual.
hhr
Posts: 208
Joined: Nov 29, 2019 10:41

Re: FreeBasic's Timer

Post by hhr »

I think so too, I consider you both to be experts, but I shouldn't interfere here anymore.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

@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)
Post Reply