OverTime with Sleep (& WM_Timer)

General FreeBASIC programming questions.
Post Reply
Tonigau
Posts: 36
Joined: Feb 25, 2021 20:19

OverTime with Sleep (& WM_Timer)

Post by Tonigau »

When using Sleep n I get more milliseconds than I set. similar issue with WM_Timer event.
I have tried x32 & x64 compiler & older version, run the exe on WinXP all with similar results.
The compiling PC is non networked Win7x64P.
I was previously using WM_TIMER with 1000ms & 100ms so probably didn't notice the overTime.

I just noticed this recently as I was trying to poll an input at 1 ms period.


Test Code.

Code: Select all

Dim As UInteger TimerOld, TimerDiff 

For Lp1 As UInteger = 50 To 1 Step -1
   TimerOld = Int(Timer*1000)
      Sleep Lp1
   TimerDiff = Int(Timer*1000) - TimerOld
   Print "Lp1= "; Lp1, "TimerDiff= "; TimerDiff
Next

Sleep
Output I get.

Code: Select all

C:\Programs\FreeBASIC-1.10.0-winlibs-gcc-9.3.0\fbc32  -s console "Testing ms.bas"
-----------------------------
Lp1= 100      TimerDiff= 119
Lp1= 96       TimerDiff= 107
Lp1= 92       TimerDiff= 93
Lp1= 88       TimerDiff= 92
Lp1= 84       TimerDiff= 92
Lp1= 80       TimerDiff= 92
Lp1= 76       TimerDiff= 76
Lp1= 72       TimerDiff= 76
Lp1= 68       TimerDiff= 76
Lp1= 64       TimerDiff= 76
Lp1= 60       TimerDiff= 61
Lp1= 56       TimerDiff= 60
Lp1= 52       TimerDiff= 61
Lp1= 48       TimerDiff= 61
Lp1= 44       TimerDiff= 45
Lp1= 40       TimerDiff= 46
Lp1= 36       TimerDiff= 45
Lp1= 32       TimerDiff= 45
Lp1= 28       TimerDiff= 29
Lp1= 24       TimerDiff= 30
Lp1= 20       TimerDiff= 30
Lp1= 16       TimerDiff= 30
Lp1= 12       TimerDiff= 14
Lp1= 8        TimerDiff= 14
Lp1= 4        TimerDiff= 14

----------------------------
Lp1= 50       TimerDiff= 59
Lp1= 49       TimerDiff= 61
Lp1= 48       TimerDiff= 61
Lp1= 47       TimerDiff= 61
Lp1= 46       TimerDiff= 45
Lp1= 45       TimerDiff= 45
Lp1= 44       TimerDiff= 45
Lp1= 43       TimerDiff= 46
Lp1= 42       TimerDiff= 45
Lp1= 41       TimerDiff= 45
Lp1= 40       TimerDiff= 45
Lp1= 39       TimerDiff= 45
Lp1= 38       TimerDiff= 46
Lp1= 37       TimerDiff= 45
Lp1= 36       TimerDiff= 45
Lp1= 35       TimerDiff= 45
Lp1= 34       TimerDiff= 45
Lp1= 33       TimerDiff= 45
Lp1= 32       TimerDiff= 45
Lp1= 31       TimerDiff= 30
Lp1= 30       TimerDiff= 30
Lp1= 29       TimerDiff= 30
Lp1= 28       TimerDiff= 29
Lp1= 27       TimerDiff= 29
Lp1= 26       TimerDiff= 30
Lp1= 25       TimerDiff= 28
Lp1= 24       TimerDiff= 27
Lp1= 23       TimerDiff= 27
Lp1= 22       TimerDiff= 27
Lp1= 21       TimerDiff= 28
Lp1= 20       TimerDiff= 28
Lp1= 19       TimerDiff= 27
Lp1= 18       TimerDiff= 27
Lp1= 17       TimerDiff= 27
Lp1= 16       TimerDiff= 28
Lp1= 15       TimerDiff= 12
Lp1= 14       TimerDiff= 12
Lp1= 13       TimerDiff= 12
Lp1= 12       TimerDiff= 12
Lp1= 11       TimerDiff= 12
Lp1= 10       TimerDiff= 12
Lp1= 9        TimerDiff= 12
Lp1= 8        TimerDiff= 12
Lp1= 7        TimerDiff= 12
Lp1= 6        TimerDiff= 12
Lp1= 5        TimerDiff= 12
Lp1= 4        TimerDiff= 12
Lp1= 3        TimerDiff= 12
Lp1= 2        TimerDiff= 12
Lp1= 1        TimerDiff= 12
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: OverTime with Sleep (& WM_Timer)

