CPU Process Time

I need to get the CPU time (in percentage) for an indivual process, and the overall CPU utilization on the system...like Task Manager.

I have the Process ID, and using GetProcessTimes I can get values for Kernal/User, but I am not sure what the conversion is to get the percentage of CPU utilization.

Initally I need to get this working on NT/2000, but I would also like to have it work under Windows 9x.

I will add more points if necessary.
lordxAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MadshiCommented:
In win9x there is no API to get the per process CPU usage. There's one utility (wintop) which can do that, but only with the help of a little vxd. Getting the overall CPU utilization in win9x is possible without a driver, though. I just don't remember how right now...   :-)

In winNT based systems it's all possible. Here I have some code for getting the overall CPU utilization. It's Delphi code, I hope that's no problem for you:

function GetProcessorTime : int64;
type
  TPerfDataBlock = packed record
    signature              : array [0..3] of wchar;
    littleEndian           : cardinal;
    version                : cardinal;
    revision               : cardinal;
    totalByteLength        : cardinal;
    headerLength           : cardinal;
    numObjectTypes         : integer;
    defaultObject          : cardinal;
    systemTime             : TSystemTime;
    perfTime               : comp;
    perfFreq               : comp;
    perfTime100nSec        : comp;
    systemNameLength       : cardinal;
    systemnameOffset       : cardinal;
  end;
  TPerfObjectType = packed record
    totalByteLength        : cardinal;
    definitionLength       : cardinal;
    headerLength           : cardinal;
    objectNameTitleIndex   : cardinal;
    objectNameTitle        : PWideChar;
    objectHelpTitleIndex   : cardinal;
    objectHelpTitle        : PWideChar;
    detailLevel            : cardinal;
    numCounters            : integer;
    defaultCounter         : integer;
    numInstances           : integer;
    codePage               : cardinal;
    perfTime               : comp;
    perfFreq               : comp;
  end;
  TPerfCounterDefinition = packed record
    byteLength             : cardinal;
    counterNameTitleIndex  : cardinal;
    counterNameTitle       : PWideChar;
    counterHelpTitleIndex  : cardinal;
    counterHelpTitle       : PWideChar;
    defaultScale           : integer;
    defaultLevel           : cardinal;
    counterType            : cardinal;
    counterSize            : cardinal;
    counterOffset          : cardinal;
  end;
  TPerfInstanceDefinition = packed record
    byteLength             : cardinal;
    parentObjectTitleIndex : cardinal;
    parentObjectInstance   : cardinal;
    uniqueID               : integer;
    nameOffset             : cardinal;
    nameLength             : cardinal;
  end;
var  c1, c2, c3      : cardinal;
     i1, i2          : integer;
     perfDataBlock   : ^TPerfDataBlock;
     perfObjectType  : ^TPerfObjectType;
     perfCounterDef  : ^TPerfCounterDefinition;
     perfInstanceDef : ^TPerfInstanceDefinition;
begin
  result := 0;
  perfDataBlock := nil;
  try
    c1 := $10000;
    while true do begin
      ReallocMem(perfDataBlock, c1);
      c2 := c1;
      case RegQueryValueEx(HKEY_PERFORMANCE_DATA, '238', nil, @c3, pointer(perfDataBlock), @c2) of
        ERROR_MORE_DATA : c1 := c1 * 2;
        ERROR_SUCCESS   : break;
        else              exit;
      end;
    end;
    perfObjectType := pointer(cardinal(perfDataBlock) + perfDataBlock^.headerLength);
    for i1 := 0 to perfDataBlock^.numObjectTypes - 1 do begin
      if perfObjectType^.objectNameTitleIndex = 238 then begin   // 238 -> "Processor"
        perfCounterDef := pointer(cardinal(perfObjectType) + perfObjectType^.headerLength);
        for i2 := 0 to perfObjectType^.numCounters - 1 do begin
          if perfCounterDef^.counterNameTitleIndex = 6 then begin    // 6 -> "% Processor Time"
            perfInstanceDef := pointer(cardinal(perfObjectType) + perfObjectType^.definitionLength);
            result := PInt64(cardinal(perfInstanceDef) + perfInstanceDef^.byteLength + perfCounterDef^.counterOffset)^;
            break;
          end;
          inc(perfCounterDef);
        end;
        break;
      end;
      perfObjectType := pointer(cardinal(perfObjectType) + perfObjectType^.totalByteLength);
    end;
  finally FreeMem(perfDataBlock) end;
