前言
前段时间因为项目需求,需要实时获取系统当前的运行状态,遂查阅了不少资料,基于/proc目录下的部分文件,实现了系统CPU、内存、网络和磁盘的实时监测。
一、CPU使用情况获取
获取CPU使用情况是从/proc/stat文件中获取的,/proc/stat 包含了系统启动以来的许多关于kernel和系统的统计信息,其中包括CPU运行情况、中断统计、启动时间、上下文切换次数、运行中的进程等等信息
cpu 1149770 0 309685 239871041 7 0 0 0 cpu0 1149770 0 309685 239871041 7 0 0 0 intr 0 swap 0 0 ctxt 892809418 btime 1525518899 processes 379246 procs_running 1 procs_blocked 0
“cpu” 这行展示所有CPU在user-sapce、kernel mode上的一些时间,接着是各个CPU的统计情况。
“intr” 这行 展示系统中断的信息,第一个为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。
的中断自系统启动以来所发生的次数。
“ctxt” 这行展示自系统启动以来CPU发生的上下文交换的次数。
“btime”这行展示从系统启动到现在为止的时间(以Epoch时间开始计算, 1970-01-01 00:00:00 +0000 (UTC)),单位为秒。
“processes” 这行展示自系统启动以来所创建的任务的个数目(total_forks)。
“procs_running” 这行显示当前运行队列的任务的数目。
“procs_blocked” 这行显示当前被阻塞的任务的数目。
计算CPU占用率的话,只需要关注第一行即可,各参数含义如下:
user |
从系统启动开始累计到当前时刻,用户态的CPU时间,不包含nice值为负进程。 |
nice |
从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间 |
system |
从系统启动开始累计到当前时刻,核心时间 |
idle |
从系统启动开始累计到当前时刻,除IO等待时间以外其它等待时间 |
iowait |
从系统启动开始累计到当前时刻,IO等待时间 |
irq |
从系统启动开始累计到当前时刻,硬中断时间 |
softirq |
从系统启动开始累计到当前时刻,软中断时间 |
因为/proc/stat中的数值都是从系统启动开始累计到当前时刻的积累值,所以需要在不同时间点t1和t2取值进行比较运算,当两个时间点的间隔较短时(我取的是1s),就可以把这个计算结果看作是CPU的即时利用率。
CPU的即时利用率的计算公式:
CPU在t1到t2时间段总的使用时间 = ( user2+ nice2+ system2+ idle2+ iowait2+ irq2+ softirq2) - ( user1+ nice1+ system1+ idle1+ iowait1+ irq1+ softirq1)
CPU在t1到t2时间段空闲使用时间 = (idle2 - idle1)
CPU在t1到t2时间段即时利用率 = 1 - CPU空闲使用时间 / CPU总的使用时间
源码
void get_cpuinfo(CPU_PACKED &cpuinfo) { char buff[256] = {0}; ifstream in("/proc/stat"); if (!in) { cout << "get cpu info failed" << endl; return; } in.getline(buff, sizeof(buff)); stringstream ss(buff); ss >> cpuinfo.name; ss >> cpuinfo.user; ss >> cpuinfo.nice; ss >> cpuinfo.system; ss >> cpuinfo.idle; ss >> cpuinfo.iowait; ss >> cpuinfo.irq; ss >> cpuinfo.softirg; in.close(); } double calc_cpuoccupy(CPU_PACKED cpuinfo1, CPU_PACKED cpuinfo2) { double info1d = cpuinfo1.user + cpuinfo1.nice + cpuinfo1.system + cpuinfo1.idle + cpuinfo1.softirg + cpuinfo1.iowait + cpuinfo1.irq; double info2d = cpuinfo2.user + cpuinfo2.nice + cpuinfo2.system + cpuinfo2.idle + cpuinfo2.softirg + cpuinfo2.iowait + cpuinfo2.irq; double sub1 = cpuinfo1.idle; double sub2 = cpuinfo2.idle; double cpu_use; if ((sub1 - sub2) != 0) cpu_use = 100.0 - ((sub2 - sub1) / (info2d - info1d)) * 100.0; else cpu_use = 0; //double cpu_use = cpuinfo1.user/info1d; return cpu_use; }
二、内存使用情况
内存使用情况是从/proc/meminfo文件中获取的
[root ~]# cat /proc/meminfo MemTotal: 1048576 kB MemFree: 927940 kB Cached: 31468 kB Buffers: 0 kB Active: 46764 kB Inactive: 50516 kB Active(anon): 32312 kB Inactive(anon): 33500 kB Active(file): 14452 kB Inactive(file): 17016 kB Unevictable: 0 kB Mlocked: 0 kB SwapTotal: 131072 kB SwapFree: 86620 kB Dirty: 16 kB Writeback: 0 kB AnonPages: 65812 kB Shmem: 164 kB Slab: 23172 kB SReclaimable: 6552 kB SUnreclaim: 16620 kB
这里关注的是MemTotal、MemFree和Cached三个值,使用中的内存 = MemTotal-MemFree-Cached
void calc_memoccupy(MEM_PACKED &meminfo) { char buff[256] = {0}; string name; unsigned long free_mem; unsigned long cached; int index = 0; ifstream in("/proc/meminfo"); if (!in) { cout << "get cpu info failed" << endl; return; } stringstream ss; while (!in.eof() && index < 4) { in.getline(buff, sizeof(buff)); ss.str(""); ss << buff; if (index == 0) { ss >> name; ss >> meminfo.total_mem; } else if (index == 1) { ss >> name; ss >> free_mem; } else if (index == 3) { ss >> name; ss >> cached; } index++; } meminfo.used_mem = meminfo.total_mem - free_mem - cached; in.close(); }
三、网络传输(上传和下载的速度)
网络使用情况是从/proc/net/dev文件中获取的
[root ~]# cat /proc/net/dev Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed lo: 4057260174 245081 0 0 0 0 0 0 4057260174 245081 0 0 0 0 0 0 venet0: 21610450920 22790055 0 0 0 0 0 0 22011662266 22005133 0 148 0 0 0 0
网络上传和下载速度是根据网卡venet0单位时间(1s)内发收的字节数计算出来的
void read_netdev(unsigned long &ups, unsigned long &downs) { ifstream in("/proc/net/dev"); if (!in) { cout << "get network info failed" << endl; return; } string line; std::vector<string> lines; while (!in.eof()) { getline(in, line); if (in.fail()) break; lines.push_back(line); } vector<string> items = splitstring(lines[lines.size() - 1]); ups = atol(items[1].c_str()); downs = atol(items[9].c_str()); in.close(); } void calc_netspeed(NET_PACKED &netinfo) { unsigned long ups1, ups2, downs1, downs2; read_netdev(ups1, downs1); sleep(1); read_netdev(ups2, downs2); netinfo.upspeed = (float)(ups2 - ups1); netinfo.downspeed = (float)(downs2 - downs1); }
四、硬盘使用情况
硬盘使用情况分两部分:硬盘空间使用情况和硬盘实时的读写情况。
硬盘的使用情况可以通过statfs()函数获取,读写速度是通过单位时间(1s)内读写的扇区个数来计算的
[root ~]# cat /proc/diskstats 1 0 ram0 0 0 0 0 0 0 0 0 0 0 0 1 1 ram1 0 0 0 0 0 0 0 0 0 0 0 1 2 ram2 0 0 0 0 0 0 0 0 0 0 0 1 3 ram3 0 0 0 0 0 0 0 0 0 0 0 1 4 ram4 0 0 0 0 0 0 0 0 0 0 0 1 5 ram5 0 0 0 0 0 0 0 0 0 0 0 1 6 ram6 0 0 0 0 0 0 0 0 0 0 0 1 7 ram7 0 0 0 0 0 0 0 0 0 0 0 1 8 ram8 0 0 0 0 0 0 0 0 0 0 0 1 9 ram9 0 0 0 0 0 0 0 0 0 0 0 1 10 ram10 0 0 0 0 0 0 0 0 0 0 0 1 11 ram11 0 0 0 0 0 0 0 0 0 0 0 1 12 ram12 0 0 0 0 0 0 0 0 0 0 0 1 13 ram13 0 0 0 0 0 0 0 0 0 0 0 1 14 ram14 0 0 0 0 0 0 0 0 0 0 0 1 15 ram15 0 0 0 0 0 0 0 0 0 0 0 7 0 loop0 0 0 0 0 0 0 0 0 0 0 0 7 1 loop1 0 0 0 0 0 0 0 0 0 0 0 7 2 loop2 0 0 0 0 0 0 0 0 0 0 0 7 3 loop3 0 0 0 0 0 0 0 0 0 0 0 7 4 loop4 0 0 0 0 0 0 0 0 0 0 0 7 5 loop5 0 0 0 0 0 0 0 0 0 0 0 7 6 loop6 0 0 0 0 0 0 0 0 0 0 0 7 7 loop7 0 0 0 0 0 0 0 0 0 0 0 8 0 sda 30526 2009 1087215 193416 115412736 102258023 1811485376 87116184 0 18093240 87295592 8 1 sda1 22754 483028 5686677 45493256 8 2 sda2 166 662 8265 66120 8 3 sda3 6528 570989 123499806 987893792 8 4 sda4 2887 30896 88516083 708124240 9 0 md0 0 0 0 0 0 0 0 0 0 0 0
void calc_rwspeed(unsigned long &readsectors, unsigned long &writesectors) { ifstream in("/proc/diskstats"); if (!in) { cout << "get disk speed info failed with Reason:" << strerror(errno) << endl; return; } string line; while (!in.eof()) { getline(in, line); size_t pos = line.find("sda"); if (pos < line.size()) { line = line.substr(pos + 4, line.size()); break; } } vector<string> items = splitstring(line); readsectors = atol(items[2].c_str()); writesectors = atol(items[6].c_str()); in.close(); } void calc_diskoccupy(string path, DISK_PACKED &diskinfo) { struct statfs disk; if (statfs(path.c_str(), &disk) == -1) { cout << "Failed to get disk info with Reason:" << strerror(errno) << endl; return; } diskinfo.total_disk = disk.f_blocks * disk.f_bsize; diskinfo.avail_disk = disk.f_bavail * disk.f_bsize; diskinfo.free_disk = disk.f_bfree * disk.f_bsize; unsigned long reads1, writes1, reads2, writes2; calc_rwspeed(reads1, writes1); sleep(1); calc_rwspeed(reads2, writes2); diskinfo.read_speed = (reads2 - reads1) * disk.f_bsize; diskinfo.write_speed = (writes2 - writes1) * disk.f_bsize; }
完整代码详见我的Gihub。