Làm thế nào để tính toán mức sử dụng CPU của một quá trình bằng PID trong Linux từ C?


94

Tôi muốn lập trình [trong C] tính% sử dụng CPU cho một ID quy trình nhất định trong Linux.

Làm cách nào chúng ta có thể nhận được% sử dụng CPU theo thời gian thực cho một quá trình nhất định?

Để làm rõ hơn:

  • Tôi sẽ có thể xác định mức sử dụng CPU cho processid hoặc process được cung cấp.
  • Quá trình không cần phải là quá trình con.
  • Tôi muốn giải pháp bằng ngôn ngữ 'C'.

còn về việc bắt (grep-ing) đầu ra hàng đầu thì sao.
dusoft 14/09/09

Thats thực sự không phải là một cách tốt nhất để làm hiệu quả; y
codingfreak

Có thể sẽ yêu cầu một cuộc gọi hệ thống "đắt tiền" để bắt đầu 'đầu'.
Liran Orevi 14/09/09

@Liran: Đã nói đúng :)
vpram86 14/09/09

Quên cách này làm việc .... trong C
codingfreak

Câu trả lời:


148

Bạn cần phân tích dữ liệu từ /proc/<PID>/stat. Đây là một số trường đầu tiên (từ Documentation/filesystems/proc.txttrong nguồn hạt nhân của bạn):

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

Có thể bạn đang theo đuổi utimevà / hoặc stime. Bạn cũng sẽ cần đọc cpudòng từ /proc/statđó, giống như sau:

cpu  192369 7119 480152 122044337 14142 9937 26747 0 0

Điều này cho bạn biết thời gian CPU tích lũy được sử dụng trong các danh mục khác nhau, tính theo đơn vị giây. Bạn cần lấy tổng các giá trị trên dòng này để lấy số time_totalđo.

Đọc cả hai utimestimecho quá trình bạn quan tâm và đọc time_totaltừ đó /proc/stat. Sau đó, ngủ trong một giây hoặc lâu hơn, và đọc lại tất cả chúng. Bây giờ bạn có thể tính toán mức sử dụng CPU của quy trình theo thời gian lấy mẫu, với:

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

Có lý?


11
"Jiffy" là một đơn vị thời gian CPU. Chính xác những gì nó tương ứng với thời gian đồng hồ treo tường phụ thuộc vào kiến ​​trúc và cách cấu hình hạt nhân của bạn, nhưng điều quan trọng là nó /proc/statcho bạn biết tổng cộng CPU đã thực thi /proc/<PID>/statbao nhiêu jiffies và cho bạn biết có bao nhiêu jiffies đã được thực thi bởi một quy trình đơn lẻ.
caf

1
@advocate: Đó là một tệp giả cài đặt một giao diện để truy xuất số liệu thống kê thực thi quy trình từ hạt nhân.
caf

4
Gửi đến những người đang tìm kiếm thêm thông tin về các lĩnh vực: man proclà bạn của bạn (tìm kiếm /proc/[pid]/stat)
redShadow

1
So sánh giải pháp của caf với giải pháp do zizzu cung cấp (bên dưới), giải pháp của caf cho thời gian của hệ thống và người dùng riêng biệt nhưng không nhân một trong hai giá trị này với số CPU. Nó không nên làm điều đó?
linuxfan

2
Rõ ràng OP không đồng ý. Điều quan trọng ở đây là sử dụng /prochệ thống tệp giả: việc giảng dạy các chức năng truy cập hệ thống tệp C tiêu chuẩn giống như fopen()và ở scanf()bên cạnh điểm.
caf

11

getrusage () có thể giúp bạn xác định việc sử dụng quy trình hiện tại hoặc quy trình con của nó

Cập nhật: Tôi không thể nhớ một API. Nhưng tất cả các chi tiết sẽ nằm trong / proc / PID / stat, vì vậy nếu chúng ta có thể phân tích cú pháp nó, chúng ta có thể nhận được phần trăm.

