ultramoo
ultramoo

Reputation: 33

Getting process instance name from a process id / object (Faster way)

Currently, the solution to get a Instance Name from a Process ID is from the code below. Problem is, this takes a lot of time and CPU resources!

That is to say when you have a system that's running at least 100 processes, it takes a considerable amount of time to cycle through the loops to find it. (like 1 to 2 seconds) And when I am looking to find up to 30 of those processes, it takes up to 30 seconds to find them all...

Can't you simply get a instance name from a process object?

private static string GetProcessInstanceName(int pid)
{
  PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");

  string[] instances = cat.GetInstanceNames();
  foreach (string instance in instances)
  {

     using (PerformanceCounter cnt = new PerformanceCounter("Process",  
          "ID Process", instance, true))
     {
        int val = (int) cnt.RawValue;
        if (val == pid)
        {
           return instance;
        }
     }
  }
  throw new Exception("Could not find performance counter " + 
      "instance name for current process. This is truly strange ...");
}

Upvotes: 3

Views: 5299

Answers (4)

mheyman
mheyman

Reputation: 4325

The FranzHuber23 Solution sped the original by only looking at processes that start with the process-in-question's name. An improvement beyond that uses PLINQ (parallel LINQ). Optionally, Parallel.ForEach() or a construct that uses Task could provide a similar speedup but both those will have complicated source to return just the first found and cancel the concurrent searches (nicely hidden by ParallelEnumerable.FirstOrDefault()).

public static string PerformanceCounterInstanceName(this Process process)
{
    var matchesProcessId = new Func<string, bool>(instanceName =>
    {
        using (var pc = new PerformanceCounter("Process", "ID Process", instanceName, true))
        {
            if ((int)pc.RawValue == process.Id)
            {
                return true;
            }
        }

        return false;
    });

    string processName = Path.GetFileNameWithoutExtension(process.ProcessName);
    return new PerformanceCounterCategory("Process")
       .GetInstanceNames()
       .AsParallel()
       .FirstOrDefault(instanceName => instanceName.StartsWith(processName)
                                       && matchesProcessId(instanceName));
}

Upvotes: 2

FranzHuber23
FranzHuber23

Reputation: 4292

A very fast and well-working solution is this one:

public static string GetInstanceNameForProcessId(int processId)
    {
        var process = Process.GetProcessById(processId);
        string processName = Path.GetFileNameWithoutExtension(process.ProcessName);

        PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");
        string[] instances = cat.GetInstanceNames()
            .Where(inst => inst.StartsWith(processName))
            .ToArray();

        foreach (string instance in instances)
        {
            using (PerformanceCounter cnt = new PerformanceCounter("Process",
                "ID Process", instance, true))
            {
                int val = (int)cnt.RawValue;
                if (val == processId)
                {
                    return instance;
                }
            }
        }
        return null;
    }

from Rick Strahl. The only issue I had was the same as one in the commentaries on his blog:

One thing to mention related to windows process instance names is that they change dynamically when one of the processes exits.

For example if chrome#8 exits, chrome#9 will become chrome#8 and chrome#10

will become chrome#9. At this point getting the value of the counter previously created for chrome#10 will throw an exception. This is really annoying if you want to to monitor multiple instances of multiple processes as it gets down to monitoring process exits and recreating all the counters (really ugly).

One way would be to change the way process instance names are generated (see http://support.microsoft.com/kb/281884) but this has the potential of affecting other apps using the perfmon api.

Upvotes: 1

Josh Anderson
Josh Anderson

Reputation: 438

This should get you all of the current processes

var allProcesses = System.Diagnostics.Process.GetProcesses();

you can then iterate through the array to find the specific id's you are looking for

Upvotes: -1

Avi Turner
Avi Turner

Reputation: 10456

Why not use the System.Diagnostics.Process.GetProcessById function?

private static string GetProcessInstanceName(int pid)
{ 
    string name = String.Empty;
    Process proc = System.Diagnostics.Process.GetProcessById(pid);
    if(proc != null)
    {
        name = proc.ProcessName;
    }
    return name;
}

Upvotes: 1

Related Questions