Wie berechnet man die CPU-Auslastung eines Prozesses durch PID unter Linux aus C?

94

Ich möchte programmgesteuert [in C] die CPU-Auslastung% für eine bestimmte Prozess-ID unter Linux berechnen.

Wie können wir die Echtzeit-CPU-Auslastung% für einen bestimmten Prozess ermitteln?

Um es noch deutlicher zu machen:

  • Ich sollte in der Lage sein, die CPU-Auslastung für die bereitgestellte Prozess-ID oder den Prozess zu bestimmen.
  • Der Prozess muss nicht der untergeordnete Prozess sein.
  • Ich möchte die Lösung in der Sprache 'C'.
Codingfreak
quelle
Was ist mit dem Fangen (Greifen) der Ausgabe von Top?
Dusoft
Das ist wirklich nicht der beste Weg, um effizient zu arbeiten; y
Codingfreak
Erfordert wahrscheinlich einen "teuren" Systemaufruf, um "top" zu starten.
Liran Orevi
@Liran: Zu Recht gesagt :)
vpram86
Vergessen Sie diese Art, Dinge zu tun ... in C
Codingfreak

Antworten:

148

Sie müssen die Daten aus analysieren /proc/<PID>/stat. Dies sind die ersten Felder (aus Documentation/filesystems/proc.txtIhrer Kernelquelle):

Table 1-3: Contents of the stat files (as of 2.6.22-rc3)
..............................................................................
 Field          Content
  pid           process id
  tcomm         filename of the executable
  state         state (R is running, S is sleeping, D is sleeping in an
                uninterruptible wait, Z is zombie, T is traced or stopped)
  ppid          process id of the parent process
  pgrp          pgrp of the process
  sid           session id
  tty_nr        tty the process uses
  tty_pgrp      pgrp of the tty
  flags         task flags
  min_flt       number of minor faults
  cmin_flt      number of minor faults with child's
  maj_flt       number of major faults
  cmaj_flt      number of major faults with child's
  utime         user mode jiffies
  stime         kernel mode jiffies
  cutime        user mode jiffies with child's
  cstime        kernel mode jiffies with child's

Du bist wahrscheinlich hinterher utimeund / oder stime. Sie müssen auch die cpuZeile lesen /proc/stat, die wie folgt aussieht:

cpu  192369 7119 480152 122044337 14142 9937 26747 0 0

Hier erfahren Sie die kumulierte CPU-Zeit, die in verschiedenen Kategorien verwendet wurde, in Einheiten von Sekundenschnelle. Sie müssen die Summe der Werte in dieser Zeile nehmen, um ein time_totalMaß zu erhalten.

Lesen Sie beide utimeund stimeden Prozess, an dem Sie interessiert sind, und lesen Sie time_totalaus /proc/stat. Schlafen Sie dann etwa eine Sekunde und lesen Sie sie alle noch einmal. Sie können jetzt die CPU-Auslastung des Prozesses über die Abtastzeit berechnen mit:

user_util = 100 * (utime_after - utime_before) / (time_total_after - time_total_before);
sys_util = 100 * (stime_after - stime_before) / (time_total_after - time_total_before);

Sinn ergeben?

caf
quelle
11
Ein "Jiffy" ist eine Einheit der CPU-Zeit. Was genau es in der /proc/statWanduhrzeit entspricht, hängt von der Architektur und der Konfiguration Ihres Kernels ab. Wichtig ist jedoch, dass Sie wissen, wie viele Jiffies die CPU insgesamt ausgeführt hat und /proc/<PID>/statwie viele Jiffies von a ausgeführt wurden einzelner Prozess.
Café
1
@advocate: Es ist eine Pseudodatei, die eine Schnittstelle implementiert, um Prozessausführungsstatistiken vom Kernel abzurufen.
Café
4
Für Leute, die nach mehr Informationen über die Felder suchen: man procist dein Freund (Suche nach /proc/[pid]/stat)
redShadow
1
Wenn man die Lösung von caf mit der von zizzu (unten) bereitstellt, gibt die Lösung von caf die System- und Benutzerzeiten getrennt an, multipliziert jedoch keinen dieser Werte mit der Anzahl der CPUs. Sollte es das nicht tun?
Linuxfan
2
Anscheinend war das OP anderer Meinung. Die wichtigste Erkenntnis hierbei ist die Verwendung des /procPseudo-Dateisystems: Das Erlernen von Standardfunktionen für den Zugriff auf C-Dateisysteme ist wie fopen()und scanf()nebensächlich.
Café
11

