五、系统平均负载,使用stress、mpstat、pidstat工具,找出平均负载升高的根源,3分,少一个截图扣1分,少1条心得扣1分
(一)系统平均负载
Load指标表示特定时间间隔内,系统有多少个正在运行的任务。包含:
①正在CPU上面运行的任务数量(运行状态)
②等待CPU调度运行的任务数量(不可中断状态)
③等待IO执行结果的任务数量(不可中断状态)
根据工程经验,一般来说,当系统的Load指标值大于系统中总CPU核数的1.5~2倍时,表明系统负载较重,需要分析原因,采取措施降低Load指标值。否则可能产生系统卡顿的现象。如果系统的Load指标值大于系统中总CPU核数的3倍时,,表明系统负载非常严重。
注:若支持超线程技术,这里的总CPU核数 就换成 总逻辑CPU数
(二)工具说明:
1. stress
stress是Linux系统压力测试工具,可以对CPU、Memory、IO、磁盘进行压力测试。这里我们把它用作异常进程模拟平均负载升高的场景。
2. mpstat
mpstat可以查看所有cpu的平均负载,也可以查看指定cpu的负载。所以mpstat其实就是主要查看CPU负载的一个工具。是一款常用的多核CPU性能分析工具,用来实时查询每个CPU的性能指标,以及所有CPU的平均指标。
语法:mpstat [ 选项 ] [ <时间间隔> [ <次数> ] ]
选项:[ -P { <cpu_list> | ON | ALL } ]
间隔时间:每次报告的间隔时间(秒)
次数:显示报告的次数
3.pidstat
pidstat是一个常用的进程性能分析工具,用来实时查看进程的CPU,内存,IO,以及上下文切换等性能指标。
语法:pidstat [ 选项 ] [ <时间间隔> [ <次数> ] ]
(三)实验
stress 消耗 CPU 资源的方式是通过调用 sqrt 函数计算由 rand 函数产生的随机数的平方根实现的,执行指令stress -c 4 产生 4 个这样的进程不断的进行计算:
执行指令mpstat -P ALL 1
%usr表示用户所有使用的CPU百分比
%sys表示内核进程使用的 CPU 百分比
从上图可以看出CPU几乎都是在用户态运行,运行时间接近99%,只能看出来CPU可能会出现严重负载的情况,但看不出来详细的系统平均负载情况,于是我执行了top命令:
我这才发现了此时的CPU出现了严重负载的情况。于是我执行指令pidstat -u 1 对CPU出现严重负载的情况进行查明:
由上图可知,CPU几乎全部的时间都在运行这4个stress进程,可见此时系统的高负载是由这4个stress进程导致的。
(四)心得体会
①经过这一问的学习,我对stress、mpstat、pidstat工具有了系统性的认识,已经能够熟练的使用它们了
②通过上述实验,我发现平均负载过高可能是CPU密集型进程导致的。
③当发生CPU密集型进程导致的高负载的情况时,我们可以通过top命令查看此时的负载情况,然后利用pidstat命令找到导致发生高负载情况的进程,然后进行解决
六、参考P81页的代码,编写程序,父进程打印控制菜单,并接受命令(上面列出的命令至少5个),然后创建子进程,让子进程去处理任务,而父进程继续打印菜单并接受命令。说明调试过程以及新的体会,并给出截图,少一个命令扣1分,少1条心得扣1分
(一)程序
menu.c代码:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char * argv[]) {
pid_t pid;
char cmd;
char * arg_psa[] = {"ps","-a",NULL};
char * arg_psx[] = {"ps","-x",NULL};
char * arg_stress[] = {"stress","-c","4","-t","100",NULL};
char * arg_uptime[] = {"uptime",NULL};
char * arg_pidstat[] = {"pidstat","-u","1","3",NULL};
while(1) {
printf("-----------------------------\n");
printf("input a run 'ps -a' commend\n");
printf("input x run 'ps -x' commend\n");
printf("input s run 'stress -c 4 -t 100' commend\n");
printf("input u run 'uptime' commend\n");
printf("input p run 'pidstat -u 1 3' commend\n");
printf("input q exit\n");
cmd = getchar(); //接受输入字符
getchar();
if((pid = fork()) < 0) { //创建子进程
perror("fork error:");
return -1;
}
if(pid == 0) { //子进程
switch(cmd) {
case 'a':
execve("/bin/ps",arg_psa,NULL);
break;
case 'x':
execve("/bin/ps",arg_psx,NULL);
break;
case 's':
execve("/usr/bin/stress",arg_stress,NULL);
break;
case 'u':
execve("/usr/bin/uptime",arg_uptime,NULL);
break;
case 'p':
execve("/usr/bin/pidstat",arg_pidstat,NULL);
break;
case 'q':
break;
default:
perror("wrong cmd:\n");
break;
}
exit(0);
} else if(pid > 0) { //父进程
if(cmd == 'q')
break;
}
}
while(waitpid(-1,NULL,WNOHANG)>0);
return 0;
}
运行结果:
进行调试:
输入 a 显示一个终端的所有进程:
输入x 显示没有控制终端的进程,同时显示各个命令的具体路径:
输入 s 模拟平均负载升高的场景:
输入 u 可以查看此时的平均负载情况:
输入 p 查看每个进程使用CPU的情况:
通过以上运行结果,我们可知可以借用此程序去模拟第五问中的实验。
(二)心得体会
①个人感觉这程序其实是模拟了一个终端,我们可以在这里实现输入输出,可以自行的添加功能。
②让我对fork系统调用有了更生动的认识