一、前言
今天在 7DGroup 的群里,有人提了个问题,ps 统计出来的 CPU 百分比为什么比 top 统计出来的少很多?
二、问题现象
如下图:
从上面的图来加一下,确实差别比较大呀。
top 里面:
$$ 800 -16.9-7.6-22.1-29.9-8.8-24.4-16.9-20.3 = 653.1 $$
而 ps 里面只有 300% 以下。
三、问题分析
什么会这样呢?
先得了解 ps 和 top 有什么区别:
Top 是一个 monitoring tool,但 ps 是一个 snapshot tool。这是一个本质的区别。
ps 是取当前数据的,从
/proc/pid
目录中取出来。 top 是在一直取数据,并且根据刷新周期做计算的。ps怎么计算CPU的呢?
- 有几参数如下:
- 系统启动时间: 是系统自启动以来的总时间长度。
- 线程启动时间:线程启动的时间点。
- 线程CPU时间:线程用CPU的时间长度。
- 线程时间 = 系统启动时间 - 线程启动时间
- 线程CPU使用率 = 线程CPU时间 * 1000 / 线程时间
- 计算出的CPU使用率百分比 = 线程CPU使用率 / 10. 线程CPU使用率%10
- 举例说明:
- 系统启动时间: 15456374.085712
- 线程启动时间:9470058.848042
- 线程CPU时间:987163
- 线程时间 = 15456374.085712 - 9470058.848042 = 5986315.23767
- 线程CPU使用率 = 987163 * 1000 / 5986315.23767 = 164.9
- 计算出的CPU使用率百分比 = 164.9 / 10. 164.9%10 = 16.5
- 有几参数如下:
ps 计算百分比的数据取自 /proc/ 目录
- 从/proc/pid/stat 取出如下几个时间:
- utime:用户模式的CPU时间消耗
- stime:内核模式的CPU时间消耗
- cutime:用户模式的CPU时间消耗,包括子进程
- cstime:内核模式的CPU时间消耗,包括子进程
- starttime:线程启动时间点
- 从/proc/pid/stat 取出如下几个时间:
时间消耗是通过 CPU 时间片来统计的。计算的基础就是 CPU 时间片,CPU 频率就是每秒内的 CPU 计算次数(但是单精双精浮点运算时 CPU 时间片是不一样的,这个要注意下)。
下面我们只从取出的值的结果来做计算。
如果想用 ps 像 top 一样计算一定时间周期内的 CPU 使用率,可以按如下方式计算。
[root@7dgroup 2287]# ps -p 2287 -o %cpu,cputime,etime,etimes
%CPU TIME ELAPSED ELAPSED
0.3 00:00:00 01:03 63
这里有两个参数,etime 和 etimes(这两个参数的 header 都是 ELAPSED),这两个参数别是:
etime:线程自启动以来的持续时间,格式是
[DD-]hh:]mm:ss
。etimes:线程自启动以来的持续时间,以秒为单位。
比如说,上面这个 2287 进程,在第一次取值时,如上所示。
要计算到当前时间消耗了多少 CPU ,需要再取一次数据:
[root@7dgroup 2287]# ps -p 2287 -o %cpu,cputime,etime,etimes
%CPU TIME ELAPSED ELAPSED
0.3 00:00:01 04:30 270
计算一下时间:
前一次取值时:
CPU 时间片消耗是:0。计算过程是:(003600+0060+00)
CPU 时间窗口是63。计算过程是:1*60+3 = 63.
后一次取值时:
CPU 时间片消耗是:1。计算过程是:003600+0060+1
CPU 时间窗口是:270。计算过程是:4*60+30 = 270.
CPU 使用率计算是:
$$ ((1-0)/(270-63))*100 = 0.4 $$
所以这个进程在这段时间内所用的 CPU 百分比是 0.4%。
有兴趣的也可以撸一下 ps 的源代码:
如果对 top 计算结果有异议的,也可以去撸下 top 的源码。
四、总结
上面逻辑了这么多,那么我们在看一个系统的资源使用率时,要看 ps 还是 top 呢?
ps 和 top 的关系如下所示:
top 是一个时间周期内的资源统计。ps 是一个个时间点的资源值。
如果要监控一个系统的整体资源使用率的话,建议用 top 来看。
如果要分析到一个具体的线程使用的 CPU 资源时,再用 ps 来看。