CHỈNH SỬA: Vì% CPU không được tính thẳng, bạn có thể sử dụng loại lấy mẫu ở đây. Đọc ctime và utime cho PID tại một thời điểm và đọc lại các giá trị tương tự sau 1 giây. Tìm hiệu và chia cho hàng trăm. Bạn sẽ được sử dụng cho quá trình đó trong một giây qua.

(có thể phức tạp hơn nếu có nhiều bộ xử lý)


2
Lệnh gọi hệ thống getrusage () giúp tôi tính toán mức sử dụng CPU của một tiến trình như thế nào ??
codingfreak 14/09/09

@codingfreak. tôi đã hiểu sai câu hỏi. Bây giờ sau khi bạn cập nhật nó, rõ ràng.
vpram86 14/09/09

1
@Aviator CPU% = (processusertime + processkerneltime) / (CPUusertime + CPUkerneltime) Làm cách nào để lấy các giá trị cho "processusertime", v.v. ??? Tôi thấy các giá trị khác nhau trong tệp "/ proc / PID / stat". Vậy cái nào tương ứng với giá trị nào ??
codingfreak 14/09/09

@codingfreak: Khó tính thời gian của CPU. U cần phải lặp qua tất cả PID stats tôi đoán (mặc dù không chắc chắn)
vpram86

@Aviator sẽ có một số cách này hay cách khác để làm điều đó ... kể từ khi ứng dụng thậm chí như trên nên tính toán việc sử dụng CPU để hiển thị trong kết quả của họ
codingfreak

6

Bước dễ dàng để thực hiện cho người mới bắt đầu như tôi:

  1. Đọc dòng đầu tiên của /proc/statđể có được total_cpu_usage1.
    sscanf(line,"%*s %llu %llu %llu %llu",&user,&nice,&system,&idle);
    total_cpu_usage1 = user + nice + system + idle;
  1. Đọc /proc/pid/statđâu pidlà PID của quá trình bạn muốn biết mức sử dụng CPU, như sau:
    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. Bây giờ tổng hợp usertimesystemtime và getproc_times1
  2. Bây giờ hãy đợi 1 giây trở lên
  3. Làm lại, và lấy total_cpu_usage2proc_times2

Công thức là:

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

Bạn có thể lấy số lượng CPU từ /proc/cpuinfo.


2
Giải pháp của bạn là tốt nhưng để có được số lượng CPU, hãy làm cho nó đơn giản hơn. Bao gồm anh chàng này #include <unistd.h>và gọi phương pháp nàyint nb = sysconf(_SC_NPROCESSORS_ONLN);
David Guyon

1
Tôi không hiểu tại sao lại nhân với (số bộ xử lý), giả sử delta (proc_times) là cho lõi mà nó thực thi. Nếu không nhân với hệ số hoặc CPU, nó sẽ chính xác.
JayabalanAaron

5

Tôi đã viết hai hàm C nhỏ dựa trên câu trả lời cafs để tính toán mức sử dụng cpu của người dùng + nhân của một quá trình: https://github.com/fho/code_snippets/blob/master/c/getusage.c


có một phiên bản đã biên dịch của nó vì Nó mang lại cho tôi lỗi khi biên dịch và tôi cũng có thể sử dụng nó như thế nào?
Medhat

Tôi không có hàm main () do đó nó không phải là một chương trình "độc lập" mà bạn có thể biên dịch và thực thi. Bạn sẽ phải viết một hàm main () mà không một số điều với các chức năng của getusage.c
fho

Nó không thực sự sử dụng các hàm C. Chỉ cần sử dụng một ngôn ngữ tùy ý để phân tích cú pháp đầu ra lệnh.
Graham

4

Bạn có thể đọc manpage for proc để biết thêm chi tiết, nhưng tóm lại bạn có thể đọc / proc / [number] / stat để biết thông tin về một process. Điều này cũng được sử dụng bởi lệnh 'ps'.

Tất cả các trường và mã định dạng scanf của chúng được ghi lại trong thẻ proc manpag e.

Dưới đây là một số thông tin từ trang đã sao chép (nó khá dài):

          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.

