Windows Management Instrumentation (WMI) and Performance Monitoring

By ServerWatch Staff (Send Email)
Posted Jul 18, 2001


by Marcin Policht


Performance statistics are typically retrieved using the Windows 2000 System Monitor. However, if you want to automate the data collection process, you also have the option of using Windows Management Instrumentation (WMI).

WMI is one of the technologies integrated by Microsoft in Windows 2000 (and the upcoming XP and .NET). It offers a powerful set of system management features, available through scripting API. WMI accesses managed environments by employing COM objects called providers. Each provider is responsible for handling communication between WMI and data generated by a software or hardware component.

In the case of performance monitoring, this data is generated by performance libraries according to settings stored in the registry. These registry values are also read during AutoDiscovery/AutoPurge (ADAP) processes which take place every time the WMI service starts. Performance statistics are typically retrieved using the Windows 2000 System Monitor. However, if you want to automate the data collection process, you also have the option of using Windows Management Instrumentation (WMI). In the first of two articles on WMI, Marcin Policht describes in detail interaction with the WMI Performance Counter Provider.

WMI uses this information to populate its internal database, called the repository, with the list of counter objects registered with the system. The repository is arranged in a complex hierarchy of inter-related classes (some of them linked by parent-child relationships).

Performance related classes can be found by enumerating children of the Win32_PerfRawData class. Here is a short script GetPerfClasses.vbs, which accomplishes this task:


'*********************************************
'*** assign values to variables
strClass = "Win32_PerfRawData"
strNamespace = "root/cimv2"
strComputer = WScript.Arguments(0)

'*********************************************
'*** connect to WMI using moniker and retrieve collection of
'*** all subclasses of Win32_PerfRawData
Set colSubClasses = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _
                                     strComputer & "/" & strNameSpace).SubclassesOf(strClass)

'*********************************************
'*** enumerate all of the Subclasses in the For loop
For Each objSubClass In colSubClasses
                  WScript.Echo objSubClass.Path_.Class
Next

In order to list performance classes on the TARGET-SYSTEM computer, you would run:

cscript //nologo GetPerfClasses.vbs TARGET-SYSTEM

The results would resemble the following list:

Win32_PerfRawData_ContentFilter_IndexingServiceFilter
Win32_PerfRawData_ContentIndex_IndexingService
Win32_PerfRawData_IAS_IASAuthenticationServer
Win32_PerfRawData_IAS_IASAuthenticationClients
Win32_PerfRawData_IAS_IASAccountingServer
Win32_PerfRawData_IAS_IASAccountingClients
Win32_PerfRawData_ISAPISearch_HttpIndexingService
Win32_PerfRawData_MSDTC_DistributedTransactionCoordinator
Win32_PerfRawData_PerfDisk_PhysicalDisk
Win32_PerfRawData_PerfNet_Server
Win32_PerfRawData_PerfNet_ServerWorkQueues
Win32_PerfRawData_PerfNet_Redirector
Win32_PerfRawData_PerfNet_Browser
Win32_PerfRawData_PerfOS_Cache
Win32_PerfRawData_PerfOS_Processor
Win32_PerfRawData_PerfOS_Memory
Win32_PerfRawData_PerfOS_Objects
Win32_PerfRawData_PerfOS_PagingFile
Win32_PerfRawData_PerfOS_System
Win32_PerfRawData_PerfProc_Process
Win32_PerfRawData_PerfProc_Thread
Win32_PerfRawData_PerfProc_JobObject
Win32_PerfRawData_PerfProc_JobObjectDetails
Win32_PerfRawData_PerfProc_ProcessAddressSpace_Costly
Win32_PerfRawData_PerfProc_Image_Costly
Win32_PerfRawData_PerfProc_FullImage_Costly
Win32_PerfRawData_PerfProc_ThreadDetails_Costly
Win32_PerfRawData_RemoteAccess_RASPort
Win32_PerfRawData_RemoteAccess_RASTotal
Win32_PerfRawData_RSVP_ACSPerRSVPService
Win32_PerfRawData_Spooler_PrintQueue
Win32_PerfRawData_TapiSrv_Telephony
Win32_PerfRawData_Tcpip_NBTConnection
Win32_PerfRawData_Tcpip_NetworkInterface
Win32_PerfRawData_Tcpip_IP
Win32_PerfRawData_Tcpip_ICMP
Win32_PerfRawData_Tcpip_TCP
Win32_PerfRawData_Tcpip_UDP


The naming reflects the fact that data accessible via these classes is presented in a raw format (which might require additional calculations). Class names also clearly indicate the types of objects they represent (for example Win32_PerfRawData_PerfOS_Processor corresponds to Processor object visible in System Monitor, Win32_PerfRawData_PerfOS_Memory is equivalent to Memory object, etc).

A class can have one or more instance, depending on the number of instances of performance objects (e.g. 2 instances of the Win32_PerfRawData_PerfOS_Processor class on a dual CPU system). Each class also has a set of properties, with names matching the names of object counters in System Monitor. Besides its data type, each property, in turn, also has a set of additional characteristics, specified by qualifiers. One of them, called CounterType, determines what type of additional calculations might be necessary to translate the raw property value into the form appearing in the System Monitor.


