FreeBasic's Timer

General FreeBASIC programming questions.
Post Reply
neil
Posts: 592
Joined: Mar 17, 2022 23:26

Re: FreeBasic's Timer

Post by neil »

@Imortis
Thanks This is exactly what I was looking for.
neil
Posts: 592
Joined: Mar 17, 2022 23:26

Re: FreeBasic's Timer

Post by neil »

@hhr
I already use dodicat's regulator when I can. Sometimes you need something faster than Sleep 1.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

Sometimes you need something faster than Sleep 1.
Sleep 1 giving 15.625 ms or Sleep 1 giving one millisecond?
neil
Posts: 592
Joined: Mar 17, 2022 23:26

Re: FreeBasic's Timer

Post by neil »

Sometimes you need nanoseconds.
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FreeBasic's Timer

Post by fxm »

My previous 'delay()' code, modified as follows, provides acceptable accuracy from 0.1 ms (for 0.1 ms requested, only some values up to 10 times larger on a very large number of calls):

Code: Select all

Sub delay(Byval t As Single)  '' delay 't' expressed in milliseconds
    Dim As Double t1 = Timer
    Dim As Double t2
    Dim As Double t3 = t / 1000
    If t > 32 Then
        Sleep t - 32, 1
    End If
    Do
        t2 = Timer
        If t2 < t1 Then t1 = t2
    Loop Until t2 >= t1 + t3
End Sub

'------------------------------------------------------------------

Dim As Double t
Dim As Single t0 = 1000

For N As Integer = 1 To 5
    Print "Delay="; t0; " ms"
    For I As Integer = 1 To 4
        t = Timer
        delay(t0)
        Print Using"#.###### s"; Timer - t
    Next I
    Print
    t0 /= 10
Next N

Sleep
Delay= 1000 ms
1.000022 s
1.000006 s
1.000005 s
1.000010 s

Delay= 100 ms
0.100006 s
0.100004 s
0.100010 s
0.100005 s

Delay= 10 ms
0.010002 s
0.010001 s
0.010001 s
0.010005 s

Delay= 1 ms
0.001001 s
0.001001 s
0.001001 s
0.001001 s

Delay= 0.1 ms
0.000103 s
0.000101 s
0.000101 s
0.000101 s
Last edited by fxm on May 24, 2023 13:31, edited 1 time in total.
Reason: Large-grained threshold of 'delay()' adjusted to 32ms (instead of 300ms) as proposed by deltarho.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

Sometimes you need nanoseconds.
Absolute drivel! We don't even need microseconds.

Milliseconds are more than adequate, provided that Sleep is linked to a multimedia timer and not the system clock.

Linked to the system clock, Sleep 1, Sleep2, …, Sleep 15 all wait for 15.625 ms, or randomly less because the system clock has a frequency of 64Hz.
neil
Posts: 592
Joined: Mar 17, 2022 23:26

Re: FreeBasic's Timer

Post by neil »

@fxm
Here's what I got. It seems OK.

Delay= 1000 ms
1.000010 s
1.000003 s
1.000004 s
1.000004 s

Delay= 100 ms
0.100000 s
0.100000 s
0.100000 s
0.100000 s

Delay= 10 ms
0.010000 s
0.010000 s
0.010000 s
0.010000 s

Delay= 1 ms
0.001000 s
0.001000 s
0.001000 s
0.001000 s

Delay= 0.1 ms
0.000100 s
0.000100 s
0.000100 s
0.000100 s
neil
Posts: 592
Joined: Mar 17, 2022 23:26

Re: FreeBasic's Timer

Post by neil »

The delay code using the timer does appear to be accurate to 100,000 nanoseconds or 100 microseconds or 0.1 milliseconds.
However you want to look at it.
No complaints here.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

@fxm

I have VeryHiResSleep( n ) as a macro which uses Sleep and QueryPerformanceCounter. The accuracy is the same as yours but is nothing like as compact as yours and is limited to n >= 1. So, your code blows mine out of the water. :)

FreeBASIC is so fast I am not sold on stepping forward when t is greater than 300 and most people will be looking for a delay much less than 300ms anyway.

I cannot see how 'If t2 < t1 Then t1 = t2' can ever be true. We have 't1 = Timer' at the head of the Sub and 't2 = Timer' inside the Do/Loop so t2 must always be greater than t1.

We also don't need t2.

A bit ruthless, but I ended up with:

Code: Select all

Sub delay(Byval t As Single)  '' delay 't' expressed in milliseconds
  Dim As Double t1 = t / 1000
  Dim As Double t2
  Dim As Double t3 = Timer
  t2 = t1 + t3 ' Avoids addition in Loop
  Do : Loop Until Timer >= t2
