Windows C++ Get CPU and Memory Utilisation With Performance Counters

The aim of this example is to create a simple program that will display CPU and memory uisng PDH Performance Counters. We will be using the windows command line compiler cl.exe that comes with Visual Studio C++ for this example. Leave any questions or problems as comments and I will endeavour to answer them.

This article assumes that you have VC++ installed and configured. See Problems and Solutions Installing VC++ Express Edition, to install and run vcvars32.bat.

Versions used in this example
Windows XP SP2
Visual Studio Express Editions 2008 VC++
Links to these files can be found here

Write and compile the application
  1. While you can get Memory status fairly easlily with GlobalMemoryStatusEx, there is no equivalent function for CPU. Therefore you have to use PDH Performance Counter Interface to get CPU utilisation. Write the application and save is as check.cpp.

    Also note that CPU is a difference between two PdhCollectQueryData calls, so if you call this once and try to get PdhGetFormattedCounterValue you will get an error.

     1. #include <iostream>
     2. #include <windows.h>
     3. #include <stdio.h>
     4. #include <pdh.h>
     5. #include <pdhmsg.h>
     7. #define KB 1024
     8. void main(int argc, char *argv[]){
    10.     PDH_HQUERY hquery;
    11.     PDH_HCOUNTER hcountercpu;
    12.     PDH_HCOUNTER hcounterram;
    13.     PDH_STATUS status;
    14.     LPSTR pMessage;
    15.     PDH_FMT_COUNTERVALUE countervalcpu;
    16.     PDH_FMT_COUNTERVALUE countervalram;
    17.     MEMORYSTATUSEX memstat;
    19.     memstat.dwLength = sizeof (memstat);
    21.     if((status=PdhOpenQuery(NULL, 0, &hquery))!=ERROR_SUCCESS){
    22.         printf("PdhOpenQuery %lx\n", status);    
    23.         goto END;
    24.     }
    26.     if((status=PdhAddCounter(hquery,
    27.                             "\\Processor(_Total)\\% Processor Time",
    28.                             0, 
    29.                             &hcountercpu))!=ERROR_SUCCESS){
    30.         printf("PdhAddCounter (cpu) %lx\n", status);    
    31.         goto END;
    32.     }
    33.     if((status=PdhAddCounter(hquery,
    34.                             "\\Memory\\Available Bytes",
    35.                             0, 
    36.                             &hcounterram))!=ERROR_SUCCESS){
    37.         printf("PdhAddCounter (ram) %lx\n", status);    
    38.         goto END;
    39.     }
    41.     /*Start outside the loop as CPU requires difference 
    42.     between two PdhCollectQueryData s*/
    43.     if((status=PdhCollectQueryData(hquery))!=ERROR_SUCCESS){
    44.         printf("PdhCollectQueryData %lx\n", status);    
    45.         goto END;
    46.     }
    48.     while(true){
    50.         if((status=PdhCollectQueryData(hquery))!=ERROR_SUCCESS){
    51.             printf("PdhCollectQueryData %lx\n", status);    
    52.             goto END;
    53.         }
    54.         if(GlobalMemoryStatusEx(&memstat)==0){
    55.             printf("GlobalMemoryStatusEx %d\n", GetLastError());
    56.             goto END;
    57.         }
    59.         if((status=PdhGetFormattedCounterValue(hcountercpu, 
    60.                                                 PDH_FMT_LONG, 
    61.                                                 0, 
    62.                                                 &countervalcpu))!=ERROR_SUCCESS){
    63.             printf("PdhGetFormattedCounterValue(cpu) %lx\n", status);    
    64.             goto END;
    65.         }
    66.         if((status=PdhGetFormattedCounterValue(hcounterram, 
    67.                                                 PDH_FMT_LONG, 
    68.                                                 0, 
    69.                                                 &countervalram))!=ERROR_SUCCESS){
    70.             printf("PdhGetFormattedCounterValue(ram) %lx\n", status);    
    71.             goto END;
    72.         }
    73.         printf("cpu %3d%% \tmem %3d%% \tavail (%d mb)\n", 
    74.             countervalcpu.longValue, 
    75.             memstat.dwMemoryLoad, 
    76.             countervalram.longValue/(KB*KB));
    78.         Sleep(1000);
    80.     }
    81. END:
    82.     ;
    83. }
    Hide line numbers

  2. Open a prompt to the working directory and compile the code using the windows cl.exe compiler. You just need to include the pdh.lib.

    ..workspace\PerfCounter>cl check.cpp pdf.lib

  3. Now run the program in the command prompt. You should see the cpu and memory snapshot displayed every second.


Anonymous said...

thanks for the code.
One suggestion: the compilation command is: cl perf.cpp PDH.lib, not cl perf.cpp PDF.lib.

Anonymous said...

Windows Vista 32 bit Home Basic
Visual C++ 2008 express

On executing the app, I am getting the following error:

PdhAddCounter (cpu) c0000bb8

Could you please let me know why this error is coming
Used your code as is

righteous said...

I have no idea about the error code. c0000bb8 is too huge to be any kind of 'normal' error code.

Comment out the CPU bit and see if the memory(RAM) bit works.

I have have to run this bit of code on Vista to see if I can duplicate the error, when I have some free time :)

TAGORE said...

How to calculate cpu utilization of each process running in windows system
plz Help me! I am new for counters

Anonymous said...

How to calculate cpu utilization of each process running in windows system
plz Help me! I am new for counters

Silvia Jacinto said...

I accidentally viewed your blog and I was so amazed with your work that it touched the deepness of my heart and it made me sentimental. Thanks for posting. Visit my site too.

Naviya Nair said...

Very interesting and good Explanation
ASP NET Training
ASP NET Training
ASP NET Online Training
C-Sharp Training
Dot Net Training in Chennai
Online .Net Training

MVC Training
WCF Training
Web-API Training
LINQ Training
Entity Framework

Dot Net Interview Questions