Jump to content

Sleep down to 100 Nano seconds


monoceres
 Share

Recommended Posts

If you want it even more accurate, you should to all assigning outside of the func:

Func _HighPrecisionSleep(ByRef $aSleep)
    DllCall($aSleep[0],"dword","ZwDelayExecution","int",0,"ptr",$aSleep[2])
EndFunc

Func _HighPrecisionSleep_Init($iMicroSeconds=0)
    Local $aSleep[3] = [DllOpen("ntdll.dll"),DllStructCreate("int64 time;")]
    $aSleep[2] = DllStructGetPtr($aSleep[1])
    DllStructSetData($aSleep[1],"time",-1*($iMicroSeconds*10))
    Return $aSleep
EndFunc

Func _HighPrecisionSleep_Set(ByRef $aSleep, $iMicroSeconds)
    DllStructSetData($aSleep[1],"time",-1*($iMicroSeconds*10))
EndFunc

Func _HighPrecisionSleep_UnInit(ByRef $aSleep)
    DllClose($aSleep[0])
    Dim $aSleep[3] = [0,0,0]
EndFunc

$Sleep = _HighPrecisionSleep_Init(10)

_HighPrecisionSleep($Sleep) ; sleep 10 microseconds

_HighPrecisionSleep_Set($Sleep,100)
_HighPrecisionSleep($Sleep) ; sleep 100 microseconds

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

  • 5 months later...

Just wanted to say thank you for this function, I actually come to use it on my ALIBI Controller app, in which I use the TCP UDF from Kip.

because if I send data in a loop which has no sleep, the receiver of the data misses some bits, and with a 1ms sleep its slow as hell...

But with this UDF with which I have such great precision I can get the send-loop tight but still not so fast that the receiver misses anything.

So to the guys who said thats its useless, think again >_<

[font="Impact"]Use the helpfile, It´s one of the best exlusive features of Autoit.[/font]http://support.microsoft.com/kb/q555375ALIBI Run - a replacement for the windows run promptPC Controller - an application for controlling other PCs[size="1"]Science flies us to the moon. Religion flies us into buildings.[/size][size="1"]http://bit.ly/cAMPZV[/size]
Link to comment
Share on other sites

  • 7 months later...

Seemed easier this way:

Func _HPSleep($iSleep, $fMs = 1)
    ; default is milliseconds, otherwise microseconds (1 ms = 1000 µs)
    If $fMs Then $iSleep *= 1000 ; convert to ms
    DllCall("ntdll.dll", "dword", "NtDelayExecution", "int", 0, "int64*", -10 * $iSleep)
EndFunc

In testing, about 1 ms is as low as AutoIt can measure:

Sleep(1000) ; more accurate results
For $i = 1 To 10
    $timer = TimerInit()
    _HPSleep(1) ; 1 ms
    ConsoleWrite(TimerDiff($timer) & @CRLF)
Next

/edit:

Changed Zw -> Nt

Edited by wraithdu
Link to comment
Share on other sites

Link to comment
Share on other sites

