Thursday, January 12, 2012

Performance Counters in .Net


Introduction

Performance counters allow us to monitor physical devices such as Processor, Memory, CLR, Network, Threads etc. Windows provides performance monitor utility to view performance counters. To open that utility need to go to Start -> Run and type “perfmon” and press enter. Below is the screenshot of Performance Monitor utility.



This application monitors various system components, as per above image it displays the processor time utilization. There are multiple performance counters available to monitor different devices. Those performance counters are grouped under categories. Below screenshot displays Add Counter window of performance monitor utility.



Above image displays various categories like Processor, Process, Print Queue, Power Meter etc. Each category has its own counters, as per above image Processor category has “% C1 Time”, “% C2 Time” and so on. Category may have instances and if it has then it will be displayed in instance list. Instance list of selected category is available below the category list. 

Enumerating available categories

Dotnet provides PerformanceCounterCategory class to get all the categories of performance counters. This class is available in System.Diagnostics namespace. GetCategories methods returns collection of PerformanceCounterCategory. Let’s have a look on below code.

//Get all performance categories
PerformanceCounterCategory[] perfCats = PerformanceCounterCategory.GetCategories();
foreach (PerformanceCounterCategory category in perfCats.OrderBy(c => c.CategoryName))
{
    Console.WriteLine("Category Name: {0}", category.CategoryName);
}

Output –

Category Name: .NET CLR Data
Category Name: .NET CLR Exceptions
Category Name: .NET CLR Interop
Category Name: .NET CLR Jit
Category Name: Active Server Pages
Category Name: APP_POOL_WAS
Category Name: ASP.NET
Category Name: Per Processor Network Interface Card Activity
Category Name: PhysicalDisk
Category Name: Print Queue
Category Name: Process
Category Name: Processor



The above code displays all available performance counter categories order by category name.

Performance Counters by Category

Below example demonstrates how we can get all the performance counters for given category. We can also get all the counters for all the categories if you don’t specify category name in below code but it will take a while to execute. So in below code I have retrieved performance counters only for "Memory" category.

//Get all performance categories
PerformanceCounterCategory[] perfCats = PerformanceCounterCategory.GetCategories();

//Get single category by category name.
PerformanceCounterCategory cat = perfCats.Where(c => c.CategoryName == "Memory").FirstOrDefault();
Console.WriteLine("Category Name: {0}", cat.CategoryName);

//Get all instances available for category
string[] instances = cat.GetInstanceNames();
if (instances.Length == 0)
{
    //This block will execute when category has no instance.
    //loop all the counters available withing category
    foreach (PerformanceCounter counter in cat.GetCounters())
        Console.WriteLine("     Counter Name: {0}", counter.CounterName);
}
else
{
    //This block will execute when category has one or more instances.
    foreach (string instance in instances)
    {
        Console.WriteLine("  Instance Name: {0}", instance);
        if (cat.InstanceExists(instance))
            //loop all the counters available withing category
            foreach (PerformanceCounter counter in cat.GetCounters(instance))
                Console.WriteLine("     Counter Name: {0}", counter.CounterName);
    }
}

Output –

Category Name: Memory
     Counter Name: Page Faults/sec
     Counter Name: Available Bytes
     Counter Name: Committed Bytes
     Counter Name: Commit Limit
     Counter Name: Write Copies/sec
     Counter Name: Transition Faults/sec
     Counter Name: Cache Faults/sec
     Counter Name: Demand Zero Faults/sec
     Counter Name: Pages/sec
     Counter Name: Pages Input/sec
     Counter Name: Page Reads/sec
     Counter Name: Pages Output/sec
     Counter Name: Pool Paged Bytes
     Counter Name: Pool Nonpaged Bytes
     Counter Name: Page Writes/sec
     Counter Name: Pool Paged Allocs
     Counter Name: Pool Nonpaged Allocs
     Counter Name: Free System Page Table Entries
     Counter Name: Cache Bytes
… … …

The above code returns name of the counters available in 'Memory' category. Memory category doesn’t contain any instances so it will list all the performance counters without displaying instance name. We can also execute same code for category which has instances. So let’s execute the same code with “Processor” category.

PerformanceCounterCategory cat = perfCats.Where(c => c.CategoryName == "Processor").FirstOrDefault();

Output –

Category Name: Processor
  Instance Name: _Total
     Counter Name: % Processor Time
     Counter Name: % User Time
     Counter Name: % Privileged Time
     Counter Name: Interrupts/sec
     Counter Name: % DPC Time
     Counter Name: % Interrupt Time
     Counter Name: DPCs Queued/sec
     Counter Name: DPC Rate
     Counter Name: % Idle Time
     Counter Name: % C1 Time
     Counter Name: % C2 Time
     Counter Name: % C3 Time
     Counter Name: C1 Transitions/sec
     Counter Name: C2 Transitions/sec
     Counter Name: C3 Transitions/sec
  Instance Name: 0
     Counter Name: % Processor Time
     Counter Name: % User Time
     Counter Name: % Privileged Time
     … … …
  Instance Name: 1
     Counter Name: % Processor Time
     Counter Name: % User Time
     Counter Name: % Privileged Time
     … … …

As per change in category of above code, now output displays all the performance counters available in 'Processor' category. Processor category has three instances so it will list all the performance counters with instance name.

Reading Performance Counter Value

PerformanceCounter class used to retrieve value of performance counter. This class is also available in System.Diagnostics namespace. We need to pass CategoryName, CounterName and InstanceName (Optional) to PerformanceCounter class constructor or we need to set those properties to performance counter instance explicitly. Performance counter instance has NextValue method which can be used to retrieve the value of give performance counter. 

Let’s have a look on below code.

DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0,0,1);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();

void timer_Tick(object sender, EventArgs e)
{
    using (PerformanceCounter perfCounter = new PerformanceCounter("Memory",
             "Available MBytes"))
    {
        float value = perfCounter.NextValue();
        Console.WriteLine("Total Memory Available: {0} MB.", value);
    }
}

Output –

Total Memory Available: 236 MB.
Total Memory Available: 239 MB.
Total Memory Available: 236 MB.
Total Memory Available: 231 MB.
Total Memory Available: 218 MB.
Total Memory Available: 221 MB.
Total Memory Available: 237 MB.
Total Memory Available: 237 MB.



Adding custom categories and counters

The new counters and categories can be added and measured through C# code. Dotnet provides PerformanceCounterCategory class to create new category and CounterCreationData class to create new performance counter.  You can create multiple counters under single category. The create method of PerformanceCounterCategory accepts collection of CounterCreationData. Let’s have a look on below code.

string category = "MyCategory";
string counter1 = "Counter1";
//Check whether category is exist or not
if (!PerformanceCounterCategory.Exists(category))
{
    //creates collection of CounterCreationData
    CounterCreationDataCollection counterDataCollection =
           new CounterCreationDataCollection();

    //added new CounterCreationData to counterDataCollection
    counterDataCollection.Add(new CounterCreationData(counter1,
          "My custom counter", PerformanceCounterType.NumberOfItems32));

    //Creates new category based on information and creates
      counters available in counter data collection
    PerformanceCounterCategory.Create(category, "My Category", PerformanceCounterCategoryType.SingleInstance, counterDataCollection);
}

Output –

As per above image from performance monitor tool, MyCategory is created and Counter1 is added to it. You can delete category by calling PerformanceCounterCategory.Delete method. To create and delete performance counters and categories you need administrative privileges



See Also –

4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. hi, excellent work. its very useful. i have found the APP_POOL_WAS performance counter in iis7 on "Windows 7" OS. I Check the same counter in "Microsoft® Windows Server® 2008 Standard" server, but i couldn't find it. server has iis7 version. why its not visible in the windows server 2008.?

    ReplyDelete
  3. Really Nice Information,Thank You Very Much For Sharing.
    Web Development Company

    ReplyDelete
  4. What's about performance in ASP.NET page using PerformanceCounter class for ASP.NET PerformanceCounters ?

    ReplyDelete