FreeBasic's Timer

General FreeBASIC programming questions.
Post Reply
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

fxm wrote: May 27, 2023 20:52
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

What bothers me to have 2 separate articles is that there is a lot of description in common, because 'regulate()' is a superset of 'delay()'.
Splitting into two articles leads to a lot of duplicated description, which is not favorable to the maintenance of the documentation.
An idea ?
hhr
Posts: 208
Joined: Nov 29, 2019 10:41

Re: FreeBasic's Timer

Post by hhr »

@deltarho
Unfortunately, TimerInterval(Win10) does not work in Windows 7.
Message: Sorry, I need Win 10.

I don't know much about graphics programming either.
The people who know something about it are probably all waiting for the result.

@fxm
I tried your suggestion. So you can really keep the CPU load very low.

Maybe you can describe in the same article first 'delay()' and then regulate()'?
Last edited by hhr on May 28, 2023 9:34, edited 1 time in total.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

fxm wrote: May 28, 2023 8:56 What bothers me to have 2 separate articles is that there is a lot of description in common, because 'regulate()' is a superset of 'delay()'.
Splitting into two articles leads to a lot of duplicated description, which is not favorable to the maintenance of the documentation.
An idea ?

For example, just such a preamble is already common to the 2 articles:
Preambule:

SLEEP keyword
  • Generally the SLEEP procedure has not a good accuracy with respect to the delay requested and does not allow to produce very small waiting times.

    The accuracy of SLEEP is variable depending on the OS cycle time:
    Windows NT/2K/XP: 15 ms, 9x/Me: 50 ms, Linux: 10ms, DOS: 55 ms.
    And using for the delay values lower than these accuracy values does not allow SLEEP to produce the corresponding wait values (always higher wait, and of the order of these values) except for the delay value '0'.
TIMER keyword
  • The accuracy of the time returned by TIMER is much greater than that generally of the SLEEP keyword to generate a wait:
    for modern processors, sub-microsecond accuracy is expected.

    On some platforms, the return value of TIMER is reset at midnight, so if the start and end time are on either side of the reset point, their difference will be negative. This could cause unexpected behavior in some programs if this event is ignored.


[added]
..... unless putting all these common descriptions in a third article about SLEEP and TIMER use limitation, and refer to them in the 2 previous ones ?
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

@hhr

I wrote TimerInterval(Win10) not long after Windows 10 was released. Obviously, there was a reason why I included Win10 in the title, but I could not remember why. I had been messing with the timer interval at the end of Windows 7 and wrote a few GUIs for that. I just tried one of them, and it was not happy with Windows 10. I won't pursue this. Your code seems to work on Win 7 and Win 10, so you have done a better job than me. :)

Why are you still on Windows 7? Mainstream support ended on January 13, 2015.

@fxm

A bit of a conundrum!

I agree with hhr - “describe in the same article first 'delay()' and then regulate()'”

Since regulate() should be in Programmer's Guide > Graphics then that is where they should be together.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

deltarho[1859] wrote: May 28, 2023 11:55 @fxm

A bit of a conundrum!

I agree with hhr - “describe in the same article first 'delay()' and then regulate()'”

Since regulate() should be in Programmer's Guide > Graphics then that is where they should be together.

I am not against integrating all of this in one and the same article because it was my first idea.
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: FreeBasic's Timer

Post by coderJeff »

deltarho[1859] wrote: May 26, 2023 23:03 Now how about this as a radical suggestion. I firmly believe that your two procedures are so powerful they should be included as keywords in the fbc; delay( amount ) and regulate( amount ). The onus now is on coderJeff. :)
I started to think about this since adding new things has been long time challenge of where to fit them. Not just keyword/namespace, but also physically where new contributions should live and how they are to be maintained.
- './examples' is out of date - needs maintenance
- we can make a place for maintained headers easily,
- We don't have anything in the fbc build / package process for run time things written in fb itself to be distributed as part of a release

Anyway, distracted myself by trying to create a visualization of what we have now (incomplete).

On the user side:
Image

On development side:
Image
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: FreeBasic's Timer

Post by coderJeff »

fxm wrote: May 28, 2023 12:06
deltarho[1859] wrote: May 28, 2023 11:55 @fxm

A bit of a conundrum!

I agree with hhr - “describe in the same article first 'delay()' and then regulate()'”

Since regulate() should be in Programmer's Guide > Graphics then that is where they should be together.
I am not against integrating all of this in one and the same article because it was my first idea.
This sounds good to me. It is a reasonable way to get it done and share with users. I think it fair to ask users to give feedback or help with other platforms (dos/linux/etc).

A next step would be how to build these kind of additions in to the fbc development system itself so that users need not copy/paste code from the manual. I mention as a possible next step because there are some users that might have useful contributions they would freely give to the project, but they don't necessarily want to host / maintain the contribution. There is no good place to add in user contributed source, and I don't think we want to convert user's fb code to C to put in the rtlib.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

