Linux下計算進程的CPU占用和內存占用的編程方法


Linux下沒有直接可以調用系統函數知道CPU占用和內存占用。那么如何知道CPU和內存信息呢。只有通過proc偽文件系統來實現。

proc偽文件就不介紹了,只說其中4個文件。一個是/proc/stat,/proc/meminfo,/proc/<pid>/status,/proc/<pid>/stat

摘自:http://www.blogjava.net/fjzag/articles/317773.html

/proc/stat:存放系統的CPU時間信息

該文件包含了所有CPU活動的信息,該文件中的所有值都是從系統啟動開始累計到當前時刻。不同內核版本中該文件的格式可能不大一致,以下通過實例來說明數據該文件中各字段的含義。

實例數據:2.6.24-24版本上的

fjzag@fjzag-desktop:~$ cat /proc/stat

cpu 38082 627 27594 893908 12256 581 895 0 0

cpu0 22880 472 16855 430287 10617 576 661 0 0

cpu1 15202 154 10739 463620 1639 4 234 0 0

intr 120053 222 2686 0 1 1 0 5 0 3 0 0 0 47302 0 0 34194 29775 0 5019 845 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

ctxt 1434984

btime 1252028243

processes 8113

procs_running 1

procs_blocked 0

第一行的數值表示的是CPU總的使用情況,所以我們只要用第一行的數字計算就可以了。下表解析第一行各數值的含義:

參數 解析(單位:jiffies)

(jiffies是內核中的一個全局變量,用來記錄自系統啟動一來產生的節拍數,在linux中,一個節拍大致可理解為操作系統進程調度的最小時間片,不同linux內核可能值有不同,通常在1ms到10ms之間)

user (38082) 從系統啟動開始累計到當前時刻,處於用戶態的運行時間,不包含 nice值為負進程。

nice (627) 從系統啟動開始累計到當前時刻,nice值為負的進程所占用的CPU時間

system (27594) 從系統啟動開始累計到當前時刻,處於核心態的運行時間

idle (893908) 從系統啟動開始累計到當前時刻,除IO等待時間以外的其它等待時間iowait (12256) 從系統啟動開始累計到當前時刻,IO等待時間(since 2.5.41)

irq (581) 從系統啟動開始累計到當前時刻,硬中斷時間(since 2.6.0-test4)

softirq (895) 從系統啟動開始累計到當前時刻,軟中斷時間(since 2.6.0-test4)stealstolen(0) which is the time spent in other operating systems when running in a virtualized environment(since 2.6.11)

guest(0) which is the time spent running a virtual CPU for guest operating systems under the control of the Linux kernel(since 2.6.24)

結論2:總的cpu時間totalCpuTime = user + nice + system + idle + iowait + irq + softirq + stealstolen + guest

可以利用scanf,sscanf,fscanf讀取這些信息,具體可以查man proc.我的程序中只取了前4個。

/proc/meminfo:存放系統的內存信息

[ubuntu@root ~]#cat /proc/meminfo
MemTotal:        2061616 kB
MemFree:         1093608 kB
Buffers:          151140 kB
Cached:           479372 kB
SwapCached:            0 kB
Active:           516964 kB
Inactive:         374672 kB
Active(anon):     261412 kB
Inactive(anon):     5604 kB
Active(file):     255552 kB
Inactive(file):   369068 kB

……

別的就不說了,主要看第一個MemTotal,系統總的物理內存,它比真實的物理內存要小一點

/proc/<pid>/status:存放進程的CPU時間信息以及一些綜合信息

[ubuntu@root ~]#cat /proc/889/status
Name:    Xorg
State:    S (sleeping)
Tgid:    889
Pid:    889
PPid:    881
TracerPid:    0
Uid:    0    0    0    0
Gid:    0    0    0    0
FDSize:    256
Groups:   
VmPeak:       99036 kB
VmSize:       52424 kB
VmLck:           0 kB
VmHWM:       57004 kB
VmRSS:       45508 kB
VmData:       35668 kB
VmStk:         136 kB
VmExe:        1660 kB
VmLib:        6848 kB
VmPTE:         120 kB
VmPeak是占用虛擬內存的峰值,也就是最高的一個值,而且是虛擬內存,所以有時候會比物理內存要大。PS和TOP指令都是利用VmPeak計算內存占用的。

VmRSS是進程所占用的實際物理內存。

/proc/<pid>/stat:保存着進程的CPU信息。

[ubuntu@root ~]#cat /proc/889/stat
889 (Xorg) S 881 889 889 1031 889 4202752 5307477 0 0 0 34943 12605 0 0 20 0 1 0 8146 89399296 11377 4294967295 134512640 136211844 3221201472 3221200460 5456930 0 0 3149824 1367369423 3223423286 0 0 17 0 0 0 0 0 0

