Within Windows there are many system level processes that publish performance counters.

For example there are performance counters that allow you to see CPU time, memory usage, and disk usage of the system. Since performance counters are a standard system function they are an ideal method for tracking the performance your applications. Luckily, Microsoft has provided several classes within the .NET Framework to publish custom performance counters.

These custom counters can be used to publish performance information directly from your applications. For instance, if you have a file parsing service that parses files and inserts records into a database, you can publish a custom performance counter to expose the number of records inserted. This information can then be used to determine the speed at which records are being inserted, which can help in making decisions on scaling options and hardware requirements.

Performance counters can also be used to determine whether or not a process has completely locked up. If the data represented by a performance counter doesn't change within a specified time frame then you can determine that there has been an issue and publish an alert. A very good example of this is in the case of monitoring MSMQ messages. Generally you expect the number of messages within an MSMQ queue to change fairly rapidly -- if at some point the number of messages stops changing then there is a good chance something is wrong.

Publishing your counter

Performance counters are organised into categories which contain multiple counters that usually monitor different aspects of the same system function. Within each counter there can also be multiple instances. For example, if we want to monitor the number of messages in an MSMQ we would go to the category "MSMQ Queue", select the counter "Messages in Queue", and then select the instance that we want to monitor (in this case each queue is an instance).

After you have determined how you will organise your custom counters you will have to create them. The code shown below creates a counter named "SampleCounter" in the category "SampleCategory".


public void CreateCounter ()
{
  //Create the collection that will hold 
  // the data for the counters we are
  // creating.
  CounterCreationDataCollection counterData =
    new CounterCreationDataCollection ();

  //Create the CreationData object. 
  CounterCreationData sampleCounter=
    new CounterCreationData ();

  // Set the counter's type to NumberOfItems32
  sampleCounter.CounterType =
    PerformanceCounterType.NumberOfItems32;

  //Set the counter's name
  sampleCounter.CounterName = "Sample Counter";

  //Add the CreationData object to our
  //collection
  counterData.Add (sampleCounter);

  //Create the counter in the system using the
  //collection. 
  PerformanceCounterCategory.Create("SampleCategory",
    "Simple performance counter from C#.",
    PerformanceCounterCategoryType.SingleInstance,
    counterData);
}

Create a counter

Note that only one counter is added in this code. If more than one counter needs to be created simply copy the code that creates the sampleCounter object and add it to the counterData array. Any counters added to the counterData array will be created when you call the Create method on the PerformanceCounterCategory object.

Also notice the "SingleInstance" portion of the Create() call. This disables multiple instances for the specified counter. If you need multiple instances you can simply change "SingleInstance" to "MultiInstance" when you call the Create method.

Once the Create() method is called the counter is ready for you to write data to it. The code below shows how to correctly instantiate the performance counter object and how to check to see if the category currently exists.


//The counter is instantiated in the
//class scope because instantiating 
//the counter each time you need to
//write to it would lead to performance
//issues.
PerformanceCounter counter = null;

public void WriteToCounter()
{
  //If the category doesn't exist, create it.
  if (!PerformanceCounterCategory.Exists (
    "SampleCategory"))
     CreateCounter ();

  //Setup the counter we will write to. 
  counter = new PerformanceCounter 
  ("SampleCategory", "SampleCounter", false);

  //Start the timer that will write to the
  //counter.
  timer.Enabled = true;
}

Instantiate the performance counter

In this code we instantiate the PerformanceCounter object so that its scope is not just the scope of the code that will be writing to it. This is done for a couple of reasons.

The first is that the code uses a Timer to write data to the performance counter. Because of this the PerformanceCounter object must be in scope when the Timer's Tick event is fired.

Second, instantiating the PerformanceCounter before writing to it every time can have a major performance impact on the overall application's performance (more on this later).

Now that we have instantiated the PerformanceCounter we are able to write to it. As mentioned above, this is done in the Timer's Tick method which is shown below.


private void timer_Tick (object sender, EventArgs e) 
{
  counter.RawValue = DateTime.Now.Second;
  
  if (timer.Interval > 100000)
      timer.Interval = 1000;
  else 
      timer.Interval += timer.Interval;

}

Timer's Tick method

This code simply sets the PerformanceCounter.RawValue property to the current second and then modifies the counter's interval to make the counter's value a little more dynamic. The RawValue property is the current value of the PerformanceCounter, and that is the value that will be displayed when you read the PerformanceCounter.

In production applications you will more than likely want to store some base values to be published via the custom performance counter. For instance, in the file parsing system mentioned above you would want to store the total number of records parsed, the total number of records parsed within the last minute, and possibly the average time to insert a record into the database. All of these numbers would be published from different performance counters within your application's performance counter category.

Reading performance counters

The easiest way to read a performance counter is to use the PerfMon snap-in for Microsoft Management Console. To run PerfMon and pull up your custom counter follow these steps:

  • Click the Start menu and click on "Run"
  • Type "perfmon" and hit enter
  • The PerfMon snap-in should appear, and more than likely has a few default counters already added.
  • Right-click in the graph area and click "Add Counters"
  • Under "Performance object:" choose "SampleCategory"
  • Under "Select counters from list:" make sure "SampleCounter" is selected
  • Click "Add"
  • Click "Close"

The SampleCounter should now be displayed in the graph. If you are not currently sending data to the counter the line will be flat but will begin to change once you start sending data.

A more complex, but often much more useful way of reading performance counters is to do so programmatically. This allows you to poll the counter whenever you need to and store the counter's data for examination. I have discussed this previously: "A sample app to monitor performance counters and send alerts" .

The cost of instantiation

Because of the way performance counters work, it is likely that you will be writing a large amount of data to them -- for example each time a record gets added to the database you may want to add to a total record count and publish that via a performance counter. Since this is the case, whenever possible you should instantiate the PerformanceCounter object(s) once, and only once, instead of instantiating them each time you write data to them. The reason for this is that instantiating a PerformanceCounter object is a resource intensive task and if you instantiate a new PerformanceCounter object each time you need to write to it you could adversely affect application performance.

Take, for example, the two snippets of code below.


private void btnInstantiationExample2_Click
  (object sender, EventArgs e)

{
  Stopwatch time = new Stopwatch ();
  time.Start ();

  if (!PerformanceCounterCategory.Exists (
      "SampleCategory"))
       CreateCounter ();

  for (int i=0; i< 100000; i++)
  {
      PerformanceCounter counter =
        new PerformanceCounter ("SampleCategory","SampleCounter", false);
      counter.RawValue = i;
  }
  time.Stop ();
  MessageBox.Show ("Time: " +
        time.Elapsed.TotalSeconds.ToString() );
}

Incorrect instantiation

private void btnInstantiationExample_Click (object sender, EventArgs e) { Stopwatch time = new Stopwatch (); time.Start (); if (!PerformanceCounterCategory.Exists("SampleCategory")) CreateCounter(); PerformanceCounter counter = new PerformanceCounter ("SampleCategory", "SampleCounter", false); for (int i=0; i < 100000; i++) counter.RawValue = i; time.Stop(); MessageBox.Show ("Time: " + time.Elapsed.TotalSeconds.ToString() );

Correct instantiation

While both of these snippets perform the exact same function, the code in example two runs over 5,000 times faster than the code in example one. This is because of the simple fact that the code in example two instantiates the PerformanceCounter object once, and the code in example one instantiates the PerformanceCounter object once for each iteration of the loop.

Cast your .NET This was published in Cast your .NET, check every Thursday for more stories

Related links

Leave a comment

You must read and type the 6 chars within 0..9 and A..F

* indicates mandatory fields.

Log in


Sign up | Forgot your password?

What's on?