Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   CPU und Memory Nutzung eines Prozesses (https://www.delphipraxis.net/185175-cpu-und-memory-nutzung-eines-prozesses.html)

af99 20. Mai 2015 12:03

Delphi-Version: XE5

CPU und Memory Nutzung eines Prozesses
 
Hallo Zusammen,

ich bastele gerade an einem Programm mit dem ich die CPU und Hauptspeicher Nutzung eines benannten Prozessen ermitteln möchte.
Folgende Funktionen habe ich hierzu im Netz gefunden

Delphi-Quellcode:
function ShowMemoryUsage(ProcessId: DWORD): DWORD;
var
   hProcess: THandle;
   PMC: PPROCESS_MEMORY_COUNTERS;
   cb: Integer;
begin
   Result := 0;
   // cb := SizeOf(PMC); // = 4;
   cb := SizeOf(PMC^);
   GetMem(PMC, cb);
   try
     PMC^.cb := cb;
     hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessId);
     begin
       if ( hProcess = 0 ) then
         Exit;
       // if ( GetProcessMemoryInfo(hProcess, @PMC, SizeOf(PMC)) ) then
       if ( GetProcessMemoryInfo(hProcess, PMC, SizeOf(PMC^)) ) then
         //Result := (PMC^.WorkingSetSize Div 1024)
         Result := (PMC^.WorkingSetSize)
       else
       begin
         returntext := 'CRITICAL - ' + SysErrorMessage(GetLastError);
         returncode := 1;
       end;
     end;
   finally
     CloseHandle(hProcess);
     FreeMem(PMC, SizeOf(_PROCESS_MEMORY_COUNTERS));
   end;
end;


function GetProcessMemorySize(sProcessName: string; var nMemSize: Cardinal): Boolean;
var
  l_nWndHandle, l_nProcID, l_nTmpHandle: HWND;
  l_pPMC: PPROCESS_MEMORY_COUNTERS;
  l_pPMCSize: Cardinal;
begin
  l_nWndHandle := FindWindow(nil, PChar(sProcessName));
  if l_nWndHandle = 0 then
  begin
    writeln('fehler');
    Result := False;
    Exit;
  end;
  l_pPMCSize := SizeOf(PROCESS_MEMORY_COUNTERS);
  GetMem(l_pPMC, l_pPMCSize);
  l_pPMC^.cb := l_pPMCSize;
  GetWindowThreadProcessId(l_nWndHandle, @l_nProcID);
  l_nTmpHandle := OpenProcess(PROCESS_ALL_ACCESS, False, l_nProcID);
  if (GetProcessMemoryInfo(l_nTmpHandle, l_pPMC, l_pPMCSize)) then
    nMemSize := l_pPMC^.WorkingSetSize
  else
  begin
    writeln('fehler');
    nMemSize := 0;
  end;
  FreeMem(l_pPMC);
  CloseHandle(l_nTmpHandle);
  Result := True;
end;

// Get ProcessID By ProgramName (Include Path or Not Include)
function GetPIDByProgramName(const APName: string): THandle;
var
  isFound: boolean;
  AHandle, AhProcess: THandle;
  ProcessEntry32: TProcessEntry32;
  APath: array[0..MAX_PATH] of char;
begin
  try
    Result := 0;
    AHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    ProcessEntry32.dwSize := Sizeof(ProcessEntry32);
    isFound := Process32First(AHandle, ProcessEntry32);

    while isFound do
    begin
      AhProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
      false, ProcessEntry32.th32ProcessID);
      GetModuleFileNameEx(AhProcess, 0, @APath[0], sizeof(APath));
      if (UpperCase(StrPas(APath)) = UpperCase(APName)) or
         (UpperCase(StrPas(ProcessEntry32.szExeFile)) = UpperCase(APName)) then
      begin
        Result := ProcessEntry32.th32ProcessID;
        break;
      end;
      isFound := Process32Next(AHandle, ProcessEntry32);
      CloseHandle(AhProcess);
    end;
  finally
    CloseHandle(AHandle);
  end;
end;


function GetCpuUsage(PID:cardinal):single;
const
    cWaitTime=750;
var
    h : Cardinal;
    mCreationTime,mExitTime,mKernelTime, mUserTime:_FILETIME;
    TotalTime1,TotalTime2:int64;
begin
     {We need to get a handle of the process with PROCESS_QUERY_INFORMATION privileges.}
    h:=OpenProcess(PROCESS_QUERY_INFORMATION,false,PID);
    {We can use the GetProcessTimes() function to get the amount of time the process has spent in kernel mode and user mode.}
    GetProcessTimes(h,mCreationTime,mExitTime,mKernelTime,mUserTime);
    TotalTime1:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32)) + int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));

    {Wait a little}
    Sleep(cWaitTime);

    GetProcessTimes(h,mCreationTime,mExitTime,mKernelTime,mUserTime);
    TotalTime2:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32)) + int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));

    {This should work out nicely, as there were approx. 250 ms between the calls
    and the result will be a percentage between 0 and 100}
    Result:=((TotalTime2-TotalTime1)/cWaitTime)/100;
    CloseHandle(h);
