计算Linux系统的CPU利用率

通过读取系统的/proc/stat 信息来计算CPU的利用率

cpu 信息的读取

摘自参考博客:https://blog.csdn.net/x_i_y_u_e/article/details/50684508

在Linux/Unix下,CPU利用率分为用户态,系统态和空闲态,分别表示CPU处于用户态执行的时间,系统内核执行的时间,和空闲系统进程执行的时间。平时所说的CPU利用率是指:CPU执行非系统空闲进程的时间 / CPU总的执行时间。

在Linux的内核中,有一个全局变量:Jiffies。 Jiffies代表时间。它的单位随硬件平台的不同而不同。系统里定义了一个常数HZ,代表每秒种最小时间间隔的数目。这样jiffies的单位就是1/HZ。Intel平台jiffies的单位是1/100秒,这就是系统所能分辨的最小时间间隔了。每个CPU时间片,Jiffies都要加1。 CPU的利用率就是用执行用户态+系统态的Jiffies除以总的Jifffies来表示。

在Linux系统中,可以用/proc/stat文件来计算cpu的利用率(详细的解释可参考:http://www.linuxhowtos.org/System/procstat.htm)。这个文件包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻。

在本机上的信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 root@hw103:/home/yky# cat/proc/stat 
cpu 7283854 35392 293546 204419077 75835 0 8385 0 0 0
cpu0 365010 48 18204 8453603 767 0 4306 0 0 0
cpu1 292817 9 14990 8526563 1358 0 2114 0 0 0
cpu2 286689 0 11880 8538662 1033 0 752 0 0 0
cpu3 287106 14624 12945 8523209 641 0 320 0 0 0
cpu4 293293 0 11784 8532282 604 0 147 0 0 0
cpu5 371312 2824 13669 8408187 40794 0 406 0 0 0
cpu6 358116 10934 14014 8453775 1230 0 68 0 0 0
cpu7 313971 6281 12243 8504303 1575 0 28 0 0 0
cpu8 318084 0 11598 8506770 2036 0 15 0 0 0
cpu9 294503 0 11137 8530318 2185 0 10 0 0 0
cpu10 307922 144 12434 8516570 1177 0 15 0 0 0
cpu11 291752 0 11502 8533957 1128 0 4 0 0 0
cpu12 315096 0 15927 8503001 3528 0 3 0 0 0
cpu13 375976 0 17927 8442873 2041 0 1 0 0 0
cpu14 299344 0 10140 8523716 2818 0 1 0 0 0
cpu15 288470 3 10146 8538685 1240 0 0 0 0 0
cpu16 301148 0 10681 8523612 2185 0 0 0 0 0
cpu17 263183 4 9149 8565345 771 0 0 0 0 0
cpu18 262518 370 10343 8562955 2105 0 11 0 0 0
cpu19 280230 3 10399 8546414 1227 0 6 0 0 0
cpu20 278962 0 10346 8547585 1221 0 9 0 0 0
cpu21 277042 143 11502 8547940 1048 0 2 0 0 0
cpu22 275560 0 9458 8549093 1271 0 153 0 0 0
cpu23 285740 0 11118 8539648 1838 0 6 0 0 0
intr 91288599 43 2 0 0 0 0 0 0 1 0 0 0 4 0 0 0 41 0 2 0 0 0 0 0 0 0 334158 0 1 2473208 45518 96917 44876 138077 45263 45258 54441 0 0 44198 44198 44198 44198 44198 44198 441
98 44198 0 0 44198 44198 44198 44198 44198 44198 44198 44198 0 0 44199 44199 44199 44199 44199 44199 44199 44199 0 0 44199 44199 44199 44199 44199 44199 44199 44199 0 0 44198 44198 44198 44198 44198 44198 44198 44198 0 0 44198 44198 44198 44198 44198 44198 44198 44198 0 0 44199 44199 44199 44199 44199 44199 44199 44199 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0ctxt 42731429
btime 1553933982
processes 190449
procs_running 5
procs_blocked 0
softirq 57291816 8 26401645 17536 5419485 334063 0 1044 10019160 0 15098875

第一行cpu是总的cpu信息,其他的cpu0-cpu23 是24个核的信息。

计算cpu利用率只用到前7个参数, 对应的参数解释为:

1
2
	 user	 nice  system idle      iowait   irq  softirq
cpu 7283854 35392 293546 204419077 75835 0 8385

user (7283854) 从系统启动开始累计到当前时刻,用户态的CPU时间(单位:jiffies) ,不包含 nice值为负进程。1jiffies=0.01秒
nice (35392) 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间(单位:jiffies)
system (293546) 从系统启动开始累计到当前时刻,核心时间(单位:jiffies)
idle (204419077) 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies)
iowait (75835) 从系统启动开始累计到当前时刻,硬盘IO等待时间(单位:jiffies) ,
irq (0) 从系统启动开始累计到当前时刻,硬中断时间(单位:jiffies)
softirq (8385) 从系统启动开始累计到当前时刻,软中断时间(单位:jiffies)

