Как рассчитать загрузку ЦП процесса по PID в Linux из C?

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

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

Чтобы было еще яснее:

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

13 ответов

Решение

Вам нужно разобрать данные из /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);

Есть смысл?

getrusage() может помочь вам определить использование текущего процесса или его потомка

Обновление: я не могу вспомнить API. Но все детали будут в / proc /PID/ stat, поэтому, если мы сможем разобрать его, мы сможем получить процент.

РЕДАКТИРОВАТЬ: Поскольку CPU % не является простым для вычисления, вы можете использовать здесь выборки типа вещи. Считайте ctime и utime для PID в определенный момент времени и снова прочитайте те же значения через 1 сек. Найдите разницу и разделите на сто. Вы получите использование для этого процесса в течение одной секунды.

(может быть более сложным, если есть много процессоров)

Легкий шаг за шагом для нубов, как я:)

прочитайте первую строку / proc / stat, чтобы получить total_cpu_usage1

sscanf(line,"%*s %llu %llu %llu %llu",&user,&nice,&system,&idle);
total_cpu_usage1 = user + nice + system + idle;

прочитайте / proc / pid / stat, где pid - это pid процесса, который вы хотите знать об использовании процессора, например:

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

теперь суммируйте пользовательское и системное время и получите proc_times1

теперь подождите 1 секунду или больше

сделайте это снова, и получите total_cpu_usage2 и proc_times2

формула:

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

Вы можете получить номер процессора из / proc / cpuinfo

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

Вы можете прочитать man-страницу для proc для более подробной информации, но в итоге вы можете прочитать /proc/[number]/stat, чтобы получить информацию о процессе. Это также используется командой 'ps'.

Все поля и их спецификаторы формата scanf описаны в документации по proc.

Вот некоторая информация из скопированной справочной страницы (она довольно длинная):

          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.

Это мое решение...

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

Посмотрите на команду "pidstat", звучит именно так, как вам нужно.

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

Когда вы хотите отслеживать указанный процесс, обычно это делается с помощью сценариев. Вот пример Perl. Это ставит проценты так же, как и top, сбрасывая его на один процессор. Затем, когда какой-то процесс активно работает с двумя потоками, загрузка процессора может превышать 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 секунда для сна не обязательна. Вы можете использовать в любое время. В результате вы получите среднюю нагрузку за указанный период времени. Когда вы будете использовать его для мониторинга, конечно, последние значения вы должны выставить наружу. Это необходимо, потому что мониторинг обычно вызывает сценарии периодически, и сценарий должен завершить свою работу как можно скорее.

htop -p <pid-of-process> . В нем будут перечислены все процессоры и их использование.

Использование strace обнаружило, что использование ЦП необходимо рассчитывать по периоду времени:

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

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

Устанавливать psacct или же acct пакет. Затем используйте sa команда для отображения времени процессора, используемого для различных команд. страница руководства

Хорошая инструкция с сайта nixCraft.

Другие вопросы по тегам