วิธีคำนวณการใช้งาน CPU ของกระบวนการโดย PID ใน Linux จาก C?


95

ฉันต้องการเขียนโปรแกรม [ใน C] คำนวณ% การใช้งาน CPU สำหรับ ID กระบวนการที่กำหนดใน Linux

เราจะรับ% การใช้งาน CPU แบบเรียลไทม์สำหรับกระบวนการที่กำหนดได้อย่างไร

เพื่อให้ชัดเจนยิ่งขึ้น:

  • ฉันควรจะสามารถกำหนดการใช้งาน CPU สำหรับ processid หรือกระบวนการที่ให้มา
  • กระบวนการไม่จำเป็นต้องเป็นกระบวนการย่อย
  • ฉันต้องการคำตอบในภาษา 'C'

สิ่งที่เกี่ยวกับการจับ (grep-ing) เอาต์พุตด้านบน
dusoft

นั่นไม่ใช่วิธีที่ดีที่สุดในการทำงานอย่างมีประสิทธิภาพ y
codingfreak

อาจต้องใช้การเรียกระบบ "ราคาแพง" เพื่อเริ่ม "ด้านบน"
Liran Orevi

@Liran: พูดถูก :)
vpram86

ลืมวิธีการทำสิ่งนี้ .... ใน C
codingfreak

คำตอบ:


153

/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 สะสมที่ใช้ในหมวดหมู่ต่างๆในหน่วย jiffies คุณต้องหาผลรวมของค่าในบรรทัดนี้เพื่อtime_totalวัดผล

อ่านทั้งสองutimeและstimeสำหรับกระบวนการที่คุณสนใจในกำลังและอ่านจาก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);

เข้าท่า?


12
"ระยะสั้น" คือหน่วยของเวลา CPU สิ่งที่สอดคล้องกับเวลานาฬิกาแขวนนั้นขึ้นอยู่กับสถาปัตยกรรมและวิธีกำหนดค่าเคอร์เนลของคุณ แต่สิ่งสำคัญคือจะ/proc/statบอกจำนวน jiffies ที่ CPU ดำเนินการทั้งหมดและ/proc/<PID>/statบอกคุณว่ามีการดำเนินการ jiffies กี่ครั้งโดย a กระบวนการเดียว
คาเฟ่

1
@advocate: เป็นไฟล์หลอกที่ใช้อินเทอร์เฟซเพื่อดึงข้อมูลสถิติการดำเนินการกระบวนการจากเคอร์เนล
คาเฟ่

4
สำหรับผู้ที่กำลังมองหาข้อมูลเพิ่มเติมเกี่ยวกับฟิลด์: man procคือเพื่อนของคุณ (ค้นหา/proc/[pid]/stat)
redShadow

1
เมื่อเปรียบเทียบโซลูชันของ Caf กับโซลูชันที่จัดทำโดย zizzu (ด้านล่าง) โซลูชันของ Caf จะให้เวลาของระบบและผู้ใช้แยกกัน แต่จะไม่คูณค่าใดค่าหนึ่งกับจำนวน CPU มันไม่ควรทำอย่างนั้นเหรอ?
linuxfan

2
เห็นได้ชัดว่า OP ไม่เห็นด้วย ข้อมูลเชิงลึกที่สำคัญคือการใช้/procระบบไฟล์หลอก: การสอนฟังก์ชันการเข้าถึงระบบไฟล์ C มาตรฐานเหมือนfopen()และscanf()อยู่ข้างประเด็น
คาเฟ่

11

getrusage ()สามารถช่วยคุณในการกำหนดการใช้งานของกระบวนการปัจจุบันหรือลูกของมัน

อัปเดต: ฉันจำ API ไม่ได้ แต่รายละเอียดทั้งหมดจะอยู่ใน / proc / PID / stat ดังนั้นหากเราแยกวิเคราะห์ได้เราจะได้เปอร์เซ็นต์

แก้ไข: เนื่องจาก% CPU ไม่ตรงไปตรงมาในการคำนวณคุณสามารถใช้ประเภทการสุ่มตัวอย่างได้ที่นี่ อ่าน ctime และ utime สำหรับ PID ในช่วงเวลาหนึ่งและอ่านค่าเดิมอีกครั้งหลังจากผ่านไป 1 วินาที หาความแตกต่างแล้วหารด้วยร้อย คุณจะได้รับการใช้ประโยชน์จากกระบวนการนั้นในช่วง 1 วินาทีที่ผ่านมา

