Leaderboard
Popular Content
Showing content with the highest reputation on 04/09/2023 in all areas
-
Parallelism
noellarkin reacted to JPCare for a topic
Autoit was not designed for parallel processing. Nevertheless, it is possible to program the execution of parallel processes via AutoIt. To do so, you have to specifically design you program in two parts : - Part 1 : initialization, launching of parallel processes, consolidation of results - Part 2 : process to be executed in several independent instances How possible ? -------------------- 1/ The Run instruction of AutoIt can be used to launch a Part 2 process on a given cpu thread, directly via the Windows start command with the /Affinity parameter or via an utility program for the same function. Obviously, the Part 2 launched processes must be compiled exe files, as they must include all necessary libraries for their independent executions. Examples Run(@ComSpec & " /C start /affinity "&$Affinitymask&" proc.exe") By repeating the instruction with different hexadeciimal affinity masks in $Mask, you will launch proc.exe parallel instances. There is another way with an utility program that nicely accepts a cpu id (from 0 on) as a parameter instead of an affinity mask : $slaunch="StartAffinity.exe proc.exe "&$cpuid Run($slaunch) 2/ Each parallely launched Part 2 process must be started with its specific execution environment, ie at least its cpuid of execution, either via parameters within the Run instruction ($CmdLine) or via a few envset instructions just before each Run instruction, to be mirrored inside each process by envget declarations of globals (the launching instructions of parallel processes are executed sequentially !). 3/ Just before termination, each launched Part 2 process writes its results into a specific file (for example a file named after its cpuid). 4/ After having launched the Part 2 parallel processes, the Part 1 main program waits for the appearance of the file of results when created by each terminating Part 2 parallel process (these files have been swept off before the launching loop) to consolidate the results. Experimental proof of concept --------------------------------------- Two AutoIt scripts are provided : Divisoptkim.au3 (Part 1) and loopkim.au3 (Part 2). Aim : find the integer divisors of an integer number. The loopkim.au3 MUST BE COMPILED to exe by the AutoIt compiler on your OS. Place the files, Divisoptkim.au3, loopkim.exe (plus the StartAffinity.exe file if your OS is Windows XP) in the same directory, and from there start Divisoptkim.au3. (no compilation needed for Divisoptkim provided that the au3 extension is associated with AutoIt on your machine). The loopkim processes will run in several independent instances if you entered a sufficiently big number. Good numbers for testing : 5040, 66049, 13 444 333 222 110, 133 444 333 222 110, 333 333 333 333 333. Do not hesitate trying the proposed big numbers (ca 10-15 seconds execution time on a dual core processor), otherwise the execution time might be less than a hearbeat. The graphical display of Windows Task Manager (Resources Monitor) will show what happens on each cpu load. Note that the software internally redefines the level of parallelism for "too small" numbers. To do so, it automatically reduces the number of allocated cpus so that each one gets a reasonable task (minimum length of the segment of candidate numbers). When executions terminate, as many Journal_x.txt files are (re)created as the number of parallel executions of loopkim.exe, with x = cpuid (from 0 on). A standard run with default parameters will use all allocated cpus and potentially reach the 100% load level on the allocated range of cpus. If you select the second allocation method (if you have at least 2 threads), only the even cpus (0,2...) will be allocated, and the average load on the range of allocated cpus will potentially culminate at a 50% level. Warning. This demo software was tested on basic desktop machines with Intel cpus on various configurations, from XP Home / dual core to Window 11 / 20 cpus. Changes in the code may be necessary in other environments. For XP. A utility is required in the Part 1 process launch instruction, as the XP start command does not accept the /affinity parameter. At least two utility programs are available. StartAffinity can be downloaded from http://www.adsciengineering.com/StartAffinity/. Another (bigger) tool can be found in the Heise software archiv site : search for "launch". Both utilities seem to work perfectly on recent Oses, although developped many years ago. If your OS is XP, the Part 1 script checks that StartAffinity is in the execution directory. All Oses. If you load a copy of StartAffinity into the execution directory, the software will use it to launch Part 2 processes instead of the Start command. Note. Had to care for really big numbers (Divisopkimv2) by rejecting sizes longer than 15 digits. AutoIt will automatically use 64 bit long integers and shift to real format under uncontrollable circumstances, which is no longer compatible with calculations as programmed in my demo software. Will later develop a version with the BigNum library... 05th may, well, no, I definitely won't add anything to the existing demo software... The tested BigNum lib proved of poor value compared with my own hand written procedures for long division and mod... Efforts to extend a language beyond the limits of its original design create monsters. The demo software stands within these limits, nevertheless reveals how some "impossible features" can be implemented in AutoIt as it stands. If you wish easier ways, there are many other languages that implement parallelim in their original designs. Divisoptkimv2.au3 loopkim.au31 point -
Yepp, it fails with my testfile. Downloaded the original scite and go not problems when editing it. Here's what I see when opening first in original scite and after that in the latest Scite4AutoIt (destroying it): Some things I checked: Original file starts with 26 69 6e 63 6c 75 defect file starts with ef bb bf 63 75 - seems like the first 3 bytes are simply overwritten with the UTF-8 Header renaming the Folder AppData\Local\AutoIt v3\SciTE\ does not change anything in this behaviour after re-adding the overwritten "#in" and saving the file, it stays fine Notepad++ detects my testfile as "UTF" and the file after saving it with the Scite4AutoIt-Editor as "UTF-8-BOM" hope this helps...1 point
-
View color in a minimized or inactive window
Dsmoeg999 reacted to 636C65616E for a topic
PixelSearch will search based on what is rendered (basically, what is visible on your screen). A minimized window isn't rendered ...1 point -
@Gianni I would not have realized these scripts exist. Thank you for posting the links. This will help alot.1 point
-
ghostscript 9.56.1 gswin32c.exe -dNOPAUSE -dBATCH -dSAFER -sDEVICE=txtwrite -dTextFormat=3 -sOutputFile=- -q input.pdf > output.txt 2>error.txt1 point
-
Just a fun exercise using SQLite: (inspired by this post: (https://www.autoitscript.com/forum/topic/209982-datediff_workdaysonly/) find a past or future "target" date starting from a certain date and counting a number of days, excluding any number of days of the week from the count. formally, a WorkDay function by default only Saturday and Sunday are considered non-working, but you can pass a string with the numbers corresponding to the days of the week to be considered non-working according to this scheme: (0=Sunday, 1=Monday, 2=Tuesday, 3=Wednesday, 4 =Thursday, 5=Friday, 6=Saturday) for example, to consider Thursday, Saturday and Sunday as non-working, pass the following string as the third parameter to the _WorkDay() function: "4,6,0" To run the script you need to download the "precompiled binaries for Windows" sqlite3.dll (32 or 64 according to your AutoIt version) from this link (https://www.sqlite.org/download.html) and save it in the same folder as this script. (hope there are no bugs. Suggestions for improvement and bug report are welcome). Have fun. #include <SQLite.au3> ; -- Start the SQLite engine ------------------- Global Static $g__sSQliteDll = _SQLite_Startup(".\sqlite3.dll", False, True) Global Static $hDb = _SQLite_Open() ; by default will open a memory database. ; ---------------------------------------------- ; by default only Saturday and Sunday are considered non-working, ; but you can pass a string with the numbers corresponding to the days of the week ; to be considered non-working according to this scheme: ; (0=Sunday, 1=Monday, 2=Tuesday, 3=Wednesday, 4 =Thursday, 5=Friday, 6=Saturday) ; for example, to consider Thursday, Saturday and Sunday as non-working, ; pass the following string as the third parameter to the _WorkDay() function: "4,6,0" ; MsgBox(64, 'example', "in four working days from today it will be the " & _WorkDay(@YEAR & "-" & @MON & "-" & @MDAY, 4)) MsgBox(64, 'example', "nine working days ago was the " & _WorkDay(@YEAR & "-" & @MON & "-" & @MDAY, -9)) _SQLite_Shutdown() Func _WorkDay($StartDate, $iDays = 0, $sHolidays = "0,6") ; $sHolidays: (0=Sunday, 1=Monday, 2=Tuesday, 3=Wednesday, 4=Thursday, 5=Friday, 6=Saturday) If Not $iDays Then Return $StartDate Local Static $asOrder[] = ['DESC', 'ASC'] ; $iDirection: if negative, search backward, if positive, search forward Local $iDirection = ($iDays < 0 ? -1 : 1) ; we generate a week for each requested day, ; this in order to be able to manage even the worst case scenario, ; where only one day per week could be selected (only one working day per week). Local $iWeeks = Abs($iDays) + 1 ; weeks involved Local $iNumDays = (7 * $iWeeks) * $iDirection ; toal number of days to be generated Local $aMyRcordset, $iMyRows, $iMyColumns, $Date1, $Date2, $StartRange, $EndRange ; shift StartDate by +/- 1 day (exclude starting day from the search) _SQLite_GetTable(-1, "SELECT date('" & $StartDate & "','" & $iDirection & " day');", $aMyRcordset, $iMyRows, $iMyColumns) $Date1 = $aMyRcordset[2] ; fetch the data from the array resulting from the previous query ; Generate EndDate (add $iNumDays to start date) _SQLite_GetTable(-1, "SELECT date('" & $Date1 & "','" & $iNumDays & " days');", $aMyRcordset, $iMyRows, $iMyColumns) $Date2 = $aMyRcordset[2] ; fetch the data from the array resulting from the previous query ; adjust Start / End date according to direction If $iDirection < 0 Then $StartRange = $Date2 $EndRange = $Date1 Else $StartRange = $Date1 $EndRange = $Date2 EndIf ; https://www.geekytidbits.com/date-range-table-sqlite/ ; a bit intricate (messed up) query (but maybe it can be simplified) Local $Query = "WITH RECURSIVE " & _ "cnt(x) AS ( " & _ "SELECT julianday('" & $StartRange & "') " & _ "UNION ALL " & _ "SELECT x+1 FROM cnt " & _ "LIMIT ((julianday('" & $EndRange & "') - julianday('" & $StartRange & "'))+1)) " & _ "SELECT date(x) as date FROM cnt where strftime('%w', date) NOT IN (" & _ "WITH RECURSIVE split(value, str) AS ( " & _ "SELECT null, '" & $sHolidays & "' || ',' " & _ ; list of non-working days of the week "UNION ALL " & _ "SELECT " & _ "substr(str, 0, instr(str, ',')), substr(str, instr(str, ',')+1) " & _ "FROM split WHERE str!='') SELECT value FROM split WHERE value IS NOT NULL) " & _ " ORDER BY date " & $asOrder[$iDirection = 1] & ";" _SQLite_GetTable(-1, $Query, $aMyRcordset, $iMyRows, $iMyColumns) ; execute above query ; _ArrayDisplay($aMyRcordset) Return $aMyRcordset[Abs($iDays) + 1] ; return the target date EndFunc ;==>_WorkDay1 point
-
Using DllCallAddress() is even faster, but as the team said, it's only worth to optimize when you've got a lot of calls, normally the bottlenecks are somewhere else. I analyzed how many calls are made in SMF and switched to DllCallAddress() for some calls of which literally million of calls where made in huge and complex searches. Overall gain I would say is max 5 to 10% in speed, now the hardware itself seems to be the bottleneck and slowest part in searching for files. #include <WinAPISys.au3> $iTimer = TimerInit() For $i = 1 To 1000000 _WinAPI_GetTickCount64() Next ConsoleWrite(_WinAPI_GetTickCount64() & @CRLF) ConsoleWrite(TimerDiff($iTimer) & @CRLF & @CRLF) $iTimer = TimerInit() For $i = 1 To 1000000 DllCall('kernel32.dll', 'uint64', 'GetTickCount64') Next ConsoleWrite(DllCall('kernel32.dll', 'uint64', 'GetTickCount64')[0] & @CRLF) ConsoleWrite(TimerDiff($iTimer) & @CRLF & @CRLF) $iTimer = TimerInit() $dll = DllOpen("kernel32.dll") For $i = 1 To 1000000 DllCall($dll, 'uint64', 'GetTickCount64') Next ConsoleWrite(DllCall($dll, 'uint64', 'GetTickCount64')[0] & @CRLF) DllClose($dll) ConsoleWrite(TimerDiff($iTimer) & @CRLF & @CRLF) $iTimer = TimerInit() Global $hInstance_Kernel32_dll = _WinAPI_GetModuleHandle("kernel32.dll") Global $hAddress_Kernel32_dll_GetTickCount64 = _WinAPI_GetProcAddress($hInstance_Kernel32_dll, "GetTickCount64") For $i = 1 To 1000000 DllCallAddress('uint64', $hAddress_Kernel32_dll_GetTickCount64) Next ConsoleWrite(DllCallAddress('uint64', $hAddress_Kernel32_dll_GetTickCount64)[0] & @CRLF) ConsoleWrite(TimerDiff($iTimer) & @CRLF & @CRLF)1 point
-
DllClose() is still a good idea? - (Moved)
genius257 reacted to mistersquirrle for a topic
Maybe not really needed anymore on Windows 10/11 and/or current version of AutoIt. I see it there as a "good practice" for managing your resources if you ever write in other languages where it matters more. So it's not "useless and superfluous", and it might be useful for people still using older versions of Windows that maybe don't handle it as well. As Nine said, you're saving microseconds, but there is a small gain in opening the DLL yourself, around 9-10%. Unless you're making literally millions of calls though, it's not going to make much of a difference. Here's a test I did for 1,000,000 runs with kernel32 calling GetTickCount64: +———————————————+—————————————————+———————————————+——————————————+—————————————+ | Function Name | Time Taken (ms) | Avg Time (ms) | Std Dev (ms) | Faster By % | +———————————————+—————————————————+———————————————+——————————————+—————————————+ | DllCall | 8179.74 | 0.0082 | 0.0056 | 0.00 | +| DllCall(Open) | 7444.30 | 0.0074 | 0.0032 | 8.99 | +———————————————+—————————————————+———————————————+——————————————+—————————————+ | Total time | 15624.03 | | | | +———————————————+—————————————————+———————————————+——————————————+—————————————+ So, is it worth doing? Yeah, why not? Is it necessary if you open a DLL to close it? Nah, AutoIt and/or Windows will manage that pretty well for you. Is not doing it hurting you? Nah.1 point -
Setup PERMANENT Font For RichEdit Control
pixelsearch reacted to Nine for a topic
You could wrap a function around like this : #include <GUIConstantsEx.au3> #include <GuiRichEdit.au3> #include <WindowsConstants.au3> #include <WinAPIGdi.au3> #include <FontConstants.au3> Example() Func Example() Local $hGui, $hRichEdit, $iMsg $hGui = GUICreate("Example (" & StringTrimRight(@ScriptName, StringLen(".exe")) & ")", 320, 350, -1, -1) $hRichEdit = _GUICtrlRichEdit_CreateEx($hGui, "This is a test.", 10, 10, 300, 220, _ BitOR($ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL)) _GUICtrlRichEdit_AppendText($hRichEdit, @CRLF & "This is more text") GUISetState(@SW_SHOW) While True $iMsg = GUIGetMsg() Select Case $iMsg = $GUI_EVENT_CLOSE _GUICtrlRichEdit_Destroy($hRichEdit) ; needed unless script crashes ; GUIDelete() ; is OK too Exit EndSelect WEnd EndFunc ;==>Example Func _GUICtrlRichEdit_CreateEx($hWnd, $sText, $iLeft, $iTop, $iWidth = 150, $iHeight = 150, $iStyle = -1, $iExStyle = -1) Local $hCtrl = _GUICtrlRichEdit_Create($hWnd, $sText, $iLeft, $iTop, $iWidth, $iHeight, $iStyle, $iExStyle) If @error Then Return SetError(@error) Local $hFont = _WinAPI_CreateFont(20, 0, 0, 0, 600, False, False, False, $DEFAULT_CHARSET, _ $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $DEFAULT_QUALITY, 0, 'Arial') _SendMessage($hCtrl, $WM_SETFONT, $hFont, True) _WinAPI_DeleteObject($hFont) Return $hCtrl EndFunc Where you would have the definition of the font standardized...1 point