Link to home
Start Free TrialLog in
Avatar of Evarest
Evarest

asked on

Get CPU Usage of processes

How can I get a list of the CPU usage % of each running process on my system? Just like in Windows Tasklist...

Thanks!
Evarest
Avatar of DavidBirch2dotCom
DavidBirch2dotCom

ARRRRG I want to CRY !!!!!! that was the second time I accedently changed page once  i had writen a large post !!! once i hit a link in google and it opened in the page :( then i hit one of those domains for sale pages and it opened a pop-up in this page :(:(:(:(

ANYWAY now your all feeling sorry for me ;) I am going to write this in notpad...

I have successfuly used process explorer for this task, it gives the memory usage of every process running.  It also gives an indecation of which programs 'own' other processes which is interesting.  It also gives a list of DLL's inuse by that proccess which has given me some suprises!

you may download process explorer from http://www.sysinternals.com/ntw2k/freeware/procexp.shtml the link is at the bottom of the page,

there are also many other applications for this task including
http://www.xmlsp.com/pview/prcview.htm 
and many others though I havnt tired any of them

There are also some related threads on this

https://www.experts-exchange.com/questions/21043478/process-cpu-usage.html
https://www.experts-exchange.com/questions/10337673/Debugging-Tools.html

Hope that helps

David

P>S> there I finaly managed to post ;)
The following sources/pages give you information about how you can get Windows process information with Delphi. I suggest you play a bit with them.
http://www.howtodothings.com/showarticle.asp?article=142
http://delphi.about.com/library/weekly/aa080304a.htm

An commercial implementation which works as an Delphi plugin is MiTeC System Information Components. Information about that can be found at http://www.mitec.cz. This plugin can collect a lot of information about the pc and also about processes.
Avatar of Evarest

ASKER

Thanks for your answers! However, to make clearify my question a bit more:

i'm in need of freeware code that enables me to get a list of all processes (which i can), along with the CPU usage of each separate process (which i can't do).

I know that there're more programs out there which can give you this information (beginning with Windows Task List), but i need it in my own program.

Also interesting to know: it should primarily work on WinXP, and if possible (preferably) also on Win2k.

Thanks in advance!
Evarest
Avatar of Wim ten Brink
Perhaps you can use Windows Machine Instrumentation to get the info you need. WMI can provide a lot of system information including process information, but it's not easy to use.
Avatar of Evarest

ASKER

Indeed that's maybe a little overkill, as it's not really worthwhile digging around in WMI itself...

The PDH.dll documentation also isn't really what it should be, that's why I decided to try experts-exchange. Maybe they had some wrapper library or some toolbox that could make it more easy to implement this function...

It seems that there isn't really an "easy" way to get this working after all...
Avatar of Evarest

ASKER

Workshop_Alex, you can disregard my last post: i've further looked into WMI and found that you can extract the CPU from it. However, it seems not to function very well. Translating from C++ and VBScript code, i get:

uses
  ActiveX, WbemScripting_TLB;

var
  WbemServices: ISWbemServices;
  N1, D1: int64;

function ADsEnumerateNext(pEnumVariant: IEnumVARIANT; cElements: ULONG;
  var pvar: OleVARIANT; var pcElementsFetched: ULONG): HRESULT; safecall; external 'activeds.dll';

procedure DumpWMI_Process(Process: SWBemObject);
var
 Enum: IEnumVARIANT;
 varArr: OleVariant;
 lNumElements: ULong;
 SProp: ISWbemProperty;
 Prop: OleVariant;
 PropName: string;
begin
 N1 :=0;
 D1 :=0;
 Enum :=Process.Properties_._NewEnum as IEnumVariant;
 while (Succeeded(ADsEnumerateNext(Enum, 1, VarArr, lNumElements))) and
       (lNumElements > 0) do
  begin
   if Succeeded(IDispatch(varArr).QueryInterface(SWBemProperty, SProp)) and
      Assigned(SProp)
    then
     begin
      try
       if (SProp.Name <> 'PercentProcessorTime')and
          (SProp.Name <> 'Timestamp_Sys100NS')
        then continue;

       PropName  := SProp.Name;
       Prop := SProp.Get_Value;
       if PropName = 'PercentProcessorTime'
        then N1 :=Prop
         else D1 :=Prop;
       Finalize(SProp);
       Finalize(PropName);
       Finalize(Prop);
      except
       on E: Exception do
        begin
         // WriteLn(ErrOutput, PropName, ': ', E.Message);
        end;
      end;
     end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 Enum: IEnumVARIANT;
 varArr: OleVariant;
 lNumElements: ULong;
 A,B,C,D: int64;
begin
 A :=0; B :=0;
 C :=0; D :=0;
 try
  Enum :=WbemServices.ExecQuery( 'Select * from Win32_PerfRawData_PerfProc_Process where name="procalert"',
                                 'WQL',
                                 wbemFlagBidirectional,
                                 nil )._NewEnum as IEnumVariant;
  while (Succeeded(ADsEnumerateNext(Enum, 1, varArr, lNumElements))) and
        (lNumElements > 0) do
   begin
    DumpWMI_Process(IUnknown(varArr) as SWBemObject);
   end;
  A :=N1;
  C :=D1;

  First :=false;
  sleep(1000);
  Enum :=WbemServices.ExecQuery( 'Select * from Win32_PerfRawData_PerfProc_Process where name="procalert"',
                                 'WQL',
                                 wbemFlagBidirectional,
                                 nil )._NewEnum as IEnumVariant;
  while (Succeeded(ADsEnumerateNext(Enum, 1, varArr, lNumElements))) and
        (lNumElements > 0) do
   begin
    DumpWMI_Process(IUnknown(varArr) as SWBemObject);
   end;
  B :=N1;
  D :=D1;
 finally
  Memo1.Lines.Add(FloatToStr((B-A)/(D-C)*100));
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 WbemServices :=CoSWbemLocator.Create.ConnectServer( '[PCNAME]', 'root\cimv2', '',
                                                     '', '', '', 0, nil);
end;


If you review this code, you'll notice it's quite slow (sleep(1000) is called). This line is needed to calculate the CPU usage which i show in the Memo1. Is it possible to speed it up by using some other function of WMI?

Also, and more important, it seems to contain a memoryleak. Just run it a few times to see it for yourself... Maybe you see the cause?

I'm not used to WMI, and quite frankly it seems not to be the most convenient way to get the information, but I really can't find any other way...

Evarest
SOLUTION
Avatar of DavidBirch2dotCom
DavidBirch2dotCom

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Evarest

ASKER

Thanks for your code! I've implemented it, and it works fine except for what I said in my last post. The WMI still seems to contain some memoryleak... If you run the following:

uses
  ActiveX, WbemScripting_TLB;

var
  WbemServices: ISWbemServices;
  N1, D1: int64;

function ADsEnumerateNext(pEnumVariant: IEnumVARIANT; cElements: ULONG;
  var pvar: OleVARIANT; var pcElementsFetched: ULONG): HRESULT; safecall; external 'activeds.dll';

function Prop(const Obj: ISWbemObject; Name: string): int64;
begin
 try
  result :=obj.Properties_.Item(Name, 0).Get_Value;
 except
  result :=0;
 end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
 Enum: IEnumVARIANT;
 varArr: OleVariant;
 lNumElements: ULong;
begin
 Enum :=WbemServices.ExecQuery( 'Select * from Win32_PerfRawData_PerfProc_Process where name="taskmgr"',
                                'WQL',
                                wbemFlagBidirectional,
                                nil )._NewEnum as IEnumVariant;
 try
  while (Succeeded(ADsEnumerateNext(Enum, 1, varArr, lNumElements))) and
        (lNumElements > 0) do
   begin
    N1 :=Prop(IUnknown(varArr) as SWBemObject, 'PercentProcessorTime');
    D1 :=Prop(IUnknown(varArr) as SWBemObject, 'Timestamp_Sys100NS');
   end;
 finally
  varArr :=Null;
  Enum :=nil;
 end;
end;

Timer set to 100 or so, you'll see the memory filling up slowly. First it stays around the starting value, but after a while it'll increase. I know, as i'd use the sleep(1000), it would take ages to fill up the memory, but nevertheless, I cannot allow such a memoryleak in my program...

Maybe you find something i forgot to free, but at the moment I'm not using WMI after all :-(

The components are indeed too expensive, as i'm just a student with a programming hobby in my spare time...

For Workshop_Alex:
About this piece of code:
  Finalize(SProp);
  Finalize(PropName);
  Finalize(Prop);

Better replace it with:
  SProp := nil;
  PropName := nil;
  Prop := nil;

I'm not used working with Variants... I use Finalize in all my code, if there's a string in the record. In the help file of Delphi, they say you should use Finalize to free memory allocated to a non-terminated string or a variant...

All this freeing is quite a "blurry" in Delphi i find. I hope that i use it correctly, if i use Dispose to free a record:

Dispose(PMyRec(MyRec));

and Finalize to free any residing strings in MyRec (called before calling Dispose)

Finalize(PMyRec(MyRec)^);

I've increased the points, as I'm going to split them between Workshop_alex who has helped me with the WMI a lot, and DavidBirch2dotCom, who pointed me to the WMI components which can be interesting for other developers (but not for me at the moment as i said earlier on)...

Evarest
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Evarest

ASKER

Thanks Workshop_Alex for your explanation! Interfaces still aren't my speciality, as I only started using them when you pointed me to their use a few questions back...

The memoryleak isn't solved though. As you correctly guessed, I created WbemServices in the OnCreate event. This because i found it useless to recreate the same instance over and over.

Using your code, the same memoryleak persisted. It's quite an odd memoryleak, as I pointed out in my last post...

However, i got so many from this WMI question, that I'm quite happy to grant everyone their points :-)

Thanks a lot!
Evarest
Well, about memory leaks, I've created lots of applications already and memoryleaks just happen. They are unavoidable. Your own code might be perfect but all the components you use, the Windows API's you call and whatever else might still be leaking. Best thing to do is just check your code to make sure you're cleaning up everything the proper way, using the correct release mechanism for the creation mechanisms used.