ProcessGetPath catching exception consumes too much time Topic is solved

Report problems with documented functionality
User avatar
Tebayaki
Posts: 7
Joined: 04 Aug 2021, 17:59

ProcessGetPath catching exception consumes too much time

19 Aug 2023, 06:48

I wrote a function to get the file paths of all running processes, however some processes throw exceptions due to insufficient privileges.
That's normal, but when I tried to catch these exceptions, I found that it taked too much time.

Code: Select all

pid := ProcessExist("winlogon.exe")
DllCall("QueryPerformanceFrequency", "Int64*", &freq := 0)
DllCall("QueryPerformanceCounter", "Int64*", &CounterBefore := 0)
loop 100
    try
        ProcessGetPath(pid)
DllCall("QueryPerformanceCounter", "Int64*", &CounterAfter := 0)
MsgBox "Elapsed QPC time is " . (CounterAfter - CounterBefore) / freq * 1000 " ms"
It takes 732ms on my pc, I don't think it is normal. Can this be optimized?
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: ProcessGetPath catching exception consumes too much time

20 Aug 2023, 23:45

Tebayaki wrote:
19 Aug 2023, 06:48
It takes 732ms on my pc
 
Consumes about 363ms on my pc
 
Tebayaki wrote:
19 Aug 2023, 06:48
Can this be optimized?
 
I can't understand why your code is slow, but a work around based on AutoHotkey source code
consumes < 0.3ms for a insufficient privilege process... And it is < 3.0ms for a proper one.
 

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance

pid := ProcessExist("winlogon.exe")
DllCall("QueryPerformanceFrequency", "Int64*", &freq := 0)
DllCall("QueryPerformanceCounter", "Int64*", &CounterBefore := 0)
loop 100
    try
        ProcessGetPath2(pid)
DllCall("QueryPerformanceCounter", "Int64*", &CounterAfter := 0)
MsgBox "Elapsed QPC time is " . (CounterAfter - CounterBefore) / freq * 1000 " ms"


ProcessGetPath2(pid)
{
    Local hProcess  ;  PROCESS_QUERY_LIMITED_INFORMATION := 0x1000 ; 4096

    If ( hProcess := DllCall("Kernel32\OpenProcess", "uint",0x1000, "uint",0, "uint",pid, "ptr") ) = 0
         Return
    Else DllCall("Kernel32\CloseHandle", "ptr",hProcess)

    Return ProcessGetPath(pid)
}
lexikos
Posts: 9592
Joined: 30 Sep 2013, 04:07
Contact:

Re: ProcessGetPath catching exception consumes too much time

21 Aug 2023, 02:57

This is just the normal cost of ProcessExist, nothing to do with exception handling. ProcessGetPath allows a process name and therefore relies on ProcessExist to identify the process, before attempting to retrieve the path.

ProcessExist enumerates all processes to find a match. When you pass a PID, it does this to verify that the PID is valid. On v1, this is the only method Process Exist uses, and it is always this slow. v2 has been optimized to directly open the process and verify that it is still running, but it cannot do this if it doesn't have permission to open the process, so it falls back to the older method.

When ProcessExist(pid) fails with ERROR_ACCESS_DENIED, it cannot assume that the PID is valid because:
// OpenProcess can succeed for erroneous PID values; e.g. values of 1501 to 1503 can
// open the process with ID 1500. This is likely due to the undocumented fact that
// PIDs are a multiple of four: https://devblogs.microsoft.com/oldnewthing/20080228-00/?p=23283
...
// OpenProcess can succeed for a process which has already exited if another process
// still has an open handle to it. So check whether it's still running:
In other words, ERROR_ACCESS_DENIED could also be returned for an invalid PID, or in a case where the process has a handle open, but the process itself has exited.

So when ProcessExist fails to open the process, it falls back to the old method of enumerating all processes. Another reason for falling back to enumeration when you give it a number is that process names can consist solely of digits, although ProcessExist might not be able to tell you the PID of such a process if its name coincides with a valid PID.

ProcessGetPath could skip the enumeration when given a PID, but in that case it could give an "access denied" error when you've really passed an invalid PID.
lexikos
Posts: 9592
Joined: 30 Sep 2013, 04:07
Contact:

Re: ProcessGetPath catching exception consumes too much time  Topic is solved

30 Aug 2023, 03:23

v2.0.6 optimizes ProcessGetPath, ProcessSetPriority and ProcessClose to avoid enumerating processes when given a valid PID. If the PID is not a multiple of 4, a full enumeration of processes is still performed to confirm that it is invalid.

Return to “Bug Reports”

Who is online

Users browsing this forum: No registered users and 72 guests