getrusage () kann Ihnen dabei helfen, die Verwendung des aktuellen Prozesses oder seines untergeordneten Prozesses zu bestimmen

Update: Ich kann mich nicht an eine API erinnern. Alle Details befinden sich jedoch in / proc / PID / stat. Wenn wir sie also analysieren könnten, könnten wir den Prozentsatz ermitteln.

BEARBEITEN: Da die Berechnung von CPU% nicht einfach ist, können Sie hier Stichproben verwenden. Lesen Sie ctime und utime für eine PID zu einem bestimmten Zeitpunkt und lesen Sie dieselben Werte nach 1 Sekunde erneut. Finde den Unterschied und dividiere durch hundert. Sie erhalten die Nutzung für diesen Prozess für die letzte Sekunde.

(Wird möglicherweise komplexer, wenn viele Prozessoren vorhanden sind.)

vpram86
quelle
2
Wie hilft mir der Systemaufruf getrusage () bei der Berechnung der CPU-Auslastung eines Prozesses?
Codingfreak
@codingfreak. Ich habe die Frage falsch verstanden. Jetzt, nachdem du es aktualisiert hast, klar.
vpram86
1
@Aviator CPU% = (Prozessbenutzungszeit + Prozesskernzeit) / (CPU-Zeit + CPU-Zeit) Wie kann ich die Werte für "Prozesszeit" usw. abrufen? ??? Ich sehe verschiedene Werte in der Datei "/ proc / PID / stat". Welcher entspricht also welchem ​​Wert?
Codingfreak
@codingfreak: Die CPU-Zeit ist schwer zu berechnen. Sie müssen alle PID-Statistiken durchlaufen, obwohl ich nicht sicher
bin
@Aviator gibt es die eine oder andere Möglichkeit, dies zu tun ... da sogar Anwendungen wie top die CPU-Auslastung berechnen sollten, um sie in ihrer Ausgabe
anzuzeigen
6

Einfacher Schritt für Schritt für Anfänger wie mich:

  1. Lesen Sie die erste Zeile von /proc/stat, um zu erhalten total_cpu_usage1.
    sscanf(line,"%*s %llu %llu %llu %llu",&user,&nice,&system,&idle);
    total_cpu_usage1 = user + nice + system + idle;
  1. Lesen Sie, /proc/pid/statwo pidist die PID des Prozesses Sie die CPU - Auslastung wissen möchten, wie folgt aus :
    sscanf(line,
    "%*d %*s %*c %*d" //pid,command,state,ppid

    "%*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu"

    "%lu %lu" //usertime,systemtime

    "%*ld %*ld %*ld %*ld %*ld %*ld %*llu"

    "%*lu", //virtual memory size in bytes
    ....)
  1. Jetzt summiere usertimeund systemtimeund bekommeproc_times1
  2. Warten Sie nun mindestens 1 Sekunde
  3. Mach es noch einmal und hol total_cpu_usage2undproc_times2

Die Formel lautet:

(number of processors) * (proc_times2 - proc_times1) * 100 / (float) (total_cpu_usage2 - total_cpu_usage1)

Sie können die Anzahl der CPUs von erhalten /proc/cpuinfo.

