FreeBasic's Timer
Re: FreeBasic's Timer
@Imortis
Thanks This is exactly what I was looking for.
Thanks This is exactly what I was looking for.
Re: FreeBasic's Timer
@hhr
I already use dodicat's regulator when I can. Sometimes you need something faster than Sleep 1.
I already use dodicat's regulator when I can. Sometimes you need something faster than Sleep 1.
-
- Posts: 4310
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
Sleep 1 giving 15.625 ms or Sleep 1 giving one millisecond?Sometimes you need something faster than Sleep 1.
Re: FreeBasic's Timer
Sometimes you need nanoseconds.
Re: FreeBasic's Timer
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.
Reason: Large-grained threshold of 'delay()' adjusted to 32ms (instead of 300ms) as proposed by deltarho.
-
- Posts: 4310
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
Absolute drivel! We don't even need microseconds.Sometimes you need nanoseconds.
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.
Re: FreeBasic's Timer
@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
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
Re: FreeBasic's Timer
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.
However you want to look at it.
No complaints here.
-
- Posts: 4310
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
@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:
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
Re: FreeBasic's Timer
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.
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):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.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 >
30032' test prevents the 'delay()' procedure from unnecessarily hogging the CPU for more than30032 ms, by using 'Sleep t -30032, 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.
Reason: Large-grained threshold of 'delay()' adjusted to 32ms (instead of 300ms) as proposed by deltarho.
-
- Posts: 4310
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
@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:
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
Re: FreeBasic's Timer
To be puristic, the counter reinitialization may happen during the loop (at most aboutdeltarho[1859] wrote: ↑May 21, 2023 8:30 I am being pedantic, but I don't like to see unnecessary calculations in the loop.
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.
Reason: Large-grained threshold of 'delay()' adjusted to 32ms (instead of 300ms) as proposed by deltarho.
-
- Posts: 4310
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
It could, but at least we know not with Windows. PowerBASIC resets its Timer at midnight.fxm wrote:To be puristic, the counter reset may happen during the loop
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.
Re: FreeBasic's Timer
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.
- 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.
Reason: Large-grained threshold of 'delay()' adjusted to 32ms (instead of 300ms) as proposed by deltarho.
-
- Posts: 4310
- Joined: Jan 02, 2017 0:34
- Location: UK
- Contact:
Re: FreeBasic's Timer
So am I come to think of it. I keep forgetting how smart gcc is.fxm wrote:I am sure the value evaluation (of this constant term) is done at compile time.
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.