end;
Für die Ermittlung des Memory Verbrauchs habe ich 2 Funktionen die ich beide versucht habe.
Ich habe nun 2 Programme geschrieben. Ein Consolenprogramm und eine VCL Formularanwendung.

In beiden Programmen rufe ich die Funktionen so auf
Delphi-Quellcode:
ww := GetProcessMemorySize(prozess_name, dmem)

oder (ich habe beide probiert)

dmem := ShowMemoryUsage(GetPIDByProgramName(prozess_name));
Wenn ich das VCL Formular Programm nun auf einem Windows Server 2008 R2 starte wird mir der Memoryverbrauch angezeicgt. Wenn ich hingegen das Consolenprogramm starte wird mir "fehler" an der Console ausgegeben
kommt hier her
Delphi-Quellcode:
  l_nWndHandle := FindWindow(nil, PChar(sProcessName));
  if l_nWndHandle = 0 then
  begin
    writeln('fehler');
    Result := False;
    Exit;
  end;
Ich habe die Console auch mal als Administrator ausgeführt. Es kommt auch "fehler" raus.
Auf einem Windows Server 2003 funktionieren beide Programme

CPU Nutzung kommt auf allen Servern und auch bei beiden Programmen raus

?!?!? Verstehe ich nicht.
Kann mir einer helfen

Viele Grüße
Andreas

af99 20. Mai 2015 12:47

AW: CPU und Memory Nutzung eines Prozesses
 
Ich glaube das ich ein Berechtigungsproblem. Scheinbar dürfen die Funktionen "GetProcessMemorySize" und "ShowMemoryUsage" den "OpenProcess" nicht aufrufen die Funktion GetCpuUsage aber schon.
Ich bin jetzt nicht genug Windows Administrator um das nachvollziehen zu können. Kann man irgendwie das Kommando mit einem Benutzer/Kennwort aufrufen???
Wobei die RDP Sitzung habe ich mit einem Administrator Account aufgemacht und wie Beschrieben die Console auch als Administrator gestartet.
Oder hat einer eine andere Lösung?

Dalai 20. Mai 2015 12:55

AW: CPU und Memory Nutzung eines Prozesses
 
Hachja, Meldungen wie "Es ist ein Fehler aufgetreten" sind immer wieder schön zu sehen :roll:. Wie wär's mit GetLastError, wenn eine Funktion wie FindWindow fehlschlägt? Oder gar gleich sowas:
Delphi-Quellcode:
WriteLn(SysErrorMessage(GetLastError));
damit man etwas konkretere Angaben bekommt.

MfG Dalai

himitsu 20. Mai 2015 12:56

AW: CPU und Memory Nutzung eines Prozesses
 
Würdest du die Rückgabewerte der aufgerufenen WinAPIs auswerten, dann wüsstest du, warum die nicht so wollen, wie so sollen.

af99 20. Mai 2015 13:05

AW: CPU und Memory Nutzung eines Prozesses
 
OK, habe WriteLn(SysErrorMessage(GetLastError)); eingebaut

GetProcessMemorySize gibt "Der an einen Systemaufruf übergebene Datenbereich ist zu klein" zurück. Hiermit kann ich nichts anfangen
ShowMemoryUsage gibt "Zugriff verweigert" zurück. Das hatte ich ja vermutet. Nun die Frage wie kann ich Aufruf berechtigen??
ok " Rückgabewerte der aufgerufenen WinAPIs auswerten" Wie mach ich das?

Dalai 20. Mai 2015 13:29

AW: CPU und Memory Nutzung eines Prozesses
 
Zitat:

Zitat von af99 (Beitrag 1302313)
GetProcessMemorySize gibt "Der an einen Systemaufruf übergebene Datenbereich ist zu klein" zurück. Hiermit kann ich nichts anfangen

Aber ich bin mir sicher, dass dein Compiler dich warnt, dass die Variable l_pPMCSize wahrscheinlich nicht initialisiert wurde in der genannten Funktion. Also solltest du das beheben, und dann mit einer passenden Größe Speicher anfordern. Ohne jetzt genauer geschaut zu haben, könnten noch weitere ähnliche Warnungen vorhanden sein.

Ups, hab die Zuweisung der Größe übersehen, sorry. Die Meldung bedeutet, dass der Puffer, den du an eine Funktion übergeben hast, zu klein ist, um die Daten vollständig zurückzugeben. Du solltest ermitteln, welche API-Funktion genau diesen Fehler wirfst, und dann den Puffer vergrößern.

Zitat:

ShowMemoryUsage gibt "Zugriff verweigert" zurück. Das hatte ich ja vermutet. Nun die Frage wie kann ich Aufruf berechtigen??
Welchen Prozess versuchst du denn zu öffnen? Einen, der mit demselben Berechtigugnskontext läuft wie dein Programm? Oder den eines anderen Nutzers? Für letzteres braucht man Adminrechte.