I wonder how this function will perform in assembly. :(

What do mean? In the end, zwDelayExecution boils down to machine code instructions, they always execute the same.

Code is just code is just code.

Broken link? PM me and I'll send you the file!

Link to comment
Share on other sites

What do mean? In the end, zwDelayExecution boils down to machine code instructions, they always execute the same.

Code is just code is just code.

I just meant how accurate the sleep would be. Like you said, it takes autoit some time to call the function so maybe in assembly we could get a better measurement..

Link to comment
Share on other sites

  • 6 months later...
  • 3 months later...

Interesting, using my function above:

; pretty good
$timer = TimerInit()
For $i = 1 To 100
    _HPSleep(10) ; 10 ms
Next
ConsoleWrite(TimerDiff($timer) & @CRLF)
; i got 999.876225456811

; still pretty good
$timer = TimerInit()
For $i = 1 To 100
    _HPSleep(1) ; 1 ms
Next
ConsoleWrite(TimerDiff($timer) & @CRLF)
; i got 99.9358030598962

; i think we hit an AutoIt limit at 1ms of sleep
$timer = TimerInit()
For $i = 1 To 100
    _HPSleep(100, 0) ; 100 microsec = 0.1 ms
Next
ConsoleWrite(TimerDiff($timer) & @CRLF)
; i got 99.962453081157
Link to comment
Share on other sites

  • 1 year later...

I have two Questions.

Amusing the sleep value doesn't change and will get run thousands of time. Which would be the better code to use ?

;Varaibles - Example A
   $SleepDll=DllOpen("ntdll.dll")
   $SleepStruct=DllStructCreate("int64 time;")
   DllStructSetData($SleepStruct,"time",-10000)

   While 1
   DllCall($SleepDll,"dword","ZwDelayExecution","int",0,"ptr",DllStructGetPtr($SleepStruct))
   WEnd

   ;All in One - Example B
   While
   DllCall("ntdll.dll", "dword", "NtDelayExecution", "int", 0, "int64*", -10000) 
   WEnd

If i understand the function and how autoit works, Example A is the better. It only opens, creates and edits once whereas example b needs to do everything new every loop. Am i correct?

Second question.

I was looking into sleep(), where i found sleep(1) and sleep(100) is basicly the same. Aside from sleep(100) is just calling the same function 100 times, something to do with a tick. So If i had this function set to 10-15ms "which is the same as sleep(1). Would this be better in terms of performance or effect?

Link to comment
Share on other sites

Sleep(1) is equivalent to sleep(10), not sleep(100). The lowest the sleep goes is 10ms, changing it to any other number than 1-10 shouldn't affect any performance situations, and even if it did, it would only affect it in the very low ms range. Also, you're sleeping the script, there's no performance happening at that time in your script anyways, so it's all moot.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

@BrewManAh. I agree sleep(1) is not the same as sleep(100). Infact from what i found sleep(1) - sleep(10) all yield the same 15ms sleep.

In terms of the examples i posted from what i could find.

Example A yields better performances in lower sleeps but when you start increasing the sleep they tend to become the same. More important for others I guess who are after pin-point timers.

Edited by IanN1990
Link to comment
Share on other sites

  • 5 months later...

Sorry to bring this up again.

Out of curiosity I was looking again at ways for smaller and more precise ways to make my script pause, or rather run as quickly as possible without consuming a CPU core all for itself. Using

$hDll = DllOpen("ntdll.dll")
$rounds = 500
Sleep(1000)

$begin = TimerInit()

For $i = 1 To $rounds
    _HPSleep(3, 1)
Next

$dif = TimerDiff($begin)
MsgBox(0, "test", "total: " & $dif & @crlf & "average: " & $dif / $rounds)

Func _HPSleep($iSleep, $fMs = 1)
    ; default is milliseconds, otherwise microseconds (1 ms = 1000 µs)
    If $fMs Then $iSleep *= 1000 ; convert to ms
    DllCall($hDll, "dword", "NtDelayExecution", "int", 0, "int64*", -10 * $iSleep)
EndFunc   ;==>_HPSleep
would return nothing shorter than 15ms.

Then I noticed something odd. When opening Media Player Classic Home Cinema, loading a video, stopping it and running the script again, I could finally get results that were pretty close to how long I want the script to pause, down to 1ms. I even checked the sate of the cores of my CPUs, and they were throttling as always.

It doesn't matter if MPC-HC's window is minimized or not, as long as I start and stop a video, timers and sleep functions in AutoIt finally return somewhat precise numbers. I even tried other media players, with varying results.

So why is it that although MPC-HC (and other players) seems idle in the task manager, it has positive influence on sleep commands in AutoIt?

Link to comment
Share on other sites

That wasn't an april's fool posting in case you were thinking that. I'm also wondering if there's a way to reproduce the observed effect in AutoIt.

Edited by Sven
Link to comment
Share on other sites

There are ways of setting the max/min setting for the resolution of timers in windows using MultiMedia timer functions. These are probably being used when there's a video playing to keep things in sync better.

http://msdn.microsoft.com/en-us/library/windows/desktop/dd743609(v=vs.85).aspx

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Thanks. "timeBeginPeriod" is exactly what I needed.

It also shows that AutoIt's sleep() function is indeed hardcoded to go as low as 10ms.

Here's a new code example:

$hDll_ntdll = DllOpen("ntdll.dll")
$hDll_winmm = DllOpen("winmm.dll")

$rounds = 500
$resolution = 0


$result1 = _test(); tests for and shows the standard timer resolution
MsgBox(0, "test 1", "Example for standard timer resolution" & @CRLF & @CRLF & "total: " & $result1 & @CRLF & "average: " & $result1 / $rounds)

$result2 = _test(1); sets timer resolution to 1ms and performs test
MsgBox(0, "test 1", "Example for 1ms timer resolution" & @CRLF & @CRLF & "total: " & $result2 & @CRLF & "average: " & $result2 / $rounds)

$result1 = _test(); to show that the timer resolution was successfully reset
MsgBox(0, "test 1", "Example for standard timer resolution" & @CRLF & @CRLF & "total: " & $result1 & @CRLF & "average: " & $result1 / $rounds)



Func _Test($highPrecision = 0)
    Sleep(1000)

    $begin = TimerInit()

    For $i = 1 To $rounds
        _HPSleep(1, 1, $highPrecision)
    Next

    $dif = TimerDiff($begin)
    Return ($dif)
EndFunc   ;==>_Test

Func _HPSleep($iSleep, $fMs = 1, $highPrecision = 0)
    ; default is milliseconds, otherwise microseconds (1 ms = 1000 µs)
    If $fMs Then $iSleep *= 1000 ; convert to ms
    if $highPrecision > 0 Then DllCall($hDll_winmm, "int", "timeBeginPeriod", "int", $highPrecision)
    DllCall($hDll_ntdll, "dword", "NtDelayExecution", "int", 0, "int64*", -10 * $iSleep)
    if $highPrecision > 0 Then DllCall($hDll_winmm, "int", "timeEndPeriod", "int", $highPrecision)
EndFunc   ;==>_HPSleep

A word of caution, directly from Microsoft, http://msdn.microsoft.com/en-us/library/windows/desktop/dd757624(v=vs.85).aspx

This function affects a global Windows setting. Windows uses the lowest value (that is, highest resolution) requested by any process. Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. High resolutions can also prevent the CPU power management system from entering power-saving modes. Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.

Edited by Sven
Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

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