zizzu
quelle
2
Ihre Lösung ist gut, aber um die Anzahl der CPUs zu ermitteln, machen Sie es einfacher. Schließen Sie diesen Kerl ein #include <unistd.h>und nennen Sie diese Methodeint nb = sysconf(_SC_NPROCESSORS_ONLN);
David Guyon
1
Ich verstehe nicht, warum mit der (Anzahl der Prozessoren) multipliziert wird, vorausgesetzt, Delta (proc_times) ist für den Kern, auf dem es ausgeführt wurde. Ohne mit dem Faktor oder den CPUs zu multiplizieren, sollte es korrekt sein.
JayabalanAaron
5

Ich habe zwei kleine C-Funktionen basierend auf der Antwort von cafs geschrieben, um die Benutzer- und Kernel-CPU-Auslastung eines Prozesses zu berechnen: https://github.com/fho/code_snippets/blob/master/c/getusage.c

fho
quelle
Gibt es eine kompilierte Version davon, da sie mir beim Kompilieren Fehler gibt und wie kann ich sie verwenden?
Medhat
Ich habe keine main () -Funktion, daher ist es kein "eigenständiges" Programm, das Sie kompilieren und ausführen können. Sie müssten eine main () -Funktion schreiben, die einige Dinge mit den Funktionen von getusage.c macht
für den
Es werden nicht wirklich C-Funktionen verwendet. Verwenden Sie einfach eine beliebige Sprache, um die Befehlsausgabe zu analysieren.
Graham
4

Sie können die Manpage für proc für weitere Details lesen, aber zusammenfassend können Sie / proc / [number] / stat lesen, um Informationen über einen Prozess zu erhalten. Dies wird auch vom Befehl 'ps' verwendet.

Alle Felder und ihre Scanf-Formatspezifizierer sind in der Proc-Manpag e dokumentiert .

Hier sind einige Informationen aus der Manpage kopiert (es ist ziemlich lang):

          pid %d The process ID.

          comm %s
                 The  filename of the executable, in parentheses.  This is
                 visible whether or not the executable is swapped out.

          state %c
                 One character from the string "RSDZTW" where  R  is  runâ
                 ning,  S is sleeping in an interruptible wait, D is waitâ
                 ing in uninterruptible disk sleep,  Z  is  zombie,  T  is
                 traced or stopped (on a signal), and W is paging.

          ppid %d
                 The PID of the parent.

          pgrp %d
                 The process group ID of the process.

          session %d
                 The session ID of the process.

          tty_nr %d
                 The tty the process uses.

          tpgid %d
                 The  process group ID of the process which currently owns
                 the tty that the process is connected to.
Andre Miller
quelle
"CPU-Auslastung" und "aktueller Status" sind wie Standort und Geschwindigkeit. Wenn Sie einen kennen, können Sie den anderen nicht kennen. Die CPU-Auslastung hängt von der Dauer ab. Sie müssen daher selbst überprüfen, wie oft sich Ihr Prozess im Status „R“ befindet.
Bombe
Hmm, gute Frage, ich habe immer nur angenommen, dass es da sein würde! Vermutlich sollten Sie in der Lage sein, es aus diesen Variablen zu berechnen
Andre Miller
Wenn Sie die Ausgabe des Befehls top überprüfen, können Sie die CPU-Auslastung sehen ... aber ich bin nicht daran interessiert, die Top-Ausgabe zu durchsuchen, um die CPU-Auslastung zu berechnen ...
Codingfreak
@ Codingfreak: ps auxist besser :)
vpram86
@Aviator - Ich habe dir bereits gesagt, du sollst vergessen, die Ausgabe eines Shell-Befehls zu
überprüfen
2

Schauen Sie sich den Befehl "pidstat" an, der genau so klingt, wie Sie es benötigen.

James Anderson
quelle
@James - Ich kann auf meinem FEDORA 9-Computer nicht auf den Befehl pidstat zugreifen.
Codingfreak
@codingfreak - Sie müssen Sysstat Tool dafür installieren
Chintan Parikh
2

Das ist meine Lösung ...

/*
this program is looking for CPU,Memory,Procs also u can look glibtop header there was a lot of usefull function have fun..
systeminfo.c
*/
#include <stdio.h>
#include <glibtop.h>
#include <glibtop/cpu.h>
#include <glibtop/mem.h>
#include <glibtop/proclist.h>