end;
 
var LastTickCount     : cardinal = 0;
    LastProcessorTime : int64    = 0;
function GetProcessorUsage : integer;
var tickCount     : cardinal;
    processorTime : int64;
begin
  result := 0;
  tickCount     := GetTickCount;
  processorTime := GetProcessorTime;
  if (LastTickCount <> 0) and (tickCount <> LastTickCount) then
    result := 100 - Round(((processorTime - LastProcessorTime) div 100) / (tickCount - LastTickCount));
  LastTickCount     := tickCount;
  LastProcessorTime := processorTime;
end;

GetProcessorUsage gives you the overall CPU utilization in percent. Hope this helps a bit...

Regards, Madshi.
0
MadshiCommented:
P.S: Those types are declared in some C(++) header, just search for it...
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
makerpCommented:
use the performance data helper (PDH), look it up. or use my classes. you will need to get the pdh.dll and link to the pdh.lib. you can get the performance counter string for the process by simply using performnace monitor.

\Process(<process name>)\<counter_name>

to use my class

obj.init()
obj.addCounter("\\Process(<process name>)\\<counter_name>");
obj.updateCounters();
printf("val %d\n",obj.getCounter("\\Process(<process name>)\\<counter_name>")));

/*
      Written By      :      Paul Maker
      Date            :      23/10/2001
      File            :      PdhQuery.h
      Description      :      Genericaly wraps the PDH stuff in windows NT
*/

#ifndef __PM_PDH_QUERY__
#define __PM_PDH_QUERY__

#include <pdh.h>  
#include <pdhmsg.h>
#include <windows.h>

#define MAX_RAW_VALUES                        1//20

class PdhQuery
{
protected:
      /* user defined struct that the PDH calls use, i define it local to the class
      to avoid any undue namespace pollution*/
      typedef struct _tag_PDHCounterStruct
      {
            HCOUNTER hCounter;      
            int nNextIndex;        
            int nOldestIndex;      
            int nRawCount;          
            PDH_RAW_COUNTER a_RawValue[MAX_RAW_VALUES];
      }PDHCOUNTERSTRUCT, *PPDHCOUNTERSTRUCT;

      /* query handle */
      HQUERY query_handle;

      /* list of names and counters */
      int count;
      char **names;
      PDHCOUNTERSTRUCT *counters;

      int last_error;
      char last_error_str[100];

      bool upSizeNames(char *name);
      bool upSizeCounters();
      bool downSizeNames();
      bool downSizeCounters();

      int lookUpIndex(char *name);

public:
      PdhQuery();
      ~PdhQuery();

      /* sets the object up */
      bool init();

      /* adds a counter, pass it the fully qualified counter name */
      bool addCounter(char *name);

      /* update the counters */
      bool updateCounters();

      /* gets the value of a counter */
      long getCounter(char *name);

      /* dont free the pointer returned, its managed in the class */
      char *getLastErrorString();
};

#endif /* __PM_PDH_QUERY__ */

/*
      Written By      :      Paul Maker
      Date            :      29/10/2001
      File            :      PdhQuery.cpp      
      Description      :      Wraps the NT Performance Data Helper
*/

#include "stdafx.h"

#include <malloc.h>
#include <string.h>

#include "PdhQuery.h"

/* zero the object */
PdhQuery::PdhQuery()
{
      count = 0;
      names = 0;
      counters = 0;
      last_error = 0;
}

/* close the object down */
PdhQuery::~PdhQuery()
{
      /* free the names */
      for(int i=0;i<count;i++)
      {
            if(names[i]) free(names[i]);
      }
      if(names)free(names);
      /* free the counter array, this is not a pointer to pointer just a straight
      array */
      if(counters)free(counters);
      /* close the query handle */
      PdhCloseQuery(query_handle);
}