Performance Counter Provider

Windows 2000 supports two types of WMI providers, which allow access to performance data:
- Performance Counter Provider
- Performance Monitor Provider

This article will describe interaction with Performance Counter Provider (the Performance Monitor Provider will be covered in my next article). Performance Counter Provider is installed by default in Windows 2000, so it's readily available (unlike the Performance Monitor Provider, which has to be properly registered). However, the data available through this provider appears in "raw" (non-calculated) format.

As described before, the CounterType qualifier for each property of an appropriate Win32_PerfRawData WMI class can be used to determine how to derive useful information. CounterType is a numeric value, which is described by CookingType string. You can find references to each of the CookingType strings in the Windows 2000 Resource Kit. Here is the list of CounterType values and corresponding CookingType strings, as specified in the Microsoft Platform Software Development Kit:

CounterType Value CounterType String
0 PERF_COUNTER_RAWCOUNT_HEX
256 PERF_COUNTER_LARGE_RAWCOUNT_HEX
2816 PERF_COUNTER_TEXT
65536 PERF_COUNTER_RAWCOUNT
65792 PERF_COUNTER_LARGE_RAWCOUNT
73728 PERF_DOUBLE_RAW
4195328 PERF_COUNTER_DELTA
4195584 PERF_COUNTER_LARGE_DELTA
4260864 PERF_SAMPLE_COUNTER
4523008 PERF_COUNTER_QUEUELEN_TYPE
4523264 PERF_COUNTER_LARGE_QUEUELEN_TYPE
5571840 PERF_COUNTER_100NS_QUEUELEN_TYPE
6620416 PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE
272696320 PERF_COUNTER_COUNTER
272696576 PERF_COUNTER_BULK_COUNT
537003008 PERF_RAW_FRACTION
541132032 PERF_COUNTER_TIMER
541525248 PERF_PRECISION_SYSTEM_TIMER
542180608 PERF_100NSEC_TIMER
542573824 PERF_PRECISION_100NS_TIMER
543229184 PERF_OBJ_TIME_TIMER
543622400 PERF_PRECISION_OBJECT_TIMER
549585920 PERF_SAMPLE_FRACTION
557909248 PERF_COUNTER_TIMER_INV
558957824 PERF_100NSEC_TIMER_INV
574686464 PERF_COUNTER_MULTI_TIMER
575735040 PERF_100NSEC_MULTI_TIMER
591463680 PERF_COUNTER_MULTI_TIMER_INV
592512256 PERF_100NSEC_MULTI_TIMER_INV
805438464 PERF_AVERAGE_TIMER
807666944 PERF_ELAPSED_TIME
1073742336 PERF_COUNTER_NODATA
1073874176 PERF_AVERAGE_BULK
1073939457 PERF_SAMPLE_BASE
1073939458 PERF_AVERAGE_BASE
1073939459 PERF_RAW_BASE
1073939712 PERF_PRECISION_TIMESTAMP
1073939715 PERF_LARGE_RAW_BASE
1107494144 PERF_COUNTER_MULTI_BASE
2147483648 PERF_COUNTER_HISTOGRAM_TYPE


You can collect the performance data by querying values of instances of Win32_PerfRawData subclasses with the following script:

'*********************************************
'*** ignore run-time errors
On Error Resume Next

'*********************************************
'*** assign values to variables
strClass= WScript.Arguments(0)
strNamespace = "root/cimv2"
strComputer = WScript.Arguments(1)

'*********************************************
'*** connect to WMI using moniker and retrieve collection of
'*** all instances of class specified as the script argument
Set colInstances = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _
                                     strComputer & "/" & strNameSpace).InstancesOf(strClass)

'*********************************************
'*** enumerate values and CounterType qualifier for each
'*** property of each instance of the specified class
For Each objInstance In colInstances
                For Each objProperty In objInstance.Properties_ 
                                   WScript.Echo objProperty.Name & Chr(9) & _
                                                objProperty.Value & Chr(9) & objProperty.Qualifiers_.Item("countertype")
                Next
Next


If you save this script as GetPerfCounters.vbs, by running the following:

cscript //nologo GetPerfCounters.vbs Win32_PerfRawData_PerfOS_Memory TARGET-SYSTEM

you would generate the listing containing properties, their current values, and CounterType qualifier values of an instance of Win32_PerfRawData_PerfOS_Memory class on the TARGET_SYSTEM computer. Here is a sample listing:

Property Name Property Value CounterType Value
AvailableBytes 27213824 65792
AvailableKBytes 26576 65792
AvailableMBytes 25 65792
CacheBytes 32694272 65792
CacheBytesPeak 32866304 65792
CacheFaultsPersec 138566 272696320
CommitLimit 318345216 65792
CommittedBytes 96124928 65792
DemandZeroFaultsPersec 146738 272696320
FreeSystemPageTableEntries 194787 65536
PageFaultsPersec 262541 272696320
PageReadsPersec 21992 272696320
PagesInputPersec 41788 272696320
PagesOutputPersec 2816 272696320
PagesPersec 44604 272696320
PageWritesPersec 176 272696320
PercentCommittedBytesInUse 23468 537003008
PercentCommittedBytesInUse_Base 77721 1073939459
PoolNonpagedAllocs 14326 65536
PoolNonpagedBytes 3489792 65792
PoolPagedAllocs 23324 65536
PoolPagedBytes 21929984 65792
PoolPagedResidentBytes 21753856 65792
SystemCacheResidentBytes 7221248 65792
SystemCodeResidentBytes 3428352 65792
SystemCodeTotalBytes 774144 65792
SystemDriverResidentBytes 290816 65792
SystemDriverTotalBytes 1966080 65792
TransitionFaultsPersec 86606 272696320
WriteCopiesPersec 5083 272696320


Note that the names of counters correspond to the ones presented in the System Monitor. Their values are meaningful in some cases (such as AvailableBytes, listing total number of Available Bytes), while in others they don't seem to make any sense. Such values need to be recalculated according to a formula dependent on the counter type. Here is an example: PagesPersec has the CounterType qualifier equal to 272696320, which corresponds to PERF_COUNTER_COUNTER Counter Type string. According to the description in the Windows 2000 Resource Kit, the formula for calculating the actual value of the Pages/Sec counter of Memory object is:

(N1 - N0)/((D1 - D0)/F)

where (N1 - N0) is the number of operations during monitoring interval and (D1 - D0) is a number of processor ticks during this interval. F represents frequency of the ticks. Ticks are basic units of measuring length of time during which a thread can execute. Each thread is assigned a quantum, which is a multiple of clock intervals. Value of a tick is hardware dependent (you can measure it using a tool from www.sysinternals.com called CLOCKRES.EXE) and is typically in a range of 10 - 15 ms.

If you set the value of interval high enough, you might get approximate results by measuring time interval in seconds, rather than in ticks. For example, the following script compares the number of pages per second during arbitrarily set time intervals. The script captures values of the monitored counter at the beginning (value N0) and the end of the interval (value N1). The difference between N1 and N0 is divided by number of seconds in the interval. This procedure is repeated in the infinite loop - if you decide to end the script, press Ctrl+C at the Command Prompt window from which you launched it.

'*********************************************
'*** assign values to variables
strClass = "Win32_PerfRawData_PerfOS_Memory"
strNamespace = "root/cimv2"
strProperty = "PagesPersec"
intInterval = WScript.Arguments(0) 'interval (in seconds)
strComputer = WScript.Arguments(1) 'target computer name

'*********************************************
'*** connect to WMI using moniker and retrieve collection of
'*** all instances of class specified as the script argument
Set colInstances = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _ 
                                      strComputer & "/" & strNameSpace).InstancesOf(strClass)

'*********************************************
'*** capture the initial value of the Counter you want to monitor
For Each objInstance In colInstances
                intN0 = objInstance.Properties_.Item(strProperty)
                WScript.Echo intN0 Next

'*********************************************
'*** destroy the objects and collections you created
Set objInstance = Nothing
Set colInstances = Nothing

'*********************************************
'*** in the infinite loop, capture the Counter value at
'*** the end of the interval
While True

        '*********************************************
        '*** go to sleep for intInverval seconds
        WScript.Sleep(intInterval * 1000)

        '*********************************************
        '*** connect to WMI using moniker and retrieve collection of
        '*** all instances of class specified as the script argument
        Set colInstances = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _
                                             strComputer & "/" & strNameSpace).InstancesOf(strClass)

        '********************************************* 
        '*** capture the final value of the Counter you want to monitor
        For Each objInstance In colInstances
                    intN1 = objInstance.Properties_.Item(strProperty)
                    WScript.Echo intN1
        Next

        '*********************************************
        '*** display the result 
        WScript.Echo strProperty & Chr(9) & (intN1 - intN0)/(intInterval)

        '*********************************************
        '*** get ready for the next loop
        Set objInstance = Nothing
        Set colInstances = Nothing
        intN0 = intN1
Wend


If you save this script as GetCounter.vbs, in order to monitor the counter in 5 second intervals on a TARGET-SYSTEM computer, you would run:

cscript //nologo GetCounter.vbs 5 TARGET-SYSTEM


As you can see, the process of collecting performance data with WMI is fairly complex. Using Performance Monitor Provider simplifies this slightly. I will describe the procedure for implementing it in my next article. Fortunately, Windows XP offers considerable improvements in Performance Monitoring capabilities by introducing new providers, presenting calculated data directly.

In case you want to learn more about WMI (including how to manage Windows processes, services, even logs, scheduled tasks, Windows Installer applications, etc.) check out my recently released book:

WMI Essentials for Automating Windows Management

Page 1 of 1


Comment and Contribute

Your name/nickname

Your email

(Maximum characters: 1200). You have characters left.