Monitoring Processes for Performance

Microsoft® Windows® 2000 Scripting Guide

Performance monitoring is typically directed at entire systems; for example, administrators often monitor such things as the available bytes of memory or total processor use on a computer. This kind of monitoring is extremely useful because it identifies problems, such as rapid diminution of available memory, that can have a detrimental effect on the performance of the computer itself. However, monitoring performance of the system as a whole typically does not indicate why memory is diminishing. To help answer that question, you can monitor the performance of individual processes.

Monitoring the performance of individual processes is particularly useful when you are trying to identify memory leaks. To help diagnose memory leaks in Windows 2000, you can monitor several process properties, including:

  • Threads and pool space. If a process is leaking memory, the number of threads owned by the process and the amount of pool space used increase in a stair-step pattern. The usage of both threads and pool space remain flat for a while, jump dramatically, and then remain flat again. This pattern can repeat indefinitely, with threads and pool space both increasing over time. If a process releases threads and pool space appropriately, these totals remain relatively stable over time.

  • Working set size. The working set is the amount of physical memory assigned to a process. If the working set is too small, the process incurs a high number of page faults as it repeatedly accesses the disk drive to locate data not currently in memory. If the working set is too large, fewer page faults occur, but the process retains memory that it no longer needs, and which might be required by other processes. A steady increase in the size of the working set can mean that the process is not releasing memory appropriately.

  • Page file bytes. Page file bytes typically correspond to memory consumption. Memory leaks often cause a similar increase in both the working set size and the page file bytes.

  • Processor use. Processor use is determined in part by the number of threads allocated to a process. A process that is not destroying threads receives a disproportionate amount of processor time.

All of these key indicators of process performance can be monitored by using WMI. A list of important process properties available through the Win32_Process class is shown in Table 14.1.

Table 14.1 WMI Win32_Process Properties

Property

Description

ExecutablePath

Local path to the executable file.

ExecutionState

Current status of the process. Valid values are:

0 - Unknown

1 - Other

2 - Ready

3 - Running

4 - Blocked

5 - Suspended Blocked

6 - Suspended Ready

KernelModeTime

Kernel mode usage, in milliseconds.

Name

Name of the executable file responsible for the process, equivalent to the Image Name property in Task Manager.

The name is hard-coded into the application itself and is not affected by changing the file name. For example, even if you rename Calc.exe, the name Calc.exe will still appear in Task Manager and in any WMI scripts that retrieve the process name.

PageFaults

Number of page faults generated by the process.

PageFileUsage

Amount of page file space (in kilobytes) currently used by the process.

PeakWorkingSetSize

Maximum size of the working set (in kilobytes) used by the process since it was created.

Priority

Scheduling priority of the process. Priorities range from 0 (lowest priority) to 31 (highest priority).

ProcessID

Numeric identifier used to distinguish one process from another. ProcessIDs are valid from process creation time to process termination. Upon termination, that same numeric identifier can be applied to a new process.

This means that you cannot use ProcessID alone to monitor a particular process. For example, an application could have a ProcessID of 7, and then fail. When a new process is started, the new process could be assigned ProcessID 7. A script that checked only for a specified ProcessID could thus be "fooled" into thinking that the original application was still running.

QuotaNonPagedPoolUsage

Quota of nonpaged pool usage available to the process.

QuotaPagedPoolUsage

Quota of paged pool usage available to the process.

ThreadCount

Number of active threads associated with a process. Each process must have at least one thread.

UserModeTime

User mode usage (in milliseconds).

WorkingSetSize

Amount of memory (in bytes) the process needs to execute efficiently. If adequate memory is not available, "disk thrashing" occurs. (Disk thrashing refers to those times when the operating system must repeatedly access the hard disk.)

Scripting Steps

Process performance can be monitored in several different ways, including:

  • Monitoring process performance information (memory use, page file use, and threads created) for each individual process.

  • Monitoring processor use by process.

Monitoring process performance information

Listing 14.4 contains a script that monitors process performance information. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace root\cimv2 on the computer, and set the impersonation level to "impersonate."

  3. Use the ExecQuery method to query the Win32_Process class. This returns a collection consisting of all the processes running on the computer.

  4. For each process in the collection, echo the following information:

    • Process name

    • Process ID

    • Thread count

    • Page file use

    • Total page faults

    • Current working set size

Listing 14.4 Monitoring Process Performance

  
1
2
3
4
5
6
7
8
9
10
11
12
13
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
 ("SELECT * FROM Win32_Process")
For Each objProcess in colProcessList
 Wscript.Echo "Process: " & objProcess.Name
 Wscript.Echo "Process ID: " & objProcess.ProcessID
 Wscript.Echo "Thread Count: " & objProcess.ThreadCount
 Wscript.Echo "Page File Size: " & objProcess.PageFileUsage
 Wscript.Echo "Page Faults: " & objProcess.PageFaults
 Wscript.Echo "Working Set Size: " & objProcess.WorkingSetSize
Next

The script shown in Listing 14.4 is designed to display process information once and then terminate. Alternatively, you might want to view process performance over time. To do this, include a For-Next loop in your script, and use the Wscript.Sleep command to pause the script for the appropriate interval. For example, the script shown in Listing 14.5 runs 10 times, displaying the current process data each time, and pauses 60 seconds (60,000 milliseconds) before retrieving updated process information.

Listing 14.5 Monitoring Process Performance Over Time

  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
For i = 1 to 10
Set colProcessList = objWMIService.ExecQuery
 ("SELECT * FROM Win32_Process")
 For Each objProcess in colProcessList
 Wscript.Echo "Process: " & objProcess.Name
 Wscript.Echo "Process ID: " & objProcess.ProcessID
 Wscript.Echo "Thread Count: " & objProcess.ThreadCount
 Wscript.Echo "Page File Size: " & objProcess.PageFileUsage
 Wscript.Echo "Page Faults: " & objProcess.PageFaults
 Wscript.Echo "Working Set Size: " & objProcess.WorkingSetSize
 Next
 Wscript.Echo
 Wscript.Sleep 60000
Next

Monitoring processor use

Listing 14.6 contains a script that monitors processor use by process. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace root\cimv2 on the computer, and set the impersonation level to "impersonate."

  3. Use the ExecQuery method to query the Win32_Process class. This returns a collection consisting of all the processes running on the computer.

  4. For each process in the collection, calculate the total processor use.

    1. Add the values for KernelModeTime and UserModeTime.

      Together, KernelModeTime and UserModeTime tell you the total amount of processor time allocated to a process. To ensure that these values are added and not concatenated, use the VBScript function CSng to convert the variant data to the single data type.

    2. Divide the combined value by 10,000,000.

      Processor use times are reported in 100-nanosecond increments. (A nanosecond is one-billionth of a second; 100 nanoseconds equal one ten-millionth of a second.) This calculation results in processor use being reported in seconds.

  5. Echo the process name and total processor use.

Listing 14.6 Monitoring Processor Use by Process

  
1
2
3
4
5
6
7
8
9
10
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcesses = objWMIService.ExecQuery _
 ("SELECT * FROM Win32_Process")
For Each objProcess in colProcesses
 sngProcessTime = (CSng(objProcess.KernelModeTime) + _
 CSng(objProcess.UserModeTime)) / 10000000
 Wscript.Echo objProcess.Name & VbTab & sngProcessTime
Next