pid=889 進程號

utime=34943 該任務在用戶態運行的時間,單位為jiffies

stime=12605 該任務在核心態運行的時間,單位為jiffies

cutime=0 所有已死線程在用戶態運行的時間,單位為jiffies

cstime=0 所有已死在核心態運行的時間,單位為jiffies

可以利用scanf,sscanf,fscanf讀取這些信息,具體可以查man proc.

結論3:進程的總Cpu時間processCpuTime = utime + stime + cutime + cstime,該值包括其所有線程的cpu時間。


以上這些數據都可以通過文件讀取的方式,可以按照一行一行的讀取,然后采用scanf,sscanf,fscanf獲取信息。

占用內存的計算方法:

pmem = VmRSS / MemTotal * 100;

計算CPU占用的方法:

取一次processCpuTime1和totalCpuTime1;

間隔一段時間;

再取一次processCpuTime2和totalCpuTime2;

pcpu = 100 * (processCpuTime2 – processCpuTime1)/(totalCpuTime2 - totalCpuTime1);


代碼

 1 get_cpu.h
 2 
 3 #ifdef __cplusplus
 4 extern "C"{
 5 #endif
 6 
 7 #define VMRSS_LINE 15//VMRSS所在行
 8 #define PROCESS_ITEM 14//進程CPU時間開始的項數
 9 
10 typedef struct        //聲明一個occupy的結構體
11 {
12         unsigned int user;  //從系統啟動開始累計到當前時刻,處於用戶態的運行時間,不包含 nice值為負進程。
13         unsigned int nice;  //從系統啟動開始累計到當前時刻,nice值為負的進程所占用的CPU時間
14         unsigned int system;//從系統啟動開始累計到當前時刻,處於核心態的運行時間
15         unsigned int idle;  //從系統啟動開始累計到當前時刻,除IO等待時間以外的其它等待時間iowait (12256) 從系統啟動開始累計到當前時刻,IO等待時間(since 2.5.41)
16 }total_cpu_occupy_t;
17 
18 typedef struct
19 {
20     pid_t pid;//pid號
21     unsigned int utime;  //該任務在用戶態運行的時間,單位為jiffies
22     unsigned int stime;  //該任務在核心態運行的時間,單位為jiffies
23     unsigned int cutime;//所有已死線程在用戶態運行的時間,單位為jiffies
24     unsigned int cstime;  //所有已死在核心態運行的時間,單位為jiffies
25 }process_cpu_occupy_t;
26 
27     int get_phy_mem(const pid_t p);//獲取占用物理內存
28     int get_total_mem();//獲取系統總內存
29     unsigned int get_cpu_total_occupy();//獲取總的CPU時間
30     unsigned int get_cpu_process_occupy(const pid_t p);//獲取進程的CPU時間
31     const char* get_items(const char* buffer,int ie);//取得緩沖區指定項的起始地址
32     
33     extern float get_pcpu(pid_t p);//獲取進程CPU占用
34     extern float get_pmem(pid_t p);//獲取進程內存占用
35     extern int get_rmem(pid_t p);//獲取真實物理內存
36     
37     
38 #ifdef __cplusplus
  1 get_cpu.c
  2 
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <unistd.h>   //頭文件
  6 #include <assert.h>
  7 #include "get_cpu.h"
  8 
  9 int get_phy_mem(const pid_t p)
 10 {
 11     char file[64] = {0};//文件名
 12   
 13     FILE *fd;         //定義文件指針fd
 14     char line_buff[256] = {0};  //讀取行的緩沖區
 15     sprintf(file,"/proc/%d/status",p);//文件中第11行包含着
 16 
 17     fprintf (stderr, "current pid:%d\n", p);                                                                                                  
 18     fd = fopen (file, "r"); //以R讀的方式打開文件再賦給指針fd
 19 
 20     //獲取vmrss:實際物理內存占用
 21     int i;
 22     char name[32];//存放項目名稱
 23     int vmrss;//存放內存峰值大小
 24     for (i=0;i<VMRSS_LINE-1;i++)
 25     {
 26         fgets (line_buff, sizeof(line_buff), fd);
 27     }//讀到第15行
 28     fgets (line_buff, sizeof(line_buff), fd);//讀取VmRSS這一行的數據,VmRSS在第15行
 29     sscanf (line_buff, "%s %d", name,&vmrss);
 30     fprintf (stderr, "====%s:%d====\n", name,vmrss);
 31     fclose(fd);     //關閉文件fd
 32     return vmrss;
 33 }
 34 
 35 int get_rmem(pid_t p)
 36 {
 37     return get_phy_mem(p);
 38 }
 39 
 40 
 41 int get_total_mem()
 42 {
 43     char* file = "/proc/meminfo";//文件名
 44   
 45     FILE *fd;         //定義文件指針fd
 46     char line_buff[256] = {0};  //讀取行的緩沖區                                                                                                
 47     fd = fopen (file, "r"); //以R讀的方式打開文件再賦給指針fd
 48 
 49     //獲取memtotal:總內存占用大小
 50     int i;
 51     char name[32];//存放項目名稱
 52     int memtotal;//存放內存峰值大小
 53     fgets (line_buff, sizeof(line_buff), fd);//讀取memtotal這一行的數據,memtotal在第1行
 54     sscanf (line_buff, "%s %d", name,&memtotal);
 55     fprintf (stderr, "====%s:%d====\n", name,memtotal);
 56     fclose(fd);     //關閉文件fd
 57     return memtotal;
 58 }
 59 
 60 float get_pmem(pid_t p)
 61 {
 62     int phy = get_phy_mem(p);
 63       int total = get_total_mem();
 64       float occupy = (phy*1.0)/(total*1.0);
 65       fprintf(stderr,"====process mem occupy:%.6f\n====",occupy);
 66       return occupy;
 67 }
 68 
 69 unsigned int get_cpu_process_occupy(const pid_t p)
 70 {
 71     char file[64] = {0};//文件名
 72     process_cpu_occupy_t t;
 73   
 74     FILE *fd;         //定義文件指針fd
 75     char line_buff[1024] = {0};  //讀取行的緩沖區
 76     sprintf(file,"/proc/%d/stat",p);//文件中第11行包含着
 77 
 78     fprintf (stderr, "current pid:%d\n", p);                                                                                                  
 79     fd = fopen (file, "r"); //以R讀的方式打開文件再賦給指針fd
 80     fgets (line_buff, sizeof(line_buff), fd); //從fd文件中讀取長度為buff的字符串再存到起始地址為buff這個空間里
 81 
 82     sscanf(line_buff,"%u",&t.pid);//取得第一項
 83     char* q = get_items(line_buff,PROCESS_ITEM);//取得從第14項開始的起始指針
 84     sscanf(q,"%u %u %u %u",&t.utime,&t.stime,&t.cutime,&t.cstime);//格式化第14,15,16,17項
 85 
 86     fprintf (stderr, "====pid%u:%u %u %u %u====\n", t.pid, t.utime,t.stime,t.cutime,t.cstime);
 87     fclose(fd);     //關閉文件fd
 88     return (t.utime + t.stime + t.cutime + t.cstime);
 89 }
 90 
 91 
 92 unsigned int get_cpu_total_occupy()
 93 {
 94     FILE *fd;         //定義文件指針fd
 95     char buff[1024] = {0};  //定義局部變量buff數組為char類型大小為1024
 96     total_cpu_occupy_t t;
 97                                                                                                              
 98     fd = fopen ("/proc/stat", "r"); //以R讀的方式打開stat文件再賦給指針fd
 99     fgets (buff, sizeof(buff), fd); //從fd文件中讀取長度為buff的字符串再存到起始地址為buff這個空間里
100     /*下面是將buff的字符串根據參數format后轉換為數據的結果存入相應的結構體參數 */
101     char name[16];//暫時用來存放字符串
102     sscanf (buff, "%s %u %u %u %u", name, &t.user, &t.nice,&t.system, &t.idle);
103     
104 
105     fprintf (stderr, "====%s:%u %u %u %u====\n", name, t.user, t.nice,t.system, t.idle);
106     fclose(fd);     //關閉文件fd
107     return (t.user + t.nice + t.system + t.idle);
108 }
109 
110 
111 float get_pcpu(pid_t p)
112 {
113     unsigned int totalcputime1,totalcputime2;
114       unsigned int procputime1,procputime2;
115     totalcputime1 = get_cpu_total_occupy();
116     procputime1 = get_cpu_process_occupy(p);
117     usleep(500000);//延遲500毫秒
118     totalcputime2 = get_cpu_total_occupy();
119     procputime2 = get_cpu_process_occupy(p);
120     float pcpu = 100.0*(procputime2 - procputime1)/(totalcputime2 - totalcputime1);
121     fprintf(stderr,"====pcpu:%.6f\n====",pcpu);
122     return pcpu;
123 }
124 
125 const char* get_items(const char* buffer,int ie)
126 {
127     assert(buffer);
128     char* p = buffer;//指向緩沖區
129     int len = strlen(buffer);
130     int count = 0;//統計空格數
131     if (1 == ie || ie < 1)
132     {
133         return p;
134     }
135     int i;
136     
137     for (i=0; i<len; i++)
138     {
139         if (' ' == *p)
140         {
141             count++;
142             if (count == ie-1)
143             {
144                 p++;
145                 break;
146             }
147         }
148         p++;
149     }
150 
151     return p;
152 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM