在Linux中如果要监视一个进程的运行情况,如查看它的CPU使用效率和内存使用情况,就需要从系统的 /proc目录的读取一些系统信息。然后分析得到结果,proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。用户和应用程序 可以通过proc得到系统的信息,并可以改变内核的某些参数。
1、从/proc文件系统获取相关的性能参数
cpu使用率: /proc/stat
内存使用情况: /proc/meminfo
网络负载信息: /proc/net/dev
相应的计算方法:(摘自:什么是proc文件系统,见参考资料)
(1) 处理器使用率
(2) 内存使用率
(3) 流入流出数据包
(4) 整体网络负载
这些数据分别要从/proc/stat、/proc/net/dev、/proc/meminfo三个文件中提取。如里有问题或对要提取的数据不太清楚, 可以使用man proc来查看proc文件系统的联机手册。
(1) 处理器使用率
这里要从/proc/stat中提取四个数据:用户模式(user)、低优先级的用户模式(nice)、内核模式(system)以及空闲的处理器时间 (idle)。它们均位于/proc/stat文件的第一行。CPU的使用率使用如下公式来计算。
在Linux系统中,CPU利用率的计算来源在/proc/stat文件,这个文件的头几行记录了每个CPU的用户态,系统态,空闲态等状态下的不同的 Jiffies,常用的监控软件就是利用/proc/stat里面的这些数据来计算CPU的利用率的。/proc/stat/
root@brain-desktop:~# cat /proc/stat
cpu 2262 0 4387 204441 3670 101 27 0 0
cpu0 2262 0 4387 204441 3670 101 27 0 0
输出解释
CPU 每行的每个参数意思(cpu是所有cpu数据和例如cpu0,cpu1,cpu2等等)为:
参数 解释
user (2662) 从系统启动开始累计到当前时刻,用户态的CPU时间(单位:jiffies) ,不包含 nice值为负进程。1jiffies=0.01秒
nice (0) 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间(单位:jiffies)
system (4387) 从系统启动开始累计到当前时刻,核心时间(单位:jiffies)
idle (204441) 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies)
iowait (3670) 从系统启动开始累计到当前时刻,硬盘IO等待时间(单位:jiffies) ,
irq (101) 从系统启动开始累计到当前时刻,硬中断时间(单位:jiffies)
softirq (27) 从系统启动开始累计到当前时刻,软中断时间(单位:jiffies)
CPU使用率 = 100 *(user + nice + system)/(user + nice + system + idle)
要计算用户和系统的相对使用率要对/proc/stat数据进行两次采集,再进行计算
total1 = user1 + nice1 + system1 + idle1 ,total2同理(total1采集时间比total2晚,所以total1> total2)
用户使用率 = 100 * (user1 - user2)/ (total1 - total2)
系统使用率 = 100 * (system1 - system2)/ (total1 - total2)
(2) 内存使用率
这里需要从/proc/meminfo文件中提取两个数据,当前内存的未使用量(MemFree)以及内存总量(MemTotal)。
内存使用百分比 = 100 * ((MemTotal - MemFree) / MemTotal)
root@brain-desktop:~# cat /proc/meminfo
MemTotal: 509208 kB
MemFree: 93596 kB
(3)网络利用率
为了得到网络利用率的相关数据,需要从/proc/net/dev文件中获得两个数据:从本机输出的数据包数,流入本机的数据包数。它们都位于这个文件的 第四行。性能收集程序开始记录下这两个数据的初始值,以后每次获得这个值后均减去这个初始值即为从集群启动开始从本节点通过的数据包。利用上述数据计算出网络的丢包率,方法如下:
丢包率 = (第二次采集总丢包数 - 第一次采集总丢包数) / 采集时间
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 10732 132 0 0 0 0 0 0 10732 132 0 0 0 0 0 0
eth0: 33096 179 0 0 0 0 0 0 15743 146 0 0 0 0 0 0
下面是我写的代码,其中用到了定时器30S进行一次信息采集,最开始获取cpu对于total使用率,而不是用户和系统相对的使用率
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
static int g_cpu_used_user = 0; //表示cpu用户使用率
static int g_cpu_used_system = 0; //表示cpu系统使用率
static unsigned long cpu_total = 0;
static unsigned long cpu_user = 0;
static unsigned long cpu_system = 0;//分别cpu总时间,用户时间,系统时间
static unsigned int mem_free; //存放未使用内存
static unsigned int mem_used; //存放已使用内存
static unsigned int R_bytes = 0;
static unsigned int R_packets = 0;
static short int R_drop = 0;
static unsigned int T_bytes = 0;
static unsigned int T_packets = 0;
static short T_drop = 0;
static short int R_drop_per = 0; //网络接收丢包率
static short int T_drop_per = 0; //网络接收丢包率
struct occupy //存放cpu数据结构体
{
char name[20];
unsigned int user;
unsigned int nice;
unsigned int system;
unsigned int idle;
};
struct mem_occupy //存放内存数据结构体
{
char name_total[20];
unsigned int total;
char name_free[20];
unsigned int free;
};
struct net_occupy //存放网口数据结构体
{
char name[20];
unsigned int R_bytes;
unsigned int R_packets;
unsigned int R_errs;
unsigned int R_drop;
unsigned int fifo;
unsigned int frame;
unsigned int compressed;
unsigned int multicast;
unsigned int T_bytes;
unsigned int T_packets;
unsigned int T_errs;
unsigned int T_drop;
};
int cal_occupy(struct occupy *ncpu);
void get_occupy(struct occupy *ocpu);
int get_cpu_info(void);
int get_mem_info(struct mem_occupy *mem);
int get_net_info(void);
static void get_opera_data(void);
void settimer_get_opera_data(void);
/*******获取cpu数据,存入静态全局变量
g_cpu_used_eser和g_cpu_used_system中*/
int get_cpu_info()
{
struct occupy cpu;
get_occupy(&cpu); //获取数据存入结构体
cal_occupy(&cpu); //根据数据计算cpu使用率
printf("cpu_num = 1 user used:%d system used:%d\n",
g_cpu_used_user, g_cpu_used_system);
}
int cal_occupy(struct occupy *ncpu)
{
unsigned long od,nd;
unsigned long id,sd;
od = cpu_total;
nd = (unsigned long)(ncpu->user + ncpu->nice + ncpu->system + ncpu->idle);
id = (unsigned long)(ncpu->user - cpu_user);
sd = (unsigned long)(ncpu->system - cpu_system);
if ((nd - od) != 0) {
g_cpu_used_user = (int)(id * 100)/(nd - od);
g_cpu_used_system = (int)(sd * 100)/(nd - od);
} else {
g_cpu_used_user = 0;
g_cpu_used_system = 0;
}
//将计算获得数据储存
cpu_total = nd;
cpu_user = ncpu->user;
cpu_system = ncpu->system;
return (1);
}
/*从/proc/stat文件中提取cpu数据状态*/
void get_occupy(struct occupy *ocpu)
{
FILE *fd;
char buff[256];
struct occupy *ncpu;
ncpu = ocpu;
fd = fopen("/proc/stat", "r");
if (!fd) {
perror("cannot open /proc/stat");
exit(EXIT_FAILURE);
}
while(fgets(buff, sizeof(buff), fd)) {
if(strstr(buff, "cpu") != NULL) {
sscanf(buff,"%s %u %u %u %u", ncpu->name, &(ncpu->user),
&(ncpu->nice), &(ncpu->system), &(ncpu->idle));
break;
}
}
printf("%u %u %u %u",ncpu->user,ncpu->nice,ncpu->system,ncpu->idle);
fclose(fd);
}
/*从 /proc/meminfo 文件中提取内存数据*/
int get_mem_info(struct mem_occupy *mem)
{
FILE *fd;
char buff[256];
fd = fopen("/proc/meminfo", "r");
if (!fd) {
perror("Cannot open /proc/meminfo");
return(0);
}
fgets(buff, sizeof(buff), fd);
if (strstr(buff, "MemTotal") != NULL) {
sscanf(buff, "%s %u", mem->name_total, &mem->total);
} else return(0);
fgets(buff, sizeof(buff), fd);
if (strstr(buff, "MemFree") != NULL) {
sscanf(buff, "%s %u", mem->name_free, &mem->free);
} else return(0);
mem_free = mem->free;
mem_used = mem->total - mem->free;
printf("mem_free = %u ,mem_used = %u",mem_free,mem_used);
return (1);
}
/*提取网口数据,计算丢包率*/
int get_net_info()
{
FILE *fd;
int i, n = 0;
char buff[256];
unsigned int R_bytes_new = 0;
unsigned int R_packets_new = 0;
unsigned int R_drop_new = 0;
unsigned int T_bytes_new = 0;
unsigned int T_packets_new = 0;
unsigned int T_drop_new = 0;
struct net_occupy netinfo[4];
fd = fopen("/proc/net/dev", "r+");
if (!fd) {
perror("Cannot open /proc/net/dev");
return(0);
}
while(fgets(buff, sizeof(buff), fd)) {
n++;
if(n > 3) {
sscanf(buff,"%s %u %u %u %u %u %u %u %u %u %u %u %u",
netinfo[n-4].name, &netinfo[n-4].R_bytes, &netinfo[n-4].R_packets,
&netinfo[n-4].R_errs, &netinfo[n-4].R_drop, &netinfo[n-4].fifo,
&netinfo[n-4].frame, &netinfo[n-4].compressed, &netinfo[n-4].multicast,
&netinfo[n-4].T_bytes, &netinfo[n-4].T_packets, &netinfo[n-4].T_errs,
&netinfo[n-4].T_drop);
}
}
for(i = 0; i < n - 4; i++) {
R_bytes_new += netinfo[i].R_bytes;
R_packets_new += netinfo[i].R_packets;
R_drop_new += netinfo[i].R_drop;
T_bytes_new += netinfo[i].T_bytes;
T_packets_new += netinfo[i].T_packets;
T_drop_new += netinfo[i].T_drop;
}
if (0 == (R_packets_new - R_packets)) {
R_drop_per = 0;
}
else
R_drop_per = (unsigned short int)((R_drop_new - R_drop)* 100.0 /
(R_packets_new - R_packets));
if (0 == (T_packets_new - T_packets)) {
T_drop_per = 0;
}
else
T_drop_per = (unsigned short int)((T_drop_new - T_drop)* 100.0 /
(T_packets_new - T_packets));
printf("R_drop = %u T_drop = %u\n",R_drop_per,T_drop_per);
R_bytes = R_bytes_new;
R_drop = R_drop_new;
R_packets = R_packets_new;
T_bytes = T_bytes_new;
T_drop = T_drop_new;
T_packets = T_packets_new;
return(1);
}
static void get_opera_data(void)
{
struct mem_occupy mem;
get_cpu_info();
get_mem_info(&mem);
get_net_info();
}
void settimer_get_opera_data(void)
{
struct sigevent se;
struct itimerspec ts, ots;
timer_t tid;
memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = get_opera_data;//定时执行函数,获取运维数据
se.sigev_value.sival_int = 0;
if (timer_create(CLOCK_REALTIME, &se, &tid) < 0) {
perror("timer_creat of operation and maintenance\n");
}
ts.it_value.tv_sec = 28;
ts.it_value.tv_nsec = 0;
ts.it_interval = ts.it_value;
if (timer_settime(tid, 0, &ts, &ots) < 0) {
perror("time_settime of operation and maintenance\n");
}
}
int main()
{
get_opera_data();
settimer_get_opera_data();
while(1);
return(1);
}
部分还引用参考了其他文章