int PdhQuery::lookUpIndex(char *name)
{
      int retval = -1;
      for(int i=0;i<count;i++)
      {
            if(names[i]) /* care */
            {
                  if(!stricmp(names[i],name))
                  {
                        retval = i;
                        break;
                  }
            }
      }
      return retval;
}

bool PdhQuery::upSizeNames(char *name)
{
      bool retval = false;
      if(names = (char**)realloc(names,((count + 1) * sizeof(char*))))
      {
            names[count] = NULL;
            if(names[count] = strdup(name)) retval = true;
            else
            {
                  downSizeNames();
                  last_error = PDH_MEMORY_ALLOCATION_FAILURE;
            }
      }
      else last_error = PDH_MEMORY_ALLOCATION_FAILURE;
      return retval;
}

bool PdhQuery::upSizeCounters()
{
      bool retval = false;
      if(counters = (PDHCOUNTERSTRUCT*)realloc(counters,
                                                                   ((count + 1) * sizeof(PDHCOUNTERSTRUCT))))
      {
            retval = true;
      }
      else last_error = PDH_MEMORY_ALLOCATION_FAILURE;
      return retval;
}

bool PdhQuery::downSizeNames()
{
      bool retval = true;
      if(names[count]) free(names[count]);
      names = (char**)realloc(names,(count * sizeof(char*)));
      return retval;
}

bool PdhQuery::downSizeCounters()
{
      bool retval = true;
      counters = (PDHCOUNTERSTRUCT*)realloc(counters,
                                                                   (count * sizeof(PDHCOUNTERSTRUCT)));
      return retval;
}

/* init the object */
bool PdhQuery::init()
{
      bool retval = false;
      if((last_error = PdhOpenQuery(NULL,1,&query_handle)) == ERROR_SUCCESS)
      {
            retval = true;
      }
      return retval;
}

/* add a counter */
bool PdhQuery::addCounter(char *name)
{
      bool retval = false;

      if(upSizeCounters())
      {
            if((last_error = PdhAddCounter(query_handle,
                                                         name,
                                                       (DWORD)&counters[count],
                                                       &counters[count].hCounter)) == ERROR_SUCCESS)
            {
                  if(upSizeNames(name))
                  {
                        ++count;
                        retval = true;
                  }
                  else
                  {
                        PdhRemoveCounter(counters[count].hCounter);
                        downSizeCounters();
                  }
            }
            else downSizeCounters();
      }
      return retval;
}

bool PdhQuery::updateCounters()
{
      bool retval = false;
      if((last_error = PdhCollectQueryData(query_handle)) == ERROR_SUCCESS) retval = true;
      return retval;
}

long PdhQuery::getCounter(char *name)
{
      int i =0;
      long retval = -1;
      if((i = lookUpIndex(name)) > -1)
      {
            PDH_FMT_COUNTERVALUE pdhFormattedValue;      
            if((last_error = PdhGetFormattedCounterValue(counters[i].hCounter,
                                                         PDH_FMT_LONG,
                                                         NULL,
                                                         &pdhFormattedValue)) == ERROR_SUCCESS)
            {
                  retval = pdhFormattedValue.longValue;
            }
      }
      return retval;
}

char *PdhQuery::getLastErrorString()
{
      switch(last_error)
      {
      case ERROR_SUCCESS:
            strcpy(last_error_str,"There is no error");
            break;
      case PDH_INVALID_ARGUMENT:
            strcpy(last_error_str,"Invalid argument");
            break;
      case PDH_MEMORY_ALLOCATION_FAILURE:
            strcpy(last_error_str,"Memory allocation failure");
            break;
      case PDH_CSTATUS_BAD_COUNTERNAME:
            strcpy(last_error_str,"The counter name path string could not be parsed "
                                            "or interpreted");
            break;
      case PDH_CSTATUS_NO_COUNTER:
            strcpy(last_error_str,"The specified counter was not found");
            break;
      case PDH_CSTATUS_NO_COUNTERNAME:
            strcpy(last_error_str,"An empty counter name path string was passed in");
            break;
      case PDH_CSTATUS_NO_MACHINE:
            strcpy(last_error_str,"A machine entry could not be created");
            break;
      case PDH_CSTATUS_NO_OBJECT:
            strcpy(last_error_str,"The specified object could not be found");
            break;
      case PDH_FUNCTION_NOT_FOUND:
            strcpy(last_error_str,"The calculation function for this counter could "
                                            "not be determined");
            break;
      case PDH_INVALID_HANDLE:
            strcpy(last_error_str,"The query handle is not valid");
            break;
      case PDH_NO_DATA:
             strcpy(last_error_str,"No data for that counter");
            break;
      }
      return last_error_str;
}
0
HTML5 and CSS3 Fundamentals

