Reading performance counter data in .NET

Nothing you can’t easily write yourself, but while playing around, I wrote this one myself, and learned one or two things.

Firsltry, it demonstrates the wrinkle that when reading % processor time you need to specify the instance name of the processor, or the special instance name “_Total”.

Secondly you’ll notice that the % CPU time is a performance counter of type Timer100NsInverse, which results in it showing weird large numbers.

MDSN says “Counters of this type calculate active time by measuring the time that the service was inactive and then subtracting the percentage of active time from 100 percent.”

In other words, it tells you your processor’s IDLE time, as a count of some units of 100Ns intervals, measured over some other arbitrarily sized interval which you presumably need to find out from the counter sample timestamps… complicated, sigh.

I used UltimateTimer for the timer, of course...

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace pcpusher
{
    class Program
    {
        static Dictionary<string, string> CountersToMetrics = new Dictionary<string,string>
        {
            { @"\Processor(_Total)\% Processor Time", "percentProcessorTime" }
         };

        static Dictionary<string, PerformanceCounter> CountersToPC = new Dictionary<string,PerformanceCounter>();

        static void Main(string[] args)
        {
            foreach (var k in CountersToMetrics.Keys)
            {
                 var parts = k.Split(new []{'\\'}, StringSplitOptions.RemoveEmptyEntries);
                try
                {
                     var safePart = parts[0].Contains("(") ? parts[0].Substring(0, parts[0].IndexOf("(")) : parts[0];
                     var pc = new PerformanceCounter(safePart, parts[1], readOnly: true);
                    if (parts[0].Contains("(_Total)"))
                    {
                        pc.InstanceName = "_Total";
                    }
                    CountersToPC.Add(k, pc);
                }
                catch (Exception e)
                {
                    Console.WriteLine("can't get PC: " + k + " " + e.Message);
                }
             }

            using (var timer1 = UltimateTimer.ThreadPoolTimer.Create(onTimer1))
            {
                timer1.SetTimer(DateTime.Now, 1000, 10);
                Console.WriteLine("Press any key to end process");
                Console.ReadLine();
                timer1.Close();
            }
         }

        private static void onTimer1()
        {
             foreach (var k in CountersToMetrics.Keys)
            {
                 try
                {
                    var sample1 = CountersToPC[k].NextSample();
                    Console.WriteLine(k + " @ " + sample1.TimeStamp100nSec + "(" + sample1.CounterType + ")" + " : " + sample1.RawValue);
                }
                catch (Exception e)
                {
                     Console.WriteLine(k + " couldn't read " + e.Message);
                }
            }
        }
    }
}