So I initiate a single article to put in the Programmer's Guide:
.....
.....

Graphics
  • .....
    .....
    Fine-grain procedure for waiting and in-loop procedure for fine-regulating FPS
For now, I am focusing on behavior and tuning for Windows only.


But already a question for the future:
Could we consider defining the basic setting principle adapted to each platform by means of compilation directives as follows ?

Code: Select all

#ifdef __FB_WIN32__
    Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 16)
#elseif __FB_LINUX__
    Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 10)
#elseif __FB_DOS__
    Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 55)
#else
    Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 16)
#endif

Sub delay(Byval amount As Single, Byval threshold As Single)
    '' '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
This still allows the user to explicitly fine-tune their personal value based on the real OS cycle (if different from the base setting).
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FreeBasic's Timer

Post by dodicat »

Using my normal regulator for sleep with an extra parameter and my normal regulator for while with a couple of extras, these can be used independently or together.
Together they can switch from sleep to while as per required framerate.
I haven't used a framecounter function, I have them inbuilt, but I have a framecounter rigged in the loop to test.
I notice that the rigged framecounter can lag at high fps (>2000 or so)
I have accounted for -ve or 0 required framerates, but left silly high values hanging.
Two graphics are included.
EDIT.. fixed a little error.

Code: Select all

Function readkey(x As Long,y As Long,st As String,message As String,clr As Ulong) As String
      Static As String j,blink
      Var c=Color
      Var i=Inkey()
      If Left(i,1)=Chr(08) Then j=Mid(j,1,Len(j)-1)
      Select Case Left(i,1)
      Case Chr(0) To Chr(254)
            If Left(i,1)<>Chr(08) Then
                  j=j+Left(i,1)
            End If
      End Select
      If Frac(Timer)>.5 Then blink=" " Else blink="_"
      If Left(i,1)=Chr(27) Then j=""
      If i<>Chr(13) Then
            Locate x,y,0
            Color clr
            Print  st & j & blink 
            Color c
      Else
            j=Rtrim(j,Chr(13))
            message=j
            j=""
      End If
      Return i
End Function

Function regulate Overload(MyFps As Long,Byref fps As Long) As Double
      Dim As Double k=1/MyFps
      Static As Double timervalue
      Var c=timervalue
      Do While (Timer - TimerValue) <= k
      Loop 
      Var ans=(Timer-timervalue)
      timervalue=Timer
      fps=1/(timervalue-c)
      If Abs(Myfps-fps)>MyFps\2 Then fps=60
      Return ans*60
End Function


Function Regulate(Byval MyFps As Long,Byref fps As Long,Byref gap As Double) As Double
      Static As Double timervalue,_lastsleeptime,t3,frames
      Var T=Timer
      frames+=1
      If (t-t3)>=1 Then t3=t:fps=frames:frames=0
      Var sleeptime=_lastsleeptime+((1/myfps)-T+timervalue)*1000
      If sleeptime<1 Then gap=sleeptime:sleeptime= 1
      _lastsleeptime=sleeptime
      timervalue=T
      Return sleeptime
End Function

Sub ball()
      Static  As Double x= 10
      Static  As Double y = 10
      Static  As Double dx=.5
      Static  As Double dy =.5
      x += dx : y += dy
      If x<10 Or x>=630 Then dx = -dx
      If y<10 Or y>=470 Then dy = -dy
      Circle(x,y),10,4,,,,f 
End Sub


Sub drawline(x As Long,y As Long,angle As Single,length As Long,col As Ulong)
      Var x2=x+length*Cos(angle)
      Var y2=y-length*Sin(angle)
      Line(x,y)-(x2,y2)
      Circle(x2,y2),20,6,,,,f
End Sub

Sub pendulum
      #define dmod(x,y) (y)*Frac((x)/(y)) 
      Const pi=4*Atn(1)
      Static As Single angle
      angle+=.005
      angle=dmod(angle,2*pi)
      drawline(400,100,.4*Sin(angle)-pi/2,300,4) 
End Sub

Dim As String message="30"
Dim As Long fps
Dim As Long MyChoice,counter,flag
Dim As String LastChoice
Dim As Double gap,speed
gap=2


