Leaderboard
Popular Content
Showing content with the highest reputation on 05/22/2023 in all areas
-
1 point
-
In case you are curious how to do that in regex: This is one should work: #include <StringConstants.au3> test("(000.96*A)") test("(001.96*A)") test("(012.96*A)") test("(005*A)") Func test($input) Local $array = StringRegExp($input, "\(0*((?:\d+\.\d+)?\d+)\*", $STR_REGEXPARRAYGLOBALMATCH, 1) ConsoleWrite($array[0] & @CRLF) EndFunc ;==>test Jos1 point
-
For what it's worth, I tend to agree with @AndyG. Identifying and fixing the root cause of an issue is almost always better than time spent patching or working around the issue. If you fix (or at least mitigate) the issue, then you hopefully don't have to waste time dealing with it again and again or risk it causing additional problems. I have found WMI much more reliable in getting process info than some of the WinAPI UDF's that use Win32 API's. I haven't dug into why, but when using the WinAPI UDF's, WMI returns some information that the WinAPI UDF's do not. Here's a quick script that displays selected process info (including CPU time) for all running processes: #AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d #include <Constants.au3> #include <WinAPILocale.au3> #include <Array.au3> list_process_info() ;========================================================================== Func list_process_info() ;========================================================================== Enum $PROCESS_PID, $PROCESS_NAME, $PROCESS_EXE_PATH, $PROCESS_CPU_TIME, $PROCESS_COLS Local $aProcesses[0][$PROCESS_COLS] Local $oComError = ObjEvent("AutoIt.Error", "com_error_handler"), _ $oProcesses = "" Local $sTotalCpuTime = "" With ObjGet("winmgmts:") ;Get list of currently running processes $oProcesses = .ExecQuery("SELECT Handle, Name, ExecutablePath, KernelModeTime, UserModeTime FROM Win32_Process") ;If no processes found, then return with message If $oProcesses.Count = 0 Then Return MsgBox($MB_ICONWARNING, "Warning", "No processes found.") If @error Then Return MsgBox($MB_ICONERROR, "WMI ExecQuery Error", $oComError.Description) ;For each process For $oProcess in $oProcesses With $oProcess ;Calculate total cpu time duration and convert to hh:mm:ss $sTotalCpuTime = _WinAPI_GetDurationFormat($LOCALE_USER_DEFAULT, .KernelModeTime + .UserModeTime, "hh:mm:ss") ;Add process info to the array _ArrayAdd($aProcesses, .Handle & "|" & .Name & "|" & .ExecutablePath & "|" & $sTotalCpuTime) EndWith Next EndWith ;Display process info _ArraySort($aProcesses, 1, 0, 0, $PROCESS_CPU_TIME) ;Sort by cpu time in descending order _ArrayDisplay($aProcesses, "List of processes", "", 0, Default, "PID|NAME|PATH|CPU TIME") EndFunc ;========================================================================== Func com_error_handler($oError) ;========================================================================== #forceref $oError Return ; Return so @error can be trapped by the calling function EndFunc Resulting array:1 point
-
Hi! Nice example of the XY-Problem! What the Problem is: What the User think the Problem is: No, you are lying to yourself! The MAIN problem is that the app is crashing....you need to fix THIS! You don't have to solve problems, you have to eliminate problems!1 point
-
Find out CPU (used) Time of processes.
Jemboy reacted to mistersquirrle for a topic
Well I thought that it wasn't too hard, however it appears that on my system the normal function of _WinAPI_GetProcessTimes doesn't cut it. I needed to open the process myself (likely with debug enabled) to reliably get CPU time information. Check out this script: ;~ #RequireAdmin ;~ #AutoIt3Wrapper_UseX64=y #include <WinAPI.au3> #include <ProcessConstants.au3> Global $iNanoSecondsToMilliSeconds = 10000 Global $sProcessName = 'explorer.exe' Global $iProcessId = ProcessExists($sProcessName) If $iProcessId = 0 Or @error Then ConsoleWrite('Process does not exist, or error: ' & @error & @CRLF) Exit EndIf ;~ Global $aProcessTimes = _WinAPI_GetProcessTimes() Global $ghProcess = _WinAPI_OpenProcess($PROCESS_QUERY_LIMITED_INFORMATION, 0, $iProcessId, True) Global $aProcessTimes = __WinAPI_GetProcessTimes($ghProcess) If @error Then ConsoleWrite('Unable to get process times: ' & @error & ', ' & _WinAPI_GetLastError() & ', Msg: ' & _WinAPI_GetLastErrorMessage() & @CRLF) Exit EndIf ;~ For $i = 0 To UBound($aProcessTimes) - 1 ;~ ConsoleWrite('Index: ' & $i & ', type: ' & VarGetType($aProcessTimes[$i]) & ', string data: ' & String($aProcessTimes[$i]) & ', int data: ' & Int($aProcessTimes[$i]) & @CRLF) ;~ Next ConsoleWrite('Process ID: ' & $iProcessId & ', name: ' & $sProcessName & ' times: ' & @CRLF) ConsoleWrite(@TAB & 'Kernel mode: ' & __MillisecondToTimestamp(($aProcessTimes[1] / $iNanoSecondsToMilliSeconds)) & ' (' & $aProcessTimes[1] & ')' & @CRLF) ConsoleWrite(@TAB & ' User mode: ' & __MillisecondToTimestamp(($aProcessTimes[2] / $iNanoSecondsToMilliSeconds)) & ' (' & $aProcessTimes[2] & ')' & @CRLF) ConsoleWrite(@TAB & ' Total: ' & __MillisecondToTimestamp((($aProcessTimes[1] + $aProcessTimes[2]) / $iNanoSecondsToMilliSeconds)) & @CRLF) Exit Func __MillisecondToTimestamp($iMs, $bSeconds = False, $bColonSeparator = True) Local $sTimestamp If $bSeconds Then $iMs *= 1000 $iMs = Int($iMs, 0) ; Auto Int ; Convert the milliseconds to days, hours, minutes, and seconds $iDays = (($iMs >= 86400000) ? Int($iMs / 86400000) : 0) $iHours = Int(Mod($iMs, 86400000) / 3600000) $iMinutes = Int(Mod($iMs, 3600000) / 60000) $iSeconds = Int(Mod($iMs, 60000) / 1000) ; Format the timestamp as [DD ]hh:mm:ss.zzz ; Not using StringFormat here because it's considerably slower when you do it 10K+ times, so probably doesn't matter at all for this $sTimestamp = _ ($iDays > 0 ? String($iDays) & (($bColonSeparator) ? ' ' : 'd') : '') & _ StringRight('0' & String($iHours), 2) & (($bColonSeparator) ? ':' : 'h') & _ StringRight('0' & String($iMinutes), 2) & (($bColonSeparator) ? ':' : 'm') & _ StringRight('0' & String($iSeconds), 2) & _ ((Not $bSeconds) ? _ (($bColonSeparator) ? '.' : 's') & StringRight('00' & String($iMs), 3) & (($bColonSeparator) ? '' : 'ms') : _ (($bColonSeparator) ? '' : 's')) Return $sTimestamp EndFunc ;==>__MillisecondToTimestamp Func __WinAPI_GetProcessTimes($hProcess) ;~ If Not $iPID Then $iPID = @AutoItPID ;~ Local $hProcess = DllCall('kernel32.dll', 'handle', 'OpenProcess', 'dword', ((_WinAPI_GetVersion() < 6.0) ? 0x00000400 : 0x00001000), _ ;~ 'bool', 0, 'dword', $iPID) ;~ If @error Or Not $hProcess[0] Then Return SetError(@error + 20, @extended, 0) Local $tFILETIME = DllStructCreate($tagFILETIME) Local $aCall = DllCall('kernel32.dll', 'bool', 'GetProcessTimes', 'handle', $hProcess, 'struct*', $tFILETIME, 'uint64*', 0, _ 'uint64*', 0, 'uint64*', 0) If __CheckErrorCloseHandle($aCall, $hProcess) Then Return SetError(@error, @extended, 0) Local $aRet[3] $aRet[0] = $tFILETIME $aRet[1] = $aCall[4] $aRet[2] = $aCall[5] Return $aRet EndFunc ;==>__WinAPI_GetProcessTimes It did require a bit of tweaking, as since I mentioned using the default UDF function wasn't working on my system, with or without running as admin. Here's the output for explorer.exe: Process ID: 29536, name: explorer.exe times: Kernel mode: 01:10:35.937 (42359375000) User mode: 00:17:03.328 (10233281250) Total: 01:27:39.265 Sidenote, I am planning on releasing a UDF that makes getting some process information like CPU time very easy and fast. I'm not sure when I'm going to post it, but keep an eye out if interested.1 point -
Find out CPU (used) Time of processes.
Jemboy reacted to argumentum for a topic
tasklist /v /fo csv >tasklist2.csv1 point -
He also provide Bans.1 point
-
Txt split to ini file
Zedna reacted to pixelsearch for a topic
@ioa747 I tried to improve the processing time of the script, in case there are plenty of users (100, 500 you name it) and a big datalar.txt file, like the one provided by mucitbey last year, which had 6.535 lines and generated 75 ini files (from 30/05/2022 to 12/08/2022 included) In my precedent script (and probably yours) I found the 2 instructions that slowed the damn thing : * IniWrite is slow, when there are plenty of sections, probably because the file is opened and closed for each Iniwrite, idk. * _ArraySearch is slow too (e.g GetUserIndex) Retrieving constantly a user name (while providing his ID) is slow when we have to loop through all rows of an array, again and again. _ArrayBinarySearch would certainly retrieve the name faster So, this is what I did to get super quick results, even on thousands of lines in Datalar.txt * No more IniWrite, but FileWriteLine, as you will notice in the script below. * Scripting.Dictionary object (instead of _ArraySearch) which retrieves a username at the speed of light. Also, Scripting.Dictionary can be used for other interesting purposes (like $oData in the script) Here are some notes concerning the 2 major arrays and 2 dictionaries objects found in the script below : $aUser[ ][4] ============ $aUser[ ][0] = User ID (unique) $aUser[ ][1] = User Name (unique, as Name is also, unfortunately, a unique section in daily .ini files) $aUser[ ][2] = Time1 (if empty, then user was absent this day, this will be useful to add absents in LV) $aUser[ ][3] = Time2 (if filled, then Time1 is already filled, e.g user ID found twice in $adata for same day) $oUser() ======== Key = User ID (unique) . Same number of Keys as $aUser number of rows Item = Index of this User in $aUser, it will allow an immediate search in $aUser, instead of slow _ArraySearch $aData[ ][5] ============ $aData[ ][0] = unused $aData[ ][1] = User ID (not unique, usually same ID found twice each day) $aData[ ][2] = unused $aData[ ][3] = Date (same date on contiguous rows, processed day by day) $aData[ ][4] = Time1 OR Time2 (this column is already sorted for same day) $oData() ======== Key = User ID (unique). Used when day changes, to add at once in LV all daily workers, sorted by day & time. Item = Index of this User in $aUser, it will allow an immediate search in $aUser, instead of slow _ArraySearch #include <File.au3> #include <MsgBoxConstants.au3> #include <SendMessage.au3> Opt("MustDeclareVars", 1) Global $g_iLinesUser, $g_idListview Main() Func Main() Local $aUser, $aUserBackup, $oUser, $aData, $oData Local $WM_SETREDRAW = 0x000B, $LVM_GETITEMCOUNT = 0X1004, $GUI_EVENT_CLOSE = -3 _FileReadToArray(@ScriptDir & "\" & "Users.txt", $aUser, $FRTA_NOCOUNT, "=") ; 2D array If @error Then Exit MsgBox($MB_TOPMOST, "_FileReadToArray error = " & @error, "Users.txt") $g_iLinesUser = UBound($aUser) ReDim $aUser[$g_iLinesUser][4] ; add 2 empty columns at the right (to update time1 and time2 per user for 1 working day) $aUserBackup = $aUser ; keep a copy with last 2 empty columns for all users. Reuse this backup when date changes. $oUser = ObjCreate("Scripting.Dictionary") Fill_oUser($aUser, $oUser) _FileReadToArray(@ScriptDir & "\" & "Datalar.txt", $aData, $FRTA_NOCOUNT) ; 1D array If @error Then Exit MsgBox($MB_TOPMOST, "_FileReadToArray error = " & @error, "Datalar.txt") $oData = ObjCreate("Scripting.Dictionary") Local $hGUI = GUICreate("", 470, 500, -1, -1) ; title later, to include number of rows in it $g_idListview = GUICtrlCreateListView("CART ID | DATE|TIME-1 |TIME-2 |NAME AND SURNAME ", 10, 10, 450, 480) Local $hListview = GUICtrlGetHandle($g_idListview) _SendMessage($hListview, $WM_SETREDRAW, False) ; _GUICtrlListView_BeginUpdate . False = don't redraw after a change Local $sDate = "", $aTemp, $iEmptyRows, $UserIndex For $li = 0 To UBound($aData) - 1 $aTemp = StringSplit(StringStripWS($aData[$li], 1+2), ", ", $STR_NOCOUNT) ; strip leading (1) and trailing (2) eventual white space If @error Then ContinueLoop ; eliminate accidental blank lines. Help file StringSplit: "@error = 1 when no delimiters were found" If StringLen($aTemp[3]) < 10 Then $aTemp[3] = "0" & $aTemp[3] ; days "1" to "9" will become "01" to "09" everywhere in the script. If $sDate <> $aTemp[3] Then ; $sDate is the old date, $aTemp[3] is the new date. If $sDate Then ; always False when $li = 0 (first data line processed) ; Update LV : add all working users for 1 day, then add all absents for 1 day . Prepare ini file for 1 day (all users) DayChange($sDate, $aUser, $oData) ; Reuse $aUserBackup (before processing a new date) $aUser = $aUserBackup ; reuse backup, e.g. blank columns 2 & 3 in $aUser, for all users, when date changes. $g_iLinesUser = UBound($aUser) ; as it may have increased in Func GetUserIndex (if an eventual ID wasn't found in $aUser) ; If undefined ID's had been added to $oUser, then re-generate $oUser (this shouldn't happen, according to mucitbey) If $oUser.Count <> $g_iLinesUser Then $oUser.RemoveAll() Fill_oUser($aUser, $oUser) EndIf ; remove all keys in $oData (before processing a new date) $oData.RemoveAll() ; add 1 empty line between each day processed in LV (sort of vertical separator) GUICtrlCreateListViewItem("", $g_idListview) $iEmptyRows += 1 ; don't count this line in the total number of lines in LV (displayed later in GUI title) EndIf $sDate = $aTemp[3] ; old date = new date EndIf $UserIndex = GetUserIndex($aTemp[1], $aUser, $oUser) ; user index (row) in $aUser If Not $oData.Exists($aTemp[1]) Then ; 1st entry for this ID (will update column Time1 in $aUser) $aUser[$UserIndex][2] = $aTemp[4] ; time1 $oData.Add($aTemp[1], $UserIndex) ; key = User ID, item = User index in $aUser Else ; 2nd entry for this ID (it will update column Time2 in $aUser) $aUser[$UserIndex][3] = $aTemp[4] ; time2 EndIf Next If $sDate Then DayChange($sDate, $aUser, $oData) _SendMessage($hListview, $WM_SETREDRAW, True) ; _GUICtrlListView_EndUpdate . True = redraw after a change Local $iNbRows = GUICtrlSendMsg($g_idListview, $LVM_GETITEMCOUNT, 0, 0) WinSetTitle($hGUI, "", "_ank_ File Splitting (" & ($iNbRows - $iEmptyRows) & " rows)") GUISetState(@SW_SHOW, $hGUI) Do Until GUIGetMsg() = $GUI_EVENT_CLOSE ; Cleaning (not really necessary but ok) $oUser = 0 ; force Object deletion (AutoIt help file, topic "Obj/COM Reference") $oData = 0 ; ditto GUIDelete($hGUI) EndFunc ;==>Main ;================================================ Func GetUserIndex($ID, ByRef $aUser, ByRef $oUser) If $oUser.Exists($ID) Then Local $iIndex = $oUser.Item($ID) ; $iIndex in $aUser of regular ID Else ; this should never happen (mucitbey) but better prevent it, just in case... Local $iIndex = $g_iLinesUser ; $iIndex in $aUser of Undefined ID ; add the Undefined ID in $aUser $g_iLinesUser += 1 ReDim $aUser[$g_iLinesUser][4] ; not really fast but as it should never happen... $aUser[$iIndex][0] = $ID $aUser[$iIndex][1] = "Undefined ID " & $ID ; this creates a unique "name" (+++) ; add the Undefined ID in $oUser $oUser.Add($ID, $iIndex) ; key = User Undefined ID, item = User index in $aUser EndIf Return $iIndex ; 0+ EndFunc ;==>GetUserIndex ;================================================ Func DayChange($sDate, ByRef $aUser, ByRef $oData) ; Update LV : add all working users for 1 day ; Color eventually background of LV rows Local $aPresent = $oData.Keys(), $iIndex For $i = 0 To Ubound($aPresent) - 1 $iIndex = $oData.Item($aPresent[$i]) ; $iIndex in $aUser of an ID GUICtrlCreateListViewItem($aUser[$iIndex][0] &"|"& $sDate &"|"& _ $aUser[$iIndex][2] &"|"& $aUser[$iIndex][3] &"|"& $aUser[$iIndex][1], $g_idListview) ; color eventually background of this LV row If StringLeft($aUser[$iIndex][1], 12) = "Undefined ID" Then GUICtrlSetBkColor(-1, 0xFF0000) ; red ElseIf ($aUser[$iIndex][2] > "08:10:00" And $aUser[$iIndex][2] < "17:00:00") _ OR ($aUser[$iIndex][3] > "08:10:00" And $aUser[$iIndex][3] < "17:00:00") Then GUICtrlSetBkColor(-1, 0xC0FFFF) ; light blue EndIf Next ; Prepare .ini file for 1 day (all users) ; Update LV : add all absents for 1 day Local $sIniFile = @ScriptDir & "\" & $sDate & ".ini" Local $hIni = FileOpen($sIniFile, $FO_OVERWRITE + $FO_UNICODE) ; more reliable than $FO_ANSI If $hIni = -1 Then Exit MsgBox($MB_TOPMOST, "FileOpen error", $sIniFile) For $i = 0 To $g_iLinesUser - 1 FileWriteLine($hIni, _ "[" & $aUser[$i][1] & "]" & @crlf & _ ; ini section = [User Name] "Value01=" & $aUser[$i][0] & @crlf & _ ; User ID "Value02=" & $sDate & @crlf & _ ; Date "Value03=" & $aUser[$i][2] & @crlf & _ ; Time1 "Value04=" & $aUser[$i][3] & @crlf) ; Time2 If Not $aUser[$i][2] Then ; user was absent that day (as he got no time1) ; add 1 line in ListView for the absent user (with blank time1 & time2) GUICtrlCreateListViewItem($aUser[$i][0] &"|"& $sDate &"|"& "" &"|"& "" &"|"& $aUser[$i][1], $g_idListview) EndIf Next FileClose($hIni) EndFunc ;==>DayChange ;================================================ Func Fill_oUser(ByRef $aUser, ByRef $oUser) For $i = 0 To $g_iLinesUser - 1 $oUser.Add($aUser[$i][0], $i) ; key = User ID, item = User index in $aUser (immediate retrieve of a user in $aUser, instead of slow _ArraySearch) Next EndFunc ;==>Fill_oUser My only regret ? I wish I used the Scripting.Dictionary Object a long time ago, it's damn quick and easy to use1 point