Bagaimana cara menghitung penggunaan CPU dari proses oleh PID di Linux dari C?

94

Saya ingin secara terprogram [dalam C] menghitung% penggunaan CPU untuk ID proses tertentu di Linux.

Bagaimana kita bisa mendapatkan% penggunaan CPU waktu nyata untuk proses tertentu?

Untuk membuatnya lebih jelas:

  • Saya harus dapat menentukan penggunaan CPU untuk proses atau proses yang disediakan.
  • Proses tidak perlu proses anak.
  • Saya ingin solusi dalam bahasa 'C'.
codingfreak
sumber
bagaimana dengan menangkap (grep-ing) keluaran dari atas.
dusoft
Itu benar-benar bukan cara terbaik untuk melakukan dengan efisien; y
codingfreak
Mungkin akan membutuhkan panggilan sistem yang "mahal" untuk memulai 'atas'.
Liran Orevi
@ Liran: Benar dikatakan :)
vpram86
Lupakan cara melakukan sesuatu ini .... di C
codingfreak

Jawaban:

149

Anda perlu mengurai data dari /proc/<PID>/stat. Ini adalah beberapa kolom pertama (dari Documentation/filesystems/proc.txtdalam sumber kernel Anda):

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

Anda mungkin mengejar utimedan / atau stime. Anda juga perlu membaca cpubaris dari /proc/stat, yang terlihat seperti:

cpu  192369 7119 480152 122044337 14142 9937 26747 0 0

Ini memberi tahu Anda waktu CPU kumulatif yang telah digunakan dalam berbagai kategori, dalam satuan jiffies. Anda perlu menjumlahkan nilai pada garis ini untuk mendapatkan time_totalukuran.

Baca baik utimedan stimeuntuk proses Anda tertarik, dan membaca time_totaldari /proc/stat. Kemudian tidur sebentar, dan baca semuanya lagi. Anda sekarang dapat menghitung penggunaan CPU dari proses selama waktu pengambilan sampel, dengan:

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

Masuk akal?

kafe
sumber
12
"Jiffy" adalah satuan waktu CPU. Persisnya waktu jam dinding tergantung pada arsitektur dan bagaimana kernel Anda dikonfigurasi, tetapi yang penting adalah /proc/statmemberi tahu Anda berapa banyak jiff yang telah dieksekusi CPU secara total, dan /proc/<PID>/statmemberi tahu Anda berapa banyak jiffy yang telah dieksekusi oleh a proses tunggal.
kafe
1
@advocate: Ini adalah file semu yang mengimplementasikan antarmuka untuk mengambil statistik eksekusi proses dari kernel.
caf
4
Kepada orang yang mencari informasi lebih lanjut tentang bidang: man procadalah teman Anda (cari /proc/[pid]/stat)
redShadow
1
Membandingkan solusi caf dengan yang disediakan oleh zizzu (di bawah), solusi caf memberikan waktu sistem dan pengguna secara terpisah tetapi tidak mengalikan salah satu dari nilai ini dengan jumlah CPU. Bukankah seharusnya begitu?
linuxfan
2
Rupanya OP tidak setuju. Wawasan utama di sini adalah menggunakan /procsistem file semu: pengajaran tentang fungsi akses sistem file C standar seperti fopen()dan scanf()tidak penting.
caf
11

getrusage () dapat membantu Anda dalam menentukan penggunaan proses saat ini atau turunannya

Pembaruan: Saya tidak dapat mengingat API. Tapi semua detail ada di / proc / PID / stat, jadi kalau bisa kita parsing, kita bisa mendapatkan persentasenya.

EDIT: Karena CPU% tidak langsung menghitung, Anda dapat menggunakan jenis sampel di sini. Baca waktu dan waktu untuk PID pada suatu titik waktu dan baca kembali nilai yang sama setelah 1 detik. Temukan selisihnya dan bagi dengan ratus. Anda akan mendapatkan pemanfaatan untuk proses itu selama satu detik terakhir.