Screen 12
Var t=Timer
Do
      counter+=1
      Screenlock
      Cls
      
      If Timer-t>=1 Then
            t=Timer
            speed= counter 'lagging framecounter
            counter=0
      End If
      
      readkey(4,2,Ucase("Input required framerate, ESC to finish "),message,3)
      Color 7
      Locate 7,2
      Print "required framerate ";message
      Locate 10,2
      Print "actual framerate   ";fps
      Locate 13,2
      Print "lagging framerate  ";speed
      Locate 16,2
      Color 5
      Print Iif(flag=true,"Regulate with sleep","Regulate with while")
      ball
      pendulum
      
      Screenunlock
      
      MyChoice=Valint(message)
      If Mychoice<=0 Then message=LastChoice:Continue Do
      
      If gap>1 Then
            Sleep  regulate(MyChoice,fps,gap) ,1
            flag=true
      Else
            gap=regulate(MyChoice,fps)
            flag=false
      End If
      
      
      LastChoice=message 
      
Loop Until Multikey(1)'esc


 
Last edited by dodicat on May 29, 2023 16:56, edited 1 time in total.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

@fxm

#ifdef __FB_WIN32__
Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
_setTimer

Declare Sub delay(Byval amount As Single, Byval threshold As Single = 3) 'Note 3 for threshold
#elseif __FB_LINUX__
Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 10)
#elseif __FB_DOS__
Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 55)
#else
Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 16)
#endif

Sub delay(Byval amount As Single, Byval threshold As Single)
'' 'amount' : requested temporisation to apply, in milliseconds
'' 'threshold' : 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
#ifndef __FB_WIN32__
t2 = Timer
If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60
Loop Until t2 >= t3
#else
Loop Until Timer >= t3
#endif

End Sub
Last edited by deltarho[1859] on May 28, 2023 19:33, edited 5 times in total.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

@dodicat

If I input 60, the actual framerate is nearly on the deck.

The issue is resolved with

Code: Select all

Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(Byval As Ulong = 1) As Long
_setTimer()
When it comes to regulating fps Windows is a clear winner with its 1000Hz timer.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

deltarho[1859] wrote: May 28, 2023 19:00 @fxm

#ifdef __FB_WIN32__
Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
_setTimer

Declare Sub delay(Byval amount As Single, Byval threshold As Single = 3) 'Note 3 for threshold
#elseif __FB_LINUX__
Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 10)
#elseif __FB_DOS__
Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 55)
#else
Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 16)
#endif

I think you can not force Windows user to overclock his OS cycle period to 1ms for his whole program, only because he calls 'delay()' or 'regulate()' once. This can degrade the operation of the rest of its program.
This choice must remain his, in my opinion.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FreeBasic's Timer

Post by dodicat »

deltarho[1859] wrote: May 28, 2023 19:29 @dodicat

If I input 60, the actual framerate is nearly on the deck.

The issue is resolved with

Code: Select all

Declare Function _setTimer Lib "winmm" Alias "timeBeginPeriod"(Byval As Ulong = 1) As Long
_setTimer()
When it comes to regulating fps Windows is a clear winner with its 1000Hz timer.
60 is on the dividing line between sleeping and looping.
It is OK here, but maybe
If gap>1.1 Then
...
using "timeBeginPeriod" set at 1 is of course the best way in windows, but I was avoiding doing that.
but setTimer and freeTimer around the sleep, and not embracing the whole program.
Other windows background things will then not be affected.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

fxm wrote:I think you can not force Windows user to overclock his OS cycle period to 1ms for his whole program, only because he calls 'delay()' or 'regulate()' once. This can degrade the operation of the rest of its program.

Do you have any evidence of degradation?

I have never used timeEndPeriod. I have let Windows do that for me on an application's closure.

Things are a little better now with the removal of the global timer resolution. I don't know what took Microsoft so long to do that – timeBeginPeriod was introduced with Windows 2000.

The timer resolution increases every time we open a web browser, and we have no choice with that.

Watching a film on Netflix, or whatever? We'll be running at 4ms for quite a while; especially if we watch a couple of episodes of a series.

Are you forgetting your CPU load of 23% without using the 1000Hz timer?

I would use a default of 3ms and mention the option to remove the use of the 1000Hz timer and change the threshold to 2x16. I would then warn the user of a dramatic increase in CPU load. I doubt many would go for that option. :)
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

From:
https://learn.microsoft.com/en-us/windo ... eginperiod
Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. High resolutions can also prevent the CPU power management system from entering power-saving modes. Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.


Otherwise, the 'delay()' procedure proposal updated from your second note:

Code: Select all

#ifdef __FB_WIN32__
    Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 16)
#elseif __FB_LINUX__
    Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 10)
#elseif __FB_DOS__
    Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 55)
#else
    Declare Sub delay(Byval amount As Single, Byval threshold As Single = 2 * 16)
#endif

Sub delay(Byval amount As Single, Byval threshold As Single)
    '' '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
    #if Not defined(__FB_WIN32__) And Not defined(__FB_LINUX__)
        t2 = Timer
        If t2 < t1 Then t1 -= 24 * 60 * 60 : t3 -= 24 * 60 * 60
    Loop Until t2 >= t3
    #else
    Loop Until Timer >= t3
    #endif
End Sub
Post Reply