平均负载
平均负载是单位单位时间内,系统中可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数。
可运行状态进程
那什么是可运行状态进程喃?
可运行状态的进程是指那些正在使用 CPU 或者正在等待 CPU 的进程。通过使用top命令,我们可以动态的看到系统中进程的相关信息,进程的状态在“S”列中,其中处于显示为R的进程的进程即为可运行状态进程。
通过ps aux | grep " R "可以筛选处于可运行状态的进程。
$ top
Tasks: 291 total, 1 running, 233 sleeping, 0 stopped, 2 zombie
%Cpu(s): 25.7 us, 8.7 sy, 0.2 ni, 59.7 id, 5.5 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 7868592 total, 1094908 free, 4054456 used, 2719228 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 2771784 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
26845 root 20 0 4804728 108808 80532 S 18.8 1.4 2:09.99 chrome
不可中断状态进程
不可中断状态进程是指正处于内核态关键流程中的进程,并且这些流程是不可打断的。通过ps aux | grep " D "可以筛选处于可运行状态的进程。
$ ps aux | grep " D "
root 13892 0.0 0.0 15968 936 pts/20 S+ 12:32 0:00 grep --color=auto D
不可中断状态实际上是系统对进程和硬件设备的一种保护机制。例如当进程在读写磁盘数据时,如果被其他进程或中断打断,就很可能出现磁盘数据和进程数据不一致的问题,因此为了保证数据的一致性,进程在得到磁盘回复前,是会保持不可中断状态的。
如何确定平均负载是否合理
通过上面我们可以知道,平均负载就是平均活跃进程数,和cpu没有关系。比如如果你的设备的cpu个数为4个,平均活跃进程数个数为也是4个,那么就意味着平均负载为1,超过1就说明有进程竞争不到cpu。
因此我们需要首先确定设备的cpu个数,以及活跃进程数。
top命令下在按1可以显示每个cpu的使用情况,因此也可查看cpu个数:
$ top
top - 12:42:17 up 6 days, 23:26, 3 users, load average: 1.30, 1.77, 1.82
Tasks: 288 total, 1 running, 233 sleeping, 0 stopped, 2 zombie
%Cpu0 : 10.6 us, 6.8 sy, 0.0 ni, 82.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 9.5 us, 7.5 sy, 0.0 ni, 72.2 id, 10.8 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 9.5 us, 7.8 sy, 0.0 ni, 81.6 id, 1.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 9.6 us, 5.2 sy, 0.0 ni, 79.0 id, 6.2 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 7868592 total, 897068 free, 4131036 used, 2840488 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 2626532 avail Mem
可以看到一共有4个cpu,cpu0-cpu3。
也可以通过下面的方式获取设备cpu个数:
$ grep 'model name' /proc/cpuinfo | wc -l
4
proc其实是虚拟文件系统,是操作系统内核提供给用户的查询中心,用户可以通过它查看系统硬件及当前运行的进程信息。其中cpuinfo记录cpu的相关信息。
直接查看平均负载
1.直接使用top,从上面的top输出可以看到,“load average“字段即表示的是平均负载数据。
2.使用uptime
$ uptime
13:31:53 up 7 days, 15 min, 3 users, load average: 1.62, 1.57, 1.42
其中
13:31:53 //当前时间
up 7 days, 15 min //系统运行时间
3 user //正在登录用户数
1.62 //过去 1 分钟的平均负载
1.57 //过去 5 分钟的平均负载
1.42 //过去 15 分钟的平均负载
我们就可以这三个不同时间间隔的平均值,来分析系统负载趋势的:
- 如果三个值基本相同,或者相差不大,那就说明系统负载很平稳;
- 如果 1 分钟的值远小于 15 分钟的值,就说明系统最近 1 分钟的负载在减少;
- 如果 1 分钟的值远大于 15 分钟的值,就说明最近 1 分钟的负载在增加,很可能出现cpu性能问题;
CPU使用率
CPU 使用率,是单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应。例如存在下面三种情况:
- CPU密集型进程,CPU使用率和平均负载基本一致;
- IO密集型进程,平均负载升高,CPU使用率不一定升高;
- 大量等待CPU的进程调度,平均负载升高,CPU使用率也升高。
查看CPU使用率
mpstat
$ mpstat -P ALL 1 3
其中-P ALL表示监控所有CPU;
1表示每1秒输出一组数据;
3表示一共输出3次。
pidstat
$ pidstat -u 5 1
5表示每5秒输出一组数据;
1表示一共输出1次。
统计应用程序cpu平均使用率
上面说道proc虚拟文件系统是内核提供给用户的查询资源使用情况的接口,那么我们可以通过proc获取当前应用程序的cpu使用率情况,来确认我们的应用程序是否消耗的了计算资源。那么,存放每个进程具体cpu使用的信息具体位置在哪儿喃?
执行ls /proc命令,你会看到以数字命名的文件夹,这个数字其实表示的是进程号PID,因此我们可以找到我们要获取的应用程序PID文件下的stat内容,就可以获取具体的cpu使用情况。
可以使用如下命令查看当前bash进程的使用情况。
$ cat /proc/$$/stat
1638 (bash) S 1606 1638 1638 34817 2913 4194304 2279 2424 0 0 7 1 1 0 20 0 1 0 60862910 25358336 1453 18446744073709551615 4194304 5192964 140724846396576 0 0 0 65536 3670020 1266777851 1 0 0 17 1 0 0 0 0 0 7290352 7326856 7483392 140724846405224 140724846405229 140724846405229 140724846407662 0
那如果是进程本身想要查看自己的使用情况喃?
proc提供了self文件夹来查询。运行下面命令,可以看到输出了cat进程的信息。
$ cat /proc/self/stat
11440 (cat) R 1638 11440 1638 34817 11440 4194304 92 0 0 0 0 0 0 0 20 0 1 0 60931259 9408512 174 18446744073709551615 4194304 4240236 140725943190176 0 0 0 0 0 0 0 0 0 17 2 0 0 0 0 0 6340112 6341364 27090944 140725943193558 140725943193578 140725943193578 140725943197679 0
如果需要使用使用c++对应用程序进行资源测试,来统计应用程序cpu使用,则可以使用下面的方式:
unsigned long cpu_utime, cpu_stime, cpu_cutime, cpu_cstime;
unsigned long last_cpu_proc;
// 下面查寻流程应该可以设计为一个线程,其中sleep_time可以为间隔时间
FILE* file = fopen("/proc/self/stat", "r");
if (nullptr == file) {
std::cout << "[ERROR] Command fopen failed" << std::endl;
return;
}
fscanf(file, "%*s %*s %*c %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld %ld %ld %ld",
&cpu_utime, &cpu_stime, &cpu_cutime, &cpu_cstime);
fclose(file);
auto now_cpu_proc = cpu_utime + cpu_stime + cpu_cutime + cpu_cstime;
auto cpu_percent = (now_cpu_proc - last_cpu_proc) * 1000.0F / sleep_time;
last_cpu_proc = now_cpu_proc;
需要注意的上面代码是不能直接使用的,仅提供了一个示例。其中sleep_time这里并没有定义,sleep_time其实是一个循环周期的时间间隔。因为只获取cpu使用率的数据并不准确,我们需要多次循环执行,获取一个平均值。例如设计应用程序启动时开始统计cpu使用情况,每次间隔100ms读取一次,应用程序执行10分钟,最后统计平均的数据。