Come calcolare l'utilizzo della CPU di un processo tramite PID in Linux da C?


94

Voglio calcolare programmaticamente [in C] la% di utilizzo della CPU per un dato ID di processo in Linux.

Come possiamo ottenere la percentuale di utilizzo della CPU in tempo reale per un dato processo?

Per renderlo più chiaro:

  • Dovrei essere in grado di determinare l'utilizzo della CPU per il processid o il processo fornito.
  • Il processo non deve essere necessariamente il processo figlio.
  • Voglio la soluzione in linguaggio "C".

che dire di catturare (grep-ing) l'output di top.
dusoft

Questo non è davvero il modo migliore per essere efficienti; y
codingfreak

Probabilmente richiederà una chiamata di sistema "costosa" per avviare "top".
Liran Orevi

@Liran: Giustamente detto :)
vpram86

Dimentica questo modo di fare le cose .... in C
codingfreak

Risposte:


148

È necessario analizzare i dati da /proc/<PID>/stat. Questi sono i primi pochi campi (dal Documentation/filesystems/proc.txtsorgente del kernel):

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

Probabilmente stai cercando utimee / o stime. Dovrai anche leggere la cpuriga da /proc/stat, che assomiglia a:

cpu  192369 7119 480152 122044337 14142 9937 26747 0 0

Questo ti dice il tempo CPU cumulativo che è stato utilizzato in varie categorie, in unità di jiffies. È necessario prendere la somma dei valori su questa riga per ottenere una time_totalmisura.

Leggi entrambi utimee stimeper il processo che ti interessa e leggi time_totalda /proc/stat. Quindi dormi per un secondo o giù di lì e leggili di nuovo. È ora possibile calcolare l'utilizzo della CPU del processo durante il tempo di campionamento, con:

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);

Ha senso?


11
Un "jiffy" è un'unità di tempo della CPU. Esattamente ciò a cui corrisponde nel tempo dell'orologio da parete dipende dall'architettura e da come è configurato il kernel, ma l'importante è che /proc/statti dica quanti jiffies ha eseguito la CPU in totale e /proc/<PID>/statti dice quanti jiffies sono stati eseguiti da un unico processo.
caf

1
@advocate: è uno pseudo-file che implementa un'interfaccia per recuperare le statistiche di esecuzione del processo dal kernel.
caf

4
Per chi cerca maggiori informazioni sui campi: man procè tuo amico (cerca /proc/[pid]/stat)
redShadow

1
Confrontando la soluzione di caf con quella fornita da zizzu (sotto), la soluzione di caf fornisce i tempi di sistema e utente separatamente ma non moltiplica nessuno di questi valori per il numero di CPU. Non dovrebbe farlo?
linuxfan

2
Apparentemente l'OP non era d'accordo. L'intuizione chiave qui è usare lo /procpseudo-file system: l'insegnamento dell'accesso al file system C standard funziona come fopen()ed scanf()è fuori questione.
caf

11

getrusage () può aiutarti a determinare l'utilizzo del processo corrente o del suo figlio

Aggiornamento: non ricordo un'API. Ma tutti i dettagli saranno in / proc / PID / stat, quindi se potessimo analizzarli, possiamo ottenere la percentuale.

EDIT: poiché la percentuale di CPU non è semplice da calcolare, qui puoi usare il campionamento di cose. Leggere ctime e utime per un PID in un determinato momento e leggere di nuovo gli stessi valori dopo 1 sec. Trova la differenza e dividi per cento. Otterrai l'utilizzo per quel processo per un secondo.

(potrebbe diventare più complesso se ci sono molti processori)


2
In che modo la chiamata di sistema getrusage () mi aiuta a calcolare l'utilizzo della CPU di un processo?
codingfreak

@codingfreak. ho frainteso la domanda. Ora, dopo averlo aggiornato, chiaro.
vpram86

1
@ Aviator CPU% = (processusertime + processkerneltime) / (CPUusertime + CPUkerneltime) Come posso ottenere i valori per "processusertime" e così via. ??? Vedo valori diversi in basso nel file "/ proc / PID / stat". Quindi quale corrisponde a quale valore ??
codingfreak

@codingfreak: il tempo della CPU è difficile da calcolare. Hai bisogno di scorrere tutte le statistiche PID immagino (anche se non sono sicuro)
vpram86

@Aviator ci sarebbe un modo o nell'altro per farlo ... dal momento che anche applicazioni come top dovrebbero calcolare l'utilizzo della CPU da mostrare nel loro output
codingfreak

6

Facile passo passo per principianti come me:

  1. Leggi la prima riga di /proc/statper ottenere total_cpu_usage1.
    sscanf(line,"%*s %llu %llu %llu %llu",&user,&nice,&system,&idle);
    total_cpu_usage1 = user + nice + system + idle;
  1. Leggi /proc/pid/statdov'è pidil PID del processo di cui vuoi conoscere l'utilizzo della CPU, in questo modo:
    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. Ora somma usertimee systemtimee ottieniproc_times1
  2. Ora aspetta 1 secondo o più
  3. Fallo di nuovo e ottieni total_cpu_usage2eproc_times2

La formula è:

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

Puoi ottenere la quantità di CPU da /proc/cpuinfo.


