基本原理 1)系统CPU使用率等于两个时间点的CPU非空闲时间差除以CPU时间总量差得到的百分比,这两者可从/proc/stat文件获得。
2)系统内存使用率等于系统物理内存消耗量除以系统物理内存总量(memtotal,以KB为单位)得到的百分比,这两者可从/proc/meminfo文件获得。
3)进程CPU使用率等于进程CPU时间(pct,以jiffies为单位)除以进程运行时间(pt)得到的百分比,pct从/proc/pid/stat文件读取utime和stime字段相加即得,pt等于系统运行时间(st,以秒为单位)减去进程启动时间(pst,以jiffies为单位),st从/proc/uptime文件获得,pst从/proc/pid/stat文件读取starttime字段获得。
4)进程内存使用率等于进程驻留集大小(rss)除以系统物理内存总量(memtotal,以KB为单位)得到的百分比,rss从/proc/pid/stat读取rss字段得到,以页数为单位。
代码实现 1)基本结构和接口定义在proc_stat.h头文件内,如下所示
1
struct sys_cpu_time
2

{
3
unsigned long long user,old_user;
4
unsigned long long nice,old_nice;
5
unsigned long long sys,old_sys;
6
unsigned long long idle,old_idle;
7
unsigned long long wait,old_wait;
8
unsigned long long hirq,old_hirq;
9
unsigned long long sirq,old_sirq;
10
};
11
12
struct sys_uptime
13

{
14
double uptime;
15
double idle;
16
};
17
18
struct sys_mem_info
19

{
20
unsigned long main_total;
21
unsigned long main_free;
22
unsigned long main_used;
23
unsigned long main_buffers;
24
unsigned long main_cached;
25
unsigned long swap_total;
26
unsigned long swap_free;
27
unsigned long swap_used;
28
unsigned long swap_cached;
29
};
30
31
struct system_stat
32

{
33
sys_cpu_time ct;
34
sys_mem_info mi;
35
sys_uptime ut;
36
};
37
38
struct process_stat
39

{
40
char name[16];
41
char state;
42
int ppid;
43
int pgrp;
44
int session;
45
int tty_nr;
46
int tpgid;
47
unsigned int flags;
48
unsigned long minflt;
49
unsigned long cminflt;
50
unsigned long majflt;
51
unsigned long cmajflt;
52
unsigned long utime;
53
unsigned long stime;
54
long cutime;
55
long cstime;
56
long priority;
57
long nice;
58
long threads;
59
long iterealvalue;
60
unsigned long long starttime;
61
unsigned long vsize;
62
long rss;
63
};
64
65
struct sys_mem_entry
66

{
67
const char *name;
68
unsigned long *val;
69
} ;
70
71
static const int PROC_STAT = 0x0001;
72
static const int PROC_MEM = 0x0002;
73
static const int PROC_UPTIME = 0x0004;
74
static const int PROC_ALL = PROC_STAT|PROC_MEM|PROC_UPTIME;
75
76
bool get_system_stat(system_stat& ss,int flag);
77
78
bool get_system_usage(float& cpu,float& mem);
79
80
bool get_process_stat(pid_t id,process_stat& ps);
81
82
bool get_process_usage(pid_t id,float& cpu,float& mem,unsigned long long& uptime); 以上sys_cpu_time、sys_mem_info和process_stat结构只是从对应文件中选取了用于计算CPU和内存使用率必须的部分字段,如果需求扩展,可以在其后添加更多的字段;sys_mem_info中的main_used和swap_used是引申字段,它们并不对应于/proc/meminfo文件。
2)实现在proc_stat.cpp文件内,如下所示
1
static const char* PROC_FILE_STAT = "/proc/stat";
2
static const char* PROC_FILE_MEMINFO = "/proc/meminfo";
3
static const char* PROC_FILE_UPTIME = "/proc/uptime";
4
5
static int compare_sys_mem_entry(const void *a, const void *b)
6

{
7
return strcmp(static_cast<const sys_mem_entry*>(a)->name,static_cast<const sys_mem_entry*>(b)->name);
8
}
9
10
inline ssize_t file2str(const char* file,char* buf,size_t len,int* pfd=NULL)
11

{
12
int fd = -1;
13
if(pfd) fd = *pfd;
14
15
if(-1 == fd)
{
16
fd=open(file,O_RDONLY,0);
17
if(-1==fd) return -1;
18
if(pfd) *pfd = fd;
19
}else
20
lseek(fd,0,SEEK_SET);
21
22
ssize_t ret = read(fd,buf,len-1);
23
if(NULL==pfd) close(fd);
24
if(ret <= 0) return -1;
25
buf[ret] = '\0';
26
27
return ret;
28
}
29
30
bool get_system_stat(system_stat& ss,int flag)
31

{
32
assert(flag&PROC_ALL);
33
34
char buf[2048];
35
ssize_t ret;
36
37
if(flag & PROC_STAT)
{
38
static __thread int stat_id = -1;
39
ret = file2str(PROC_FILE_STAT,buf,sizeof(buf),&stat_id);
40
if (-1==ret) return false;
41
sys_cpu_time* ct = &ss.ct;
42
if(7!=sscanf(buf,"cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu",&ct->user,&ct->nice,&ct->sys,&ct->idle,
43
&ct->wait,&ct->hirq,&ct->sirq))
44
return false;
45
}
46
47
if(flag & PROC_UPTIME)
{
48
static __thread int uptime_id = -1;
49
ret = file2str(PROC_FILE_UPTIME,buf,sizeof(buf),&uptime_id);
50
if(-1==ret) return false;
51
sys_uptime* ut = &ss.ut;
52
if(2!=sscanf(buf,"%lf %lf",&ut->uptime,&ut->idle))
53
return false;
54
}
55
56
if(flag & PROC_MEM)
{
57
static __thread int mem_id = -1;
58
ret = file2str(PROC_FILE_MEMINFO,buf,sizeof(buf),&mem_id);
59
if(-1==ret) return false;
60
61
sys_mem_info *mi = &ss.mi;
62
const sys_mem_entry mem_table[] =
{
63
{"Buffers", &mi->main_buffers},
64
{"Cached", &mi->main_cached},
65
{"MemFree", &mi->main_free},
66
{"MemTotal", &mi->main_total},
67
{"SwapCached", &mi->swap_cached},
68
{"SwapFree", &mi->swap_free},
69
{"SwapTotal", &mi->swap_total}
70
};
71
72
char *beg,*end = buf + ret;
73
char *colon,*lf;
74
sys_mem_entry key,*sme;
75
76
for(beg=buf;beg<end;beg=lf+1)
{
77
colon = strchr(beg,':');
78
if(!colon) break;
79
*colon++ = '\0';
80
lf = strchr(colon,'\n');
81
if(!lf) break;
82
key.name = beg;
83
sme = (sys_mem_entry*)bsearch(&key,mem_table,NUM_ELEMENTS(mem_table),sizeof(sys_mem_entry),compare_sys_mem_entry);
84
if(sme) *(sme->val) = ::strtoul(beg=colon,&colon,10);
85
}
86
mi->main_used = mi->main_total - mi->main_free;
87
mi->swap_used = mi->swap_total - mi->swap_free;
88
}
89
90
return true;
91
}
92
93
bool get_system_usage(float& cpu,float& mem)
94

{
95
static __thread system_stat ss =
{0};
96
if(!get_system_stat(ss,PROC_MEM|PROC_STAT))
97
return false;
98
99
sys_cpu_time* ct = &ss.ct;
100
long long user,nice,sys,idle,wait,hirq,sirq,sum;
101
user = ct->user - ct->old_user;
102
nice = ct->nice - ct->old_nice;
103
sys = ct->sys - ct->old_sys;
104
idle = ct->idle - ct->old_idle;
105
if(idle<0) idle = 0;
106
wait = ct->wait - ct->old_wait;
107
hirq = ct->hirq - ct->old_hirq;
108
sirq = ct->sirq - ct->old_sirq;
109
ct->old_user = ct->user;
110
ct->old_nice = ct->nice;
111
ct->old_sys = ct->sys;
112
ct->old_idle = ct->idle;
113
ct->old_wait = ct->wait;
114
ct->old_hirq = ct->hirq;
115
ct->old_sirq = ct->sirq;
116
117
sum = user + nice + sys + idle + wait + hirq + sirq;
118
if(sum<1) sum = 1;
119
cpu = 100.0*(sum - idle)/sum;
120
121
sys_mem_info* mi = &ss.mi;
122
mem = 100.0*mi->main_used/mi->main_total;
123
124
return true;
125
}
126
127
bool get_process_stat(pid_t id,process_stat& ps)
128

{
129
char buf[1024],name[64];
130
131
sprintf(name,"/proc/%u/stat",id);
132
ssize_t ret = file2str(name,buf,sizeof(buf));
133
if(-1==ret) return false;
134
135
char* beg = strchr(buf,'(');
136
if(!beg) return false;
137
138
char* end = strchr(++beg,')');
139
if(!end) return false;
140
141
size_t num = end - beg;
142
if(num >= sizeof(name))
143
num = sizeof(name) -1;
144
memcpy(ps.name,beg,num);
145
ps.name[num] = '\0';
146
147
return 22/**//*1+5+1+6+6+1+1+1*/ == sscanf(end+2,
148
"%c "
149
"%d %d %d %d %d "
150
"%u "
151
"%lu %lu %lu %lu %lu %lu "
152
"%ld %ld %ld %ld %ld %ld "
153
"%Lu "
154
"%lu "
155
"%ld",
156
&ps.state, //1
157
&ps.ppid,&ps.pgrp,&ps.session,&ps.tty_nr,&ps.tpgid, //5
158
&ps.flags,//1
159
&ps.minflt,&ps.cminflt,&ps.majflt,&ps.cmajflt,&ps.utime,&ps.stime,//6
160
&ps.cutime,&ps.cstime,&ps.priority,&ps.nice,&ps.threads,&ps.iterealvalue, //6
161
&ps.starttime,//1
162
&ps.vsize,//1
163
&ps.rss); //1
164
}
165
166
bool get_process_usage(pid_t id,float& cpu,float& mem,unsigned long long& uptime)
167

{
168
system_stat ss;
169
if(!get_system_stat(ss,PROC_MEM|PROC_UPTIME))
170
return false;
171
172
process_stat ps;
173
if(!get_process_stat(id,ps))
174
return false;
175
176
long HZ = sysconf(_SC_CLK_TCK);
177
unsigned long long pct = ps.utime+ps.stime;
178
uptime = (unsigned long long)ss.ut.uptime - ps.starttime/HZ;
179
cpu = uptime ? (100.0*pct/HZ)/uptime : 0.0;
180
181
long page_size = sysconf(_SC_PAGESIZE) >> 10;
182
mem = 100.0*ps.rss*page_size/ss.mi.main_total;
183
184
return true;
185
} 以上get_system_stat接口的实现中,sys_mem_entry数组mem_table中的元素对应于sys_mem_info中的字段,并按其名称升序排列,便于二分查找。如果需求扩展改变了sys_mem_info结构的成员,只须调整mem_table,保证元素按字段名称升序排列即可。
性能优化
如果频繁调用get_xxx_usage来获得资源使用信息,那么存在着不断打开和关闭描述符操作,而在某些情况下没必要,例如读取一些系统proc文件如/proc/stat、/proc/meminfo和/proc/uptime等,只需第一次调用时打开,后续直接读数据即可,这样更高效。所以file2str的实现,支持一次打开,多次读取,当进程退出时,系统内核会自动关闭所有描述符。
posted on 2013-05-31 19:04
春秋十二月 阅读(4925)
评论(0) 编辑 收藏 引用 所属分类:
System