面试会遇到的一个问题,ps看到的CPU使用率能大于100%,有时候能准确的回答,是在排障的过程中确实见过大于100%的,那么ps命令是如果计算进程CPU使用率的呢?CPU利用率高是经常遇到的问题,常用的系统命令比如sar,pidstat ,mpstat是如何计算CPU使用率的?对于偶发的CPU高,使用ps能准确抓到CPU高的进程吗?
一、通俗的理解CPU使用率
CPU(central processing unit)中央处理器是计算机系统的运算和控制中心,我们写一段代码,经过编译汇编,最终翻译成CPU的指令,CPU就像是一个长跑运动员,我们的代码就像是指令卡,CPU拿着指令,来完成我们要做的事情,比如监听一个端口,读取网络上的数据包,应用程序返回响应;我们把CPU的计算能力比做运动员单位时间能跑的公里数,当前CPU利用率比做当前的单位时间运动员跑了多少除以他的最大能力。为了方便理解,用下面的饼图做一个形象的展示:

当然cpu并不是在单位时间内连续的完成一件事情,把相同的事情画到一个饼图方便展示CPU使用率的种类。
二、CPU使用率计算方法
CPU整体的使用率在文件/proc/stat中

cpu一行依次代表:
name user nice system idle iowait irrq softirq steal guest guest_nice ,
CPU总时间 = user + system + nice + idle + iowait + irq + softirq
命令中看到的各个过程使用率为各个阶段处以总的时间,比如
%user = user/CPU总时间
使用stress命令打压力,两次文件对比,可以看到user状态的数字明显上涨:
stress -c 1

top, sar, mpstat这些命令读取/proc/stat文件,根据命令参数的时间间隔采样文件数据,除以时间间隔,计算中最终的CPU使用率;对于单个进程的CPU使用情况,存在文件/proc/pid/stat,pidstat 这个命令会读取这个文件,计算进程使用的CPU使用情况;
三、实验模拟CPU高的场景
通过模拟单核和多核CPU跑满的情况,看下各个命令的处理结果
1.单核打满
go语言模拟单核CPU打满
package main
// CPU test
func main() {
i := 0
for {
//fmt.Println(i)
i++
}
}
top命令结果


2.多核打满
多进程代码
package main
func CPU1()() {
i := 0
for {
//fmt.Println(i)
i++
}
}
func CPU2()() {
i := 0
for {
//fmt.Println(i)
i++
}
}
// CPU test
func main() {
go CPU1()
go CPU2()
i := 0
for {
//fmt.Println(i)
i++
}
}
TOP结果图


使用top命令查看
top -H


mpstat结果

四、结论
从多核CPU利用率的结果看到,如果进程使用了多个核,ps命令看到的进程使用率是每个核使用率相加,是会超过100%。
查看man ps中的解释,ps命令计算CPU使用率的方法是
%cpu %CPU cpu utilization of the process in "##.#" format. Currently, it is the CPU time used divided by the time the process has been running (cputime/realtime ratio),
expressed as a percentage. It will not add up to 100% unless you are lucky. (alias pcpu).
可以看到,ps命令计算CPU使用率的是用CPU使用时间除以进程存活时间,ps算的是所有CPU使用率,而不是单个CPU使用率,所以相加是会大于100%的。
所以,如果要排查CPU使用率高的进程,使用ps并不能准备的反应出当前进程使用的情况,需要使用类似top,pidstat这种实时统计CPU使用率的工具查看。
网友评论