• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2404
  • Last Modified:

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.
0
lordx
Asked:
lordx
  • 3
  • 2
  • 2
1 Solution
 
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
 
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
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

 
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

  • 3
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now