Implementing custom Windows Performance Counters in C#

Custom Windows performance counters enable us to capture, publish and analyse the performance data related to one or more applications or services running in the system or the system as a whole. This gives you real time statistics for the resource consumption in your system or application. The obvious benefit is how this could help identify bottlenecks in an application but it can also serve as a benchmark that can be measured against. For example; Over time an application could have a test suite that is run and the performance counters collected. This allows for the analysis against historical runs or validates the performance counters captured verse an expected capture result.

 

Creating Custom Windows Performance Counters

Before you can capture a performance counter it has to be created. Each performance counter belongs to a performance counter category. So first we need to create the performance counter category. To do this we use the Create method in the PerformanceCounterCategory class. The below code will registers the custom performance counter category containing a single performance counter of type NumberOfItems32 on the local computer.

PerformanceCounterCategory.Create("MyCustomPerformanceCounterCategoryName",
	"MyCustomPerformanceCounterHelp",
	PerformanceCounterCategoryType.SingleInstance,
	"MyCustomPerformanceCounterName",
	"MyCustomPerformanceCounterHelp");

The counter of type NumberOfItems32 could be used to record a count of items or operations. There are several different performance counter types, represented by an enumeration called PerformanceCounterType. These include ElapsedTime, AverageTimer32, RateOfCountsPerSecond32, etc. Most real-world custom performance counters would use more than one performance counter type within a category. To achieve this we use a different overload for the Create method to add multiple performance counter type. This requires a new object, a CounterCreationDataCollection, which is a collection of CounterCreationData objects. Each CounterCreationData object is created and added to a CounterCreationDataCollection object. When creating the CounterCreationData object the performance counter type is specified. The below code demonstrates this:

CounterCreationDataCollection counterCreationDataCollection = new CounterCreationDataCollection();
counterCreationDataCollection.Add(new CounterCreationData("MyAppElapsedTime",
	"MyAppElapsedTimeHelp",
	PerformanceCounterType.ElapsedTime));
	
counterCreationDataCollection.Add(new CounterCreationData("MyAppNumberOfItems32",
	"MyAppNumberOfItems32Help",
	PerformanceCounterType.NumberOfItems32));

This populates the CounterCreationDataCollection object with 2 CounterCreationData objects that have the performance counter type of NumberOfItems32 and ElapsedTime. And then we pass the CounterCreationDataCollection to the Create method. The below code demonstrates this:

PerformanceCounterCategory.Create("MyCustomPerformanceCounterCategoryName", MyCustomPerformanceCounterHelp", PerformanceCounterCategoryType.SingleInstance, counterCreationDataCollection);

 

Once the performance counter category is created then the actual performance counters can be created. When creating a new performance counter a read-only parameter should be provided. The default value is true and will only allow performance counter values to be read. In order to capture new performance counter values this parameter needs to be set to false. The below code demonstrates creating 2 new performance counters:

PerformanceCounter myAppNumberOfItems32 = new PerformanceCounter(
	"MyCustomPerformanceCounterCategoryName",
	"MyAppNumberOfItems32", 
	false);

PerformanceCounter myAppElapsedTime = new PerformanceCounter(
	"MyCustomPerformanceCounterCategoryName",
	"MyAppElapsedTime",
	false);

 

If you try to create a performance counter category that already exists an InvalidOperationException will be thrown, so it is a good idea to first check if it exists before calling create. An existing performance counter category can also be deleted. The below code demonstrated these 2 methods:

if (PerformanceCounterCategory.Exists("MyCustomPerformanceCounterCategoryName"))
PerformanceCounterCategory.Delete("MyCustomPerformanceCounterCategoryName");

 

When creating the custom performance counter category a PerformanceCounterCategoryType (SingleInstance, MultiInstance or Unknowen) must be specified. If MultiInstance is used then an instance name must be provided or an exception is thrown with the following message: “Category XXX is marked as multi-instance.  Performance counters in this category can only be created with instance names.”

 

The creating of custom Windows performance counters and their categories would typically be done as part of an installation script, either as a pre or post deploy step. Although it can also be done on application start-up.

 

Using Custom Windows Performance Counters

Consideration should be given to exception handling when capturing or creating performance counters. If an exception occurs this should not affect the execution of the application. It is also a good idea to have a mechanism to turn the capture of performance counters on or off, and\or what performance counters are captured for an application, as capturing performance counters does incur a performance overhead.

 

The usage of the performance counter is very simple, for most it is simply a case of incrementing the value, by using the Increment method. However, for performance counters like the ElapsedTime, you would probably use a stop watch and assign the ElapsedMilliseconds value using the IncrementBy method. The below code demonstrates these 2 performance counters:

myAppNumberOfItems32.Increment();
myAppElapsedTime.IncrementBy(Convert.ToInt64(stopwatch.ElapsedMilliseconds));

 

A more complex timer such as the AverageTimer32 also requires an AverageBase. The base is used in the internal calculation of the counter. So after adding the AverageTimer32 to the CounterCreationDataCollection you need to add the AverageBase. You would receive an exception when using the counter without a base, the exception message is very explicit:

“The Counter layout for the Category specified is invalid, a counter of the type: AverageCount64, AverageTimer32, CounterMultiTimer, CounterMultiTimerInverse, CounterMultiTimer100Ns, CounterMultiTimer100NsInverse, RawFraction, or SampleFraction has to be immediately followed by any of the base counter types: AverageBase, CounterMultiBase, RawBase or SampleBase.”

 

Further reading: Performance counter Alerts using the PLA COM library

Performance Logs and Alerts (PLA) provides the ability to generate alert notifications based on performance counter thresholds. The data collector set is the primary entity used in PLA. The data collector set defines where the logs are written, when the set runs and for how long, and the credentials used to run the set. PLA uses data collectors to collect data.

Conclusion

Custom Performance counters is an upcoming feature in Warewolf but until it is released we would welcome your input on how you would like to see this implemented or any ideas you may have around custom performance counters in Warewolf. Feel free to leave a post on this blog or head over to the Community Forum and post your idea.

 

External links and References

MSDN PerformanceCounter Class

https://msdn.microsoft.com/en-us/library/system.diagnostics.performancecounter

MSDN PerformanceCounterCategory Class

https://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountercategory

MSDN PerformanceCounterCategoryType Enumeration

https://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountercategorytype

Performance Logs and Alerts

http://www.codeproject.com/Articles/64401/How-the-Windows-built-in-watchdog-infrastructure-c

 

FacebookTwitterLinkedInGoogle+RedditEmail

Leave A Comment?