Як розрахувати використання процесора процесом PID в Linux з C?


94

Я хочу програмно [в C] розрахувати% використання процесора для даного ідентифікатора процесу в Linux.

Як ми можемо отримати% використання процесора в реальному часі для даного процесу?

Щоб зробити це далі зрозумілим:

  • Я мав би змогу визначити використання центрального процесора для наданого процесода чи процесу.
  • Процес не повинен бути дочірнім.
  • Я хочу рішення на мові 'C'.

як щодо лову (grep-ing) виводу top.
dusoft

Це насправді не найкращий спосіб зробити ефективно; y
codingfreak

Можливо, знадобиться "дорогий" системний дзвінок для запуску "зверху".
Liran Orevi

@Liran: Правильно сказав :)
vpram86

Забудьте про такий спосіб робити .... в C
codingfreak

Відповіді:


148

Вам потрібно проаналізувати дані з /proc/<PID>/stat. Це перші кілька полів (з Documentation/filesystems/proc.txtвашого джерела ядра):

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

Ви, ймовірно, після utimeі / або stime. Вам також потрібно буде прочитати cpuрядок /proc/stat, який виглядає так:

cpu  192369 7119 480152 122044337 14142 9937 26747 0 0

Це повідомляє вам накопичувальний час процесора, який використовувався в різних категоріях, в одиницях джифа. Вам потрібно взяти суму значень у цьому рядку, щоб отримати time_totalміру.

Читайте як utimeі stimeдля процесу ви зацікавлені в, і читати time_totalз /proc/stat. Тоді поспіть секунду чи близько, і прочитайте їх ще раз. Тепер ви можете розрахувати використання процесором процесу за час дискретизації, за допомогою:

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

Мати сенс?


11
"Хвилювання" - це одиниця часу процесора. Точно, що це відповідає в годинникові години, залежить від архітектури та того, як налаштовано ваше ядро, але найголовніше - це те, що /proc/statповідомляє вам, скільки джипів в цілому виконував процесор, і /proc/<PID>/statскільки джифіків було виконано єдиний процес.
кафе

1
@advocate: Це псевдо-файл, який реалізує інтерфейс для отримання статистики виконання процесів із ядра.
кафе

4
Людям, які шукають додаткову інформацію про поля: man procваш друг (шукати /proc/[pid]/stat)
redShadow

1
Порівнюючи рішення caf з рішенням, наданим zizzu (нижче), рішення caf дає окремий час для системи та користувача, але не помножує жодне з цих значень на кількість процесорів. Чи не слід це робити?
linuxfan

2
Очевидно, OP не погодився. Ключове розуміння тут полягає у використанні /procпсевдо-файлової системи: викладання стандартних функцій доступу до файлової системи C, як fopen()і не scanf()має значення.
кафе

11

getrusage () може допомогти вам у визначенні використання поточного процесу або його дочірньої організації

Оновлення: Я не пам’ятаю API. Але всі деталі будуть у / proc / PID / stat, тому, якщо ми зможемо проаналізувати, ми зможемо отримати відсоток.

РЕДАГУВАТИ: Оскільки CPU% не є прямим для обчислення, ви можете використовувати тут вибірку матеріалів. Зчитуйте ctime і utime для PID в певний момент часу і знову зчитуйте ті самі значення через 1 сек. Знайдіть різницю і поділіть на сотню. Ви отримаєте можливість використовувати цей процес протягом однієї секунди.

(може стати більш складним, якщо процесорів багато)


2
Як системний дзвінок getrusage () допомагає мені підрахувати використання процесора процесом ??
codingfreak

@codingfreak. я неправильно зрозумів питання. Тепер після того, як ви оновили його, зрозуміло.
vpram86

1
@Aviator CPU% = (processusertime + processkerneltime) / (CPUusertime + CPUkerneltime) Як я можу отримати значення для "processusertime" тощо. ??? Я бачу різні значення у файлі "/ proc / PID / stat". Отже, яке з них відповідає якому значенню ??
codingfreak

@codingfreak: Час процесора важко підрахувати. Вам потрібно
прокрутити

@Aviator міг би це зробити так чи інакше ... оскільки навіть такі програми, як top, повинні розрахувати використання центрального процесора, щоб відобразити їх у своїх результатах
codingfreak

6

Простий крок за кроком для таких початківців, як я:

  1. Прочитайте перший рядок, /proc/statщоб отримати total_cpu_usage1.
    sscanf(line,"%*s %llu %llu %llu %llu",&user,&nice,&system,&idle);
    total_cpu_usage1 = user + nice + system + idle;
  1. Прочитайте, /proc/pid/statде pidPID процесу, який ви хочете знати про використання процесора, наприклад:
    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. Тепер підсумовуємо usertimeі systemtimeі отримуємоproc_times1
  2. Тепер зачекайте 1 секунду або більше
  3. Зроби це ще раз, і отримай total_cpu_usage2іproc_times2

Формула така:

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

Ви можете отримати кількість процесора з /proc/cpuinfo.


2
Ваше рішення хороше, але щоб отримати кількість процесорів, спростіть його. Включіть цього хлопця #include <unistd.h>і зателефонуйте за цим методомint nb = sysconf(_SC_NPROCESSORS_ONLN);
Девід yonюйон

1
Я не розумію, чому множити на (кількість процесорів), припускаючи, що дельта (proc_times) - це ядро, на якому воно виконувалось. Не помножуючи на коефіцієнт або процесори, це повинно бути правильно.
JayabalanAaron

5

Я написав дві маленькі функції C на основі відповіді cafs для обчислення використання процесором користувача та ядра процесора: https://github.com/fho/code_snippets/blob/master/c/getusage.c


чи є його скомпільована версія, оскільки це видає мені помилку під час компіляції, а також як я можу її використовувати?
Медхат

У мене немає функції main (), тому це не "автономна" програма, яку ви можете скомпілювати та виконати. Вам доведеться написати функцію main (), яка виконує деякі функції з функціями getusage.c
fho

Це насправді не використовує функції C. Просто використання довільної мови для синтаксичного аналізу виводу команди.
Грем

4

Ви можете прочитати сторінку для proc для більш детальної інформації, але в підсумку ви можете прочитати / proc / [номер] / stat, щоб отримати інформацію про процес. Це також використовується командою 'ps'.

Всі поля та їх специфікатори формату scanf задокументовані в man man .

Ось деякі з інформації з сторінки керівництва скопійованого (це досить довго):

          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.

«Використання центрального процесора» та «поточний стан» - це як місце розташування та швидкість. Якщо ви знаєте одне, не можете знати іншого. Використання центрального процесора залежить від тривалості, тому вам доведеться перевірити себе, наскільки часто ваш процес знаходиться в стані “R”.
Bombe

Хм, гарне запитання, я завжди просто припускав, що воно буде там! Імовірно, ви мали б змогу обчислити його за цими змінними
Андре Міллер,

Якщо ви перевірите вихід верхньої команди, ви побачите використання процесора .... але мене не цікавить прокручування верхнього виходу для розрахунку використання процесора .....
codingfreak

@codingfreak: ps auxis better :)
vpram86

@Aviator - Я вже говорив тобі забути про grepping виведення команди оболонки для визначення% ВИКОРИСТАННЯ ЦПУ
codingfreak

2

Погляньте на команду "pidstat", звучить саме так, як вам потрібно.


@James - Я не можу отримати доступ до команди pidstat на моїй машині FEDORA 9.
codingfreak

@codingfreak - для цього потрібно встановити інструмент
Sysstat

2

Це моє рішення ...

/*
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 ..?
codingfreak

1
Мені це подобається - бібліотека проста. Цікаво, чи є спосіб побачити, який відсоток від загальної потужності становить загальне використання?
Cera

1

Коли ви хочете відстежувати вказаний процес, зазвичай це робиться за допомогою сценаріїв. Ось приклад perl. Це додало відсотки так само, як і верхнє, перерахувавши його на один процесор. Тоді, коли якийсь процес активний, працюючи з 2 потоками, використання процесора може становити більше 100%. Спеціально подивіться, як рахуються ядра процесора: D, то дозвольте мені показати мій приклад:

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

Сподіваюся, це допоможе вам у будь-якому моніторингу. Звичайно, вам слід використовувати scanf або інші функції C для перетворення будь-яких регулярних виразів perl, які я використовував, у джерело C. Звичайно, 1 секунда для сну не є обов’язковою. Ви можете використовувати будь-який час. ефект полягає в тому, що ви отримаєте середнє навантаження на вказаний проміжок часу. Коли ви будете використовувати його для моніторингу, звичайно, останні значення ви повинні поставити зовні. Це потрібно, оскільки моніторинг зазвичай періодично викликає сценарії, і сценарій повинен закінчити свою роботу якомога швидше.



0

Я думаю, що варто подивитися на вихідний код команди GNU "time". час Виводить час процесора користувача / системи разом з реальним минулим часом. Він викликає системний дзвінок wait3 / wait4 (якщо він доступний), а в іншому випадку - системний дзвінок у рази. wait * системний виклик повертає структурну змінну "rusage", а час системного виклику повертає "tms". Крім того, ви можете поглянути на системний дзвінок getrusage, який також поверне дуже цікаву інформацію про час. час


GNU "час" призначений лише для дочірнього процесу "часу"
Грем

0

Замість того, щоб аналізувати це з proc, ви можете використовувати такі функції, як getrusage () або clock_gettime (), і обчислити використання процесора як співвідношення або час настінного годинника та час процесу / потоку, що використовуються на процесорі.


getrusage clock_gettime обмежені, не для всіх процесів
Грехем,

0

Використовуйте строку, виявлено, що використання центрального процесора потрібно обчислювати за періодом часу:

# 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
.
.
.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.