CPU时间=user+system+nice+idle+iowait+irq+softirq

“intr”这行给出中断的信息,第一个为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。
“ctxt”给出了自系统启动以来CPU发生的上下文交换的次数。
“btime”给出了从系统启动到现在为止的时间,单位为秒。
“processes (total_forks) 自系统启动以来所创建的任务的个数目。
“procs_running”:当前运行队列的任务的数目。
“procs_blocked”:当前被阻塞的任务的数目。

计算cpu利用率的方法就是计算出在一段时间里面,cpu工作的时间/总得时间

1
2
cpu usage=(idle2-idle1)/(cpu2-cpu1)*100
cpu usage=[(user_2 +sys_2+nice_2) - (user_1 + sys_1+nice_1)]/(total_2 - total_1)*100

第二中方法只把user+sys+nice 这三个时间看作cpu的工作时间,因为其他的几个比较小。

shell脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash

##echo user nice system idle iowait irq softirq

cpulog_start=$(cat /proc/stat | grep 'cpu'| awk 'NR==1{print $2 "\t" $3 "\t" $4 "\t" $5 "\t" $6 "\t" $7 "\t" $8}' )
cpu_use_start=$(echo $cpulog_start | awk '{print $1+$2+$3}')
cpu_iowait_start=$(echo $cpulog_start | awk '{print $5}')
cpu_total_start=$(echo $cpulog_start | awk '{print $1+$2+$3+$4+$5+$6+$7}')

sleep 10

cpulog_end=$(cat /proc/stat | grep 'cpu'| awk 'NR==1{print $2 "\t" $3 "\t" $4 "\t" $5 "\t" $6 "\t" $7 "\t" $8}' )
cpu_use_end=$(echo $cpulog_end | awk '{print $1+$2+$3}')
cpu_iowait_end=$(echo $cpulog_end | awk '{print $5}')
cpu_total_end=$(echo $cpulog_end | awk '{print $1+$2+$3+$4+$5+$6+$7}')

cpu_use_diff=`expr $cpu_use_end - $cpu_use_start`
cpu_iowait_diff=`expr $cpu_iowait_end - $cpu_iowait_start`
cpu_total_diff=`expr $cpu_total_end - $cpu_total_start`

cpu_use_rate=`expr $cpu_use_diff/$cpu_total_diff*100 | bc -l`
cpu_iowait_rate=`expr $cpu_iowait_diff/$cpu_total_diff*100 | bc -l`

echo "---------------cpuinfo----------------------"
echo "cpu_usage_rate (%) : $cpu_use_rate"
echo "cpu_iowait_rate (%): $cpu_iowait_rate"

主要的知识点讲解:

1
cpulog_start=$(cat /proc/stat | grep 'cpu'| awk 'NR==1{print $2 "\t" $3 "\t" $4 "\t" $5 "\t" $6 "\t" $7 "\t" $8}' )

这一句先将/proc/stat文件的信息读取出来然后用管道| 传递给grep 命令 ,grep 将包含cpu的信息给提取出来

