如何用C在Linux中通过PID计算进程的CPU使用率?


94

我想以编程方式[在C中]为Linux中给定的进程ID计算CPU使用率%。

如何获得给定进程的实时CPU使用率百分比?

为了进一步说明:

  • 我应该能够确定所提供的processid或进程的CPU使用率。
  • 该进程不必是子进程。
  • 我想要“ C”语言的解决方案。

捕获(grep-ing)top输出怎么样?
dusoft

那真的不是提高效率的最佳方法; y
encodingfreak

可能需要“昂贵”的系统调用才能启动“ top”。
Liran Orevi

@Liran:正确说:)
vpram86

忘记这种做事的方式....在C中
encodingfreak

Answers:


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

这将告诉您已在各种类别中以累计量为单位使用的累计CPU时间。您需要对这条线上的值求和才能得到time_total度量。

同时读取utimestime进行过程中,你有兴趣,并阅读time_total来自/proc/stat。然后睡一秒钟左右,然后再次阅读它们。现在,您可以使用以下命令计算采样时间内该进程的CPU使用率:

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
“跳动”是CPU时间的单位。确切的说,它对应于时钟时间取决于体系结构和内核配置方式,但重要的是要/proc/stat告诉您CPU总共执行/proc/<PID>/stat了多少次调试,并告诉您一个CPU已执行了多少次调试。单进程。
caf

1
@拥护者:这是一个伪文件,它实现一个接口以从内核检索进程执行统计信息。
caf 2012年

4
对于寻求有关该领域的更多信息的人们:man proc是您的朋友(搜索/proc/[pid]/stat
redShadow 2013年

1
将caf的解决方案与zizzu提供的解决方案进行比较(下图),caf的解决方案分别为系统和用户提供了时间,但是这些值都不乘以CPU数量。它不应该这样做吗?
linuxfan

2
显然,OP不同意。这里的关键见解是使用/proc伪文件系统:标准C文件系统访问功能(如fopen()scanf())的讲授并不重要。
caf

11

getrusage()可以帮助您确定当前进程或其子进程的使用情况

更新: 我不记得一个API。但是所有详细信息都将在/ proc / PID / stat中,因此,如果我们可以解析它,则可以得到百分比。

编辑: 由于CPU%不能直接计算,因此您可以在此处使用采样类型的东西。在某个时间点读取PID的ctime和utime,并在1秒后再次读取相同的值。找出差异并除以一百。您将在过去一秒钟内获得该过程的利用率。

(如果有很多处理器,可能会变得更加复杂)


2
getrusage()系统调用如何帮助我计算进程的CPU使用率?
09年

@codingfreak。我误解了这个问题。现在,在您更新它之后,清除。
vpram86

1
@Aviator CPU%=(processusertime + processkerneltime)/(CPUusertime + CPUkerneltime)如何获取“ processusertime”的值,依此类推。??? 我在“ / proc / PID / stat”文件中看到了不同的值。那么哪个对应于哪个值?
09年

@codingfreak:CPU时间很难计算。你需要遍历我猜(虽然不确定)的所有PID统计信息
vpram86

@Aviator可能有其他方法...因为甚至像top这样的应用程序也应该计算CPU使用率以在其输出中显示
encodingfreak 2009年

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. 读取要了解CPU使用情况的进程的PID,在/proc/pid/stat哪里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
    ....)
  1. 现在总结usertimesystemtime和GETproc_times1
  2. 现在等待1秒或更长时间
  3. 做一遍,并得到total_cpu_usage2proc_times2

公式为:

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

您可以从获得CPU的数量/proc/cpuinfo


2
您的解决方案很好,但是要获得CPU数量,请使其更简单。包括这个人#include <unistd.h>并调用此方法int nb = sysconf(_SC_NPROCESSORS_ONLN);
David Guyon 2014年

1
我不明白为什么要乘以(处理器数量),假设delta(proc_times)是执行它的核心。不乘以系数或CPU,它应该是正确的。
JayabalanAaron

5

我写了两个基于cafs答案的小C函​​数来计算进程的用户+内核cpu使用量:https : //github.com/fho/code_snippets/blob/master/c/getusage.c


它是否有编译版本,因为它在编译时给我错误,我该如何使用?
Medhat 2014年

我没有main()函数,因此它不是可以编译和执行的“独立”程序。您将必须编写一个main()函数来使用getusage.c的功能进行某些操作
2014年

它不是真的使用C函数。仅使用任意语言来解析命令输出。
格雷厄姆

4

您可以阅读proc联机帮助页获取更多详细信息,但总而言之,您可以阅读/ proc / [number] / stat以获取有关进程的信息。“ ps”命令也使用此命令。

所有字段及其scanf格式说明符均记录在proc manpag中

以下是复制的联机帮助页中的一些信息(很长):

          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使用率”和“当前状态”就像位置和速度。如果您知道一个,就不会。CPU使用率取决于持续时间,因此您必须检查一下自己的进程处于“ R”状态的频率。
孟买

嗯,好问题,我一直以为会在那里!大概您应该能够从这些变量中计算出它
Andre Miller 2009年

如果您检查top命令的输出,您会看到CPU使用率....,但是我对使用top输出计算CPU使用率并不感兴趣....
09年

@codingfreak:ps aux更好:)
vpram86

@Aviator-我已经告诉过您,不要忘记对shell命令的输出进行
grep


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 2012年

1

当您想要监视指定的进程时,通常是通过脚本来完成的。这是perl的示例。这样将百分比与top相同,将其缩放到一个CPU。然后,当某个进程正在使用2个线程工作时,CPU使用率可能超过100%。特别看看cpu核心是如何计算的: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

安装psacctacct打包。然后使用该sa命令显示用于各种命令的CPU时间。 手册页

一个不错的HOWTO从nixCraft网站。


0

我认为值得一看GNU“时间”命令源代码。time 输出用户/系统的cpu时间以及实际经过的时间。它调用wait3 / wait4系统调用(如果可用),否则调用次系统调用。wait *系统调用返回“ rusage”结构变量,并且系统调用返回“ tms”时间。另外,您可以查看getrusage系统调用,该系统调用还返回非常有趣的时序信息。时间


GNU“时间”仅适用于“时间”的子进程
Graham

0

除了可以从proc解析该函数​​外,还可以使用诸如getrusage()或clock_gettime()之类的函数,并以比率或挂钟时间以及CPU上使用的进程/线程的时间来计算CPU使用率。


getrusage clock_gettime是受限制的,并非适用于所有进程
Graham

0

使用strace发现需要按时间段来计算CPU使用率:

# 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
.
.
.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.