C'den Linux'ta PID ile bir işlemin CPU kullanımı nasıl hesaplanır?


95

Linux'ta belirli bir işlem kimliği için CPU kullanımı yüzdesini programlı olarak [C'de] hesaplamak istiyorum.

Belirli bir işlem için gerçek zamanlı CPU kullanımı yüzdesini nasıl elde edebiliriz?

Daha da netleştirmek için:

  • Sağlanan işlem kimliği veya işlem için CPU kullanımını belirleyebilmeliyim.
  • Sürecin alt süreç olması gerekmez.
  • Çözümü 'C' dilinde istiyorum.

peki ya tepenin çıktısını yakalama (grep-ing).
dusoft

Bu gerçekten verimli olmanın en iyi yolu değil; y
codingfreak

"Top" u başlatmak için muhtemelen "pahalı" bir sistem çağrısı gerektirecektir.
Liran Orevi

@Liran: Haklı olarak söyledim :)
vpram86

İşleri bu şekilde yapmayı unutun .... C
codingfreak

Yanıtlar:


153

Verileri çözümlemeniz gerekir /proc/<PID>/stat. Bunlar ilk birkaç alandır ( Documentation/filesystems/proc.txtçekirdek kaynağınızdan):

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

Muhtemelen peşindesiniz utimeve / veya stime. Ayrıca aşağıdaki gibi görünen cpusatırını da okumanız gerekecek /proc/stat:

cpu  192369 7119 480152 122044337 14142 9937 26747 0 0

Bu size çeşitli kategorilerde jiffie birimlerinde kullanılan kümülatif CPU zamanını söyler. Bir time_totalölçü almak için bu satırdaki değerlerin toplamını almanız gerekir .

Her iki Oku utimeve stimesüreç için ilgilendiğiniz ve okumak time_totalgelen /proc/stat. Sonra bir saniye kadar uyu ve hepsini tekrar oku. Artık sürecin CPU kullanımını örnekleme süresi üzerinden şu şekilde hesaplayabilirsiniz:

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

Mantıklı olmak?


12
"Jiffy", CPU zamanının bir birimidir. Duvar saati süresinde tam olarak neye karşılık geldiği, mimariye ve çekirdeğinizin nasıl yapılandırıldığına bağlıdır, ancak önemli olan /proc/stat, CPU'nun toplamda /proc/<PID>/statkaç jiffi çalıştırdığını ve size bir tek süreç.
caf

1
@advocate: Çekirdekten işlem yürütme istatistiklerini almak için bir arayüz uygulayan sözde bir dosyadır.
caf

4
Alanlar hakkında daha fazla bilgi arayanlar için: man procarkadaşınız (aradığınız /proc/[pid]/stat)
redShadow

1
Caf'in çözümünü zizzu'nun sunduğu çözümle (aşağıda) karşılaştırdığımızda, caf'in çözümü sistem ve kullanıcı sürelerini ayrı ayrı verir ancak bu değerlerden hiçbirini CPU sayısı ile çarpmaz. Bunu yapması gerekmiyor mu?
linuxfan

2
Görünüşe göre OP aynı fikirde değil. Buradaki temel fikir, /procsözde dosya sistemini kullanmaktır: standart C dosya sistemi erişim işlevlerinin öğretilmesi gibi fopen()ve konu scanf()yanındadır.
cafe

11

getrusage () mevcut sürecin veya alt işleminin kullanımını belirlemede size yardımcı olabilir

Güncelleme: Bir API'yi hatırlayamıyorum. Ama tüm detaylar / proc / PID / stat içinde olacaktır, bu yüzden eğer onu ayrıştırabilirsek yüzdeyi alabiliriz.

DÜZENLEME: CPU% 'nin hesaplanması kolay olmadığından, burada örnekleme türlerini kullanabilirsiniz. Bir noktada bir PID için ctime ve utime değerini okuyun ve 1 saniye sonra aynı değerleri tekrar okuyun. Farkı bulun ve yüze bölün. Bu işlem için son bir saniye boyunca yararlanacaksınız.

(çok sayıda işlemci varsa daha karmaşık hale gelebilir)


2
Getrusage () sistem çağrısı bir işlemin CPU kullanımını hesaplamama nasıl yardımcı olur?
codingfreak

@codingfreak. soruyu yanlış anladım. Şimdi güncelledikten sonra temizleyin.
vpram86

1
@Aviator CPU% = (processusertime + processkerneltime) / (CPUusertime + CPUkerneltime) "processusertime" vb. Değerleri nasıl alabilirim. ??? "/ Proc / PID / stat" dosyasında farklı değerler görüyorum. Peki hangisi hangi değere karşılık gelir?
codingfreak

@codingfreak: CPU zamanını hesaplamak zor. Sanırım tüm PID istatistiklerinde döngü
yapman gerekiyor

@Aviator bunu yapmanın bir yolu ya da başka yolu olabilir ... çünkü top gibi uygulamalar bile çıktılarında göstermek için CPU kullanımını hesaplamalıdır
codingfreak

7

Benim gibi yeni başlayanlar için kolay adım:

  1. İlk satırını okuyun /proc/statalmak için total_cpu_usage1.
    sscanf(line,"%*s %llu %llu %llu %llu",&user,&nice,&system,&idle);
    total_cpu_usage1 = user + nice + system + idle;
  1. CPU kullanımını bilmek istediğiniz işlemin PID'sinin /proc/pid/statnerede pidolduğunu şu şekilde okuyun :
    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. Şimdi özetlemek usertimeve systemtimeve getproc_times1
  2. Şimdi 1 saniye veya daha fazla bekleyin
  3. Tekrar yap ve al total_cpu_usage2veproc_times2

Formül şudur:

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

CPU miktarını buradan alabilirsiniz /proc/cpuinfo.


2
Çözümünüz iyidir ancak CPU sayısını elde etmek için daha basit hale getirin. Bu adamı dahil edin #include <unistd.h>ve bu yöntemi arayınint nb = sysconf(_SC_NPROCESSORS_ONLN);
David Guyon

1
Delta'nın (proc_times) yürütüldüğü çekirdek için olduğunu varsayarak, neden (işlemci sayısı) ile çarpıldığını anlamıyorum. Faktör veya CPU'larla çarpmadan, doğru olmalıdır.
JayabalanAaron

5

Bir işlemin kullanıcı + çekirdek cpu kullanımını hesaplamak için cafs cevabına dayalı iki küçük C işlevi yazdım: https://github.com/fho/code_snippets/blob/master/c/getusage.c


Derleme sırasında hata verdiğinden derlenmiş bir versiyonu var mı ve bunu nasıl kullanabilirim?
Medhat

Bir main () fonksiyonuna sahip değilim, bu nedenle, sizin derleyebileceğiniz ve çalıştırabileceğinizden "bağımsız" bir program değil. Getusage.c
fho

Gerçekten C işlevlerini kullanmıyor. Sadece komut çıktısını ayrıştırmak için rastgele bir dil kullanmak.
Graham

4

Daha fazla ayrıntı için proc kılavuz sayfasını okuyabilirsiniz , ancak özet olarak bir süreç hakkında bilgi almak için / proc / [sayı] / stat okuyabilirsiniz. Bu aynı zamanda 'ps' komutu tarafından da kullanılır.

Tüm alanlar ve bunların scanf formatı belirleyicileri proc manpag e'de belgelenir .

İşte kopyalanan kılavuz sayfasından bazı bilgiler (oldukça uzun):

          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.

“CPU kullanımı” ve “mevcut durum” konum ve hız gibidir. Birini tanıyorsan diğerini de bilemezsin. CPU kullanımı bir süreye bağlıdır, bu nedenle işleminizin ne sıklıkla "R" durumunda olduğunu kendiniz kontrol etmeniz gerekir.
Bombe

Hmm, güzel soru, her zaman orada olacağını varsaydım! Muhtemelen bu değişkenlerden hesaplayabilmelisiniz
Andre Miller

En üst komutun çıktısını kontrol ederseniz, CPU kullanımını görebilirsiniz .... ancak CPU kullanımını hesaplamak için üst çıktıya girmeye meraklı değilim .....
codingfreak

@codingfreak: ps auxdaha iyi :)
vpram86

@Aviator - CPU USAGE% '
sini

2

"Pidstat" komutuna bir göz atın, tam olarak istediğiniz gibi geliyor.


@James - FEDORA 9 makinemde pidstat komutuna erişemiyorum.
codingfreak

@codingfreak - bunun için Sysstat aracını yüklemeniz gerekiyor
Chintan Parikh

2

Bu benim çözümüm ...

/*
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
Libgtop kitaplığının yardımıyla görünüyor ..?
codingfreak

1
Bunu beğendim - kütüphane basit. Toplam kullanımın toplam kapasitenin yüzde kaçı olduğunu görmenin bir yolu var mı acaba?
Cera

1

Belirtilen işlemi izlemek istediğinizde, genellikle komut dosyasıyla yapılır. İşte perl örneği. Bu, yüzdeleri üstteki ile aynı şekilde koyar ve bir CPU'ya ölçeklendirir. Daha sonra 2 iş parçacığı ile çalışan bazı süreçler aktif olduğunda, cpu kullanımı% 100'den fazla olabilir. Özellikle cpu çekirdeklerinin nasıl sayıldığına bakın: D sonra örneğimi göstereyim:

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

Umarım herhangi bir izlemede size yardımcı olur. Elbette, kullandığım herhangi bir perl regexpes'i C kaynağına dönüştürmek için scanf veya diğer C işlevlerini kullanmalısınız. Tabi uyumak için 1 saniye zorunlu değil. istediğiniz zaman kullanabilirsiniz. etkisi, belirtilen zaman diliminde ortalama yük alırsınız. İzleme için kullanacağınız zaman elbette son değerleri dışarıya koymalısınız. Bu gereklidir, çünkü izleme genellikle komut dosyalarını düzenli olarak çağırır ve komut dosyası işini en kısa sürede bitirmelidir.


0

Kurun psacctveya acctpaketleyin. Ardından sa, çeşitli komutlar için kullanılan CPU zamanını görüntülemek için komutu kullanın. bir adam sayfası

NixCraft sitesinden güzel bir nasıl yapılır.


0

Bence GNU "zaman" komut kaynak koduna bakmaya değer. time Kullanıcı / sistem cpu zamanını gerçek geçen süre ile birlikte verir. Wait3 / wait4 sistem çağrısını (varsa), aksi takdirde sistem çağrısını çağırır. wait * sistem çağrısı bir "rusage" struct değişkeni döndürür ve zaman sistem çağrısı "tms" döndürür. Ayrıca, çok ilginç zamanlama bilgileri veren getrusage sistem çağrısına da göz atabilirsiniz. zaman


GNU "zaman" yalnızca "zaman" ın alt süreci içindir
Graham

0

Bunu proc'tan ayrıştırmak yerine getrusage () veya clock_gettime () gibi işlevler kullanılabilir ve cpu kullanımını bir oran veya wallclock zamanı ve cpu'da kullanılan işlem / iş parçacığı zamanı olarak hesaplayabilir.


getrusage clock_gettime sınırlıdır, tüm işlemler için değil
Graham

0

Strace kullanın, CPU kullanımının bir zaman aralığına göre hesaplanması gerektiğini buldu:

# 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
.
.
.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.