Hi,
habt ihr die neue AutoIt Version 3.3.18.0 bereits getestet?
Wie sind eure Erfahrungen damit?
![]()
Hi,
habt ihr die neue AutoIt Version 3.3.18.0 bereits getestet?
Wie sind eure Erfahrungen damit?
![]()
Ja, läuft einwandfrei ![]()
Meine Skripte sind aber nicht allzu komplex.
Mich hat vor allem der folgende Eintrag im Changelog interessiert:
Zitat
Was genau gemacht wurde steht da nicht und im verlinkten Ticket wird sich im Grunde auch ausgeschwiegen.
Da steht nur "Internal optimisation to not allocate data at each DllCall".
Das ist umso verwirrender, da im Ticket steht, dass dieses bereits in 3.3.16.1 umgesetzt wurde.
Ich wollte daher mal herausfinden, was diese Änderung konkret ausmacht und habe mal verschiedene Szenarien für DllCall mit folgendem Skript getestet:
#include <Array.au3>
#include <String.au3>
Global Const $iRUNS = 1e5 ; number of iterations for each test
Global $aResults[0][2] ; result array
Global Const $hDLLKernel32 = DllOpen("kernel32.dll"), $hDLLUser32 = DllOpen("user32.dll")
ConsoleWrite("===========================================" & @CRLF & _
"DllCall Performance Benchmark" & @CRLF & _
"AutoIt Version: " & @AutoItVersion & @CRLF & _
"Iterations: " & $iRUNS & @CRLF & _
"===========================================" & @CRLF & @CRLF)
; Warm-up (for waking the CPU)
For $i = 1 To 1e6
DllCall($hDLLKernel32, "DWORD", "GetTickCount")
Next
; determine overhead for the loop itself
Global $iOverhead = TimerInit()
For $i = 1 To $iRUNS
Next
$iOverhead = TimerDiff($iOverhead)
; run the test
ConsoleWrite("=== Test 1: functions without parameters ===" & @CRLF)
_Test_NoParams()
ConsoleWrite(@CRLF)
ConsoleWrite("=== Test 2: functions with simple parameters ===" & @CRLF)
_Test_SmallParams()
ConsoleWrite(@CRLF)
ConsoleWrite("=== Test 3: functions with string parameters ===" & @CRLF)
_Test_StringParams()
ConsoleWrite(@CRLF)
ConsoleWrite("=== Test 4: functions with dll structs ===" & @CRLF)
_Test_StructParams()
ConsoleWrite(@CRLF)
ConsoleWrite("=== Test 5: memory operations ===" & @CRLF)
_Test_MemoryOps()
ConsoleWrite(@CRLF)
; print results
ConsoleWrite("===========================================" & @CRLF)
ConsoleWrite("Results" & @CRLF)
ConsoleWrite("===========================================" & @CRLF)
For $i = 0 To UBound($aResults) - 1
ConsoleWrite(StringFormat("%-50s % 10.3f µs\n", $aResults[$i][0], $aResults[$i][1] * 1000 / $iRUNS))
Next
ConsoleWrite(@CRLF)
; Test 1: functions without parameters
Func _Test_NoParams()
; GetCurrentProcessId
Local $hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "DWORD", "GetCurrentProcessId")
Next
Local $fTime = TimerDiff($hTimer)
_PrintTestResult("GetCurrentProcessId (no params)", $fTime)
; GetTickCount
$hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "DWORD", "GetTickCount")
Next
$fTime = TimerDiff($hTimer)
_PrintTestResult("GetTickCount (no params)", $fTime)
; GetLastError
$hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "DWORD", "GetLastError")
Next
$fTime = TimerDiff($hTimer)
_PrintTestResult("GetLastError (no params)", $fTime)
EndFunc
; Test 2: functions with simple parameters
Func _Test_SmallParams()
; Sleep with 0 ms
Local $hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "NONE", "Sleep", "DWORD", 0)
Next
Local $fTime = TimerDiff($hTimer)
_PrintTestResult("Sleep(0) (1 DWORD Parameter)", $fTime)
; SetLastError
$hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "NONE", "SetLastError", "DWORD", 0)
Next
$fTime = TimerDiff($hTimer)
_PrintTestResult("SetLastError (1 DWORD Parameter)", $fTime)
EndFunc
; Test 3: functions with string parameters
Func _Test_StringParams()
; short String
Local $tCharStruct = DllStructCreate("WCHAR[5]")
Local $hPtr = DllStructGetPtr($tCharStruct)
DllStructSetData($tCharStruct, 1, "Test")
Local $hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "int", "lstrlenW", "PTR", $hPtr)
Next
Local $fTime = TimerDiff($hTimer)
_PrintTestResult("lstrlenW (4 chars)", $fTime)
; medium string
$tCharStruct = DllStructCreate("WCHAR[101]")
$hPtr = DllStructGetPtr($tCharStruct)
DllStructSetData($tCharStruct, 1, _StringRepeat("A", 100))
$hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "int", "lstrlenW", "PTR", $hPtr)
Next
$fTime = TimerDiff($hTimer)
_PrintTestResult("lstrlenW (100 chars)", $fTime)
; long string
$tCharStruct = DllStructCreate("WCHAR[10001]")
$hPtr = DllStructGetPtr($tCharStruct)
DllStructSetData($tCharStruct, 1, _StringRepeat("B", 10000))
$hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "int", "lstrlenW", "PTR", $hPtr)
Next
$fTime = TimerDiff($hTimer)
_PrintTestResult("lstrlenW (10000 chars)", $fTime)
EndFunc
; Test 4: functions with dll structs
Func _Test_StructParams()
; struct definitions
Local $tSystemTime = DllStructCreate("word Year;word Month;word DayOfWeek;word Day;" & _
"word Hour;word Minute;word Second;word Milliseconds")
Local $tFileTime = DllStructCreate("DWORD dwLowDateTime;DWORD dwHighDateTime")
; GetSystemTime
Local $hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "NONE", "GetSystemTime", "struct*", $tSystemTime)
Next
Local $fTime = TimerDiff($hTimer)
_PrintTestResult("GetSystemTime (struct SYSTEMTIME)", $fTime)
; GetSystemTimeAsFileTime
$hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "NONE", "GetSystemTimeAsFileTime", "struct*", $tFileTime)
Next
$fTime = TimerDiff($hTimer)
_PrintTestResult("GetSystemTimeAsFileTime (struct FILETIME)", $fTime)
EndFunc
; Test 5: memory operations
Func _Test_MemoryOps()
Local $iSize = 1024 ; 1KB
Local $tSource = DllStructCreate("byte[" & $iSize & "]")
Local $tDest = DllStructCreate("byte[" & $iSize & "]")
; fill source with data
For $i = 1 To $iSize
DllStructSetData($tSource, 1, Random(0, 255, 1), $i)
Next
; RtlMoveMemory 1 KB block
Local $hTimer = TimerInit()
For $i = 1 To $iRUNS
DllCall($hDLLKernel32, "NONE", "RtlMoveMemory", _
"struct*", $tDest, _
"struct*", $tSource, _
"ulong_ptr", $iSize)
Next
Local $fTime = TimerDiff($hTimer)
_PrintTestResult("RtlMoveMemory (1 KB)", $fTime)
; RtlMoveMemory 1 MB block
$iSize = 1048576 ; 1 MB
$tSource = DllStructCreate("byte[" & $iSize & "]")
$tDest = DllStructCreate("byte[" & $iSize & "]")
For $i = 1 To $iSize
DllStructSetData($tSource, 1, Random(0, 255, 1), $i)
Next
$hTimer = TimerInit()
For $i = 1 To $iRUNS / 10
DllCall($hDLLKernel32, "NONE", "RtlMoveMemory", _
"struct*", $tDest, _
"struct*", $tSource, _
"ulong_ptr", $iSize)
Next
$fTime = TimerDiff($hTimer)
_PrintTestResult("RtlMoveMemory (1 MB)", $fTime * 10)
EndFunc
; Hilfsfunktion: Ergebnis hinzufügen
Func _PrintTestResult($sTest, $fTime)
Local $iN = UBound($aResults)
; add current result
ReDim $aResults[$iN + 1][2]
$aResults[$iN][0] = $sTest
$aResults[$iN][1] = $fTime - $iOverhead
ConsoleWrite(StringFormat("%-50s: % 10.2f µs\n", $sTest, ($fTime - $iOverhead) * 1000 / $iRUNS))
EndFunc
Alles anzeigen
Die Ergebnisse habe ich dann zwischen der Version 3.3.16.1 und 3.3.18.0 gegenübergestellt und erhielt folgendes Ergebnis:
Test 3.3.16.1 3.3.18.0 Δ in %
---------------------------------------------------------------------
GetCurrentProcessId (no params) 2,0 µs 2,0 µs 0,2%
GetTickCount (no params) 1,9 µs 1,9 µs 1,1%
GetLastError (no params) 1,9 µs 1,9 µs 0,0%
GetCurrentProcessId (no params) 2,0 µs 2,0 µs -0,2%
GetTickCount (no params) 1,9 µs 1,9 µs -0,7%
GetLastError (no params) 1,9 µs 1,9 µs -2,0%
Sleep(0) (1 DWORD Parameter) 3,4 µs 3,4 µs 2,3%
SetLastError (1 DWORD Parameter) 2,8 µs 2,8 µs 1,9%
lstrlenW (4 chars) 3,0 µs 2,9 µs 3,2%
lstrlenW (100 chars) 3,0 µs 3,0 µs 2,5%
lstrlenW (10000 chars) 6,3 µs 6,5 µs -3,6%
GetSystemTime (struct SYSTEMTIME) 5,3 µs 5,3 µs -0,3%
GetSystemTimeAsFileTime (struct FILETIME) 3,9 µs 4,7 µs -20,4%
RtlMoveMemory (1 KB) 7,0 µs 6,3 µs 10,1%
RtlMoveMemory (1 MB) 52,2 µs 48,1 µs 7,8%
Alles anzeigen
Einen wirklichen Performancesprung kann ich nicht erkennen. Die Unterschiede lassen sich nichtmal signifikant von der Messungenauigkeit trennen.
Ich habe (da im Ticket ja steht, dass dieses bereits mit 3.3.16.1 umgesetzt wurde) auch mal die Version 3.3.14.0 dagegen gehalten.
Aber auch da sieht das Ergebnis ziemlich gleich aus.
Ich bin daher ziemlich ratlos was es mit der ominösen DllCall performance optimisation auf sich hat.
Ich denke, dass die Änderung den DllCall mit Dll-Namen betrifft. Dann wird vielleicht intern das DllClose nicht mehr aufgerufen, und überprüft ob die Dll bereits geöffnet ist....
Ja das wäre eine mögliche Interpretation.
Hab das auch gleich mal so getestet - aber auch das sehe ich kein relevantes Muster:
Test 3.3.16.1 3.3.18.0 Δ in %
---------------------------------------------------------------------
GetCurrentProcessId (no params) 2,4 µs 2,4 µs 1,6%
GetTickCount (no params) 2,3 µs 2,3 µs 1,6%
GetLastError (no params) 2,5 µs 2,3 µs 7,1%
GetCurrentProcessId (no params) 2,4 µs 2,4 µs 3,0%
GetTickCount (no params) 2,4 µs 2,3 µs 6,4%
GetLastError (no params) 2,4 µs 2,3 µs 3,8%
Sleep(0) (1 DWORD Parameter) 4,1 µs 3,8 µs 7,9%
SetLastError (1 DWORD Parameter) 4,0 µs 3,3 µs 18,0%
lstrlenW (4 chars) 3,8 µs 3,3 µs 12,0%
lstrlenW (100 chars) 3,5 µs 3,4 µs 4,9%
lstrlenW (10000 chars) 6,9 µs 6,7 µs 3,1%
GetSystemTime (struct SYSTEMTIME) 5,7 µs 6,0 µs -4,6%
GetSystemTimeAsFileTime (struct FILETIME) 4,3 µs 4,5 µs -4,5%
RtlMoveMemory (1 KB) 6,8 µs 6,9 µs -2,3%
RtlMoveMemory (1 MB) 51,7 µs 50,6 µs 2,1%
Alles anzeigen
Ich denke im engl Forum posten mit direkter Ansprache an @JPM könnte Licht in die Dunkelheit bringen ![]()
Ich konnte die Messung über ProcessSetPriority noch stabilisieren.
Die Ergebnisse nun zeigen dann doch ein klares Bild: Die 3.3.18.0 ist tatsächlich immer ein paar Prozentpunkte der 3.3.16.1 voraus:
| Test | 3.3.16.1 | 3.3.18.0 | Δ in % |
| ----------------------------------------- | -------- | -------- | ------ |
| GetCurrentProcessId (no params) | 2,3 µs | 2,3 µs | 0,0% |
| GetTickCount (no params) | 2,3 µs | 2,2 µs | 1,9% |
| GetTickCount (no params) | 2,3 µs | 2,2 µs | 2,5% |
| GetLastError (no params) | 2,3 µs | 2,2 µs | 3,0% |
| GetLastError (no params) | 2,3 µs | 2,2 µs | 3,2% |
| lstrlenW (100 chars) | 3,5 µs | 3,3 µs | 3,2% |
| GetCurrentProcessId (no params) | 2,4 µs | 2,3 µs | 3,4% |
| SetLastError (1 DWORD Parameter) | 3,3 µs | 3,2 µs | 3,5% |
| lstrlenW (4 chars) | 3,4 µs | 3,3 µs | 4,0% |
| lstrlenW (10000 chars) | 7,0 µs | 6,7 µs | 4,8% |
| GetSystemTime (struct SYSTEMTIME) | 5,9 µs | 5,6 µs | 5,4% |
| Sleep(0) (1 DWORD Parameter) | 4,1 µs | 3,8 µs | 6,4% |
| RtlMoveMemory (1 KB) | 7,1 µs | 6,6 µs | 6,9% |
| RtlMoveMemory (1 MB) | 53,6 µs | 49,9 µs | 6,9% |
| GetSystemTimeAsFileTime (struct FILETIME) | 4,7 µs | 4,3 µs | 8,4% |
Alles anzeigen
Habe es auch installiert und bisher gab es keine Auffälligkeiten.
Gruß Marcel