Post by deltarho[1859] »

I wasn't going to post here any more - it has been over two months since my last post. I call by now and then.

However, I had to say something about this post.

Sleep has a default resolution of 15.625ms. With a resolution of 1ms we get a very different story.

Put this at the top of your code:

Code: Select all

Declare Function _settimer Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
_settimer
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: OverTime with Sleep (& WM_Timer)

Post by deltarho[1859] »

@tonigau

I've just spotted your 'Synchronize Time & Timer(ms) ' post. I didn't run your code, but you have the same issue there.
adeyblue
Posts: 300
Joined: Nov 07, 2019 20:08

Re: OverTime with Sleep (& WM_Timer)

Post by adeyblue »

deltarho[1859] wrote: Jan 20, 2024 11:12 I call by now and then.
You should do so more often, I could've saved you three weeks - viewtopic.php?t=32483
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: OverTime with Sleep (& WM_Timer)

Post by deltarho[1859] »

@adeyblue

A console opened briefly and then closed.
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: OverTime with Sleep (& WM_Timer)

Post by deltarho[1859] »

Apologies, Adeyblue, I forgot to run in admin mode. :)
deltarho[1859]
Posts: 4313
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: OverTime with Sleep (& WM_Timer)

Post by deltarho[1859] »

Adeyblue wrote:I could've saved you three weeks
I don't understand that :?:
Tonigau
Posts: 36
Joined: Feb 25, 2021 20:19

Re: OverTime with Sleep (& WM_Timer)

Post by Tonigau »

Declare Function _settimer Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
_settimer
This did the trick with Sleep, thanks. I only see the expected int rounding now.
I was hoping my other time resolution issue was close related...

--------------------------
viewtopic.php?p=301871#p301871
The sync of RTC second tickover & Timer millisecond 000 (or close to) is still out, but I have an acceptable workaround for this now(the Take 2 snippet) with a counter reset at second tickover & reference to Timer diff values.

--------------------------
I tried to apply timeBeginPeriod to the WM_TIMER but no luck here getting reliable small event period.
What I want to do is SetTimer to 1ms to capture LOC(Com) > 0 & time stamp, then SetTimer to 10ms to inc the idle counter > IdleTimeSet to get the data.
I don't know of a com event I can use with FB (that would be ideal to time stamp first byte in)
This is a Serial Data Logger. I have binary comms data at 9600b about 15~20 packets per second.
It is working ok except my time stamps are anywhere between byte 1 & byte 15 of the buffer.

I Tried Using Sleep 1 to poll the com buffer but I can't breakout with the Button MouseUp event of the main window. Between the sleeps there about 70us of code time.

Example of WM_TIMER in Console

Code: Select all

' code example from deltarho[1859]  https://www.freebasic.net/forum/viewtopic.php?p=300958#p300958
' Modified to test SetTimer low value ms

/' < comment line to enable code block
Declare Function SmallTimerInterval  Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
SmallTimerInterval
'/

/'
Declare Function _settimer Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
_settimer
'/

/'
Declare Function _settimer Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
_HighPrecisionClock
'_settimer
'/

#Include Once "windows.bi"
#Include "VBcompat.bi"

   Const T_ms = 5   '<- ======== SetTimer ms Here ========

   Dim Shared timerID As UINT_PTR
   Dim Msg As TAGMSG
   Dim Shared As UInteger Cnt1, TimerNew
   Dim Shared As Double TimerOld
 
   Print "                                Ignore first Period(& rounding err)"

Sub MyFunc(ByVal HWND As hwnd, BYVAL uMsg AS UINT, ByVal idEvent AS Uint_Ptr, ByVal dwTime AS Dword)

  Select Case uMsg
    Case WM_TIMER
      TimerNew = Timer
                  Print "SetTimer="; T_ms; "ms  Timer="; Format(Timer, ".000"); "  Period="; Int((Timer - TimerOld)*1000); "ms"
      TimerOld = Timer
      
    Case WM_DESTROY
      KillTimer Null, TimerID
      PostThreadMessage GetCurrentThreadID, WM_QUIT, 0, 0

  End Select
End Sub

   SetConsoleTitle("SetTimer In Console example")

   timerID = SetTimer( NULL, 0,T_ms, @MyFunc )
WHILE GetMessage(@Msg, NULL, NULL, NULL) <> 0
  DispatchMessage  @Msg
  Cnt1 +=1
  If Cnt1 > 20 Then Exit While
Wend
   Sleep
Output I get...

Code: Select all

Without _settimer
                                  Ignore first Period(& rounding err)