Zitat:

ok " Rückgabewerte der aufgerufenen WinAPIs auswerten" Wie mach ich das?
Konsequent die Funktionsrückgaben auswerten. Ja, klingt doof, aber was gibt denn eine API-Funktion meist zurück? Einen Rückgabewert. Und den solltest du auswerten und bei Fehlschlag eben GetLastError rufen, sofern das im MSDN so angegeben ist für die jeweilige Funktion. Bei einigen Funktionen machst du das ja, aber eben nicht bei allen.

MfG Dalai

BUG 20. Mai 2015 13:41

AW: CPU und Memory Nutzung eines Prozesses
 
Zitat:

Zitat von af99 (Beitrag 1302313)
GetProcessMemorySize gibt "Der an einen Systemaufruf übergebene Datenbereich ist zu klein" zurück.
...
ok " Rückgabewerte der aufgerufenen WinAPIs auswerten" Wie mach ich das?

Guck dir mal den GetProcessMemory-Aufruf an, der setzt vermutlich die oben genannte Fehlermeldung. Kompilierst du zufällig für 64bit? PROCESS_MEMORY_COUNTERS könnte dann eine andere Größe haben (wegen SIZE_T) :glaskugel:
Die dynamische Speicherverwaltung (getMem/freeMem) ist an der Stelle auch völlig überflüssig, PROCESS_MEMORY_COUNTERS passt locker auf den Stack.

Auf jeden Fall gibt GetProcessMemory genau dann 0 zurück, wenn ein Fehler aufgetreten ist. Dann kannst du zum Beispiel eine Exception mit dem Errorcode werfen.
Analog bei allen anderen Systemaufrufen.

af99 20. Mai 2015 14:10

AW: CPU und Memory Nutzung eines Prozesses
 
der Fehler in ShowMemoryUsage kommt hier
Delphi-Quellcode:
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessId);
     begin
       if ( hProcess = 0 ) then
       begin
         WriteLn(SysErrorMessage(GetLastError));
         writeln('fehler');
         Exit;
       end;
das "SysErrorMessage(GetLastError));" bringt "Zugriff verweigert" in der Funktion GetCpuUsage benutze ich "h:=OpenProcess(PROCESS_QUERY_INFORMATION,false,PI D);" und ich bekomme keinen Fehler.
Delphi-Quellcode:
function GetCpuUsage(PID:cardinal):single;
const
    cWaitTime=750;
var
    h : Cardinal;
    mCreationTime,mExitTime,mKernelTime, mUserTime:_FILETIME;
    TotalTime1,TotalTime2:int64;
begin
     {We need to get a handle of the process with PROCESS_QUERY_INFORMATION privileges.}
    h:=OpenProcess(PROCESS_QUERY_INFORMATION,false,PID);
    {We can use the GetProcessTimes() function to get the amount of time the process has spent in kernel mode and user mode.}
    GetProcessTimes(h,mCreationTime,mExitTime,mKernelTime,mUserTime);
    TotalTime1:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32)) + int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));

    {Wait a little}
    Sleep(cWaitTime);

    GetProcessTimes(h,mCreationTime,mExitTime,mKernelTime,mUserTime);
    TotalTime2:=int64(mKernelTime.dwLowDateTime or (mKernelTime.dwHighDateTime shr 32)) + int64(mUserTime.dwLowDateTime or (mUserTime.dwHighDateTime shr 32));

    {This should work out nicely, as there were approx. 250 ms between the calls
    and the result will be a percentage between 0 and 100}
    Result:=((TotalTime2-TotalTime1)/cWaitTime)/100;
    CloseHandle(h);
end;
der Fehler in "GetProcessMemorySize" kommt hier
Delphi-Quellcode:
  l_nWndHandle := FindWindow(nil, PChar(sProcessName));
  if l_nWndHandle = 0 then
  begin
    WriteLn(SysErrorMessage(GetLastError));
    writeln('fehler');
    Result := False;
    Exit;
  end;

af99 20. Mai 2015 14:15

AW: CPU und Memory Nutzung eines Prozesses
 
Zitat:

Welchen Prozess versuchst du denn zu öffnen? Einen, der mit demselben Berechtigugnskontext läuft wie dein Programm? Oder den eines anderen Nutzers? Für letzteres braucht man Adminrechte.
diesen l_nWndHandle := FindWindow(nil, PChar(sProcessName));
dieser gibt 0 zutück
ich denke schon das das in dem selben Berechtigungskonzept passiert. Ist alles ein Programm in einer EXE und das läuft als Consolenprogramm. Die Console ist als Admin ausgeführt.

af99 20. Mai 2015 14:17

AW: CPU und Memory Nutzung eines Prozesses
 
Zitat:

Kompilierst du zufällig für 64bit?
nein als 32 BIT


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:32 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz