您的位置:首页 > 运维架构 > Linux

Linux下计算进程的CPU占用和内存占用的编程方法

2016-12-21 13:46 645 查看

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

代码

get_cpu.h

#ifdef __cplusplus
extern "C"{
#endif

#define VMRSS_LINE 15//VMRSS所在行
#define PROCESS_ITEM 14//进程CPU时间开始的项数

typedef struct //声明一个occupy的结构体
{
unsigned int user; //从系统启动开始累计到当前时刻,处于用户态的运行时间,不包含 nice值为负进程。
unsigned int nice; //从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间
unsigned int system;//从系统启动开始累计到当前时刻,处于核心态的运行时间
unsigned int idle; //从系统启动开始累计到当前时刻,除IO等待时间以外的其它等待时间iowait (12256) 从系统启动开始累计到当前时刻,IO等待时间(since 2.5.41)
}total_cpu_occupy_t;

typedef struct
{
pid_t pid;//pid号
unsigned int utime; //该任务在用户态运行的时间,单位为jiffies
unsigned int stime; //该任务在核心态运行的时间,单位为jiffies
unsigned int cutime;//所有已死线程在用户态运行的时间,单位为jiffies
unsigned int cstime; //所有已死在核心态运行的时间,单位为jiffies
}process_cpu_occupy_t;

int get_phy_mem(const pid_t p);//获取占用物理内存
int get_total_mem();//获取系统总内存
unsigned int get_cpu_total_occupy();//获取总的CPU时间
unsigned int get_cpu_process_occupy(const pid_t p);//获取进程的CPU时间
const char* get_items(const char* buffer,int ie);//取得缓冲区指定项的起始地址

extern float get_pcpu(pid_t p);//获取进程CPU占用
extern float get_pmem(pid_t p);//获取进程内存占用
extern int get_rmem(pid_t p);//获取真实物理内存

#ifdef __cplusplus
get_cpu.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //头文件
#include <assert.h>
#include "get_cpu.h"

int get_phy_mem(const pid_t p)
{
char file[64] = {0};//文件名

FILE *fd; //定义文件指针fd
char line_buff[256] = {0}; //读取行的缓冲区
sprintf(file,"/proc/%d/status",p);//文件中第11行包含着

fprintf (stderr, "current pid:%d\n", p);
fd = fopen (file, "r"); //以R读的方式打开文件再赋给指针fd

//获取vmrss:实际物理内存占用
int i;
char name[32];//存放项目名称
int vmrss;//存放内存峰值大小
for (i=0;i<VMRSS_LINE-1;i++)
{
fgets (line_buff, sizeof(line_buff), fd);
}//读到第15行
fgets (line_buff, sizeof(line_buff), fd);//读取VmRSS这一行的数据,VmRSS在第15行
sscanf (line_buff, "%s %d", name,&vmrss);
fprintf (stderr, "====%s:%d====\n", name,vmrss);
fclose(fd); //关闭文件fd
return vmrss;
}

int get_rmem(pid_t p)
{
return get_phy_mem(p);
}

int get_total_mem()
{
char* file = "/proc/meminfo";//文件名

FILE *fd; //定义文件指针fd
char line_buff[256] = {0}; //读取行的缓冲区
fd = fopen (file, "r"); //以R读的方式打开文件再赋给指针fd

//获取memtotal:总内存占用大小
int i;
char name[32];//存放项目名称
int memtotal;//存放内存峰值大小
fgets (line_buff, sizeof(line_buff), fd);//读取memtotal这一行的数据,memtotal在第1行
sscanf (line_buff, "%s %d", name,&memtotal);
fprintf (stderr, "====%s:%d====\n", name,memtotal);
fclose(fd); //关闭文件fd
return memtotal;
}

float get_pmem(pid_t p)
{
int phy = get_phy_mem(p);
int total = get_total_mem();
float occupy = (phy*1.0)/(total*1.0);
fprintf(stderr,"====process mem occupy:%.6f\n====",occupy);
return occupy;
}

unsigned int get_cpu_process_occupy(const pid_t p)
{
char file[64] = {0};//文件名
process_cpu_occupy_t t;

FILE *fd; //定义文件指针fd
char line_buff[1024] = {0}; //读取行的缓冲区
sprintf(file,"/proc/%d/stat",p);//文件中第11行包含着

fprintf (stderr, "current pid:%d\n", p);
fd = fopen (file, "r"); //以R读的方式打开文件再赋给指针fd
fgets (line_buff, sizeof(line_buff), fd); //从fd文件中读取长度为buff的字符串再存到起始地址为buff这个空间里

sscanf(line_buff,"%u",&t.pid);//取得第一项
char* q = get_items(line_buff,PROCESS_ITEM);//取得从第14项开始的起始指针
sscanf(q,"%u %u %u %u",&t.utime,&t.stime,&t.cutime,&t.cstime);//格式化第14,15,16,17项

fprintf (stderr, "====pid%u:%u %u %u %u====\n", t.pid, t.utime,t.stime,t.cutime,t.cstime);
fclose(fd); //关闭文件fd
return (t.utime + t.stime + t.cutime + t.cstime);
}

unsigned int get_cpu_total_occupy()
{
FILE *fd; //定义文件指针fd
char buff[1024] = {0}; //定义局部变量buff数组为char类型大小为1024
total_cpu_occupy_t t;

fd = fopen ("/proc/stat", "r"); //以R读的方式打开stat文件再赋给指针fd
fgets (buff, sizeof(buff), fd); //从fd文件中读取长度为buff的字符串再存到起始地址为buff这个空间里
/*下面是将buff的字符串根据参数format后转换为数据的结果存入相应的结构体参数 */
char name[16];//暂时用来存放字符串
sscanf (buff, "%s %u %u %u %u", name, &t.user, &t.nice,&t.system, &t.idle);

fprintf (stderr, "====%s:%u %u %u %u====\n", name, t.user, t.nice,t.system, t.idle);
fclose(fd); //关闭文件fd
return (t.user + t.nice + t.system + t.idle);
}

float get_pcpu(pid_t p)
{
unsigned int totalcputime1,totalcputime2;
unsigned int procputime1,procputime2;
totalcputime1 = get_cpu_total_occupy();
procputime1 = get_cpu_process_occupy(p);
usleep(500000);//延迟500毫秒
totalcputime2 = get_cpu_total_occupy();
procputime2 = get_cpu_process_occupy(p);
float pcpu = 100.0*(procputime2 - procputime1)/(totalcputime2 - totalcputime1);
fprintf(stderr,"====pcpu:%.6f\n====",pcpu);
return pcpu;
}

const char* get_items(const char* buffer,int ie)
{
assert(buffer);
char* p = buffer;//指向缓冲区
int len = strlen(buffer);
int count = 0;//统计空格数
if (1 == ie || ie < 1)
{
return p;
}
int i;

for (i=0; i<len; i++)
{
if (' ' == *p)
{
count++;
if (count == ie-1)
{
p++;
break;
}
}
p++;
}

return p;
}
 代码
#!/bin/sh

#功能:计算CPU的利用率,选取采样点
#计算公式:
#方法1:cpu usage=(idle2-idle1)/(cpu2-cpu1)*100
#方法2: cpu usage=[(user_2 +sys_2+nice_2) - (user_1 + sys_1+nice_1)]/(total_2 - total_1)*100
#方法3:(本脚本采用)
#total_0=USER[0]+NICE[0]+SYSTEM[0]+IDLE[0]+IOWAIT[0]+IRQ[0]+SOFTIRQ[0]
#total_1=USER[1]+NICE[1]+SYSTEM[1]+IDLE[1]+IOWAIT[1]+IRQ[1]+SOFTIRQ[1]
#cpu usage=(IDLE[0]-IDLE[1]) / (total_0-total_1) * 100

##echo user nice system idle iowait irq softirq
CPULOG_1=$(awk '/\<cpu\>/{print $2" "$3" "$4" "$5" "$6" "$7" "$8}' /proc/stat)
SYS_IDLE_1=$(echo $CPULOG_1 | awk '{print $4}')
Total_1=$(echo $CPULOG_1 | awk '{print $1+$2+$3+$4+$5+$6+$7}')

sleep 5

CPULOG_2=$(awk '/\<cpu\>/{print $2" "$3" "$4" "$5" "$6" "$7" "$8}' /proc/stat)
SYS_IDLE_2=$(echo $CPULOG_2 | awk '{print $4}')
Total_2=$(echo $CPULOG_2 | awk '{print $1+$2+$3+$4+$5+$6+$7}')

SYS_IDLE=`expr $SYS_IDLE_2 - $SYS_IDLE_1`

Total=`expr $Total_2 - $Total_1`

#method 1
#SYS_USAGE=`expr $SYS_IDLE/$Total*100 |bc -l`
#SYS_Rate=`expr 100-$SYS_USAGE |bc -l`

#method2
tmp_rate=`expr 1-$SYS_IDLE/$Total | bc -l`
SYS_Rate=`expr $tmp_rate*100 | bc -l`

#display
Disp_SYS_Rate=`expr "scale=3; $SYS_Rate/1" |bc`
echo $Disp_SYS_Rate%
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: