Taking a Snapshot of Computer Performance

Today I was asked a question about building a tool to launch end users whenever they encounter "performance issues". This is due to the increasing number of reports from multiple computers and / or applications experiencing extreme performance issues. Due to the large number of reports, we need this data collection to happen automatically, so we can calculate the data in detail later.

I've created a backend to collect information and am already collecting a bunch of information, but I'm having a hard time collecting data on process performance. Here's what I considered:

1) Using System.Diagnotics.Process.GetProcesses ():

This gives me a list of all running processes, which is good, but it requires the application to be able to run with increased visibility as it throws exceptions when I want to collect UserProcessorTime even though this information is available for each -admin for its own processes in the manager tasks. It also throws exceptions even when run as a full admin user.

2) Using PerformanceCounter

The performance counters seem to be quite powerful, but I have not been able to map the performance counter to the process ID and it seems that performance counters are mainly used to track performance over a period of time. This is not true. We are mainly looking for a pattern of processes coming from haywire.

Basically, what we are looking for (more or less) is a quick snapshot of the information displayed in the task manager process list (process name, cpu cycles, private memory usage) and without the need to apply to run an elevated level (the process list could be limited to custom procedures). This is in line with what I was asked.

EDIT: Here is what code I tried to use, sorry for missing earlier

Here's an example that tries to use performance counters to get "% cpu time" and "working set - private" for all processes.

PerformanceCounterCategory perfCategory = PerformanceCounterCategory.GetCategories().First(c => c.CategoryName == "Process");
Console.WriteLine("{0} [{1}]", perfCategory.CategoryName, perfCategory.CategoryType);
string[] instanceNames = perfCategory.GetInstanceNames();

if (instanceNames.Length > 0)
{
    foreach (string instanceName in instanceNames)
    {
        Console.WriteLine("    {0}", instanceName);
        PerformanceCounter[] counters = perfCategory.GetCounters(instanceName);

        foreach (PerformanceCounter counter in counters)
        {
            if (counter.CounterName == "Working Set - Private")
            {
                Console.WriteLine("        {0} - {1}", counter.CounterName, counter.RawValue, counter.RawValue / 1024);
            }
            if (counter.CounterName == "% Processor Time")
            {
                Console.WriteLine("        {0} - {1}", counter.CounterName, counter.RawValue);
            }
        }
    }
}

      

The results for "Working Set - Private" are in place, but for "% Processor Time" these values ​​make no sense.

Here's a sample output, as you can see,% of cpu results doesn't make any sense:

WDExpress#1
    % Processor Time - 378146424
    Working Set - Private - 136257536
taskhost
    % Processor Time - 129480830
    Working Set - Private - 1835008
svchost
    % Processor Time - 2877438445
    Working Set - Private - 4096000
IpOverUsbSvc
    % Processor Time - 15600100
    Working Set - Private - 1236992
vncserver
    % Processor Time - 238213527
    Working Set - Private - 2555904
chrome#21
    % Processor Time - 1652830595
    Working Set - Private - 56799232

      

EDIT 2:

Scott has already provided most of the answer, but now I still run into other problems with both options below:
  • Fast, inaccurate, CPU bombs

    counter.NextValue();
    Console.WriteLine("{0} - {1}", counter.CounterName, counter.NextValue());
    
          

Calling NextValue () two times in succession is collecting data very quickly, but it bombards my CPU quite a bit (and the results are probably not optimal).

  1. Accurate, VERY slow, light on CPU

    counter.NextValue();
    System.Threading.Thread.Sleep(1000);
    Console.WriteLine("{0} - {1}", counter.CounterName, counter.NextValue());
    
          

Another option is Thread.Sleep () between each call to NextValue (), but that makes it very slow (since we're probably talking over 100 processes)

+3


source to share


1 answer


Your problem with CPU time is that you shouldn't be using it RawValue

on it (you shouldn't really be using it for a working set). For cpu time, you have to take two samples calling NextValue

, one of which you will get the 2nd sample, you will have the exact numbers.



PerformanceCounterCategory perfCategory = PerformanceCounterCategory.GetCategories().First(c => c.CategoryName == "Process");
Console.WriteLine("{0} [{1}]", perfCategory.CategoryName, perfCategory.CategoryType);
string[] instanceNames = perfCategory.GetInstanceNames();

if (instanceNames.Length > 0)
{
    foreach (string instanceName in instanceNames)
    {
        Console.WriteLine("    {0}", instanceName);
        PerformanceCounter[] counters = perfCategory.GetCounters(instanceName);

        //Go through each processor counter once to get the first value, should just return 0.
        foreach (PerformanceCounter counter in counters)
        {
            if (counter.CounterName == "% Processor Time")
            {
                counter.NextValue();
            }            
        }

        //You need to wait at least 100ms between samples to get useful values, the longer you wait the better the reading.
        Thread.Sleep(150);

        foreach (PerformanceCounter counter in counters)
        {
            if (counter.CounterName == "Working Set - Private")
            {
                Console.WriteLine("        {0} - {1}", counter.CounterName, counter.RawValue, counter.RawValue / 1024);
            }
            if (counter.CounterName == "% Processor Time")
            {
                Console.WriteLine("        {0} - {1:N1}", counter.CounterName, counter.NextValue());
            }
        }
    }
}

      

+2


source







All Articles