Build a website from the ground up by first learning the fundamentals of HTML5 and CSS3, the two popular programming languages used to present content online. HTML deals with fonts, colors, graphics, and hyperlinks, while CSS describes how HTML elements are to be displayed.

makerpCommented:
use the performance data helper (PDH), look it up. or use my classes. you will need to get the pdh.dll and link to the pdh.lib. you can get the performance counter string for the process by simply using performnace monitor.

\Process(<process name>)\<counter_name>

to use my class

obj.init()
obj.addCounter("\\Process(<process name>)\\<counter_name>");
obj.updateCounters();
printf("val %d\n",obj.getCounter("\\Process(<process name>)\\<counter_name>")));

/*
      Written By      :      Paul Maker
      Date            :      23/10/2001
      File            :      PdhQuery.h
      Description      :      Genericaly wraps the PDH stuff in windows NT
*/

#ifndef __PM_PDH_QUERY__
#define __PM_PDH_QUERY__

#include <pdh.h>  
#include <pdhmsg.h>
#include <windows.h>

#define MAX_RAW_VALUES                        1//20

class PdhQuery
{
protected:
      /* user defined struct that the PDH calls use, i define it local to the class
      to avoid any undue namespace pollution*/
      typedef struct _tag_PDHCounterStruct
      {
            HCOUNTER hCounter;      
            int nNextIndex;        
            int nOldestIndex;      
            int nRawCount;          
            PDH_RAW_COUNTER a_RawValue[MAX_RAW_VALUES];
      }PDHCOUNTERSTRUCT, *PPDHCOUNTERSTRUCT;

      /* query handle */
      HQUERY query_handle;

      /* list of names and counters */
      int count;
      char **names;
      PDHCOUNTERSTRUCT *counters;

      int last_error;
      char last_error_str[100];

      bool upSizeNames(char *name);
      bool upSizeCounters();
      bool downSizeNames();
      bool downSizeCounters();

      int lookUpIndex(char *name);

public:
      PdhQuery();
      ~PdhQuery();

      /* sets the object up */
      bool init();

      /* adds a counter, pass it the fully qualified counter name */
      bool addCounter(char *name);

      /* update the counters */
      bool updateCounters();

      /* gets the value of a counter */
      long getCounter(char *name);

      /* dont free the pointer returned, its managed in the class */
      char *getLastErrorString();
};

#endif /* __PM_PDH_QUERY__ */

/*
      Written By      :      Paul Maker
      Date            :      29/10/2001
      File            :      PdhQuery.cpp      
      Description      :      Wraps the NT Performance Data Helper
*/

#include "stdafx.h"

#include <malloc.h>
#include <string.h>

#include "PdhQuery.h"

/* zero the object */
PdhQuery::PdhQuery()
{
      count = 0;
      names = 0;
      counters = 0;
      last_error = 0;
}

/* close the object down */
PdhQuery::~PdhQuery()
{
      /* free the names */
      for(int i=0;i<count;i++)
      {
            if(names[i]) free(names[i]);
      }
      if(names)free(names);
      /* free the counter array, this is not a pointer to pointer just a straight
      array */
      if(counters)free(counters);
      /* close the query handle */
      PdhCloseQuery(query_handle);
}

