Previous Table of Contents Next


Finding Processor Bottlenecks

Finding processor bottlenecks on your server is not an easy task, but it is possible. It just takes time to determine which process is consuming an inordinate amount of processor time and alleviate the situation. The starting point is to look at the big picture, using the performance counters I have included in Processor.PMW. This workspace file includes processor chart, alert, and report view settings to determine the overall processor usage. These object counters are listed in Table 6.1, which includes a description of each object counter.

Table 6.1 Processor performance object counters.

Object Counter Instance Parent Description
System % Total Processor Time N/A N/A This is the percentage of processor time that is currently in use on your system. The basic formula for calculation is ((% CPU In Use On CPU 0) + (% CPU In Use On CPU 1) ... + (% CPU In Use On CPU X)) / Total Number Of CPUs.
System System Calls/sec. N/A N/A The number of system service calls that are executed per second. If this value is lower than the number of interrupts/sec., this indicates that a hardware adapter is generating excessive interrupts.
System Context Switches/sec. N/A N/A The frequency of switches between executing threads. A high value indicates that a program’s usage of critical sections or semaphores should have a higher priority to achieve a higher throughput and less task switching.
System Processor Queue Length N/A N/A The number of threads waiting in the processor queue for processor cycles. A consistent value of 2 or higher indicates a neck. This value will always be 0 unless at least one thread is being monitored.
System Interrupts/sec. Per Processor N/A The number of interrupts the system is servicing.
Thread % Processor Time Per Processor Idle The percentage of processor time the thread is using.

The first step to finding a processor bottleneck is to obtain a baseline chart, as shown in Figure 6.4, to gain a familiarity with your system in an idle state. Then, you should use the same counters to obtain a baseline in a normal working state.


Figure 6.4  Using Performance Monitor to isolate processor bottlenecks.

The next step is to use these counters on an active system. Examine the % Total Processor Time. If this value is consistently above 90 percent, then you have a processor bottleneck. And that means it’s time to examine each process in the system to see which one is utilizing more of the processor than it should. If you have too many processes to view in a chart, you can use the report view. To select these processes, choose Edit|Add To Chart, and select Process as the object type. Then, select the % Processor Time for the counter. Next, select each application listed in the Instance field. The process that has the highest peak is generally your performance bottleneck. Let’s take a look at this process in a little more detail and with an example performance hog.

In a multithreaded environment, such as Windows NT Server, a processor shares CPU cycles among multiple threads. Each of these threads can be running or waiting for execution. For example, if you have an application that is waiting for user input or is waiting for a disk I/O request, while it is waiting, it is not scheduled for execution. So, other threads that can perform work will execute instead. However, this is based on the application design, and, in this regard, not all applications are created equal. Many applications have been ported from a different application environment, and they might not make efficient use of the Win32 APIs. For example, if you ported an MS-DOS application to a Win32 console application, you could have left programming constructs that constantly polled for user input, incremented a counter, or something similar. For example, review the BadExe application source code example shown in Listing 6.1.

Listing 6.1 The BadExe example application source code.

//------------------------------------------------------------------------------------
// THIS CODE AND INFORMATION IS PROVIDED “AS IS” WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
//
//   BadExp.C           Sample Application to demonstrate
//                        processor intensive application.
//
//
// Copyright (c) 1993-1997  Knowles Consulting. All rights Reserved.
//
//------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>

int main (void)
    {
   unsigned long uMaxNumber,x;
    char chUserInput;

    // Idle loop to eat processor time.
    for(x=0;x=4294967295;x++)
       {
      uMaxNumber=x;
       }

    // Display counter and wait for user to press a key.
    printf("Counter = %d" , uMaxNumber);
     chUserInput=getchar();

     return (0);
    }

When this application executes, it uses 80 to 98 percent of the processor, as shown in Figure 6.5. This is the definition of a processor-intensive application. Notice that I have the Process object selected for the BadExp.EXE application (or instance). This is the same object counter you will use (but of course, you will use different process instances) to determine what percentage of the processor your applications are using and which process is the bottleneck.


Figure 6.5  An example of a processor-intensive application displayed with Performance Monitor.


Previous Table of Contents Next