2
La tua soluzione è buona, ma per ottenere il numero di CPU, rendila più semplice. Includi questo ragazzo #include <unistd.h>e chiama questo metodoint nb = sysconf(_SC_NPROCESSORS_ONLN);
David Guyon

1
Non capisco perché moltiplicare per il (numero di processori), assumendo che delta (proc_times) sia per il core su cui è stato eseguito. Senza moltiplicare per il fattore o le CPU, dovrebbe essere corretto.
Jayabalan Aaron,

5

Ho scritto due piccole funzioni C basate sulla risposta cafs per calcolare l'utilizzo da parte dell'utente + CPU del kernel di un processo: https://github.com/fho/code_snippets/blob/master/c/getusage.c


c'è una versione compilata di esso in quanto mi dà un errore durante la compilazione e anche come posso usarlo?
Medhat

Non ho una funzione main () quindi non è un programma "autonomo" di quello che puoi compilare ed eseguire. Dovresti scrivere una funzione main () che fa alcune cose con le funzioni di getusage.c
fho

Non sta davvero usando le funzioni C. Basta usare un linguaggio arbitrario per analizzare l'output del comando.
Graham

4

Puoi leggere la manpage di proc per maggiori dettagli, ma in sintesi puoi leggere / proc / [numero] / stat per ottenere le informazioni su un processo. Viene utilizzato anche dal comando "ps".

Tutti i campi e i loro specificatori di formato scanf sono documentati nel manpag e proc .

Ecco alcune delle informazioni copiate dalla manpage (è piuttosto lunga):

          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.

"Utilizzo della CPU" e "stato corrente" sono come posizione e velocità. Se ne conosci uno non puoi conoscere l'altro. L'utilizzo della CPU dipende da una durata, quindi devi controllare tu stesso quanto spesso il tuo processo è nello stato "R".
Bombe

Hmm, bella domanda, ho sempre pensato che sarebbe stato lì! Presumibilmente dovresti essere in grado di calcolarlo da queste variabili
Andre Miller,

Se controlli l'output del comando top puoi vedere l'utilizzo della CPU ... ma non sono interessato a sfogliare l'output superiore per calcolare l'utilizzo della CPU .....
codingfreak

@codingfreak: ps auxis better :)
vpram86

@Aviator - Ti ho già detto di dimenticarti di grepping dell'output di un comando di shell per determinare il% di UTILIZZO della CPU
codingfreak

2

Dai un'occhiata al comando "pidstat", suona esattamente come ti serve.


@ James - Non sono in grado di accedere al comando pidstat nella mia macchina FEDORA 9.
codingfreak

@codingfreak - devi installare lo strumento Sysstat per questo
Chintan Parikh

2

Questa è la mia soluzione ...

/*
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

1
Sembra usare l'aiuto della libreria libgtop ..?
codingfreak

1
Mi piace: la libreria è semplice. Mi chiedo se c'è un modo per vedere quale% della capacità totale è l'utilizzo totale?
Cera

1

Quando si desidera monitorare il processo specificato, di solito viene eseguito tramite script. Ecco un esempio di perl. Questo ha messo le percentuali allo stesso modo di top, ridimensionandole a una CPU. Quindi, quando un processo è attivo lavorando con 2 thread, l'utilizzo della CPU può essere superiore al 100%. Guarda in particolare come vengono contati i core della CPU: D quindi lasciami mostrare il mio esempio:

#!/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;
}

Spero che ti possa aiutare in qualsiasi monitoraggio. Ovviamente dovresti usare scanf o altre funzioni C per convertire qualsiasi regexpe perl che ho usato in sorgente C. Ovviamente 1 secondo per dormire non è obbligatorio. puoi usare in qualsiasi momento. l'effetto è che otterrai un carico medio nel periodo di tempo specificato. Quando lo userai per il monitoraggio, ovviamente gli ultimi valori dovresti mettere fuori. È necessario, perché il monitoraggio di solito chiama gli script periodicamente e lo script dovrebbe terminare il suo lavoro al più presto.


0

Installa psaccto crea un acctpacchetto. Quindi utilizzare il sacomando per visualizzare il tempo della CPU utilizzato per vari comandi. una pagina man

Un bel howto dal sito nixCraft.


0

Penso che valga la pena guardare il codice sorgente del comando GNU "time". time Emette il tempo della CPU utente / sistema insieme al tempo reale trascorso. Chiama la chiamata di sistema wait3 / wait4 (se disponibile) e altrimenti chiama la chiamata di sistema times. la chiamata di sistema wait * restituisce una variabile struct "rusage" e la chiamata di sistema times restituisce "tms". Inoltre, puoi dare un'occhiata alla chiamata di sistema getrusage che restituisce anche informazioni molto interessanti sui tempi. tempo


GNU "time" è solo per il processo figlio del "tempo"
Graham

0

Invece di analizzarlo da proc, si possono usare funzioni come getrusage () o clock_gettime () e calcolare l'utilizzo della CPU come rapporto o tempo di wallclock e tempo del processo / thread utilizzato sulla CPU.


getrusage clock_gettime sono limitati, non per tutti i processi
Graham

0

Usa strace ha rilevato che l'utilizzo della CPU deve essere calcolato in base a un periodo di tempo:

# 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
.
.
.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.