(อาจซับซ้อนขึ้นหากมีโปรเซสเซอร์หลายตัว)


2
การเรียกระบบ getrusage () ช่วยฉันในการคำนวณการใช้ CPU ของกระบวนการได้อย่างไร?
codingfreak

@codingfreak. ฉันเข้าใจคำถามผิด ตอนนี้หลังจากที่คุณปรับปรุงมันชัดเจน
vpram86

1
@Aviator CPU% = (processusertime + processkerneltime) / (CPUusertime + CPUkerneltime) ฉันจะรับค่าสำหรับ "processusertime" และอื่น ๆ ได้อย่างไร ??? ฉันเห็นค่าที่แตกต่างกันในไฟล์ "/ proc / PID / stat" แล้วอันไหนสอดคล้องกับค่าไหน ??
codingfreak

@codingfreak: เวลา CPU คำนวณยาก คุณต้องวนซ้ำสถิติ PID ทั้งหมดฉันเดา (แต่ไม่แน่ใจ)
vpram86

@Aviator จะมีวิธีใดวิธีหนึ่งหรือวิธีอื่นที่จะทำ ... เนื่องจากแม้แต่แอปพลิเคชันอย่าง top ก็ควรคำนวณการใช้งาน CPU เพื่อแสดงในเอาต์พุต
codingfreak

7

ขั้นตอนง่ายๆสำหรับผู้เริ่มต้นอย่างฉัน:

  1. อ่านบรรทัดแรกของการที่จะได้รับ/proc/stattotal_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 ของกระบวนการที่คุณต้องการทราบการใช้งาน CPU อยู่ที่ไหนเช่นนี้:
    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)

คุณจะได้รับปริมาณของ CPU /proc/cpuinfoจาก


2
วิธีแก้ปัญหาของคุณดี แต่เพื่อให้ได้จำนวนซีพียูทำให้ง่ายขึ้น รวมผู้ชายคนนี้#include <unistd.h>และเรียกวิธีนี้ว่าint nb = sysconf(_SC_NPROCESSORS_ONLN);
David Guyon

1
ฉันไม่เข้าใจว่าเหตุใดจึงคูณด้วย (จำนวนโปรเซสเซอร์) โดยถือว่าเดลต้า (proc_times) เป็นแกนหลักที่ประมวลผล โดยไม่ต้องคูณด้วยแฟคเตอร์หรือซีพียูก็น่าจะถูกต้อง
JayabalanAaron

5

ฉันเขียนฟังก์ชัน C สองตัวตามคำตอบของคาเฟ่เพื่อคำนวณการใช้ซีพียูของผู้ใช้ + เคอร์เนลของกระบวนการ: https://github.com/fho/code_snippets/blob/master/c/getusage.c


มีเวอร์ชันที่คอมไพล์หรือไม่เนื่องจากทำให้เกิดข้อผิดพลาดขณะรวบรวมและฉันจะใช้งานได้อย่างไร
Medhat

ฉันไม่มีฟังก์ชัน main () ดังนั้นจึงไม่ใช่โปรแกรม "แบบสแตนด์อโลน" มากกว่าที่คุณจะรวบรวมและดำเนินการได้ คุณจะต้องเขียนฟังก์ชัน main () ที่ทำบางสิ่งด้วยฟังก์ชันของ getusage.c
fho

มันไม่ได้ใช้ฟังก์ชัน C จริงๆ เพียงแค่ใช้ภาษาที่กำหนดเองเพื่อแยกวิเคราะห์เอาต์พุตคำสั่ง
Graham

4

คุณสามารถอ่านmanpage สำหรับ procเพื่อดูรายละเอียดเพิ่มเติม แต่โดยสรุปคุณสามารถอ่าน / proc / [number] / stat เพื่อรับข้อมูลเกี่ยวกับกระบวนการ นอกจากนี้ยังใช้คำสั่ง 'ps'

ฟิลด์ทั้งหมดและตัวระบุรูปแบบ scanf ได้รับการบันทึกไว้ในproc manpag e

