MattyD Posted January 8, 2025 Posted January 8, 2025 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.
Nine Posted January 8, 2025 Posted January 8, 2025 Have you tried the QueryPerformanceCounter function (profileapi.h) ? “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
MattyD Posted January 8, 2025 Author Posted January 8, 2025 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!
Werty Posted January 8, 2025 Posted January 8, 2025 There's also the old highprecisionsleep() by monoceres... other variants throughout the thread. argumentum and MattyD 2 Some guy's script + some other guy's script = my script!
MattyD Posted January 8, 2025 Author Posted January 8, 2025 (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. expandcollapse popupGlobal $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 January 8, 2025 by MattyD
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now