第一节 祸起
本来就是想通过写个小程序测试CPU利用率从而可以检验其他的工具性能之类的数据,后来参照IPbench中的cpu_target_lukem插件实现我们的功能,原理很简单:就是我们给程序设置了极低的优先级,如果有任何计算任务都会打断它,而如果没有计算任务,我们的程序就会占用cpu时间,所以我们的程序的运行时间基本上可以算作CPU的闲暇时间。
所以我们计算总的CPU利用率的方法就是 : CPU利用率 = 1 - 程序占用cpu时间/程序总的运行时间。
主要功能实现代码如下:
[cpp] view plaincopy
- x0 = get_cycles(); //last cycle count values
- while (calc) {
- x1 = x0; //last cycle count values gives to x1
- x0 = get_cycles(); //the current count values
- delta = x0 - x1; // ?t
- total += delta; //adds ?t to a running total
- /* If the delta looks like less than a context switch,add this to idle time; otherwise add it to busy time */
- if (delta < PROFILE_CONTEXT_COST)
- idle += delta;
- timer_buffer.idle = idle;
- timer_buffer.total = total;
- }
从而本程序中的CPU利用率 = (1- timer_buffer.idle/timer_buffer.total)*100 %,
之后我们编译运行本程序,程序输出为:
[11:43.32] dbg: Average CPU time is 5.2
[11:43.34] dbg: Average CPU time is 5.2
这时候我们使用 " ps -au "命令,会找到这一条信息:
long 11741
95.7 0.0 19668 520 pts/16 SNl+ 11:40 2:58 ./a.out
熟悉ps命令的童鞋们知道,long为该进程所属用户;11741为该进程的PID号;95.7表示该进程的CPU占用率为95.7%;0.0表示该进程的物理内存占用率为0%;19668表示该进程占用了多少虚拟内存量;520表示该进程占用了多少固定内存量;pts/16表示登陆端口;SNl+为和上面介绍的进程状态一样(R/S/D/T/Z进程);11:40为该进程触发启动的时间; 2:58表示该进程占用CPU的时间;./a.out表示触动该进程的命令
。
所以ps命令显示的是我们a.out的CPU利用率高达95.7%(也就是说95.7%CPU都是闲暇的,所以我们的程序测得CPU利用率为5.2% 也相差不大)。
接着,我做了第二个测试,我把a.out拷贝了一份b.out,同时运行他们我们会看到如下信息:
a.out 显示的 :
[11:47.50] dbg: Average CPU time is 6.1
[11:47.52] dbg: Average CPU time is 6.1
b.out 显示的s :
[11:48.20] dbg: Average CPU time is 10.2
[11:48.22] dbg: Average CPU time is 10.2
这时候我使用 "ps -au" 再查看a.out和b.out信息如下:
long 11741
94.1 0.0 19668 520 pts/16 SNl+ 11:40 7:26 ./a.out
long 11905 90.9 0.0 19668 516 pts/17 SNl+ 11:46 2:08 ./b.out
卧槽,顿时崩溃啊!到了这,我产生了三个疑问:第一、为毛运行a.out和b.out显示的CPU利用率不一样……第二、为毛在ps中显示的a.out和b.out的CPU利用率不一样?第三、为毛ps中a.out和b.out的CPU利用率分别为94.1%和90.0%,而两者加一起远远大于100%?!!我晕了,那Linux到底是如何定义CPU利用率的呢?
第二节 CPU利用率和CPU负载
在Linux/Unix下,CPU利用率(CPU utilization)分为用户态,系统态和空闲态,分别表示CPU处于用户态执行的时间,系统内核执行的时间,和空闲系统进程执行的时间。平时所说的CPU利用率是指:CPU执行非系统空闲进程的时间 / CPU总的执行时间。(上述代码中使用的方法为:1
- CPU空闲运行时间/总运行时间 ,与这个计算方法原理上是一样的)
在Linux的内核中,有一个全局变量:Jiffies。 Jiffies代表时间。它的单位随硬件平台的不同而不同,系统里定义了一个常数HZ----代表每秒种最小时间间隔的数目。这样jiffies的单位就是1/HZ。Intel平台jiffies的单位是1/100秒,这就是系统所能分辨的最小时间间隔了。每个CPU时间片,Jiffies都要加1。
CPU的利用率就是用执行用户态+系统态的Jiffies除以总的Jifffies来表示。
那么,还有一个经常容易与CPU利用率(CPU
utilization)混淆的词 -- CPU负载(CPU load)。CPU负载取决于CPU队列长度而不是CPU利用率,因为一个主机负载过重时,它的CPU利用率会接近100%,从而无法准确反应负载状况,而使用CPU队列长度则可以很直接反应CPU的负载量。比如说两个系统,其中一个系统有3个进程在队列中,而另一台有6个进程在队列,如果使用CPU利用率表示负载水平,他们可能都是接近100%,而使用CPU队列长度他们的负载量完全不同。
我们如何理解CPU负载?一只单核的处理器可以形象得比喻成一条单车道!那么:
*** 0.00 表示目前桥面上没有任何的车流。 实际上这种情况与 0.00 和 1.00
之间是相同的,总而言之很通畅,过往的车辆可以丝毫不用等待的通过。
*** 1.00 表示刚好是在这座桥的承受范围内。 这种情况不算糟糕,只是车流会有些堵,不过这种情况可能会造成交通越来越慢。
*** 超过 1.00,那么说明这座桥已经超出负荷,交通严重的拥堵。 那么情况有多糟糕? 例如 2.00 的情况说明车流已经超出了桥所能承受的一倍,那么将有多余过桥一倍的车辆正在焦急的等待。3.00 的话情况就更不妙了,说明这座桥基本上已经快承受不了,还有超出桥负载两倍多的车辆正在等待。
上面的情况和处理器的负载情况非常相似。一辆汽车的过桥时间就好比是处理器处理某线程 的实际时间。Unix
系统定义的进程运行时长为所有处理器内核的处理时间加上线程 在队列中等待的时间。
和收过桥费的管理员一样,你当然希望你的汽车(操作)不会被焦急的等待。所以,理想状态 下,都希望负载平均值小于 1.00 。当然不排除部分峰值会超过 1.00,但长此以往保持这 个状态,就说明会有问题,这时候你应该会很焦急。
在多处理器系统中,负载均值是基于内核的数量决定的。以
100% 负载计算,1.00 表示单个处理器,而 2.00 则说明有两个双处理器,那么 4.00 就说明主机具有四个处理器。回到我们上面有关车辆过桥的比喻。1.00 我说过是「一条单车道的道路」。那么在单车道 1.00 情况中,说明这桥梁已经被车塞满了。而在双处理器系统中,这意味着多出了一倍的 负载,也就是说还有 50% 的剩余系统资源 ---- 因为还有另外条车道可以通行。
所以,单处理器已经在负载的情况下,双处理器的负载满额的情况是 2.00,它还有一倍的资源可以利用。
实际上Linux系统中很多都是用CPU负载均值(load average)来代表当前系统的负载状况,比如使用top命令:
[cpp] view plaincopy
- long@long-Ubuntu:~$ top
- top - 20:12:45 up 3:05, 6 users, load average: 1.16, 1.27, 1.14
- Tasks: 208 total, 1 running, 206 sleeping, 0 stopped, 1 zombie
- %Cpu(s): 11.8 us, 3.7 sy, 0.0 ni, 84.4 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
- KiB Mem: 2067372 total, 1998832 used, 68540 free, 54104 buffers
- KiB Swap: 2095100 total, 25540 used, 2069560 free, 449612 cached
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 6635 long 20 0 435m 79m 32m S 7.3 3.9 11:31.39 rhythmbox
- 4523 root 20 0 110m 61m 4804 S 5.3 3.0 8:34.14 Xorg
- 5316 long 9 -11 162m 5084 4088 S 4.3 0.2 6:01.53 pulseaudio
- 5793 long 20 0 114m 22m 13m S 4.3 1.1 0:23.38 gnome-terminal
- ……
在第一行的最后显示的为 “ load average: 1.16 , 1.27 ,1.14”
使用“uptime”命令,效果也是类似:
[cpp] view plaincopy
- long@long-Ubuntu:~$ uptime
- 20:15:01 up 3:07, 6 users, load average: 0.43, 0.97, 1.05
这三个数分别是:一分钟内、五分钟内、十五分钟内的系统负载均值。也就是说,从右向左看这几个数据,我们可以判断系统负载的发展趋势。
事实上,这正是CPU负载所需要测量的,因为负载均值不包括那些等待I/O、网络、数据或者其他不依赖CPU的进程或线程,它关注的仅仅是积极要求CPU时间的进程或线程。这与CPU利用率是有很大不同的。
负载均值与CPU利用率在两个方面有很大的区别:
1) 负载均值用来估量CPU利用率的发展趋势,而不是某一时刻的状况
2) 负载均值包括所有CPU的需求,而不仅仅是在测量时活跃的
第三节 如何计算CPU利用率
在Linux系统中,可以用/proc/stat文件来计算cpu的利用率(详细可参考)。这个文件包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻。如:
[cpp] view plaincopy
- long@long-Ubuntu:~$ cat /proc/stat
- cpu 426215 701 115732 2023866 27329 4 557 0 0 0
- cpu0 218177 117 57458 1013633 8620 0 6 0 0 0
- cpu1 208038 584 58274 1010233 18709 4 550 0 0 0
- intr 21217894 119 18974 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 146350 0 647836 370 86696 3 146156 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- ctxt 38682044
- btime 1362301653
- processes 10118
- procs_running 1
- procs_blocked 0
- softirq 11177991 0 6708342 2178 148765 86792 0 14537 1507468 29072 2680837
输出解释:
(CPU 以及CPU0、CPU1、CPU2、CPU3每行的每个参数意思(以第一行为例))
参数 | 解释 |
user (426215) | 从系统启动开始累计到当前时刻,用户态的CPU时间(单位:jiffies) ,不包含 nice值为负进程。1jiffies=0.01秒 |
nice (701) | 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间(单位:jiffies) |
system (115732) | 从系统启动开始累计到当前时刻,核心时间(单位:jiffies) |
idle (2023866) | 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies) |
iowait (27329) | 从系统启动开始累计到当前时刻,硬盘IO等待时间(单位:jiffies) , |
irq (4) | 从系统启动开始累计到当前时刻,硬中断时间(单位:jiffies) |
softirq (557) | 从系统启动开始累计到当前时刻,软中断时间(单位:jiffies) |
CPU时间=user+system+nice+idle+iowait+irq+softirq
“intr”这行给出中断的信息,第一个为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。
“ctxt”给出了自系统启动以来CPU发生的上下文交换的次数。
“btime”给出了从系统启动到现在为止的时间,单位为秒。
“processes (total_forks) 自系统启动以来所创建的任务的个数目。
“procs_running”:当前运行队列的任务的数目。
“procs_blocked”:当前被阻塞的任务的数目。
那么CPU利用率可以使用以下两个方法。先取两个采样点,然后计算其差值:
cpu usage=(idle2-idle1)/(total_2
- total_1)*100
cpu usage=[(user_2 +sys_2+nice_2) - (user_1 + sys_1+nice_1)]/(total_2 - total_1)*100
第四节 对第一节中的puzzle进行解释
再回顾一下三个疑问:第一、为毛运行a.out和b.out显示的CPU利用率不一样……第二、为毛在ps中显示的a.out和b.out的CPU利用率不一样?第三、为毛ps中a.out和b.out的CPU利用率分别为94.1%和90.0%,而两者加一起远远大于100%?!!
实际上,这些问题感觉很诡异,但是经过我一番学习之后,发现,答案其实很简单。
首先,为啥a.out和b.out显示的CPU利用率不一样?在我问我们老师Nicholas
Mc Guire的邮件上,他回复“cpu utilization is a per cpu value of how much time the CPU is spending with process X” 也就是说CPU利用率是一个程序占用一个CPU处理器多少时间的百分比值!(他说的是某个进程占有的CPU利用率,如top上显示的!而我想要算的是总的的CPU利用率,但是他提到了process
X !也就是说,如上面的双处理器的负载满额的情况是 2.00,我的机器是双核,所以,这里a.out和b.out算得分别是两个CPU核心上的利用率!)
而经过一段时间后,a.out和b.out显示的值都会很接近!因为,双核的计算任务不可能相差很大的!
如某一时间,a.out显示如下:
[cpp] view plaincopy
- [15:50.31] dbg: Average CPU time is 13.2
- [15:50.33] dbg: Average CPU time is 13.2
此时b.out显示如下:
[cpp] view plaincopy
- [15:50.31] dbg: Average CPU time is 13.0
- [15:50.33] dbg: Average CPU time is 13.0
而,此时top结果:
[cpp] view plaincopy
- long@long-Ubuntu:~$ top
- top - 15:40:31 up 7:01, 6 users, load average: 2.20, 2.40, 2.31
- Tasks: 208 total, 1 running, 206 sleeping, 0 stopped, 1 zombie
- %Cpu(s): 4.0 us, 1.2 sy, 94.9 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
- KiB Mem: 2067372 total, 1970184 used, 97188 free, 20812 buffers
- KiB Swap: 2095100 total, 72400 used, 2022700 free, 449896 cached
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 14944 long 39 19 19668 520 432 S 91.3 0.0 34:07.64 a.out
- 14952 long 39 19 19668 516 432 S 90.7 0.0 33:54.69 b.out
- 4597 root 20 0 99396 35m 5620 S 3.3 1.8 27:26.09 Xorg
这个观点可以通过如下方法论证:
如果我把a.out再拷贝两个副本分别叫c.out和d.out,那么top命令下,显示如下所示,a.out和b.out原来分别占90%左右,现在a.out、b.out、c.out和d.out则分别占40%左右,我们可以理解成,原先a.out占用cpu0的90%空闲时间(上文已经提到:因为我们的程序就是设置了极低的优先级,如果有任何计算任务都会打断,而如果没有计算任务,我们的程序就会占用cpu时间,所以占用的都是空间时间),而b.out占用cpu1的90%空闲时间,而现在c.out和a.out平分了cpu0的这90%空闲时间,d.out和b.out平分了cpu1的这90%空闲时间,所以,a.out、b.out、c.out和d.out此时的CPU利用率则分别占40%左右。
[cpp] view plaincopy
- long@long-Ubuntu:~$ top
- top - 15:53:44 up 7:14, 8 users, load average: 3.76, 3.01, 2.65
- Tasks: 213 total, 1 running, 211 sleeping, 0 stopped, 1 zombie
- %Cpu(s): 21.7 us, 9.5 sy, 68.8 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
- KiB Mem: 2067372 total, 1981532 used, 85840 free, 18416 buffers
- KiB Swap: 2095100 total, 75832 used, 2019268 free, 415140 cached
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 14944 long 39 19 19668 520 432 S 37.5 0.0 45:04.77 a.out
- 15856 long 39 19 19668 516 432 S 33.2 0.0 0:23.74 d.out
- 14952 long 39 19 19668 516 432 S 32.8 0.0 44:52.23 b.out
- 15803 long 39 19 19668 516 432 S 31.5 0.0 0:25.49 c.out
- 5297 long 20 0 251m 75m 20m S 20.2 3.7 15:53.31 compiz
第五节 Linux提供的一些查看系统信息的工具
使用下面这些命令我们可以查询总的CPU使用率、单独的CPU使用率(对于对称多处理机器SMP)、从你上次启动后的平均CPU使用率等。
4.1 老当益壮的top命令
使用top命令可以动态的查看CPU使用率。它会显示当前内核管理着的任务信息,它还会显示上线时间、负载均值、物理和交换内存使用状况。使用如下:
$ top
按Q键推出top。
[cpp] view plaincopy
- long@long-Ubuntu:~$ top
- top - 14:52:24 up 6:13, 5 users, load average: 1.06, 1.02, 1.24
- Tasks: 203 total, 1 running, 201 sleeping, 0 stopped, 1 zombie
- %Cpu(s): 27.5 us, 5.9 sy, 0.0 ni, 66.2 id, 0.3 wa, 0.0 hi, 0.0 si, 0.0 st
- KiB Mem: 2067372 total, 1808288 used, 259084 free, 41020 buffers
- KiB Swap: 2095100 total, 55040 used, 2040060 free, 539728 cached
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 5740 long 20 0 110m 27m 14m S 15.2 1.4 3:13.91 gnome-terminal
- 4597 root 20 0 95000 31m 4848 S 13.9 1.6 25:29.79 Xorg
- 5297 long 20 0 246m 70m 19m S 10.3 3.5 14:09.52 compiz
4.2 使用"mpstat"命令
使用这个命令,你需要先安装sysstat工具,对于Debian或Ubuntu用户,可以通过apt-get直接安装:
$ apt-get install sysstat
使用如下命令查看CPU使用率信息:
$ mpstat
[cpp] view plaincopy
- long@long-Ubuntu:~$ mpstat
- Linux 3.7.1 (long-Ubuntu) 2013年03月04日 _i686_ (2 CPU)
- 14时53分16秒 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
- 14时53分16秒 all 18.91 4.92 5.15 1.00 0.00 0.04 0.00 0.00 69.99
使用如下命令可以监控单独的CPU使用率信息:
$ mpstat -P ALL
[cpp] view plaincopy
- long@long-Ubuntu:~$ mpstat -P ALL
- Linux 3.7.1 (long-Ubuntu) 2013年03月04日 _i686_ (2 CPU)
- 14时53分53秒 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
- 14时53分53秒 all 18.91 4.91 5.15 0.99 0.00 0.04 0.00 0.00 70.01
- 14时53分53秒 0 19.02 4.25 5.19 0.66 0.00 0.00 0.00 0.00 70.88
- 14时53分53秒 1 18.79 5.57 5.10 1.33 0.00 0.07 0.00 0.00 69.13
4.3 使用"sar"命令
使用sar命令显示CPU使用率的语法如下:
$ sar -u 2 5 ( sar [ 选项 ] [ <时间间隔> [ <次数> ] ])
这条命令会显示2秒内的CPU使用率,总共显示5次。
[cpp] view plaincopy
- long@long-Ubuntu:~$ sar -u 2 5
- Linux 3.7.1 (long-Ubuntu) 2013年03月04日 _i686_ (2 CPU)
- 14时54分22秒 CPU %user %nice %system %iowait %steal %idle
- 14时54分24秒 all 5.51 0.00 1.50 1.00 0.00 91.98
- 14时54分26秒 all 4.52 0.00 1.26 0.00 0.00 94.22
- 14时54分28秒 all 4.02 0.00 1.76 0.00 0.00 94.22
- 14时54分30秒 all 4.77 0.00 1.51 3.77 0.00 89.95
- 14时54分32秒 all 3.77 0.00 1.51 0.00 0.00 94.72
- 平均时间: all 4.52 0.00 1.51 0.95 0.00 93.02
4.4 使用"iostat"命令
"iostat"命令可以用来查询从系统启动以来的是CPU平均使用率以及设备或者分区的I/O状况:
$ iostat
[cpp] view plaincopy
- long@long-Ubuntu:~$ iostat
- Linux 3.7.1 (long-Ubuntu) 2013年03月04日 _i686_ (2 CPU)
- avg-cpu: %user %nice %system %iowait %steal %idle
- 18.89 4.90 5.18 0.99 0.00 70.04
- Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
- sda 6.75 67.08 58.24 1512659 1313268
4.5 GUI Tools 一些有图形界面的工具
KDE桌面环境有一些系统监控器一类的工具可以用来监控CPU使用率甚至更多的系统信息(比如说CPU负载状况、物理内存以及交换分区的数据占用信息),你还可以使用它来杀死一些进程。
下表总结了若干Linux下的工具:
工具 | 简单介绍 |
top | 查看进程活动状态以及一些系统状况 |
vmstat | 查看系统状态、硬件和系统信息等 |
iostat | 查看CPU 负载,硬盘状况 |
sar | 综合工具,查看系统状况 |
mpstat | 查看多处理器状况 |
netstat | 查看网络状况 |
iptraf | 实时网络状况监测 |
tcpdump | 抓取网络数据包,详细分析 |
mpstat | 查看多处理器状况 |
tcptrace | 数据包分析工具 |
netperf | 网络带宽工具 |
dstat | 综合工具,综合了 vmstat, iostat, ifstat, netstat 等多个信息 |