นี่คือข้อมูลบางส่วนจากmanpage ที่คัดลอกมา (ค่อนข้างยาว):

          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” บ่อยเพียงใด
Bombe

อืมเป็นคำถามที่ดีฉันคิดว่ามันน่าจะอยู่ที่นั่นเสมอ! สันนิษฐานว่าคุณน่าจะคำนวณได้จากตัวแปรเหล่านี้
Andre Miller

หากคุณตรวจสอบผลลัพธ์ของคำสั่งด้านบนคุณจะเห็นการใช้งาน CPU .... แต่ฉันไม่ได้สนใจในการ greping ผ่านเอาต์พุตด้านบนเพื่อคำนวณการใช้งาน CPU .....
codingfreak

@codingfreak: ps auxดีกว่า :)
vpram86

@Aviator - ฉันได้บอกให้คุณลืมเกี่ยวกับการ grepping เอาต์พุตของคำสั่งเชลล์เพื่อกำหนด CPU USAGE%
codingfreak

2

ดูที่คำสั่ง "pidstat" ซึ่งดูเหมือนว่าคุณต้องการทุกประการ


@ เจมส์ - ฉันไม่สามารถเข้าถึงคำสั่ง pidstat ในเครื่อง FEDORA 9 ของฉันได้
codingfreak

@codingfreak - คุณต้องติดตั้งเครื่องมือ Sysstat
Chintan Parikh

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 library .. ?
codingfreak

1
ฉันชอบสิ่งนี้ - ห้องสมุดตรงไปตรงมา ฉันสงสัยว่ามีวิธีดูว่า% ของความจุทั้งหมดของการใช้งานทั้งหมดคืออะไร?
Cera

1

เมื่อคุณต้องการตรวจสอบกระบวนการที่ระบุโดยปกติจะทำโดยการเขียนสคริปต์ นี่คือตัวอย่าง perl สิ่งนี้ทำให้เปอร์เซ็นต์เป็นแบบเดียวกับด้านบนโดยย่อให้เป็นหนึ่งซีพียู จากนั้นเมื่อบางกระบวนการทำงานกับ 2 เธรดการใช้งานซีพียูอาจมากกว่า 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 อื่น ๆ เพื่อแปลง regexpes perl ที่ฉันเคยใช้เป็นแหล่ง C แน่นอน 1 วินาทีสำหรับการนอนหลับไม่ได้บังคับ คุณสามารถใช้ได้ทุกเมื่อ ผลคือคุณจะได้รับ averrage load ในช่วงเวลาที่ระบุ คุณจะใช้มันเพื่อการตรวจสอบเมื่อใดแน่นอนว่าค่าสุดท้ายที่คุณควรใส่ไว้ข้างนอก จำเป็นเนื่องจากการมอนิเตอร์มักจะเรียกใช้สคริปต์เป็นระยะ ๆ และสคริปต์ควรทำงานให้เสร็จโดยเร็ว



0

ฉันคิดว่ามันคุ้มค่าที่จะดูซอร์สโค้ดคำสั่ง "เวลา" ของ GNU เวลา ส่งออกเวลาซีพียูของผู้ใช้ / ระบบพร้อมกับเวลาที่ผ่านไปจริง มันเรียกการโทรของระบบ wait3 / wait4 (ถ้ามี) และมิฉะนั้นจะเรียกครั้งที่ระบบโทร wait * system call ส่งคืนค่าตัวแปร struct "rusage" และเวลาที่ระบบเรียกคืน "tms" นอกจากนี้คุณสามารถดูการเรียกระบบ getrusage ซึ่งส่งคืนข้อมูลเวลาที่น่าสนใจอีกด้วย เวลา


"เวลา" ของ GNU มีไว้สำหรับกระบวนการย่อยของ "เวลา" เท่านั้น
Graham

0

แทนที่จะแยกวิเคราะห์สิ่งนี้จาก proc เราสามารถใช้ฟังก์ชันเช่น getrusage () หรือ clock_gettime () และคำนวณการใช้ซีพียูเป็นอัตราส่วนหรือเวลาวอลล็อกและเวลาของกระบวนการ / เธรดที่ใช้กับซีพียู


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
.
.
.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.