SetTimer= 5ms  Timer=160983.737  Period= 160983737ms
SetTimer= 5ms  Timer=160983.753  Period= 14ms
SetTimer= 5ms  Timer=160983.768  Period= 14ms
SetTimer= 5ms  Timer=160983.784  Period= 15ms
SetTimer= 5ms  Timer=160983.801  Period= 16ms
SetTimer= 5ms  Timer=160983.815  Period= 13ms
SetTimer= 5ms  Timer=160983.830  Period= 14ms
SetTimer= 5ms  Timer=160983.846  Period= 15ms
SetTimer= 5ms  Timer=160983.862  Period= 15ms
SetTimer= 5ms  Timer=160983.877  Period= 14ms
SetTimer= 5ms  Timer=160983.893  Period= 15ms
SetTimer= 5ms  Timer=160983.908  Period= 14ms
SetTimer= 5ms  Timer=160983.925  Period= 15ms
SetTimer= 5ms  Timer=160983.940  Period= 14ms
SetTimer= 5ms  Timer=160983.955  Period= 15ms
SetTimer= 5ms  Timer=160983.971  Period= 14ms
SetTimer= 5ms  Timer=160983.987  Period= 15ms
SetTimer= 5ms  Timer=160984.002  Period= 14ms
SetTimer= 5ms  Timer=160984.018  Period= 15ms
SetTimer= 5ms  Timer=160984.034  Period= 15ms
SetTimer= 5ms  Timer=160984.050  Period= 15ms

With _settimer
                                 Ignore first Period(& rounding err)
SetTimer= 5ms  Timer=148959.580  Period= 148959580ms
SetTimer= 5ms  Timer=148959.590  Period= 9ms
SetTimer= 5ms  Timer=148959.605  Period= 14ms
SetTimer= 5ms  Timer=148959.618  Period= 12ms
SetTimer= 5ms  Timer=148959.638  Period= 19ms
SetTimer= 5ms  Timer=148959.658  Period= 19ms
SetTimer= 5ms  Timer=148959.667  Period= 9ms
SetTimer= 5ms  Timer=148959.681  Period= 12ms
SetTimer= 5ms  Timer=148959.702  Period= 19ms
SetTimer= 5ms  Timer=148959.712  Period= 9ms
SetTimer= 5ms  Timer=148959.730  Period= 16ms
SetTimer= 5ms  Timer=148959.745  Period= 15ms
SetTimer= 5ms  Timer=148959.765  Period= 19ms
SetTimer= 5ms  Timer=148959.775  Period= 9ms
SetTimer= 5ms  Timer=148959.790  Period= 14ms
SetTimer= 5ms  Timer=148959.806  Period= 15ms
SetTimer= 5ms  Timer=148959.826  Period= 18ms
SetTimer= 5ms  Timer=148959.846  Period= 19ms
SetTimer= 5ms  Timer=148959.852  Period= 5ms
SetTimer= 5ms  Timer=148959.868  Period= 15ms
SetTimer= 5ms  Timer=148959.888  Period= 18ms

Tonigau
Posts: 36
Joined: Feb 25, 2021 20:19

Re: OverTime with Sleep (& WM_Timer)

Post by Tonigau »

I think I might be going down a rabbit hole with reducing the windows timer period, especially considering the low priority in the message queue . I am too used to programming Microcontroller's .

I will explore using WaitCommEvent, EV_RXCHAR . I have enough info to get started & will get stuck I am sure.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: OverTime with Sleep (& WM_Timer)

Post by dodicat »

Calling the winproc function takes up milliseconds with getmessage.
Peekmessage seems much faster.
You still need sleep to accommodate timebegin/end period.
I have used a 1 millisecond lag, but it will be a simple function of T_ms I guess.

Code: Select all

#define WIN_INCLUDEALL
#Include Once "windows.bi"
#Include "VBcompat.bi"

   Const T_ms = 5   '<- ======== SetTimer ms Here ========
  const lag=1
   Dim Shared timerID As UINT_PTR
   Dim Msg As TAGMSG
   Dim Shared As UInteger Cnt1, TimerNew
   Dim Shared As Double TimerOld
 
   Print "                                Ignore first Period(& rounding err)"

Sub MyFunc(ByVal HWND As hwnd, BYVAL uMsg AS UINT, ByVal idEvent AS Uint_Ptr, ByVal dwTime AS Dword)

  Select Case uMsg
    Case WM_TIMER
      TimerNew = Timer
                  Print "SetTimer="; T_ms; "ms  Timer="; Format(Timer, ".000"); "  Period="; Int((Timer - TimerOld)*1000); "ms"
      TimerOld = Timer
      
    Case WM_DESTROY
      KillTimer Null, TimerID
      PostThreadMessage GetCurrentThreadID, WM_QUIT, 0, 0

  End Select
