Jump to content

Recommended Posts

Posted

Hi folks,

I was looking at writing something that spits out time code - but in order to have any chance of succeeding we need to work to a consistent clock. After doing a bit of reading this is where I've landed, but of course if anyone has a better method I'm very open to suggestion.

The goal here to kick something off every 33.33ms without tying up too much of the CPU. I don't think this does a terrible job, but a few ticks can still be off the money.
With time code I think we can get away with dropping a few messages. So if a pulse say >5ms late, I'd probably just ignore it and shoot for the next frame whenever it rolls around.

Local $nFrame = (1000/30) ;30fps (33.33ms)
Local $nElapsed, $nTarget = $nFrame, $nShift


Local $hTimer = TimerInit()
Local $iTimeout = 30000

Do
    ;Sleep until 10ms before the next tic is due. Exiting sleep does chew up some time.
    Sleep(($nFrame - $nShift) - 10) 
    
    ;Spin-Lock
    Do
        $nElapsed = TimerDiff($hTimer)
    Until $nElapsed >= $nTarget
    
    ;See how much we've missed by!
    $nShift =  $nElapsed - $nTarget
    ConsoleWrite(StringFormat("%0.2f", $nFrame + $nShift) & @CRLF)
    $nTarget += $nFrame
Until $nTarget >= $iTimeout

It's also worth mentioning that when you push the frequency of the clock past ~55Hz, the combination of Sleeps/ConsoleWrites() can't seem to keep up with the clock (at least on my laptop). So I guess that's one indicator as to how far you can push things.

Posted

Thanks mate -  That should help fine tune the spin lock I'd dare say.

When a tick is late its because we're slow coming out of sleep - so the super fine time stamp probably won't help us there!

Posted (edited)

Just awesome. You do still need the spin lock - but that's helped quite a bit.

Oops  I made a mistake, and we weren't actually sleeping (example updated!). I'll have a closer look, but just eyeballing it I don't think the result was much better than a normal sleep... Without the spin lock that function jumps around quite a bit.

Global $nFrame = (1000/30) ;30fps (33.33ms)
Global $nElapsed, $nTarget = $nFrame, $nShift

Global $hTimer = TimerInit()
Global $iTimeout = 30000

;~ _Original()
_WithSpinLock()
;~ _WithoutSpinLock()


Func _Original()
    Do
        ;Sleep until 10ms before the next tic is due. Exiting sleep does chew up some time.
        Sleep(($nFrame - $nShift) - 10)

        ;Spin-Lock
        Do
            $nElapsed = TimerDiff($hTimer)
        Until $nElapsed >= $nTarget

        ;See how much we've missed by!
        $nShift =  $nElapsed - $nTarget
        ConsoleWrite(StringFormat("%0.2f", $nFrame + $nShift) & @CRLF)
        $nTarget += $nFrame
    Until $nTarget >= $iTimeout
EndFunc


Func _WithSpinLock()
    Do
        ;Sleep until 10ms before the next tic is due. Exiting sleep does chew up some time.
        _HighPrecisionSleep((($nFrame - $nShift) - 10) * 1000)

        ;Spin-Lock
        Do
            $nElapsed = TimerDiff($hTimer)
        Until $nElapsed >= $nTarget

        ;See how much we've missed by!
        $nShift =  $nElapsed - $nTarget
        ConsoleWrite(StringFormat("%0.2f", $nFrame + $nShift) & @CRLF)
        $nTarget += $nFrame
    Until $nTarget >= $iTimeout
EndFunc


Func _WithoutSpinLock()
    Do
        _HighPrecisionSleep(($nFrame - $nShift) * 1000)
        $nElapsed = TimerDiff($hTimer)
        $nShift =  $nElapsed - $nTarget
        ConsoleWrite(StringFormat("%0.2f", $nFrame + $nShift) & @CRLF)
        $nTarget += $nFrame
    Until $nTarget >= $iTimeout
EndFunc


Func _HighPrecisionSleep($iMicroSeconds,$hDll=False)
    Local $hStruct, $bLoaded
    If Not $hDll Then
        $hDll=DllOpen("ntdll.dll")
        $bLoaded=True
    EndIf
    $hStruct=DllStructCreate("int64 time;")
    DllStructSetData($hStruct,"time",-1*($iMicroSeconds*10))
    DllCall($hDll,"dword","ZwDelayExecution","int",0,"ptr",DllStructGetPtr($hStruct))
    If $bLoaded Then DllClose($hDll)
EndFunc

 

Edited by MattyD

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...