15

I would like to display some memory statistics (working set, GCs etc.) on a web page using the .NET/Process performance counters. Unfortunately, if there are multiple application pools on that server, they are differentiated using an index (#1, #2 etc.) but I don't know how to match a process ID (which I have) to that #xx index. Is there a programmatic way (from an ASP.NET web page)?

granth
  • 8,919
  • 1
  • 43
  • 60
  • 1
    Here's a blog post that discusses this scenario in detail: http://weblog.west-wind.com/posts/2014/Sep/27/Capturing-Performance-Counter-Data-for-a-Process-by-Process-Id. Basically you need to use another Performance Counter to retrieve the 'instance names' and then run your process counters with that name. – Rick Strahl Sep 27 '14 at 21:13

5 Answers5

12
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 ...");
}
M4N
  • 94,805
  • 45
  • 217
  • 260
11

The first hit on Google:

Multiple CLR performance counters appear that have names that resemble "W3wp#1"

When multiple ASP.NET worker processes are running, Common Language Runtime (CLR) performance counters will have names that resemble "W3wp#1" or "W3sp#2"and so on. This was remedied in .NET Framework 2.0 to include a counter named Process ID in the .NET CLR Memory performance object. This counter displays the process ID for an instance. You can use this counter to determine the CLR performance counter that is associated with a process.

Also KB 281884:

By default, Performance Monitor (Perfmon.msc) displays multiple processes that have the same name by enumerating the processes in the following way:

Process#1 Process#2 Process#3

Performance Monitor can also display these processes by appending the process ID (PID) to the name in the following way:

Process_PID

1800 INFORMATION
  • 131,367
  • 29
  • 160
  • 239
  • 1
    Actually that's not right - looks like the naming is Process,Process#1,Process#2. THere's one in there with out the postfix. – Rick Strahl Sep 27 '14 at 21:12
2

Even though changing of registry settings look quite easy, unfortunately most of us dont have the rights to do it on the server (or we dont want to touch it!). In that case, there is a small workaround. I have blogged about this here.

MSV Muthu
  • 153
  • 1
  • 3
  • 8
1

The example by chiru does not work in a specific case - when you have two versions of the same program, named the same, and one is not .net and you start the .net version after the non-.net version. The .Net version will be named applicaion#1 but when you access the CLR perf counters using this name, the instance names on the counter has the name withouth the #1, so you get failures.

Nick.

0

I know it has been answered before, but just for the sake of complete working code I'm posting this solution. Please note this code based on the method submitted by M4N in this chain:

public static long GetProcessPrivateWorkingSet64Size(int process_id)
{
  long process_size = 0;
  Process process = Process.GetProcessById(process_id);
  if (process == null) return process_size;
  string instanceName = GetProcessInstanceName(process.Id);
  var counter = new PerformanceCounter("Process", "Working Set - Private", instanceName, true);
  process_size = Convert.ToInt32(counter.NextValue()) / 1024;
  return process_size;
}

public static string GetProcessInstanceName(int process_id)
{
  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 == process_id)
         return instance;
    }
  }
  throw new Exception("Could not find performance counter ");
}

Also, if you want to get the total memory of multiple instances of the same process use the above methods with the following one:

public static long GetPrivateWorkingSetForAllProcesses(string ProcessName)
{
  long totalMem = 0;
  Process[] process = Process.GetProcessesByName(ProcessName);
  foreach (Process proc in process)
  {
    long memsize = GetProcessPrivateWorkingSet64Size(proc.Id);
    totalMem += memsize;
  }
  return totalMem;
}