End Sub


   SetConsoleTitle("SetTimer In Console example")

   timerID = SetTimer( NULL, 0,T_ms, @MyFunc )
   while true
WHILE  (PeekMessage (@Msg, NULL, 0, 0, 0) > 0)'GetMessage(@Msg, NULL, NULL, NULL) <> 0
  DispatchMessage  @Msg
  Cnt1 +=1
  If Cnt1 > 20 Then Exit While, while
  timebeginperiod(1)
  sleep T_ms-lag
  timeendperiod(1)
Wend
wend
   Sleep 
Tonigau
Posts: 36
Joined: Feb 25, 2021 20:19

Re: OverTime with Sleep (& WM_Timer)

Post by Tonigau »

That works really good, I will implement in my app & note any interaction with the gui.

Just cleaned up a bit...

Code: Select all

' SetTimer low value miliseconds -  Experimental only
Declare Function SmallTimerInterval  Lib "winmm" Alias "timeBeginPeriod"(As Ulong=1) As Long
SmallTimerInterval

#Define WIN_INCLUDEALL
#Include Once "windows.bi"
#Include "VBcompat.bi"

  Const T_ms=2   '<- ======== SetTimer ms Here (+lag)========
  Const lag=1
   Dim Shared timerID As UINT_PTR
   Dim Msg As TAGMSG
   Dim Shared As UInteger Cnt1, TimerNew
   Dim Shared As Double TimerOld
 
   Print ,, "     Ignore first Period(& rounding err)"

Sub MyFunc(ByVal HWND As hwnd, BYVAL uMsg AS UINT, ByVal idEvent AS Uint_Ptr, ByVal dwTime AS Dword)
      Print "SetTimer="; T_ms; "ms  Timer="; Format(Timer, ".000"); "  Period="; Format(Timer - TimerOld, "0.00000"); "s"; "  ";  Int((Timer - TimerOld)*1000); "ms"
      TimerOld = Timer
   
   Select Case uMsg
     Case WM_TIMER
       TimerNew = Timer  
     Case WM_DESTROY
       KillTimer Null, TimerID
       PostThreadMessage GetCurrentThreadID, WM_QUIT, 0, 0
  End Select
End Sub

   SetConsoleTitle("SetTimer small ms value example [In Console]")
   timerID = SetTimer(NULL, 0, T_ms, @MyFunc)
   While true
      While  (PeekMessage (@Msg, NULL, 0, 0, 0) > 0)'GetMessage(@Msg, NULL, NULL, NULL) <> 0
        DispatchMessage  @Msg
        Cnt1 +=1
        If Cnt1 > 20 Then Exit While, while
        timebeginperiod(1)
         sleep T_ms-lag
        timeendperiod(1)
      Wend
   Wend
   Sleep

Code: Select all

                                Ignore first Period(& rounding err)
SetTimer= 2ms  Timer=317835.113  Period=317835.11381s   317835114ms
SetTimer= 2ms  Timer=317835.129  Period=0.01461s   15ms
SetTimer= 2ms  Timer=317835.131  Period=0.00101s   1ms
SetTimer= 2ms  Timer=317835.133  Period=0.00097s   1ms
SetTimer= 2ms  Timer=317835.135  Period=0.00104s   1ms
SetTimer= 2ms  Timer=317835.137  Period=0.00106s   1ms
SetTimer= 2ms  Timer=317835.139  Period=0.00106s   1ms
SetTimer= 2ms  Timer=317835.141  Period=0.00114s   2ms
SetTimer= 2ms  Timer=317835.144  Period=0.00251s   3ms
SetTimer= 2ms  Timer=317835.147  Period=0.00131s   1ms
SetTimer= 2ms  Timer=317835.149  Period=0.00106s   1ms
SetTimer= 2ms  Timer=317835.151  Period=0.00099s   1ms
SetTimer= 2ms  Timer=317835.153  Period=0.00104s   1ms
SetTimer= 2ms  Timer=317835.155  Period=0.00104s   1ms
SetTimer= 2ms  Timer=317835.157  Period=0.00106s   1ms
SetTimer= 2ms  Timer=317835.159  Period=0.00123s   1ms
SetTimer= 2ms  Timer=317835.162  Period=0.00184s   2ms
SetTimer= 2ms  Timer=317835.164  Period=0.00101s   1ms
SetTimer= 2ms  Timer=317835.166  Period=0.00088s   1ms
SetTimer= 2ms  Timer=317835.168  Period=0.00112s   1ms
SetTimer= 2ms  Timer=317835.170  Period=0.00187s   2ms
Post Reply