2

I have written a module that gets list of running processes every 250ms for Windows XP and Above. I have tried .Net & WMI way, both of them are very CPU intensive. Both of them do finish within 80ms on my machine. My host process CPU remains above 10 to 14 percentage in either case. I think the Location/ExecutionPath property is the real culprit. Is there a better way to get this information?

Edit1: In my testing - .Net way was more CPU intensive but slightly faster then WMI way. - WMI way was slower but less CPU intensive since it moved the CPU usage to WMI Provider Host

    private static int WMIWay()
    {
        string wmiQueryString = "SELECT ProcessId, ExecutablePath FROM Win32_Process";
        using (var searcher = new ManagementObjectSearcher(wmiQueryString))
        {
            using (var results = searcher.Get())
            {
                foreach (ManagementObject oReturn in results)
                {
                    if (oReturn["ExecutablePath"] != null)
                    {
                        _Processes.Add(new ProcessInfo()
                        {
                            ProcessID = (uint)oReturn["ProcessId"],
                            FilePath = oReturn["ExecutablePath"].ToString(),
                        });

                    }

                }

                return results.Count;
            }
        }


    }

    private static int NetWay()
    {
        var processes = System.Diagnostics.Process.GetProcesses();
        foreach (System.Diagnostics.Process runningProcess in processes)
        {

            if (runningProcess.Id > 4)
            {

                try
                {
                    _Processes.Add(new ProcessInfo()
                    {
                        ProcessID = (uint)runningProcess.Id,
                        FilePath = runningProcess.MainModule.FileName,
                    });

                }
                catch { }
            }
        }

        return processes.Length;
    }
02Anant
  • 328
  • 1
  • 5
  • 13
  • When you compared the performance of these two ways, which was faster and used less CPU? – Peter Ritchie Mar 24 '14 at 19:14
  • 2
    What are you doing that you need to poll the list of processes ever 250ms? Do you have to poll or would a event driven method that got notified any time a processes started or stopped work too? – Scott Chamberlain Mar 24 '14 at 19:20
  • The module is used to monitor Process Started/Ended and Hung state. For polling I am using System.Timers.Timer. I have looked into WMI Event driven method but that would require a substantial architectural change. – 02Anant Mar 24 '14 at 19:35
  • possible duplicate of [.NET Process Monitor](http://stackoverflow.com/questions/1986249/net-process-monitor) – Hans Passant Apr 17 '14 at 22:13

1 Answers1

2

Finally I decided to go the PInvoke route. In my testing this turn out to be the best solution. It did reduce CPU usage to 2 percentage and was also faster than .Net or WMI way.

    private static int PInvokeWay()
    {
        uint[] processIds = new uint[1024];
        uint bytesCopied;
        uint processCount = 0;
        if (ProcessApi.EnumProcesses(processIds, (uint)processIds.Length * sizeof(uint), out bytesCopied) || bytesCopied == 0)
        {
            processCount = bytesCopied / sizeof(int);

            for (int i = 0; i < processCount; i++)
            {
                string path;

                if (Environment.OSVersion.Version.Major >= 6)
                    path = GetExecutablePathAboveVista(processIds[i]);
                else
                    path = GetExecutablePathXP2003(processIds[i]);

                if (!string.IsNullOrWhiteSpace(path))
                {
                    _Processes.Add(new ProcessInfo()
                    {
                        ProcessID = processIds[i],
                        FilePath = path,
                    });
                }
            }
        }
        return (int)processCount;
    }

    private static string GetExecutablePathAboveVista(uint ProcessId)
    {            
        var buffer = new StringBuilder(1024);
        try
        {
            IntPtr hprocess = ProcessApi.OpenProcess(ProcessApi.PROCESS_QUERY_LIMITED_INFORMATION,
                                          false, ProcessId);
            if (hprocess != IntPtr.Zero)
            {
                try
                {
                    int size = buffer.Capacity;
                    if (ProcessApi.QueryFullProcessImageName(hprocess, 0, buffer, out size))
                    {
                        return buffer.ToString();
                    }
                }
                finally
                {
                    ProcessApi.CloseHandle(hprocess);
                }
            }
        }
        catch { }

        return string.Empty;
    }

    private static string GetExecutablePathXP2003(uint processId)
    {            
        var buffer = new StringBuilder(1024);

        try
        {
            IntPtr process = ProcessApi.OpenProcess(ProcessApi.PROCESS_QUERY_INFORMATION
                | ProcessApi.PROCESS_VM_READ, false, processId);

            if (process != IntPtr.Zero)
            {

                try
                {

                    if (ProcessApi.GetModuleFileNameExW(process, IntPtr.Zero, buffer, buffer.Capacity) != 0)
                    {
                        return buffer.ToString();
                    }
                }
                finally
                {
                    ProcessApi.CloseHandle(process);
                }

            }


        }
        catch { }

        return string.Empty;
    }
02Anant
  • 328
  • 1
  • 5
  • 13