int PdhQuery::lookUpIndex(char *name)
{
      int retval = -1;
      for(int i=0;i<count;i++)
      {
            if(names[i]) /* care */
            {
                  if(!stricmp(names[i],name))
                  {
                        retval = i;
                        break;
                  }
            }
      }
      return retval;
}

bool PdhQuery::upSizeNames(char *name)
{
      bool retval = false;
      if(names = (char**)realloc(names,((count + 1) * sizeof(char*))))
      {
            names[count] = NULL;
            if(names[count] = strdup(name)) retval = true;
            else
            {
                  downSizeNames();
                  last_error = PDH_MEMORY_ALLOCATION_FAILURE;
            }
      }
      else last_error = PDH_MEMORY_ALLOCATION_FAILURE;
      return retval;
}

bool PdhQuery::upSizeCounters()
{
      bool retval = false;
      if(counters = (PDHCOUNTERSTRUCT*)realloc(counters,
                                                                   ((count + 1) * sizeof(PDHCOUNTERSTRUCT))))
      {
            retval = true;
      }
      else last_error = PDH_MEMORY_ALLOCATION_FAILURE;
      return retval;
}

bool PdhQuery::downSizeNames()
{
      bool retval = true;
      if(names[count]) free(names[count]);
      names = (char**)realloc(names,(count * sizeof(char*)));
      return retval;
}

bool PdhQuery::downSizeCounters()
{
      bool retval = true;
      counters = (PDHCOUNTERSTRUCT*)realloc(counters,
                                                                   (count * sizeof(PDHCOUNTERSTRUCT)));
      return retval;
}

/* init the object */
bool PdhQuery::init()
{
      bool retval = false;
      if((last_error = PdhOpenQuery(NULL,1,&query_handle)) == ERROR_SUCCESS)
      {
            retval = true;
      }
      return retval;
}

/* add a counter */
bool PdhQuery::addCounter(char *name)
{
      bool retval = false;

      if(upSizeCounters())
      {
            if((last_error = PdhAddCounter(query_handle,
                                                         name,
                                                       (DWORD)&counters[count],
                                                       &counters[count].hCounter)) == ERROR_SUCCESS)
            {
                  if(upSizeNames(name))
                  {
                        ++count;
                        retval = true;
                  }
                  else
                  {
                        PdhRemoveCounter(counters[count].hCounter);
                        downSizeCounters();
                  }
            }
            else downSizeCounters();
      }
      return retval;
}

bool PdhQuery::updateCounters()
{
      bool retval = false;
      if((last_error = PdhCollectQueryData(query_handle)) == ERROR_SUCCESS) retval = true;
      return retval;
}

long PdhQuery::getCounter(char *name)
{
      int i =0;
      long retval = -1;
      if((i = lookUpIndex(name)) > -1)
      {
            PDH_FMT_COUNTERVALUE pdhFormattedValue;      
            if((last_error = PdhGetFormattedCounterValue(counters[i].hCounter,
                                                         PDH_FMT_LONG,
                                                         NULL,
                                                         &pdhFormattedValue)) == ERROR_SUCCESS)
            {
                  retval = pdhFormattedValue.longValue;
            }
      }
      return retval;
}

char *PdhQuery::getLastErrorString()
{
      switch(last_error)
      {
      case ERROR_SUCCESS:
            strcpy(last_error_str,"There is no error");
            break;
      case PDH_INVALID_ARGUMENT:
            strcpy(last_error_str,"Invalid argument");
            break;
      case PDH_MEMORY_ALLOCATION_FAILURE:
            strcpy(last_error_str,"Memory allocation failure");
            break;
      case PDH_CSTATUS_BAD_COUNTERNAME:
            strcpy(last_error_str,"The counter name path string could not be parsed "
                                            "or interpreted");
            break;
      case PDH_CSTATUS_NO_COUNTER:
            strcpy(last_error_str,"The specified counter was not found");
            break;
      case PDH_CSTATUS_NO_COUNTERNAME:
            strcpy(last_error_str,"An empty counter name path string was passed in");
            break;
      case PDH_CSTATUS_NO_MACHINE:
            strcpy(last_error_str,"A machine entry could not be created");
            break;
      case PDH_CSTATUS_NO_OBJECT:
            strcpy(last_error_str,"The specified object could not be found");
            break;
      case PDH_FUNCTION_NOT_FOUND:
            strcpy(last_error_str,"The calculation function for this counter could "
                                            "not be determined");
            break;
      case PDH_INVALID_HANDLE:
            strcpy(last_error_str,"The query handle is not valid");
            break;
      case PDH_NO_DATA:
             strcpy(last_error_str,"No data for that counter");
            break;
      }
      return last_error_str;
}
0
lordxAuthor Commented:
Thank you both (Madshi and MakerP) for the code...but I did manage to hack it together with the GetProcessTimes function...below is what I used in my program.  I include it so if someone in the future needs to do this (and pays the points), they will still get what they need.  

