When the Performance Monitoring provider is being used as an instance provider, the WMI class that is to house the performance data should roughly correspond to a given Performance Monitor object. Therefore, if your objective is to monitor the CPU performance, a WMI class should look like the Processor object in Performance Monitor. Then each property of the WMI class will relate to the respective counter name within the Processor object. For instance, in order to be able to retrieve the value of the "% User Time" counter, the WMI class definition should contain a property that corresponds to this counter.

Although you can certainly look up the counter names and their associated descriptions using the Performance Monitor GUI, doing this programmatically is a lot more fun. Coincidentally, the System.Diagnostics namespace contains a few types that come in very handy when you are working with performance counters. For example, the following code snippet will print out the names and descriptions of all performance counters that make up the Processor object:

using System;
using System.Diagnostics;
class CounterHelper {
public static void Main(string[] args) {
PerformanceCounterCategory cat =
new PerformanceCounterCategory("Processor");
foreach(PerformanceCounter cntr in cat.GetCounters("0")) {
Console.WriteLine("{0}: {1}", cntr.CounterName, cntr.CounterHelp);
}
}
}

This code is extremely simple. First, it creates an instance of PerformanceCounterCategory type, which refers to the Processor object of Performance Monitor. It then enumerates all counters within the Processor object that are returned by the GetCounters method of the PerformanceCounterCategory object. This method takes a single string parameter, which represents the name of the performance object instance. It is always safe to use "0" when dealing with Processor objects because any machine will always have at least one CPU. Finally, for each counter object returned, the code prints out the values of two properties: CounterName, which contains the display name of the counter, and CounterHelp, which is essentially a counter description. The output produced by this code resembles the following:

% Processor Time: Processor Time is expressed as a percentage of the elapsed
time that a processor is busy executing a non-Idle thread. It can be viewed as
the fraction of the time spent doing useful work. Each processor is assigned an
Idle thread in the Idle process, which consumes those unproductive processor
cycles not used by any other threads.
% User Time: User Time is the percentage of processor time spent in User Mode in
non-Idle threads. All application code and subsystem code executes in User
Mode. The graphics engine, graphics device drivers, printer device drivers,
and the window manager also execute in User Mode....

Once all required properties of a WMI class are identified, the class can be defined as follows:

[Dynamic, Provider("PerformanceMonitorProvider"),
ClassContext("local|Processor")]
class PerfMon_Processor {
[key]
string Processor;
[PropertyContext("% Processor Time")]
real32 ProcessorTime;
[PropertyContext("% User Time")]
real32 UserTime;
[PropertyContext("% Privileged Time")]
real32 PrivilegedTime;
[PropertyContext("Interrupts/sec")]
real32 Interrupts;
[PropertyContext("% DPC Time")]
real32 DPCTime;
[PropertyContext("% Interrupt Time")]
real32 InterruptTime;
[PropertyContext("DPCs Queued/sec")]
real32 DPCsQueued;
[PropertyContext("DPC Rate")]
real32 DPCRate;
[PropertyContext("DPC Bypasses/sec")]
real32 DPCBypasses;
[PropertyContext("APC Bypasses/sec")]
real32 APCBypasses;
};

Note, it is not really necessary for a WMI class definition to include the properties that refer to each and every counter within a given performance object. You can simply pick just those properties in which you are interested.

You may have noticed a couple of class and property qualifiers here that may seem unfamiliar. The first one is the Dynamic class qualifier; it simply indicates that a provider backs instances of a particular class. The Provider qualifier establishes the binding between the class and its provider; its string parameter refers to the name of __Win32Provider instance, which represents the provider registration. The ClassContext qualifier establishes the mapping between the WMI class and a particular performance object. Its parameter is a string that may contain a number of tokens separated by a vertical bar (|). The first token represents the name of the computer that houses the performance object of interest. The second token is the name of the performance object to bind to. Finally, there is the PropertyContext qualifier, which establishes the binding between a particular property of the WMI class and its respective performance counter. This qualifier's parameter is a display name of the associated performance counter.

Yet another thing to notice is the Processor property, marked with the Key qualifier. Since performance objects are represented by instances of WMI classes, every such instance must have a unique identity. Thus, the Performance Monitoring provider will automatically set the Processor property to the instance ID of the respective CPU. For instance, on a dual-CPU machine, the provider will create two instances of the PerfMon_Processor class, with their Processor properties set to 0 and 1 respectively.

Once compiled and saved into the CIM Repository, the PerfMon_Processor class is ready to be used. Accessing the performance data is no different from accessing instances of any other WMI classes. Thus, the following snippet of code continuously prints out some statistics for CPU 0:

