mistersquirrle Posted August 21, 2018 Posted August 21, 2018 (edited) TL;DR: Anyway to bypass built in sleep on TrayGetMsg() and GUIGetMsg() ? I'm currently working on a project that does some heavy array/ GDI+ processing, which depending what I have it do can take between 4s - 1min. During this time, I'd like to have the Tray icon (mainly, possibly also the GUI) for the program be responsive, so that if someone wanted to change actions or exit the script during this, they can without closing the process. Currently I have my TrayGetMsg and GUIGetMsg captures in my main program loop, working great, and once I go into the array/ GDI+ functions I tried switching it to an AdlibRegister call, unregistering it once completed. The problem with this is that it's adding ~10-20% more time into those functions, which I'd like to avoid. As I understand it, and from the helpfile: "This function automatically idles the CPU when required so that it can be safely used in tight loops without hogging all the CPU." From what I've read/ seen/ tested, this adds a 10ms sleep into the calls. I would rather avoid that sleep all together. The array/ GDI+ function that I'm doing peg the CPU at 100% (for its core) anyways, so that's not a concern of mine. My only concern for this is speed (and having things be responsive to other actions). Here's an example: expandcollapse popupLocal $iBlockSize = 20, $iWidth = 1920, $iHeight = 1080, $aBigArray[$iWidth * $iHeight], $iPercentDone, $sLastMsg Local $aSmallerArray[Int(Ceiling($iWidth / $iBlockSize)) * Int(Ceiling($iHeight / $iBlockSize))] Local $sAdlib[] = ["Registered: ", "UnRegistered: ", "Registered to _FakeTray: "], $timer, $iIndexLength = UBound($aBigArray) Local $ixBlocks = Int(Ceiling($iWidth / $iBlockSize)), $iBlockIndex, $iBlockX, $iBlockY For $j = 0 To 2 If $j = 0 Then AdlibRegister("_CheckTray", 100) ElseIf $j = 1 Then AdlibUnRegister("_CheckTray") ElseIf $j = 2 Then AdlibRegister("_FakeTray", 100) EndIf $timer = TimerInit() For $i = 0 To $iIndexLength - 1 ; Loop through $aBigArray $aBigArray[$i] = Random(1, 10, 1) $iPercentDone = Floor(($i / $iIndexLength * 100)) ; Hopefully quick maths to get progress If $sLastMsg <> "We are " & $iPercentDone & "% done" Then ; Check if we're on a new percent $sLastMsg = "We are " & $iPercentDone & "% done" ; If so, update the msg ToolTip($sLastMsg, 0, 0) ; And display the current progress EndIf $y = Floor($i / $iWidth) ; Convert index to Y coordinate $x = Floor($i - ($y * $iWidth)) ; Convert index to X coordinate $iBlockX = Floor($x / $iBlockSize) ; Convert X coord to xBlock coord $iBlockY = Floor($y / $iBlockSize) ; Convert Y coord to yBlock coord $iBlockIndex = Int($iBlockX + ($iBlockY * $ixBlocks)) ; Convert into a blockIndex ;~ If Mod($i, 10000) = 0 Then ;~ ConsoleWrite($iBlockIndex & " - " & $i & @CRLF) ;~ EndIf $aSmallerArray[$iBlockIndex] += Int($aBigArray[$i]) ; Add into $aSmallerArray Next ConsoleWrite("Time to run with Adlib" & $sAdlib[$j] & TimerDiff($timer) & @CRLF) Next Func _CheckTray() Switch TrayGetMsg() Case "Meow" Return Case "Woof" Return EndSwitch EndFunc ;==>_CheckTray Func _FakeTray() Local $sMeow = "Oink" Switch $sMeow Case "Meow" Return Case "Woof" Return EndSwitch EndFunc ;==>_FakeTray Exit On my system, this takes ~1 minute to run, output: Time to run with AdlibRegistered: 19649.335 Time to run with AdlibUnRegistered: 16264.4124 Time to run with AdlibRegistered to _FakeTray: 16860.1283 >Exit code: 0 Time: 53.92 As you can see, it's ~20.8% faster without the Adlib check, and ~16.5% faster using a (hopefully) reproduction of TrayGetMsg() without the built in sleep. These timings vary, but it's consistently much faster without the TrayGetMsg() sleep (unless it's just that slow). I've used the OnEventModes, and those also slow down performance, more so than just using the GetMsgs, so those are out (but effective, and pretty easy to use). Edited August 21, 2018 by mistersquirrle We ought not to misbehave, but we should look as though we could.
mistersquirrle Posted August 24, 2018 Author Posted August 24, 2018 I'd be OK with a 'No', I just want to know Currently I'm using the Tray/GUIGetMsg in my program, which works fine, and I've tried the OnEvent's as well, so it'll come down to which has a smaller impact on performance. I've been doing a lot of performance testing of different things, and having the OnEvent modes on really slows things down. I'm thinking at the moment though that it may be best for performance to run the OnEventModes while in my main loop, and switch to the GetMsg's / adlib (at a higher interval) for my array/GDI functions, but I'm not sure if switching between those modes often would have any ill effect. Again, if there's a way to bypass the sleep built into the *GetMsgs that would easily solve these problems, and CPU hogging isn't an issue for this/me. Or -- if there's a different way that I get receive the GUI/ Tray msgs, such as with some other Windows functions/ DLLs, I just don't know enough in that area to figure out what I would need to look at. For GUIGetMsg, I was looking at GUIRegisterMsg(), but the main issue right now is the TrayGetMsg as that's always in the main loop, the GUI isn't always around. We ought not to misbehave, but we should look as though we could.
Developers Jos Posted August 24, 2018 Developers Posted August 24, 2018 On 8/21/2018 at 5:45 AM, mistersquirrle said: TL;DR: Anyway to bypass built in sleep on TrayGetMsg() and GUIGetMsg() ? Use Event mode for both. Jos SciTE4AutoIt3 Full installer Download page - Beta files Read before posting How to post scriptsource Forum etiquette Forum Rules Live for the present, Dream of the future, Learn from the past.
mistersquirrle Posted August 25, 2018 Author Posted August 25, 2018 (edited) Thanks for the reply Jos, but the OnEvent mode also has performance issues. Using that same test, but with the OnEvent modes on (all times in ms): Time to run with Tray off, GUI off: 18216.3572 Time to run with Tray On, GUI off: 19452.3151 Time to run with Tray off, GUI On: 19975.8837 Time to run with Tray On, GUI On: 22121.3507 So running with both on in that test is slower, unfortunately. I was originally using the OnEvent modes until I discovered that they slowed everything down. I had done some other speed tests on Select vs Switch vs Ifs as well, and you can see it a lot there: Tray and GUI OnEventMode OFF | | Tray and GUI OnEventMode ON ------------------------------------------------------------------------------------------------------------------ Select | Switch | Ifs | Select | Switch | Ifs 28940.94468 | 19846.75708 | 34120.26846 | 10,000,000 times | 39401.7251 | 29542.56247 | 62362.88815 ------------------------------------------------------------------------------------------------------------------- 3140.979716 | 1956.855577 | 3363.471969 | Time for 1mil | 4024.597562 | 2930.187909 | 6344.789068 The above averages were over 6 runs of 1,000,000 times for each. This was a simple statement seeing if a variable = 1. I did a second run with checking against an array with two indexes values (ie. If $aTmp[0] = 1 And $aTmp[1] = 1 Then): Tray and GUI OnEventMode OFF | | Tray and GUI OnEventMode ON ------------------------------------------------------------------------------------------------------------------- Select | Switch | Ifs | | Select | Switch | Ifs 2983.793303 | 1481.685642 | 3709.658693 | Time for 1mil | 3703.603641 | 2753.622659 | 7324.438944 This again is the time to run each statement 1 million times, averaged over 6 runs. Edited August 25, 2018 by mistersquirrle We ought not to misbehave, but we should look as though we could.
Developers Jos Posted August 25, 2018 Developers Posted August 25, 2018 What code did you use for the OnEvent test? Jos SciTE4AutoIt3 Full installer Download page - Beta files Read before posting How to post scriptsource Forum etiquette Forum Rules Live for the present, Dream of the future, Learn from the past.
LarsJ Posted August 25, 2018 Posted August 25, 2018 (edited) I have run the code in the first post with these results: Time to run with AdlibRegistered: 14571.9029530593 Time to run with AdlibUnRegistered: 13025.2308415184 Time to run with AdlibRegistered to _FakeTray: 13365.1403195613 A few comments: A large number of loops are much faster in 64 bit code. The outer loop (j-loop) is always faster in second and third passes. In this code about 1 second faster. This gives incorrect results. It should be taken into account by introducing an initial first run. $aSmallerArray is not be reset between each pass. Tooltip: If Not Mod( $i, 20736 ) Then ToolTip("We are " & $i/20736 & "% done", 0, 0) Added _ArrayDisplayEx that can display large arrays New code: expandcollapse popup#AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 #include "Display\Functions\ArrayDisplayEx\ArrayDisplayEx.au3" Global $iBlockSize = 20, $iWidth = 1920, $iHeight = 1080, $iIndexLength = $iWidth * $iHeight, $iPercentDone, $sLastMsg Global $aBigArray[$iIndexLength], $aSmallerArray[$iWidth / $iBlockSize * $iHeight / $iBlockSize] Global $sAdlib = [" First run: ", "Registered: ", "UnRegistered: ", "Registered to _FakeTray: "] Global $ixBlocks = $iWidth / $iBlockSize, $iBlockIndex, $iBlockX, $iBlockY, $timer, $x, $y For $j = 0 To 3 If $j = 1 Then AdlibRegister("_CheckTray", 100) ElseIf $j = 2 Then AdlibUnRegister("_CheckTray") ElseIf $j = 3 Then AdlibRegister("_FakeTray", 100) EndIf $aSmallerArray = 0 Dim $aSmallerArray[$iWidth / $iBlockSize * $iHeight / $iBlockSize] $timer = TimerInit() For $i = 0 To $iIndexLength - 1 ; Loop through $aBigArray $aBigArray[$i] = Random(1, 10, 1) If Not Mod( $i, 20736 ) Then ToolTip("We are " & $i/20736 & "% done", 0, 0) $y = Floor($i / $iWidth) ; Convert index to Y coordinate $x = Floor($i - ($y * $iWidth)) ; Convert index to X coordinate $iBlockX = Floor($x / $iBlockSize) ; Convert X coord to xBlock coord $iBlockY = Floor($y / $iBlockSize) ; Convert Y coord to yBlock coord $iBlockIndex = Int($iBlockX + ($iBlockY * $ixBlocks)) ; Convert into a blockIndex $aSmallerArray[$iBlockIndex] += Int($aBigArray[$i]) ; Add into $aSmallerArray Next ConsoleWrite("Time to run with Adlib" & $sAdlib[$j] & TimerDiff($timer) & @CRLF) Next Global $aWidth = [ 0, 65 ] Global $aAlign = [ [ 0, "l" ], [ 1, "r" ] ] Global $aFeatures = [ [ "ColWidthMin", $aWidth ], _ [ "ColAlign", $aAlign ] ] _ArrayDisplayEx( $aBigArray, "$aBigArray", "", 0, $aFeatures ) _ArrayDisplayEx( $aSmallerArray, "$aSmallerArray", "", 0, $aFeatures ) Func _CheckTray() Switch TrayGetMsg() Case "Meow" Return Case "Woof" Return EndSwitch EndFunc ;==>_CheckTray Func _FakeTray() Local $sMeow = "Oink" Switch $sMeow Case "Meow" Return Case "Woof" Return EndSwitch EndFunc ;==>_FakeTray Exit #cs Time to run with Adlib First run: 9354.58487313101 Time to run with AdlibRegistered: 8572.65596364715 Time to run with AdlibUnRegistered: 8436.5804675481 Time to run with AdlibRegistered to _FakeTray: 8573.66191708517 #ce And results: Time to run with Adlib First run: 9354.58487313101 Time to run with AdlibRegistered: 8572.65596364715 Time to run with AdlibUnRegistered: 8436.5804675481 Time to run with AdlibRegistered to _FakeTray: 8573.66191708517 Now there is not much difference between the last 3 results. For arrays with 2 million elements, it's a great advantage to use compiled code. Since UDFs already exist to execute VB code (and C# code) in an AutoIt script through the .NET Framework, it's not difficult. c.vb: Imports System Class Au3Class Dim aSmallerArray As Integer() Public Function MyMethod1( iBlockSize As Integer, iWidth As Integer, iHeight As Integer ) As Integer() Dim ixBlocks As Integer = iWidth / iBlockSize ReDim aSmallerArray(ixBlocks * iHeight/iBlockSize - 1) Dim iIndexLength As Integer = iWidth * iHeight Dim aBigArray(iIndexLength-1) As Integer Dim oRnd As New Random() Dim x, y, iBlockX, iBlockY, iBlockIndex As Integer For i As Integer = 0 To iIndexLength - 1 aBigArray(i) = oRnd.Next( 1, 10+1 ) y = Math.Floor( i / iWidth ) : x = Math.Floor( i - y * iWidth ) iBlockX = Math.Floor( x / iBlockSize ) : iBlockY = Math.Floor( y / iBlockSize ) iBlockIndex = iBlockX + iBlockY * ixBlocks aSmallerArray(iBlockIndex) += aBigArray(i) Next Return aBigArray End Function Public Function MyMethod2() As Integer() Return aSmallerArray End Function End Class c.au3: #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Au3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 #include "DotNet\DotNetAll.au3" #include "Display\Functions\ArrayDisplayEx\ArrayDisplayEx.au3" Opt( "MustDeclareVars", 1 ) Example() Func Example() Local $oNetCode = DotNet_LoadVBcode( FileRead( "c.vb" ), "System.dll" ) Local $oAu3Class = DotNet_CreateObject( $oNetCode, "Au3Class" ) Local $timer = TimerInit() Local $aBigArray = $oAu3Class.MyMethod1( 20, 1920, 1080 ) Local $aSmallerArray = $oAu3Class.MyMethod2() ConsoleWrite( TimerDiff( $timer ) & @CRLF ) ; 221.589018567889 Local $aWidth = [ 0, 65 ] Local $aAlign = [ [ 0, "l" ], [ 1, "r" ] ] Local $aFeatures = [ [ "ColWidthMin", $aWidth ], _ [ "ColAlign", $aAlign ] ] _ArrayDisplayEx( $aBigArray, "$aBigArray", "", 0, $aFeatures ) _ArrayDisplayEx( $aSmallerArray, "$aSmallerArray", "", 0, $aFeatures ) EndFunc Note the time: 221 milliseconds. You cannot do anything about the Sleep function in TrayGetMsg() and GUIGetMsg(), but you can completely avoid the functions by using Windows messages directly through GUIRegisterMsg() (still in MessageLoop mode). Tests.7z Edited August 25, 2018 by LarsJ FrancescoDiMuro 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions
mistersquirrle Posted August 26, 2018 Author Posted August 26, 2018 @Jos I don't have the same code, but it was something like this (basic, and also taking a note from LarsJ about a first run): expandcollapse popup;~ #AutoIt3Wrapper_UseX64=Y Local $timer Local $iMeow = 1 For $j = 2 To 0 Step -1 If $j < 2 Then AutoItSetOption("TrayOnEventMode", $j) If $j < 2 Then AutoItSetOption("GUIOnEventMode", $j) ConsoleWrite("Tray/GUI OnEventMode: " & $j & @CRLF) $timer = TimerInit() For $i = 0 To 999999 Select Case $iMeow = 0 Case $iMeow = 2 Case $iMeow = 1 EndSelect Next ConsoleWrite("Select time: " & TimerDiff($timer) & @CRLF) $timer = TimerInit() For $i = 0 To 999999 Switch $iMeow Case 0 Case 2 Case 1 EndSwitch Next ConsoleWrite("Switch time: " & TimerDiff($timer) & @CRLF) $timer = TimerInit() For $i = 0 To 999999 If $iMeow = 0 Then EndIf If $iMeow = 2 Then EndIf If $iMeow = 1 Then EndIf Next ConsoleWrite("Ifs time: " & TimerDiff($timer) & @CRLF) Next #cs First run (Tray/GUI OnEvent not set/ changed [default]) Select time: 966.3338 Switch time: 898.1769 Ifs time: 1543.816 Tray/GUI OnEventMode: 1 Select time: 1642.5594 Switch time: 1486.2358 Ifs time: 3028.6555 Tray/GUI OnEventMode: 0 Select time: 908.7544 Switch time: 523.0475 Ifs time: 1135.5656 #ce ---------- @LarsJ Thanks for the tips, trying your code, here's my results (note that I had to disable your included file/ functions, as even when I downloaded it and put a direct path to it, it said that it wouldn't include it and gave a lot of warnings/ error/ undefineds): Time to run with Adlib First run: 12885.4199 Time to run with AdlibRegistered: 11540.2438 Time to run with AdlibUnRegistered: 11087.015 Time to run with AdlibRegistered to _FakeTray: 11600.5445 That does provide interesting results as the AdlibRegistered run with TrayGetMsg is slightly faster than without TrayGetMsg for both of us. I had also looked at your topic a bit before, and it's a bit much for me to get my head around, but I was going to look into that some more to speed up some data processing parts of my program like this, so I appreciate this example. As for the GUIRegisterMsg, I know how to use it for an actual GUI, but I'm not sure how to use it for the Tray icon? We ought not to misbehave, but we should look as though we could.
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