int main(){

glibtop_init();

glibtop_cpu cpu;
glibtop_mem memory;
glibtop_proclist proclist;

glibtop_get_cpu (&cpu);
glibtop_get_mem(&memory);


printf("CPU TYPE INFORMATIONS \n\n"
"Cpu Total : %ld \n"
"Cpu User : %ld \n"
"Cpu Nice : %ld \n"
"Cpu Sys : %ld \n"
"Cpu Idle : %ld \n"
"Cpu Frequences : %ld \n",
(unsigned long)cpu.total,
(unsigned long)cpu.user,
(unsigned long)cpu.nice,
(unsigned long)cpu.sys,
(unsigned long)cpu.idle,
(unsigned long)cpu.frequency);

printf("\nMEMORY USING\n\n"
"Memory Total : %ld MB\n"
"Memory Used : %ld MB\n"
"Memory Free : %ld MB\n"
"Memory Buffered : %ld MB\n"
"Memory Cached : %ld MB\n"
"Memory user : %ld MB\n"
"Memory Locked : %ld MB\n",
(unsigned long)memory.total/(1024*1024),
(unsigned long)memory.used/(1024*1024),
(unsigned long)memory.free/(1024*1024),
(unsigned long)memory.shared/(1024*1024),
(unsigned long)memory.buffer/(1024*1024),
(unsigned long)memory.cached/(1024*1024),
(unsigned long)memory.user/(1024*1024),
(unsigned long)memory.locked/(1024*1024));

int which,arg;
glibtop_get_proclist(&proclist,which,arg);
printf("%ld\n%ld\n%ld\n",
(unsigned long)proclist.number,
(unsigned long)proclist.total,
(unsigned long)proclist.size);
return 0;
}

makefile is
CC=gcc
CFLAGS=-Wall -g
CLIBS=-lgtop-2.0 -lgtop_sysdeps-2.0 -lgtop_common-2.0

cpuinfo:cpu.c
$(CC) $(CFLAGS) systeminfo.c -o systeminfo $(CLIBS)
clean:
rm -f systeminfo
Mohan Ram
quelle
1
Scheint mit Hilfe der libgtop Bibliothek .. ..?
Codingfreak
1
Ich mag das - die Bibliothek ist unkompliziert. Ich frage mich, ob es eine Möglichkeit gibt, festzustellen, wie viel Prozent der Gesamtkapazität die Gesamtnutzung ausmacht.
Cera
1

Wenn Sie einen bestimmten Prozess überwachen möchten, erfolgt dies normalerweise per Skript. Hier ist ein Perl-Beispiel. Dadurch werden die Prozentwerte auf die gleiche Weise wie oben angegeben und auf eine CPU verteilt. Wenn dann ein Prozess aktiv ist und mit 2 Threads arbeitet, kann die CPU-Auslastung mehr als 100% betragen. Schauen Sie sich insbesondere an, wie CPU-Kerne gezählt werden: D Lassen Sie mich dann mein Beispiel zeigen:

#!/usr/bin/perl

my $pid=1234; #insert here monitored process PID

#returns current process time counters or single undef if unavailable
#returns:  1. process counter  , 2. system counter , 3. total system cpu cores
sub GetCurrentLoads {
    my $pid=shift;
    my $fh;
    my $line;
    open $fh,'<',"/proc/$pid/stat" or return undef;
    $line=<$fh>;
    close $fh;
    return undef unless $line=~/^\d+ \([^)]+\) \S \d+ \d+ \d+ \d+ -?\d+ \d+ \d+ \d+ \d+ \d+ (\d+) (\d+)/;
    my $TimeApp=$1+$2;
    my $TimeSystem=0;
    my $CpuCount=0;
    open $fh,'<',"/proc/stat" or return undef;
    while (defined($line=<$fh>)) {
        if ($line=~/^cpu\s/) {
            foreach my $nr ($line=~/\d+/g) { $TimeSystem+=$nr; };
            next;
        };
        $CpuCount++ if $line=~/^cpu\d/;
    }
    close $fh;
    return undef if $TimeSystem==0;
    return $TimeApp,$TimeSystem,$CpuCount;
}