“Mức sử dụng CPU” và “trạng thái hiện tại” giống như vị trí và vận tốc. Nếu bạn biết cái này, bạn không thể biết cái kia. Việc sử dụng CPU phụ thuộc vào khoảng thời gian, vì vậy bạn phải tự kiểm tra tần suất quá trình của mình ở trạng thái “R”.
Bombe 14/09/09

Hmm, câu hỏi hay, tôi luôn cho rằng nó sẽ ở đó! Có lẽ bạn sẽ có thể tính toán nó từ các biến này
Andre Miller

Nếu bạn kiểm tra đầu ra của lệnh trên bạn có thể thấy việc sử dụng CPU .... nhưng tôi không Intrested trong greping qua sản lượng hàng đầu để sử dụng tính toán CPU .....
codingfreak

@codingfreak: ps auxtốt hơn :)
vpram86. 14/09/09

@Aviator - Tôi đã nói với u để quên đi grepping đầu ra của một lệnh shell để xác định CPU USAGE%
codingfreak

2

Hãy xem lệnh "pidstat", âm thanh giống chính xác những gì bạn yêu cầu.


@James - Tôi không thể truy cập lệnh pidstat trong máy FEDORA 9 của mình.
codingfreak 14/09/09

@codingfreak - bạn cần cài đặt công cụ Sysstat cho nó
Chintan Parikh

2

Đây là giải pháp của tôi ...

/*
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
Có vẻ như đang sử dụng sự trợ giúp của thư viện libgtop ..?
codingfreak

1
Tôi thích điều này - thư viện rất đơn giản. Không biết có cách nào để xem tổng dung lượng sử dụng là bao nhiêu% không?
Cera

1

Khi bạn muốn giám sát quá trình cụ thể, thường nó được thực hiện bằng cách viết kịch bản. Đây là ví dụ về perl. Điều này đặt phần trăm giống như cách trên, chuyển nó vào một CPU. Sau đó, khi một số tiến trình đang hoạt động với 2 luồng, việc sử dụng cpu có thể nhiều hơn 100%. Đặc biệt hãy xem cách tính số lõi cpu: D sau đó để tôi đưa ra ví dụ của tôi:

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

Tôi hy vọng nó sẽ giúp bạn trong bất kỳ giám sát. Tất nhiên, bạn nên sử dụng scanf hoặc các hàm C khác để chuyển đổi bất kỳ regexpe perl nào mà tôi đã sử dụng sang nguồn C. Tất nhiên 1 giây để ngủ là không bắt buộc. bạn có thể sử dụng bất kỳ lúc nào. hiệu quả là, bạn sẽ nhận được tải trọng trong khoảng thời gian xác định. Khi bạn sử dụng nó để theo dõi, tất nhiên giá trị cuối cùng bạn nên đặt bên ngoài. Nó là cần thiết, vì giám sát thường gọi các tập lệnh theo định kỳ và tập lệnh sẽ hoàn thành công việc của anh ta càng sớm càng tốt.



0

Tôi nghĩ rằng nó đáng xem xét mã nguồn lệnh GNU "time". thời gian Nó xuất ra thời gian cpu của người dùng / hệ thống cùng với thời gian thực đã trôi qua. Nó gọi cuộc gọi hệ thống wait3 / wait4 (nếu có) và nếu không nó sẽ gọi lần cuộc gọi hệ thống. cuộc gọi hệ thống wait * trả về một biến cấu trúc "rusage" và lần gọi hệ thống trả về "tms". Ngoài ra, bạn có thể xem lệnh gọi hệ thống getrusage cũng trả về thông tin thời gian rất thú vị. thời gian


GNU "thời gian" chỉ dành cho tiến trình con của "thời gian"
Graham

0

Thay vì phân tích cú pháp này từ proc, người ta có thể sử dụng các hàm như getrusage () hoặc clock_gettime () và tính toán mức sử dụng cpu dưới dạng tỷ lệ hoặc thời gian ép xung và thời gian tiến trình / luồng được sử dụng trên cpu.


clock_gettime getrusage được giới hạn, không phải cho tất cả các quá trình
Graham

0

Sử dụng strace nhận thấy mức sử dụng CPU cần được tính theo một khoảng thời gian:

# 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
.
.
.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.