(mungkin menjadi lebih kompleks jika ada banyak prosesor)

vpram86
sumber
2
Bagaimana panggilan sistem getrusage () membantu saya dalam menghitung penggunaan CPU dari suatu proses ??
codingfreak
@coding_coding. saya salah paham pertanyaan itu. Sekarang setelah Anda memperbaruinya, jelas.
vpram86
1
@ Aviator CPU% = (processusertime + processkerneltime) / (CPUusertime + CPUkerneltime) Bagaimana saya bisa mendapatkan nilai untuk "processusertime" dan seterusnya. ??? Saya melihat nilai yang berbeda di file "/ proc / PID / stat". Jadi mana yang sesuai dengan nilai yang mana ??
codingfreak
@codingfreak: Waktu CPU sulit dihitung. Anda perlu mengulang semua statistik PID saya kira (meskipun tidak yakin)
vpram86
@ Aviator akan ada beberapa cara untuk melakukannya ... karena bahkan aplikasi seperti top harus menghitung penggunaan CPU untuk ditampilkan dalam output mereka
codingfreak
7

Langkah mudah untuk pemula seperti saya:

  1. Baca baris pertama /proc/statuntuk mendapatkan total_cpu_usage1.
    sscanf(line,"%*s %llu %llu %llu %llu",&user,&nice,&system,&idle);
    total_cpu_usage1 = user + nice + system + idle;
  1. Baca di /proc/pid/statmana pidPID dari proses yang Anda inginkan untuk mengetahui penggunaan CPU, seperti ini:
    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. Sekarang jumlah usertimedan systemtimedan mendapatkanproc_times1
  2. Sekarang tunggu 1 detik atau lebih
  3. Lakukan lagi, dan dapatkan total_cpu_usage2danproc_times2

Rumusnya adalah:

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

Anda bisa mendapatkan jumlah CPU dari /proc/cpuinfo.

zizzu
sumber
2
Solusi Anda bagus tetapi untuk mendapatkan jumlah CPU, buatlah lebih sederhana. Sertakan orang ini #include <unistd.h>dan beri nama metode iniint nb = sysconf(_SC_NPROCESSORS_ONLN);
David Guyon
1
Saya tidak mengerti mengapa mengalikan dengan (jumlah prosesor), dengan asumsi delta (proc_times) adalah untuk inti yang dieksekusi. Tanpa mengalikan dengan faktor atau CPU, itu harus benar.
JayabalanAaron
5

Saya menulis dua fungsi C kecil berdasarkan jawaban cafs untuk menghitung penggunaan cpu pengguna + kernel dari suatu proses: https://github.com/fho/code_snippets/blob/master/c/getusage.c

fho
sumber
apakah ada versi kompilasi karena itu memberi saya kesalahan saat mengkompilasi dan juga bagaimana saya bisa menggunakannya?
Medhat
Saya tidak memiliki fungsi main () oleh karena itu ini bukan program "mandiri" daripada yang dapat Anda kompilasi dan jalankan. Anda harus menulis fungsi main () yang melakukan beberapa hal dengan fungsi getusage.c
fho
Ini tidak benar-benar menggunakan fungsi C. Hanya menggunakan bahasa yang berubah-ubah untuk mengurai keluaran perintah.
Graham
4

Anda dapat membaca halaman manual proc untuk lebih jelasnya, tetapi secara ringkas anda dapat membaca / proc / [number] / stat untuk mendapatkan informasi tentang suatu proses. Ini juga digunakan oleh perintah 'ps'.

Semua bidang dan penentu format scanf-nya didokumentasikan di proc manpag e.

Berikut adalah beberapa informasi dari halaman manual yang disalin (cukup panjang):

          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
sumber
"Penggunaan CPU" dan "kondisi saat ini" seperti lokasi dan kecepatan. Jika Anda mengenal satu Anda tidak bisa mengenal yang lain. Penggunaan CPU tergantung pada durasi sehingga Anda harus memeriksa sendiri seberapa sering proses Anda dalam status "R".
Bombe
Hmm, pertanyaan bagus, saya selalu berasumsi bahwa itu akan ada di sana! Agaknya Anda harus dapat menghitungnya dari variabel ini
Andre Miller
Jika Anda memeriksa output dari perintah teratas, Anda dapat melihat penggunaan CPU .... tetapi saya tidak tertarik pada hasil atas untuk menghitung penggunaan CPU .....
codingfreak
@codingfreak: ps auxlebih baik :)
vpram86
@ Aviator - Saya sudah memberi tahu Anda untuk melupakan grepping output dari perintah shell untuk menentukan PENGGUNAAN CPU%
codingfreak
2

Lihatlah perintah "pidstat", terdengar seperti yang Anda butuhkan.

James Anderson
sumber
@James - Saya tidak dapat mengakses perintah pidstat di mesin FEDORA 9 saya.
codingfreak
@codingfreak - Anda perlu menginstal alat Sysstat untuk itu
Chintan Parikh
2

Ini solusi saya ...

/*
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
sumber
1
Sepertinya menggunakan bantuan perpustakaan libgtop ..?
codingfreak
1
Saya suka ini - perpustakaannya sangat sederhana. Saya ingin tahu apakah ada cara untuk melihat berapa% dari total kapasitas penggunaan total?
Cera
1

Ketika Anda ingin memantau proses tertentu, biasanya dilakukan dengan scripting. Ini contoh perl. Ini menempatkan persen sebagai cara yang sama seperti atas, menskalakannya ke satu CPU. Kemudian ketika beberapa proses aktif bekerja dengan 2 utas, penggunaan cpu bisa lebih dari 100%. Secara khusus lihat bagaimana inti cpu dihitung: D, biarkan saya menunjukkan contoh saya:

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

Saya harap ini akan membantu Anda dalam pemantauan apa pun. Tentu saja Anda harus menggunakan scanf atau fungsi C lainnya untuk mengubah regexp perl yang saya gunakan ke sumber C. Tentu 1 detik untuk tidur tidak wajib. Anda dapat menggunakan kapan saja. Akibatnya, Anda akan mendapatkan beban rata-rata pada periode waktu yang ditentukan. Saat Anda akan menggunakannya untuk monitoring, tentu nilai terakhir harus Anda letakkan di luar. Hal ini diperlukan, karena monitoring biasanya memanggil skrip secara berkala, dan skrip harus segera menyelesaikan pekerjaannya.

Znik
sumber
0

Instal psacctatau acctpaketkan. Kemudian gunakan saperintah untuk menampilkan waktu CPU yang digunakan untuk berbagai perintah. sa halaman manual

Howto bagus dari situs nixCraft.

Penjaga pantai
sumber
0

Saya pikir ada baiknya melihat kode sumber perintah "waktu" GNU. waktu Ini mengeluarkan waktu cpu pengguna / sistem bersama dengan waktu yang berlalu secara nyata. Ini memanggil panggilan sistem wait3 / wait4 (jika tersedia) dan sebaliknya memanggil kali panggilan sistem. wait * system call mengembalikan variabel struct "rusage" dan waktu system call mengembalikan "tms". Juga, Anda dapat melihat panggilan sistem getrusage yang juga mengembalikan informasi waktu yang sangat menarik. waktu

pengguna3288728
sumber
GNU "waktu" adalah untuk proses anak dari "waktu" saja
Graham
0

Alih-alih mem-parsing ini dari proc, seseorang dapat menggunakan fungsi seperti getrusage () atau clock_gettime () dan menghitung penggunaan cpu sebagai rasio atau waktu jam dan waktu proses / utas yang digunakan pada cpu.

ensonik
sumber
getrusage clock_gettime terbatas, tidak untuk semua proses
Graham
0

Gunakan strace yang ditemukan bahwa penggunaan CPU perlu dihitung dengan jangka waktu:

# 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
sumber