End Sub
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 21, 2023 5:15 I cannot see how 'If t2 < t1 Then t1 = t2' can ever be true. We have 't1 = Timer' at the head of the Sub and 't2 = Timer' inside the Do/Loop so t2 must always be greater than t1.
  • On some platforms, the value of Timer resets to zero at midnight (see below), so if the start and end time are on either side of the reset point, the difference will be negative. This could cause unexpected behavior in some programs. In those cases, adding 86400 (the number of seconds in 24 hours) to the difference should return the correct result.
    To take into account this possible resetting of the counter, I so simply reinitialized the value stored, but a more optimized version could correct this behavior (by taking into account the value of a day expressed in seconds):

    Code: Select all

    Sub delay(Byval t As Single)  '' delay 't' expressed in milliseconds
        Dim As Double t1 = Timer
        Dim As Double t2
        Dim As Double t3 = t / 1000
        If t > 32 Then
            Sleep t - 32, 1
        End If
        Do
            t2 = Timer
            If t2 < t1 Then t1 -= 24 * 60 * 60
        Loop Until t2 >= t1 + t3
    End Sub
    
    '------------------------------------------------------------------
    
    Dim As Double t
    Dim As Single t0 = 1000
    
    For N As Integer = 1 To 5
        Print "Delay="; t0; " ms"
        For I As Integer = 1 To 4
            t = Timer
            delay(t0)
            Print Using"#.###### s"; Timer - t
        Next I
        Print
        t0 /= 10
    Next N
    
    Sleep
    

deltarho[1859] wrote: May 21, 2023 5:15 FreeBASIC is so fast I am not sold on stepping forward when t is greater than 300 and most people will be looking for a delay much less than 300ms anyway.
  • The 't > 300 32' test prevents the 'delay()' procedure from unnecessarily hogging the CPU for more than 300 32 ms, by using 'Sleep t - 300 32, 1' as first tempo part.
Last edited by fxm on May 24, 2023 13:34, edited 1 time in total.
Reason: Large-grained threshold of 'delay()' adjusted to 32ms (instead of 300ms) as proposed by deltarho.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

@fxm

OK, I'll buy that.

Added: Your explanation of 't > 300' was added after I composed and posted the following; I always compose off-line. :)

With my macro, I could have just polled the performance counter, but that would have put a lot of pressure on the CPU so I sleep for the lion's share of the delay and then fine tune with the performance counter. I described the method as being like using a Class B amplifier followed by a Class A amplifier; reducing the cost of a Class A amplifier on its own.

I popped out to do some shopping and then went to McDonald's for breakfast. During breakfast, it occurred to me that is precisely what you are doing with the 'If t > 300'. It has no effect on the accuracy of the results but reduces the number of loops required, taking pressure off the CPU.

Added: I'd like to say 'great minds think alike' but I won't because I am not in your league. :)

I am being pedantic, but I don't like to see unnecessary calculations in the loop.

To that end I would suggest:

Code: Select all

Sub delay(Byval t As Single)  '' delay 't' expressed in milliseconds
  Dim As Double t1 = Timer
  Dim As Double t2
  Dim As Double t3 = t / 1000
  If t > 300 Then
    Sleep t - 300, 1
  End If
  ' The following two lines reduces work inside the loop
  If Timer < t1 Then t1 -= 86400 ' Number of seconds in a day
  t2 = t1 + t3
  Do : Loop Until Timer >= t2
End Sub
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 21, 2023 8:30 I am being pedantic, but I don't like to see unnecessary calculations in the loop.
To be puristic, the counter reinitialization may happen during the loop (at most about 300 32 ms, but bad luck!), and not while 'Sleep' is running.
That is why I put this test inside the loop.
Last edited by fxm on May 24, 2023 13:36, edited 1 time in total.
Reason: Large-grained threshold of 'delay()' adjusted to 32ms (instead of 300ms) as proposed by deltarho.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

fxm wrote:To be puristic, the counter reset may happen during the loop
It could, but at least we know not with Windows. PowerBASIC resets its Timer at midnight.

Anyway, we don't need two multiplications in the loop, so '24 * 60 * 60' should be replaced with 86400.

We don't need 't1 + t3' in every loop, either.

Computationally, there probably isn't much in it – I just don't like to see unnecessary work inside loops. It is a habit from when our CPUs were a lot slower than they are today. Having said that, we cannot treat our CPUs with contempt; otherwise we wouldn't sleep for a while before the loop. :)
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 21, 2023 9:38 Anyway, we don't need two multiplications in the loop, so '24 * 60 * 60' should be replaced with 86400.
  • I am sure the value evaluation (of this constant term) is done at compile time.

deltarho[1859] wrote: May 21, 2023 9:38 We don't need 't1 + t3' in every loop, either.
  • My last optimization:

    Code: Select all

    Sub delay(Byval t As Single)  '' delay 't' expressed in milliseconds
        Dim As Double t1 = Timer
        Dim As Double t2
        Dim As Double t3 = t1 + t / 1000
        If t > 32 Then Sleep t - 32, 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 = 1000
    
    For N As Integer = 1 To 5
        Print "Delay="; t0; " ms"
        For I As Integer = 1 To 4
            t = Timer
            delay(t0)
            Print Using"#.###### s"; Timer - t
        Next I
        Print
        t0 /= 10
    Next N
    
    Sleep
    
Last edited by fxm on May 24, 2023 13:37, edited 1 time in total.
Reason: Large-grained threshold of 'delay()' adjusted to 32ms (instead of 300ms) as proposed by deltarho.
deltarho[1859]
Posts: 4310
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBasic's Timer

Post by deltarho[1859] »

fxm wrote:I am sure the value evaluation (of this constant term) is done at compile time.
So am I come to think of it. I keep forgetting how smart gcc is. :)

I will buy your last optimization. That will replace my macro which I have been using for a long time with the odd tweak now and then.
Post Reply