添砖加瓦:Linux系统监测

前言 

  前段时间因为项目需求,需要实时获取系统当前的运行状态,遂查阅了不少资料,基于/proc目录下的部分文件,实现了系统CPU、内存、网络和磁盘的实时监测。

一、CPU使用情况获取

  获取CPU使用情况是从/proc/stat文件中获取的,/proc/stat 包含了系统启动以来的许多关于kernel和系统的统计信息,其中包括CPU运行情况、中断统计、启动时间、上下文切换次数、运行中的进程等等信息

  

1
2
3
4
5
6
7
8
9
10
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总的使用时间

  源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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文件中获取的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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文件中获取的

1
2
3
4
5
[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)内发收的字节数计算出来的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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)内读写的扇区个数来计算的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[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

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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

posted @   落雷  阅读(242)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示