Chapter 7 Performance Counters

Performance counters are critical for tracking the overall performance of your application over time. If you are responsible for tracking and improving the performance of your system, performance counters will help you do that. While you can (and should) use them for real-time monitoring, they can be even more valuable if you store them in a database for analysis over long periods of time. In this way, you can see how new releases, usage patterns, or other events affect the performance of your application.

You can consume performance counters in your own code for self-monitoring, archiving, or automated analysis. You can also create and register your own counters which are then available to the same monitoring approach. By correlating your program’s custom counters with the system’s counters for your application, you can often find the source of problems very quickly.

Performance counters are Windows-managed objects that track values over time. These values can be arbitrary numbers, counts, rates, time spans, or other types detailed later. Each counter has a category and a name associated with it. Most counters also have instances, which are specific subdivisions by logical, discrete entities. For example, the % Processor Time counter in the Processor category has instances for each process currently running. Many counters also have meta-instances like _Total or <Global> that aggregate the data across all instances.

Many components in Windows create their own performance counters and .NET is no exception. There are hundreds of counters available to you to track nearly every aspect of your program’s performance. These counters are all described in the relevant chapters earlier in this book.

To track all the installed performance counters on a system, use the PerfMon.exe utility that comes with Windows, as described in Chapter 1. This current chapter discusses programmatic access to these counters, both consuming and creating your own.

  1. Consuming Existing Counters

To consume a counter, you just need to create a new instance of the PerformanceCounter class and pass it the category and name you want to monitor. You can optionally supply the instance and machine name as well. Here is an example that attaches the counter object to the % Processor Time counter.

PerformanceCounter cpuCtr = new PerformanceCounter("Process",
"% Processor Time", process.ProcessName);

To retrieve values, you periodically call the NextValue method on the counter:

float value = cpuCtr.NextValue();

The API documentation recommends that you call NextValue no more frequently than once per second to allow the counter sufficient time to do the next read.

To see a simple project that demonstrates consuming multiple built-in and custom counters, see the accompanying PerfCountersTypingSpeed sample.

  1. Creating a Custom Counter

To create your own custom counter, you create an instance of the CounterCreationData class, supplying a name and type. You add this to a collection, which is then added to a category.

const string CategoryName = "PerfCountersTypingSpeed";

if (!PerformanceCounterCategory.Exists(CategoryName))
{
var counterDataCollection = new CounterCreationDataCollection();

var wpmCounter = new CounterCreationData();
wpmCounter.CounterType = PerformanceCounterType.RateOfCountsPerSecond32;
wpmCounter.CounterName = "WPM";
counterDataCollection.Add(wpmCounter);

try
{
// Create the category.
PerformanceCounterCategory.Create(
CategoryName,
"Demo category to show how to create and consume counters",
PerformanceCounterCategoryType.SingleInstance,
counterDataCollection);
}
catch (SecurityException )
{
// Handle error -- no permissions to make this change!
}
}

To create a custom counter, you must have the PerformanceCounterPermission granted. In practice, this means that you should usually create new counters with an installation program that can run with elevated permissions. .NET provides the PerformanceCounterInstaller class, which can wrap multiple instances of the CounterCreationData class and install them for you, with support for rollback and removal.

There are many types of counters, grouped into a few categories, as detailed next. In addition, some counters have 32-bit and 64-bit sizes defined. You can use whichever one is most appropriate for the data you are recording.

  1. Averages

These counters show the average of the last two measurements.

  • AverageCount64—How many things are processed during an operation
  • AverageTimer32—How long it takes to process an operation
  • CountPerTimeInterval32/64—The average length of a queue for a resource
  • SampleCounter—Counts the number of operations completed in a second

The AverageCount64 and AverageTimer32 counters need the help of a second counter, AverageBase, to determine how many operations were completed since the last time the counter was updated. The AverageBase counter must be initialized right after the counter to which it applies. The following code demonstrates how to create these two counters together:

var counterDataCollection = new CounterCreationDataCollection();

// Actual average counter
var bytesPerTx = new CounterCreationData();
bytesPerTx.CounterType = PerformanceCounterType.AverageCount64;
bytesPerTx.CounterName = "BytesPerTransmission";
counterDataCollection.Add(bytesPerTx);

// Base counter to help in calculations
var bytesPerTxBase = new CounterCreationData();
bytesPerTxBase.CounterType = PerformanceCounterType.AverageBase;
bytesPerTxBase.CounterName = "BytesPerTransmissionBase";
counterDataCollection.Add(bytesPerTxBase);

PerformanceCounterCategory.Create(
"Network Statistics",
"Network statistics demo counters",
PerformanceCounterCategoryType.SingleInstance,
counterDataCollection);

To set the values, you adjust each counter according to the number of items and the number of operations to which those items apply. In this example, it is fairly simple:

bytesPerTx.IncrementBy(request.Length);
bytesPerTxBase.IncrementBy(1);

  1. Instantaneous

These are the simplest counters. They just reflect the most recent sample value.

  • NumberOfItems32/64—Most recent value for a raw number.
  • NumberOfItemsHEX32/64—Same as NumberOfItems32/64, displayed in hexadecimal format.
  • RawFraction—With RawBase base counter, shows a percentage of the total. The total value is given to the base counter and the subset of that total value is assigned to this counter. An example would be percentage of a disk in use.
  1. Deltas

Delta counters show the difference between the last two counter values.

  • CounterDelta32/64—Shows the difference between the last two recorded values.
  • ElapsedTime—Shows the time from when the component or process was started to now. For example, you can use this to track your application’s up-time. You do not provide new values to this counter after initialization.
  • RateOfCountsPerSecond32/64—Average number of operations completed per second.
  1. Percentages

Percentage counters show the percent of a resource being used. In some cases, this percent can be greater than 100%. Consider a multiprocessor system: you could represent the CPU usage as a percentage of a single core. Each instance of the counter represents one of the cores. If multiple cores are simultaneously in use, then the percentage will be larger than 100.

  • CounterTimer—Percent time a component is active in the total sample time.
  • CounterTimerInverse—Similar to CounterTimer, except that it is measuring the time a component is NOT active and then subtracting that from 100%. In other words, this counter has the same meaning as CounterTimer, but arrives at the value in an inverse way.
  • CounterMultiTimer—Similar to CounterTimer, but the active time is aggregated over all the instances, which can lead to percentages larger than 100.
  • CounterMultiTimerInverse—Multiple instances, but derived from inactive time.
  • CounterMultiTimer100Ns—Uses 100 nanosecond ticks instead of the system’s performance counter ticks.
  • CounterMultiTimer100NsInverse—Similar to CounterMultiTimer100Ns, but using the inverse logic.
  • SampleFraction—The ratio of a subset of values to the total number of values. Uses the SampleBase base counter to track the total number of values.
  • Timer100Ns—Percent time a component is active in the total sample time, measured in 100ns increments.
  • Timer100NsInverse—Same as Timer100Ns, but uses the inverse logic.

All of the CounterMulti- counters require the use of the CounterMultiBase, similar to the AverageCount64 example earlier.

When creating your own performance counters, note that you should not update them too often. A maximum of once per second is a good rule because the data will never be exposed more frequently than that. If you need to generate high-volume performance data, ETW events are a much better choice.

  1. Summary

Performance counters are the most basic building block of performance analysis. While your program does not necessarily have to create its own, consider doing so if you have discrete operations, phases, or items that have performance impact.

Consider automated ingestion and analysis of counters via .NET APIs to provide archiving and continual feedback about system performance.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.176.194