cat /proc/stat | grep 'cpu' 输出为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
root@hw103:/home/yky# cat /proc/stat | grep 'cpu'
cpu 7645369 35392 318219 206250476 80895 0 9870 0 0 0
cpu0 365256 48 18792 8544685 767 0 5678 0 0 0
cpu1 292983 9 15427 8618292 1389 0 2206 0 0 0
cpu2 287020 0 12884 8629895 1033 0 760 0 0 0
cpu3 288372 14624 13910 8613386 681 0 320 0 0 0
cpu4 293707 0 13074 8623117 646 0 147 0 0 0
cpu5 390012 2824 15130 8477387 44027 0 418 0 0 0
cpu6 362140 10934 15217 8541127 1233 0 69 0 0 0
cpu7 377620 6281 12915 8532734 1700 0 28 0 0 0
cpu8 333520 0 12524 8582987 2100 0 15 0 0 0
cpu9 348913 0 12619 8567005 2453 0 10 0 0 0
cpu10 333584 144 14002 8581939 1297 0 15 0 0 0
cpu11 292980 0 12966 8623861 1137 0 4 0 0 0
cpu12 350188 0 16793 8559301 4017 0 3 0 0 0
cpu13 430200 0 19278 8479849 2344 0 1 0 0 0
cpu14 312421 0 11483 8601843 2906 0 1 0 0 0
cpu15 343656 3 10768 8575706 1268 0 0 0 0 0
cpu16 302673 0 12190 8613170 2190 0 0 0 0 0
cpu17 263473 4 9906 8656857 771 0 0 0 0 0
cpu18 263094 370 11278 8653940 2165 0 11 0 0 0
cpu19 281216 3 11166 8637253 1280 0 6 0 0 0
cpu20 280412 0 11645 8637433 1221 0 9 0 0 0
cpu21 277219 143 11967 8639929 1048 0 2 0 0 0
cpu22 275894 0 10291 8640508 1271 0 153 0 0 0
cpu23 298806 0 11985 8618261 1939 0 6 0 0 0

awk 命令

之后使用awk命令再次进行操作。这个命令之前用的很少,参考《鸟哥的Linux私房菜》介绍:

sed常用于一整行的处理,awk则倾向于将一行分成数个“字段”来处理,awk适合处理小型的数据。

用法为:

awk '条件类型1{操作1} 条件类型1{操作2}...' filename

变量名称 意义
NF 每一行($0) 拥有的字段总数
NR awk当前处理的第几行数据
FS 目前的分割符,默认空格键
1
cpulog_start=$(cat /proc/stat | grep 'cpu'| awk 'NR==1{print $2 "\t" $3 "\t" $4 "\t" $5 "\t" $6 "\t" $7 "\t" $8}' )

NR==1 限定条件为第一行,因为第一行的数据才是cpu的总信息,{}里面的操作是输出字段,$N 就是第N个字段。

1
2
3
 $1	$2		$3		$4	  $5		$6		 $7	  $8
user nice system idle iowait irq softirq
cpu 7283854 35392 293546 204419077 75835 0 8385

expr

1
cpu_use_diff=`expr $cpu_use_end - $cpu_use_start`

使用expr 执行变量计算,然后是`` 进行反引用将值赋值给cpu_use_diff

注意shell 脚本中= 不能用空格分开 需要直接相邻

bc 命令

bc 命令是任意精度计算器语言,通常在linux下当计算器用。

简单的描述参考:http://www.runoob.com/linux/linux-comm-bc.html

而expr命令不支持小数运算,所以需要使用bc进行计算。

语法为:

1
bc(选项)(参数)

选项值

  • -i:强制进入交互式模式;
  • -l:定义使用的标准数学库
  • ; -w:对POSIX bc的扩展给出警告信息;
  • -q:不打印正常的GNU bc环境信息;
  • -v:显示指令版本信息;
  • -h:显示指令的帮助信息。

参数

文件:指定包含计算任务的文件。

参考

https://blog.csdn.net/x_i_y_u_e/article/details/50684508