Introduction
In the last project I was working on, we needed to add some performance counters to measure the duration of various parts of the system. There is information on performance counters in MSDN and also in CodeProject, but we just could not find the exact information we were looking for.
We started by creating a performance counters manager for one part of our system that specifically handled counting duration of operations. But then, we realized that we required similar functionality in other parts of the system. So we created a base class PerformanceCountersManagerBase
as a helper class for writing performance counters.
Using the Code
The attached code shows a simplified usage of the PerformanceCountersManagerBase
.
The sample is divided into 3 parts:
Core
. This contains the implementation of the PerformanceCountersManagerBase
.Impl
. This contains an implementation of MyPerformanceCountersManager
that inherits from PerformanceCountersManagerBase
.PerformanceCountersSample
. This uses the MyPerformanceCountersManager
to measure the duration and total duration of some operations in our sample.
After you install the performance counters as explained below, you can run the sample, open the performance monitor and observe the performance counters as they change over time.
Install New Performance Counters Programmatically
- Create a performance counters manager that extends
PerformanceCountersManagerBase
and defines the required performance counters:
public class MyPerformanceCountersManager : PerformanceCountersManagerBase
{
public const string CategoryName = "SampleCategory";
public const string SomeOperationDurationCounterName = "Some Operation Time";
private static int s_instanceCounter;
public static bool CountersInstalled
{
get { return PerformanceCounterCategory.Exists(CategoryName); }
}
public static void InstallCounters()
{
if (CountersInstalled) return;
var counters = new CounterCreationDataCollection
{
new CounterCreationData
{
CounterName =
SomeOperationDurationCounterName,
CounterHelp =
"Duration in milliseconds it takes to
execute some operation.",
CounterType =
PerformanceCounterType.NumberOfItems64,
},
};
PerformanceCounterCategory.Create(
CategoryName,
"Sample counters",
PerformanceCounterCategoryType.MultiInstance,
counters);
}
public MyPerformanceCountersManager(string instanceName)
{
instanceName = string.Format(
CultureInfo.InvariantCulture,
"{0}_{1}",
instanceName,
s_instanceCounter++);
PerformanceCounters.Add(
SomeOperationDurationCounterName,
CreateWritablePerformanceCounter(CategoryName,
SomeOperationDurationCounterName,
instanceName));
}
}
This class defines a performance counter called Some Operation Time
, under category SomeCategory
. The counter is of type NumberOfItems64
, which just updates the value each time it is used. For a comprehensive list of possible performance counters, please refer to MSDN.
The static
InstallCounters
method is used to define the performance counters.
This constructor is used to create instances of the performance counters. This sample uses a per instance performance counter.
- Create an installer for installing the performance counters.
Impl
contains MyPerformanceCountersInstaller
for doing just that:
[RunInstaller(true)]
public class MyPerformanceCountersInstaller : Installer
{
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
if (!PerformanceCounterCategory.Exists(MyPerformanceCountersManager.CategoryName))
{
MyPerformanceCountersManager.InstallCounters();
}
}
public override void Uninstall(IDictionary savedState)
{
base.Uninstall(savedState);
if (PerformanceCounterCategory.Exists(MyPerformanceCountersManager.CategoryName))
{
PerformanceCounterCategory.Delete(MyPerformanceCountersManager.CategoryName);
}
}
}
You can install the performance counters by opening a Visual Studio command prompt (as administrator), navigating to the impl\bin\debug directory and executing:
installutil Impl.dll
If everything goes well, you should be able to see the new category with the new performance counter similar to the following:
Using Performance Counters that Measure Duration
- Install a performance counter of type
NumberOfItems64
(as defined in the previous section). - Make sure you have a relevant instance of a performance counters manager. You can use the
NullPerformanceCountersManager
. This is an implementation of the Null
Object pattern that can save you from verifying for null
reference each time you want to use the performance counters manager.
private IPerformanceCountersManager m_performanceCountersManager =
new NullPerformanceCountersManager();
private void InitializePerformanceCountersManagerIfNecessary()
{
if (!MyPerformanceCountersManager.CountersInstalled) return;
m_performanceCountersManager = new MyPerformanceCountersManager
(Guid.NewGuid().ToString());
}
- Before the operation you want to measure, do the following:
m_performanceCountersManager.StartWatch
(MyPerformanceCountersManager.SomeOperationDurationCounterName);
- After the operation you want to measure, do the following:
m_performanceCountersManager.StopWatch
(MyPerformanceCountersManager.SomeOperationDurationCounterName);
The performance counter is updated after calling the StopWatch
with the elapsed milliseconds from the call to StartWatch
.
Using Performance Counters that Measure Total Duration
Sometimes, you need to sum the duration of each operation into one performance counter which contains their total.
- Install a performance counter of type
NumberOfItems64
(as defined in the previous section). - When you want to start the measuring cycle, call the following:
m_performanceCountersManager.ResetCounterValue(
MyPerformanceCountersManager.TotalOperationDurationCounterName);
- Each time you need to update the counter value with the elapsed time of some other counter, you can do the following:
m_performanceCountersManager.IncrementCounterValueBy(
MyPerformanceCountersManager.TotalOperationDurationCounterName,
m_performanceCountersManager.GetElapsedMilliseconds(
MyPerformanceCountersManager.SomeOperationDurationCounterName));
Note that the counter is not actually updated when calling IncrementCounterValueBy
. Only the internal value, kept in the performance counter manager, is updated.
- When you want to actually update the counter (at the end of the measuring cycle), call the following:
m_performanceCountersManager.UpdateCounter
(MyPerformanceCountersManager.TotalOperationDurationCounterName);
Other Operations with Performance Counters
Performance counters have operations like Increment
and IncrementBy
. If you need a performance counter (like counters per second), you can update the counter by using something similar to:
m_performanceCountersManager.Increment
(MyPerformanceCountersManager.OperationsPerSecondCounterName);
History
- 16th January, 2012: Initial version