my ($currApp,$currSys,$lastApp,$lastSys,$cores);
while () {
    ($currApp,$currSys,$cores)=GetCurrentLoads($pid);
    printf "Load is: %5.1f\%\n",($currApp-$lastApp)/($currSys-$lastSys)*$cores*100 if defined $currApp and defined $lastApp and defined $currSys and defined $lastSys;
    ($lastApp,$lastSys)=($currApp,$currSys);
    sleep 1;
}

Ich hoffe, es wird Ihnen bei jeder Überwachung helfen. Natürlich sollten Sie scanf oder andere C-Funktionen verwenden, um alle Perl-Regexpes, die ich verwendet habe, in C-Quellen zu konvertieren. Natürlich ist 1 Sekunde zum Schlafen nicht obligatorisch. Sie können jederzeit verwenden. Der Effekt ist, dass Sie eine durchschnittliche Belastung für den angegebenen Zeitraum erhalten. Wenn Sie es zur Überwachung verwenden, sollten Sie natürlich die letzten Werte außerhalb setzen. Dies ist erforderlich, da die Überwachung normalerweise regelmäßig Skripte aufruft und das Skript seine Arbeit so schnell wie möglich beenden sollte.

Znik
quelle
0

Installieren psacctoder acctverpacken. Verwenden Sie dann den saBefehl, um die CPU-Zeit anzuzeigen, die für verschiedene Befehle verwendet wird. sa man page

Ein schönes Howto von der nixCraft Seite.

Rettungsschwimmer
quelle
0

Ich denke, es lohnt sich, den Quellcode des GNU-Befehls "time" zu betrachten. Zeit Gibt die CPU-Zeit des Benutzers / Systems zusammen mit der tatsächlich verstrichenen Zeit aus. Es ruft den Systemaufruf wait3 / wait4 auf (falls verfügbar), andernfalls ruft es den Systemaufruf mal auf. wait * Systemaufruf gibt eine Strukturvariable "rusage" zurück und times Systemaufruf gibt "tms" zurück. Sie können sich auch den getrusage-Systemaufruf ansehen, der auch sehr interessante Timing-Informationen zurückgibt. Zeit

user3288728
quelle
GNU "Zeit" ist nur für den Kinderprozess "Zeit"
Graham
0

Anstatt dies aus proc zu analysieren, kann man Funktionen wie getrusage () oder clock_gettime () verwenden und die CPU-Auslastung als Verhältnis oder Wanduhrzeit und -zeit des auf der CPU verwendeten Prozesses / Threads berechnen.

Ensonic
quelle
getrusage clock_gettime sind begrenzt, nicht für alle Prozesse
Graham
0

Use strace hat festgestellt, dass die CPU-Auslastung nach einem bestimmten Zeitraum berechnet werden muss:

# top -b -n 1 -p 3889
top - 16:46:37 up  1:04,  3 users,  load average: 0.00, 0.01, 0.02
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  5594496 total,  5158284 free,   232132 used,   204080 buff/cache
KiB Swap:  3309564 total,  3309564 free,        0 used.  5113756 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 3889 root      20   0  162016   2220   1544 S   0.0  0.0   0:05.77 top
# strace top -b -n 1 -p 3889
.
.
.
stat("/proc/3889", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/3889/stat", O_RDONLY)       = 7
read(7, "3889 (top) S 3854 3889 3854 3481"..., 1024) = 342
.
.
.

nanosleep({0, 150000000}, NULL)         = 0
.
.
.
stat("/proc/3889", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/3889/stat", O_RDONLY)       = 7
read(7, "3889 (top) S 3854 3889 3854 3481"..., 1024) = 342
.
.
.
Jinming Lv
quelle