19.6 Performance Counters
Event logs are useful for capturing application status that is
not of a time-sensitive nature, yet needs to be recorded for future
analysis. However, to gain insight into the current state of an
application (or the system as a whole), a more real-time approach is
needed.
The Win32 solution to this need is the performance-monitoring
infrastructure, which consists of a set of performance counters that
the system and applications expose, and the Microsoft Management Console (MMC) snap-ins
used to monitor these counters in real time.
Performance counters are grouped into categories such as
"System,"
"Processor," ".NET
CLR Memory," and so on. These categories are
sometimes also referred to as "performance
objects" by the GUI tools. Each category groups a
related set of performance counters that monitor one aspect of the
system or application. Examples of performance counters in the
".NET CLR Memory" category include
"% Time in GC," "#
Bytes in All Heaps," and "Allocated
bytes/sec."
Each category may optionally have one or more instances that can be
monitored independently. For example, this is useful in the
"% Processor Time" performance
counter in the "Processor"
category, which allows one to monitor CPU utilization. On a
multiprocessor machine, this counter supports an instance for each
CPU, allowing one to monitor the utilization of each CPU
independently.
The following sections illustrate how to perform commonly needed
tasks, such as determining which counters are exposed, monitoring a
counter, and creating your own counters to expose application status
information.
19.6.1 Enumerating the Available Counters
In the following example, enumerate
all
of the available performance counters on the system. To do this,
first retrieve a list of the categories, then iterate through the
list displaying the counters and instances for each category, as
follows:
// DumpCounters.cs
using System;
using System.Diagnostics;
class DumpCounters {
static void Main( ) {
PerformanceCounterCategory[ ] cats;
cats = PerformanceCounterCategory.GetCategories( );
foreach (PerformanceCounterCategory cat in cats) {
try {
Console.WriteLine("Category: {0}", cat.CategoryName);
string[ ] instances = cat.GetInstanceNames( );
if (instances.Length = = 0) {
// Dump counters without instances
foreach (PerformanceCounter ctr in cat.GetCounters( ))
Console.WriteLine(" Counter: {0}", ctr.CounterName);
} else {
// Dump counters with instances
foreach (string instance in instances) {
Console.WriteLine(" Instance: {0}", instance);
foreach (PerformanceCounter ctr in cat.GetCounters(instance))
Console.WriteLine(" Counter: {0}", ctr.CounterName);
}
}
} catch (Exception e) { // Some perf counters don't provide details
Console.WriteLine("Exception: {0}", e.Message);
}
}
}
}
19.6.2 Reading Performance Counter Data
The following sample demonstrates
how to retrieve the current value for an
arbitrary performance counter. It incorporates error-handling code to
illustrate how to verify category, counter, and instance name before
attempting to read a performance counter value. Use the preceding
DumpCounters sample to enumerate the available
categories, counters, and instances on your machine, and pass them to
the sample on the command line:
// WatchCounter.cs - use WatchCounter <category> <counter> [<instance>]
using System;
using System.Threading;
using System.Diagnostics;
class WatchCounter {
static void Main(string[ ] args) {
// Extract the parameters
string cat = args[0], ctr = args[1];
string inst = (args.Length= =3) ? args[2] : "";
// Check the category is OK
if (!PerformanceCounterCategory.Exists(cat)) {
Console.WriteLine("Unknown category {0}", cat);
return;
}
// Check the counter is OK
if (!PerformanceCounterCategory.CounterExists(ctr, cat)) {
Console.WriteLine("Unknown counter {0}", ctr);
return;
}
// Check the instance is OK
if (inst.Length>0 &&
!PerformanceCounterCategory.InstanceExists(inst, cat)) {
Console.WriteLine("Unknown instance {0}", inst);
return;
}
// Spin in a loop, dumping the counter
Console.WriteLine("Press <ctrl+c> to end");
PerformanceCounter pc = new PerformanceCounter(cat, ctr, inst);
while (true) {
Console.WriteLine("Counter value is {0}", pc.NextValue( ));
Thread.Sleep(1000); // No! Bad programmer!
}
}
}
19.6.3 Adding a New Performance Counter
To expose real-time status information
about your applications, instantiate a read/write
PerformanceCounter object with the name of an
existing category, the name of the new counter, and the name of the
new instance, then update the value of the counter as the application
status changes. The following sample demonstrates how to create your
own counter and expose application status values through it. (To
watch the changing counter values, use the preceding
WatchCounter sample.)
// WriteCounter.cs - use WriteCounter <category> <counter> [<instance>]
using System;
using System.Threading;
using System.Diagnostics;
class WriteCounter {
static void Main(string[ ] args) {
// Extract the parameters
string cat = args[0], ctr = args[1];
string inst = (args.Length= =3) ? args[2] : "";
// Create the category if it doesn't already exist
if (!PerformanceCounterCategory.Exists(cat)) {
PerformanceCounterCategory.Create(cat, "", ctr, "");
}
// Check the counter is OK
if (!PerformanceCounterCategory.CounterExists(ctr, cat)) {
Console.WriteLine("Unknown counter {0}", ctr);
return;
}
// Create a new read/write counter & instance for an existing category
PerformanceCounter pc = new PerformanceCounter(cat, ctr, inst, false);
// Create counter and spin in a loop, incrementing it
Console.WriteLine("Press <ctrl+c> to end");
while (true) {
Console.WriteLine("Incrementing counter...");
pc.Increment( );
Thread.Sleep(1000); // No! Bad programmer!
}
}
}
|