CPU使用率的概念
CPU使用率是单位时间内CPU的使用情况,以百分比的方式展示。Linux是一个多任务的操作系统,将每个CPU的时间划分为很短的时间片,再通过调度器轮流分配给各个任务,为了维护CPU时间,Linux通过事先定义的节拍率,内核中用HZ表示,触发时间中断,并使用全局变量Jiffies记录开机以来的节拍数。每发生了一次中断,节拍数Jiffies就加1.
节拍率HZ是内核的配置选项,可以设置为100,250,1000等。不同的系统设置的节拍率可能不一样,可以使用下面的命令来查看当前系统的节拍率。
Linux通过proc虚拟文件系统,向用户空间提供系统的内部状态的信息,而/proc/stat提供的就是系统的cpu和任务统计信息。
使用下面的命令可只输出各个CPU的状态信息
cat /proc/stat | grep ^cpu
以上输出的是一个表格,第一列是CPU编号,如CPU0 CPU1等,第一行没有CPU编号表示的是所有CPU的累加信息。其他列则表示不同场景下CPU的累加节拍数,单位为USER_HZ也就是10ms,也就是不同场景下的CPU时间。
通过 man proc命令可以查看如上输出信息的具体含义。
- User 缩写为us 代表了用户CPU时间。它不包括下面的nice时间,但是包括了guest时间
- Nice 缩写为ni 代表了低优先级用户态CPU时间。也就是进程的nice只被调整为1-19之间时的CPU时间。Nice的值越大优先级越低
- System 缩写为sys 代表内核态CPU时间
- Idle 缩写为id 代表CPU空闲时间,它不包括等待io的时间iowait。
- Iowait 所系为wa,代表等待IO的CPU时间
- Irq缩写为hi 代表处理中断的CPU时间
- Softirq 缩写为si 代表数据软中断的CPU时间
- Steal 缩写为st,代表当系统正在虚拟机中运行时,被其他虚拟机占用的CPU时间
- Guest 缩写为guest 代表通过虚拟机运行其他操作系统的时间,也就是运行虚拟机的CPU时间
- Guest_nice 缩写为gnice代表以低优先级运行虚拟机的时间
通常所说的CPU使用率,就是指除了空闲时间之外的其他时间占总的CPU时间的百分比。
跟系统指标类似,linux系统也为每个进程提供了运行情况的统计信息,也就是/proc/[pid]/stat.其输出信息的具体含义同样可以通过man proc来查看。
如何查看CPU使用率
查看CPU使用率,首先想到的肯定是top ps命令。Top和ps是最常用的性能分析工具,其中:
- Top显示了系统总体的CPU和内存使用情况,以及各个进程的资源使用情况
- Ps只显示每个进程的资源使用情况
Top命令的输出格式如下
输出结果的第三行中%Cpu(s)就是系统的CPU使用率,top默认显示的是所有cpu的平均值,在该界面按下数字1就可以切换到显示每个CPU的时间了。
继续分析top的输出信息,空白行之后就是每个进程的实时信息,每个进程都一个%CPU列,就表示该进程的CPU使用率。它是用户态和内核态CPU使用率的总和,包括了进程用户空间使用的CPU、通过系统调用执行内核空间的CPU、以及在就绪队列等待运行的CPU时间。因此top命令的输出并没有区分用户态CPU和内核态CPU,如要查看每个进程在不同空间下的CPU使用率就需要使用pidstat这个命令。
Pidstat命令正是分析各个进程CPU使用情况的工具。
pidstat 1 5
上面的命令每隔1秒输出5组进程的CPU使用信息,其中包括
%usr:用户态cpu使用率
%system:内核态cpus使用率
%guest:运行虚拟机cpu使用率
%CPU:总的CPU使用率。
CPU使用率过高怎么办?
通过上面的top ps以及pidstat命令可以很快的找到cpu使用率高的进程,但是如何找到占用CPU使用率的到底是代码里的哪个函数呢?只有找到他才有可能更高效的更有针对性的去优化。
这里推荐的工具是perf,perf是linux2.6.31之后内置的性分析工具。它以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定的应用程序的性能问题。
Perf命令第一个常见用法是perf top。类似于top 它能够实时显示占用CPU时钟最多的函数或者指令,因此可以用来查找占用cpu的具体函数。
Perf top的输出结果中,第一行包含是三个数据分别是采样数Samples、事件类型Event和事件总数量Event Count。
第一列overhead,是该符号的性能事件在所有采样中所占的比例。
第二列shared,是该函数或者指令所在的动态共享对象,如内核、进程名、动态链接库名、内核模块名等
第三列object,是动态共享对象的类型。[.]表示用户空间的可执行程序或者动态链接库,[k]则表示内核空间。
最后一列symbol是符号名,也就是函数名。当函数名未知时使用16进制的地址来表示