using System;
using System.Management;

class CPUMonitor {
public static void Main(string[] args) {
while(true) {
ManagementObject mo = new ManagementObject("PerfMon_Processor='0'");
Console.WriteLine("% Processor Time: {0}", mo["ProcessorTime"]);
Console.WriteLine("% User Time: {0}", mo["UserTime"]);
Console.WriteLine("% Privileged Time: {0}", mo["PrivilegedTime"]);
System.Threading.Thread.Sleep(5000);
}
}
}

Note that every iteration of the while loop recreates the instance of ManagementObject type. Although seemingly inefficient at first, this is necessary in order to refresh the performance data. As you may remember, a property access operation invokes the IWbemClassObject::Get method, which always fetches the locally cached property value. Therefore, unless the instance of the ManagementObject type is rebound to its underlying WMI object, its properties will not be refreshed.

Generally, mapping performance objects to WMI classes is straightforward—a particular performance object category corresponds to a WMI class, counters correspond to the class properties, and performance objects map to instances of WMI classes. However, there are certain performance objects that do not easily yield themselves to this kind of modeling. The TCP object, for instance, which contains a slew of TCP/IP statistical counters, does not have any instances. Consider the following WMI class, which may be used to retrieve TCP/IP performance data:

[Dynamic, Provider("PerformanceMonitorProvider"), ClassContext("local|TCP")]
class PerfMon_TCP {
[Key]
string KeyProp;
[PropertyContext("Segments/sec")]
real32 Segments;
[PropertyContext("Connections Established")]
real32 ConnectionsEstablished;
[PropertyContext("Connections Active")]
real32 ConnectionsActive;
[PropertyContext("Connections Passive")]
real32 ConnectionsPassive;
[PropertyContext("Connection Failures")]
real32 ConnectionFailures;
[PropertyContext("Connections Reset")]
real32 ConnectionsReset;
[PropertyContext("Segments Received/sec")]
real32 SegmentsReceived;
[PropertyContext("Segments Sent/sec")]
real32 SegmentsSent;
[PropertyContext("Segments Retransmitted/sec")]
real32 SegmentsRetransmitted;
};

The class definitions in this code look very similar to those for the performance Processor object; however, it is unclear how you can access the individual instances of this class since the TCP performance object is global. One way to do this is to bind to a class and then enumerate its instances:

using System;
using System.Management;

class TCPMonitor {
public static void Main(string[] args) {
ManagementClass mc = new ManagementClass("PerfMon_TCP");
foreach(ManagementObject mo in mc.GetInstances()) {
Console.WriteLine("Key: {0}", mo["KeyProp"]);
}
}
}

Running the preceding code reveals a single instance with its KeyProp key property set to @. This means that the TCP performance object essentially maps to a singleton WMI class. Therefore, the WMI class definition above should be changed as follows:

[Singleton, Dynamic, Provider("PerformanceMonitorProvider"), ClassContext("local|TCP")]
class PerfMon_TCP {
[PropertyContext("Segments/sec")]
real32 Segments;
[PropertyContext("Connections Established")]
real32 ConnectionsEstablished;
[PropertyContext("Connections Active")]
real32 ConnectionsActive;
[PropertyContext("Connections Passive")]
real32 ConnectionsPassive;
[PropertyContext("Connection Failures")]
real32 ConnectionFailures;
[PropertyContext("Connections Reset")]
real32 ConnectionsReset;
[PropertyContext("Segments Received/sec")]
real32 SegmentsReceived;
[PropertyContext("Segments Sent/sec")]
real32 SegmentsSent;
[PropertyContext("Segments Retransmitted/sec")]
real32 SegmentsRetransmitted;
};
There are two things to notice here: first, the class is marked with the Singleton qualifier; second, there is no key property because singletons are not required to have a unique identity. Therefore, the code to retrieve the TCP performance data can be simplified as follows:

using System;
using System.Management;

class TCPMonitor {
public static void Main(string[] args) {
while(true) {
ManagementObject mo = new ManagementObject("PerfMon_TCP=@");
Console.WriteLine("Connections Established: {0}",
mo["ConnectionsEstablished"]);
Console.WriteLine("Connections Active: {0}", mo["ConnectionsActive"]);
Console.WriteLine("Connections Passive: {0}", mo["ConnectionsPassive"]);
System.Threading.Thread.Sleep(5000);
}
}
}

Source of Information : Dot NET System Management Services - Apress

0 comments


Subscribe to Developer Techno ?
Enter your email address:

Delivered by FeedBurner