Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Although the .NET Framework provides usage of performance counters under the System.Diagnostics namespace, for some reason, documentation on it does little cover using performance counters for average duration per execution. When starting using PerformanceCounterType.AverageTimer32, performance monitor did not show the expected results.

I started to dig into CodeProject and some newsgroups, and found many articles covering the same problem. After I found the solution, I started to write an article, which introduces using performance counters in .NET and especially how to use AverageTimer32 performance counter. So here it is!

I am sorry, that I only have German Windows editions, so the images contained in the article contain German names for buttons, etc. I tried to find the correct translation to English, but I am not quite sure if they are accurate. Maybe somebody can help me out with images of English versions, so that I can provide them here.

Getting started

Performance counters can monitor system components such as processors, memory, and network I/O. If you use performance counters in your application, they can publish performance-related data to compare them against acceptable criteria. Performance counters are available on Microsoft operating systems Windows 2000 and later.

Performance counters can be made visible using the Performance monitor (perfmon.exe). Later, I will show how to add and remove performance counters in the Performance monitor.

Performance Counter Types

Different performance counter types are available, covering different performance interests. They range from counts to those which calculate averages. Some of the performance counter types are for special situations only, but the following list contains the most common types you will normally use - and this article is covering:

You will find the performance counter types in the System.Diagnostics.PerformanceCounterType enumeration. Some of the counters found in that enumeration end with "Base" which indicates them as supporting counters for other counters which perform calculations (such as AverageTimer32). Whenever you set up a counter that performs calculations, you'll need to set up a supporting "Base" - counter.

Categories, Counters And Instances

Performance counters are combined together under categories, such as Processor or Memory. A category catalogues performance counters in a logical unit. A performance counter itself can be divided into instances, such as processes, threads, or physical units.

Example

When monitoring the processor load a process takes while execution, you will find the performance counter % Processor time in the category Processor. Underneath that counter, you will find an instance for each process currently running on your system.

Creation And Setup Of Performance Counters

There are two ways to create performance counters. You can either create them using the Server-Explorer or create them programmatically by code. Creating performance counters using the Server-Explorer is much easier than doing it by code, but on production machines, you might not be able to install Visual Studio .NET to take advantage of this feature. However, I will explain both ways.

Creating Performance Counters Using Server-Explorer

The simplest way to set up performance categories and counters is by using Server-Explorer integrated within Visual Studio .NET. Normally, you will find it at left side toolbar where you also have your Toolbox for designing Windows Forms. If you don't see it, you might have closed it before. Then, direct to the "View" menu and select the "Server-Explorer" option.

Setting up new categories is pretty easy. Open the "Server-Explorer" and open the tree-node "Performance counters". The tree should open and you should see all performance categories currently available on your system (Figure 1).

Figure 1

Now right-click on "Performance counters" and select "Add new category" to add a new category. Enter a name, a description, and some counters to it, and you're done. You can also right-click on a category and select "Show category" to add some more counters to any existing category (Figure 2).

Figure 2

Performance Counter Installation By Code

Performance counters can be created manually at runtime by code. It takes much more effort to do so, but once you learn how, it is as simple as doing so by Server-Explorer. When creating performance counters and/or categories by code, you must take care, that the user running the code must have the proper administrative rights. This might be a problem when using performance counters in Web Applications because the ASP.NET user does not have them.

Installing performance counters programmatically includes using some classes from the System.Diagnostics namespace:

To create a new performance category which comes along with some counts, you will first create a System.Diagnostics.CounterCreationDataCollection to hold the information about the counters you want to create. Then you create for each counter, one System.Diagnostics.CounterCreationData instance, and add it to the collection. Use the System.Diagnostics.PerformanceCategory.Create method to create the category and all related counters stored in the collection.

Let's look at some code:

if (!PerformanceCounterCategory.Exists("MyCategory"))
{
    CounterCreationDataCollection counters = new CounterCreationDataCollection();

    // 1. counter for counting totals: PerformanceCounterType.NumberOfItems32

    CounterCreationData totalOps = new CounterCreationData();
    totalOps.CounterName = "# operations executed";
    totalOps.CounterHelp = "Total number of operations executed";
    totalOps.CounterType = PerformanceCounterType.NumberOfItems32;
    counters.Add(totalOps);

    // 2. counter for counting operations per second:

    //        PerformanceCounterType.RateOfCountsPerSecond32

    CounterCreationData opsPerSecond = new CounterCreationData();
    opsPerSecond.CounterName = "# operations / sec";
    opsPerSecond.CounterHelp = "Number of operations executed per second";
    opsPerSecond.CounterType = PerformanceCounterType.RateOfCountsPerSecond32;
    counters.Add(opsPerSecond);

    // 3. counter for counting average time per operation:

    //                 PerformanceCounterType.AverageTimer32

    CounterCreationData avgDuration = new CounterCreationData();
    avgDuration.CounterName = "average time per operation";
    avgDuration.CounterHelp = "Average duration per operation execution";
    avgDuration.CounterType = PerformanceCounterType.AverageTimer32;
    counters.Add(avgDuration);

    // 4. base counter for counting average time

    //         per operation: PerformanceCounterType.AverageBase

    CounterCreationData avgDurationBase = new CounterCreationData();
    avgDurationBase.CounterName = "average time per operation base";
    avgDurationBase.CounterHelp = "Average duration per operation execution base";
    avgDurationBase.CounterType = PerformanceCounterType.AverageBase;
    counters.Add(avgDurationBase);


    // create new category with the counters above

    PerformanceCounterCategory.Create("MyCategory", 
            "Sample category for Codeproject", counters);
}

Executing the code above creates a new performance category called "MyCategory" and adds some performance counters to it ("# operations executed", "# operations / sec", "average time per operation"). But you won't be able to change values of the counters yet. Open Server-Explorer and switch to "Performance counters". You will find the new category there and also the three new counters under that category. Maybe, you'll have to refresh the view by right-clicking "Performance counters" and selecting refresh to make the changes visible (Figure 3).

Figure 3

As I told before, creating counters which require some calculation requires a supporting base counter. The example above added only three counters to the category, but four CounterCreationData instances have been added to the CounterCreationDataCollection. If you take a closer look at it, you will see that the third instance is of type System.Diagnostics.PerformanceCounterType.AverageTimer32 (avgDuration) and the last instance is of type System.Diagnostics.PerformanceCounterType.AverageBase (avgDurationBase). avgDurationBase is the supporting counter for avgDuration. When monitoring performance later, you will see how both counters work together. It is important to know that the supporting counter always must follow the counter which will monitor performance!

To create a new category and add some performance counters to it, you must:

Remember, you won't be able to create categories and/or counters that already exist!

Working With Performance Counters

After installing performance counters, you usually want to use them to monitor performance. Therefore, you can use the System.Diagnostics.PerformanceCounter class. The difference between System.Diagnostics.CounterCreationData and System.Diagnostics.PerformanceCounter is that System.Diagnostics.CounterCreationData physically adds a performance counter to a category on your local machine, while System.Diagnostics.PerformanceCounter is used to create an instance of a performance counter and to change performance values.

Create Performance Counters To Work With

Creating performance counters to work with is easy. Create a new instance of System.Diagnostics.PerformanceCounter and set the following properties properly:

You can leave the other properties at its defaults as we don't require them to change now.

// create counters to work with

_TotalOperations = new PerformanceCounter();
_TotalOperations.CategoryName = "MyCategory";
_TotalOperations.CounterName = "# operations executed";
_TotalOperations.MachineName = ".";
_TotalOperations.ReadOnly = false;

_OperationsPerSecond = new PerformanceCounter();
_OperationsPerSecond.CategoryName = "MyCategory";
_OperationsPerSecond.CounterName = "# operations / sec";
_OperationsPerSecond.MachineName = ".";
_OperationsPerSecond.ReadOnly = false;

_AverageDuration = new PerformanceCounter();
_AverageDuration.CategoryName = "MyCategory";
_AverageDuration.CounterName = "average time per operation";
_AverageDuration.MachineName = ".";
_AverageDuration.ReadOnly = false;

_AverageDurationBase = new PerformanceCounter();
_AverageDurationBase.CategoryName = "MyCategory";
_AverageDurationBase.CounterName = "average time per operation base";
_AverageDurationBase.MachineName = ".";
_AverageDurationBase.ReadOnly = false;

Changing performance Counter Values

Monitoring performance means changing performance values after a certain amount of time. To do so, we can call one of the following methods on a System.Diagnostics.PerformanceCounter instance:

// simply increment the counters

_TotalOperations.Increment();
_OperationsPerSecond.Increment();
// increment the timer by the time cost of the operation

_AverageDuration.IncrementBy(ticks);
// increment base counter only by 1

_AverageDurationBase.Increment();

Using AverageTimer32 And AverageBase

In the sample code above, you can see how we must increment the counters for calculating averages. While the counter of type PerformanceCounterType.AverageTimer32 is incremented by the time elapsed between two calls, the base counter - of type PerformanceCounterType.AverageBase - is incremented by 1 for each operation taken.

The .NET documentation for PerformanceCounterType.AverageTimer32 states the formula used to calculate the value of the counter as ((N2 - N1)/F)/(B2 - B1), where N1 and N2 are the timestamps of the start and end of the operation, B1 and B2 are the base values, and F is defined to be "the frequency of the ticks" which is divided out of the time span "so that the result can be displayed in seconds".

We should expect that we could use System.DateTime.Now.Ticks to measure N1 and N2, however, this is not the case, as these values are slightly inaccurate. In fact, we should use QueryPerformanceCounter() method via InterOp. You can choose yourself, if this is rather a bug in the framework than a lack of documentation.

[DllImport("Kernel32.dll")]
public static extern void QueryPerformanceCounter(ref long ticks);

// [...]


PerformanceCounterSample test = new PerformanceCounterSample();
Random rand = new Random();
long startTime = 0;
long endTime = 0;

for (int i=0; i<1000; i++)
{
    // measure starting time

    QueryPerformanceCounter(ref startTime);

    System.Threading.Thread.Sleep(rand.Next(500));

    // measure ending time

    QueryPerformanceCounter(ref endTime);

    // do some processing

    test.DoSomeProcessing(endTime - startTime);
}

Making Performance Visible

Most of you already know how to set up Performance Monitor to make performance counters visible. But for all those who don't know it yet, I will explain it in just a few words.

You find Performance Monitor under Administrative Tools in the Control panel. Double-click it and a window will show up with a Y-Axis ranging from 0 to 100 and a imaginary X-Axis, which depicts the time elapsed. You can add counters using the button. In the opening window, the category Processor and in the category the counter Processor time should be pre-selected. You can change the categories with the dropdown listbox and counters with the listbox under that. On the right hand side, you see the instances available. If you leave the defaults and you have a multiprocessor machine, you can see as many instances as you have processors. One instance for each processor and an instance called _Total which means the total processor time used on all processors.

If your machine is running with a single-processor, switch the category to Process and see the listbox containing the counters changing. Again processor time should be pre-selected, but now you should see instances for each process currently running. Select the Idle process and click Add, and then close the window. Now you can see that the performance monitor starts recording performance. Move your mouse a little to take processor time from the idle process, and you should see that the curve drawn moves down when you move your mouse, and again goes up to 100 when you keep quiet (if you don't have other time consuming processes running).

Figure 4

For some reasons, you might have to change the scale of the counter. To do so, right-click anywhere in performance monitor and select Properties and then Data. Select the counter of which you require to change the scale, and change the factor with the dropdown listbox, and click OK. You can also change the color and thickness of the curve drawn for that counter here.

Play with the performance monitor a little to understand how you can monitor performance using it.

Putting It All Together

The following sample sets up a new category "MyCategory" and adds some performance counters to it ("# operations executed", "# operations / sec", "average time per operation").

It simulates processing by calling the method PerformanceCounterSample.DoSomeProcessing() after some random time elapsed and updates the counters. To see the performance flow, open Performance Monitor and add the corresponding counters. You might have to change the scale of the "average" counter, because the result of the average is in seconds, but the delay between two operations always takes less than 500ms.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralNo Values in Perfmon
James M Rhodes
7:06 5 Nov '09  
After doing this myself, I found that my category and counters show up in perfmon, but the values are all "---". I thought maybe I would download your sample and see if it worked and what was different. This sample does not work either. MyCategory and the counters show up in perfmon, but values are always empty ("---") while the application is running. Any ideas? Thanks!
GeneralRe: No Values in Perfmon
James M Rhodes
8:22 5 Nov '09  
Ok. Apparently you have to restart perfmon to get the values to show up, even though the counters did show up. That seems odd, but whatever Smile
GeneralSome helper I made
JavierCanillas
4:35 8 Sep '09  
After finding myself a little alone with this performance counter, i made a library called PerformanceCounterHelper to simply the use of them. You can take a look at http://www.codeplex.com/perfmoncounterhelper[^] if you want.
GeneralThanks Voted 5 , need a reference of your article
Shivprasad koirala
18:13 27 Aug '09  
Hi Mic,

This is Shiv here. I am writing a article on performance counters can i refer your article for some code which I can put in my article for reference.

Looking forward for your reply.

Visit my 500 videos on WCF,WPF,WWF,Silverlight,UML design patters @ http://www.questpond.com

Generalperformance counter with instance for physical components
De@r
5:11 28 Jul '09  
Hi,

I have added the counter in a category with instance. I want to assign the value to counter and monitor this counter. I can do it same things if i do not use the instance but if i use the instance then value is not being incremented.So i would appreciate if anyone can help me.

Thanks!

Thanks
vijay

General70-536 - Thank you
dbaird86
10:25 10 Jan '09  
I'm studying for 70-536. This article wipes the floor with the examples of performance counters in the official Microsoft Text book for 536. Thank you.
QuestionCounter for % of memory used/available
mondo327
13:08 29 May '08  
I'm a novice at programming.

Can someone point me in the right direction for coding a perfmon counter that shows memory based on the percentage of used or available?

Thanks

Mondo
QuestionRedundancy?
K.L.K
23:28 15 Apr '08  
I don't see why 2 separate counters are needed for the total number of operations and the "average time per operation base".

Since "average time per operation base" will be incremented for every operation added, can't we just use the counter for the total number of operations ("# operations executed") as the base as the Average Base? Isn't the average base just a counter for the total number, which will then be the denominator in the timer division to get the average time?
GeneralRe: Redundancy?
Michael Groeger
0:25 16 Apr '08  
This article demonstrates the usage of several counters and so I thought it's more clear to explain the counters as they are used for a certain functionality. One, for counting the number of ops executed and another used as denominator for the average calculation.

Another thing is, and I might be wrong, cause I am out of the topic at the moment, that you cannot list the average base counter in Performance Monitor, cause Windows believes, that it's only usage is counting for the average calculation. But I might be wrong here.

Regards,
Michael
GeneralRe: Redundancy?
K.L.K
17:09 16 Apr '08  
Thanks Michael, I'll take the safe route and use both.

Another question though:

Are there any kind of listener interfaces that allow you to subscribe to a PerformanceCounter and raise an event on some kind of condition (e.g. MemoryUsage > 128MB, etc.)

Thanks,
Karthik
GeneralRe: Redundancy?
Michael Groeger
22:03 16 Apr '08  
AFAIK, no. But it should be easy to implement Smile
AnswerRe: Redundancy?
Jeropa
7:26 30 Apr '08  
I believe you can use WMI to watch performance counters.

Using the System.Management.EventQuery[^] you can subscribe to an event based on a WQL query (WQL is very similar to SQL except that you are querying on WMI objects). Whenver your the WMI object matches your WQL query a .NET event is raised from the EventQuery object into your application.

I've used this to do complex time scheduling based on the system clock and overall it works well. You just have to be careful with how many of these EventQuery objects you create as there are system limits (I think I hit them at well over 1000 objects).

This article might help you out: http://msdn.microsoft.com/en-us/library/ms974615.aspx
GeneralWhere is the dependency between Average and Base counter hidden?
cwienands
11:58 27 Nov '07  
I went through the whole code multiple times and kept on wondering: How does Windows know that this base counter is the base for the average counter? I finally found the answer in MSDN:

"The base counter must be immediately after its associated counter in the CounterCreationDataCollection collection your application uses."

Just figured I'll let everybody know Cool Besides that, great article.

Christoph
GeneralRe: Where is the dependency between Average and Base counter hidden?
digi_tron
6:19 25 Jan '08  
Oh, that's very nice of you to share with everyone. I was puzzled by the very same question. "How do you bind them?"

Thanks for the useful info.

And thanks to the article author for the very clean sample.
General.net 2.0 not working
Tic1
20:15 5 Nov '07  
I converted the provided sample solution to Framework 2.0. It works with no problems. There's a compiler warning, because the used overload of PerformanceCounterCategory.Create is deprecated.I changed it to the newer method.It created the performance counter but don't update the counter values while running.please let me know how to resolve this issue.It tried this withour changing the deprecated method also, but that is also not working.

Rajiv
GeneralRe: .net 2.0 not working
ahmed zahmed
11:58 6 Aug '08  
if you look in the .Net documentation, for .Net 2.0, you must create the counters, then stop the app and then restart. Some latency is needed between creation of the counters and usage.
GeneralMemory usage and cpu usage of an Application
abhijit bhopale
20:17 23 Oct '07  

I want to know my application's memory usage and cpu usage,
How could i do it using Performance counter using VC++??
GeneralRe: Memory usage and cpu usage of an Application
valyala
3:43 30 Oct '07  
There is no need to create these performance counters (memory and cpu usage) for your application in VC++, because Windows already provides them:

1. Open perfmon.exe, right click and select "Add counters".
2. Choose "Process" under "Performance object", select corresponding counters ("%Processor Time" for cpu usage and "Working Set" for memory usage) in the counters list.
3. Select your running application from the list of instances (each instance represents separate process running at the moment in the system).

QuestionPerformance monitor don't show my custom Counter
andresmherrera
13:38 10 May '07  
Hi,
I did run the example without change anything, then I tried to add my new counter to Performance Monitor and this not appear on list.
Using the "Server Explorer" of VS IDE I can see the Category and counters.

I have VS 2005 and was necesary convert the project.

English is not my native language, sorry for mistakes.

Thanks for some help.




PD: Someone else was loged in when I sent the message

Mauricio Herrera
QuestionPerformance monitor don't show my custom Counter
lujoboan
13:34 10 May '07  
Hi,
I did run the example without change anything, then I tried to add my new counter to Performance Monitor and this not appear on list.
Using the "Server Explorer" of VS IDE I can see the Category and counters.

I have VS 2005 and was necesary convert the project.

English is not my native language, sorry for mistakes.

Thanks for some help.

Mauricio Herrera
Generalvs2005
MsgDev
12:43 22 Mar '07  
This sample runs in 2k3 version of visual studio with 1.1 runtime but when I convert it to 2k5 2.0 framework it no long works. Anyone know why?
GeneralRe: vs2005
Michael Groeger
1:02 23 Mar '07  
Hi,

I just converted it to Framework 2.0. It works with no problems. There's a compiler warning, because the used overload of PerformanceCounterCategory.Create is deprecated. But I can compile and run the sample.


Regards,
Michael
GeneralRe: vs2005
MsgDev
5:02 23 Mar '07  
Strange. Mine converts and builds OK. I run it, it creates the counters, but the values are never updated. Performance monitor always reads zero for the values. Stepping through the code shows that the values are incremented.
GeneralRe: vs2005
Michael Groeger
5:25 23 Mar '07  
Did you use the sample code? Or did modify something?
AnswerRe: vs2005
MsgDev
4:56 26 Mar '07  
Actually I didn't change anything but after a reboot of my system it started working.


Not sure why that would do it but it did.


Sorry I didn't try that first.



Last Updated 21 Feb 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010