*Note, the code is ment to run with other variables in my program, so it needs to be hacked a bit for anyone else to use it*


float CFalconDlg::GetIdleTime()
{
     static Once=0;
     static FILETIME lastUserTime;
     static FILETIME lastKernalTime;
     FILETIME KernalTime, UserTime;

     FILETIME Enter, Exit;
     
     const size_t c_nMaxProc = 4096;
  int x=0;
     DWORD a_dwProcIds[c_nMaxProc + 1];
  DWORD uResult = 0;
  DWORD nEnumProc = 0;

     static LARGE_INTEGER Kernal, User, lastKernal, lastUser;
     LARGE_INTEGER sumKernal, sumUser;
     sumKernal.QuadPart=0;
     sumUser.QuadPart=0;
     int ProcCount=0;
     int MaxCount=0;

  if (EnumProcesses(a_dwProcIds, c_nMaxProc * sizeof(DWORD), &nEnumProc)){
       //nEnumProc /= sizeof(DWORD);
          for (size_t i = 0; i < nEnumProc; ++i) {
               MaxCount++;
               //PROCESS_ALL_ACCESS
            Profile *Pro=ServerProfiles.GetByID((int)a_dwProcIds);
               HANDLE Process;
               if (Pro && Pro->hID){
                    Process=Pro->hProcess;
                    Process=0;
                    }
               else
                    Process=OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, a_dwProcIds[i]);

               //HANDLE Process = (HANDLE)a_dwProcIds[i];
               if (GetProcessTimes(Process, &Enter, &Exit, &KernalTime, &UserTime)){
                    //Msg("Unable to get idle time", 0, 0);
               
                    memcpy(&Kernal, &KernalTime, sizeof(FILETIME));
                    memcpy(&User, &UserTime, sizeof(FILETIME));
                    //Get a running total of the process times

                    sumKernal.QuadPart+=Kernal.QuadPart;
                    sumUser.QuadPart+=sumUser.QuadPart;
         
                    ProcCount++;
                    CloseHandle(Process);
                    }
               }

          if (!Once++){
               lastKernal.QuadPart=sumKernal.QuadPart;
               lastUser.QuadPart=sumUser.QuadPart;
               }
   
          }
     
     //LARGE_INTEGER Total=lastKernal+lastUser;  
     float CurrentAmount=(float)((sumKernal.QuadPart+sumUser.QuadPart) - (lastKernal.QuadPart+lastUser.QuadPart)) / (float)100000;
     //sprintf(buffer, "Processor Usage (%0.2f) from %d/%d", CurrentAmount, ProcCount, MaxCount);
     //Msg(buffer, 0, 0);
     if (CurrentAmount < 0)
          CurrentAmount=0;
     if (CurrentAmount > 100)
          CurrentAmount=100;
     lastKernal.QuadPart=sumKernal.QuadPart;
     lastUser.QuadPart=sumUser.QuadPart;
     return CurrentAmount;

}
0
MadshiCommented:
I had a function running with "GetProcessTimes", too. Unfortunately it took up too much performance!!! Look at your CPU usage when you're running this function, it's really expensive. Using the performance counters consumes much less CPU.
0
lordxAuthor Commented:
I will monitor it...and if it seems to add to the CPU load, I will switch to the performance counters.

Thanks.

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.