首先明确一下CPU使用率和loadavg这两个概念:
指当前CPU正在执行指令的繁忙程度,越高表面CPU正在执行很多指令即有进程一直在cpu上运行着
指的是CPU负载程度,表明的是CPU当前正在运行的任务以及等待运行的任务统计,是一种趋势的体现;更详细一点来说是R和D状态的进程数量统计
分析此问题的起因是前一段时间购买的开发板,使用最新的SDK跑起来后,几乎没有什么任务在运行,CPU 100% idle,但是loadavg一直在1以上(cpu是双核A7),对比之前使用过的单核MIPS架构路由器来说,显得非常不正常。
top:查看进程状态以及CPU占用和loadavg参数
ps -aux: 查看进程cpu占用和运行状态
vmstat:查看cpu户空间和内核空间占用情况及系统中断和上下文切换状态
pidstat:查看具体某个进程对cpu占用和上下文切换状态
iostat:查看系统IO负载状态
root@wireless-tag:/# vmstat -w 1
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 75660 3948 11740 0 0 0 0 57 108 2 6 91 0 0
0 0 0 75664 3948 11740 0 0 0 0 58 51 0 0 100 0 0
0 0 0 75664 3948 11740 0 0 0 0 43 49 0 0 100 0 0
0 0 0 75664 3948 11740 0 0 0 0 45 56 0 0 100 0 0
0 0 0 75664 3948 11740 0 0 0 0 46 53 0 0 100 0 0
0 0 0 75664 3948 11740 0 0 0 0 46 57 0 0 100 0 0
0 0 0 75664 3948 11740 0 0 0 0 43 52 0 0 100 0 0
0 0 0 75664 3948 11740 0 0 0 0 42 49 0 0 100 0 0
cpu 100% idle: 说明几乎没有进程在使用cpu,中断以及上下文切换也很低
r及b队列数量为0
root@wireless-tag:/# iostat
Linux 4.9.84 (wireless-tag) 01/01/70 _armv7l_ (2 CPU)avg-cpu: %user %nice %system %iowait %steal %idle
0.57 0.00 1.73 0.02 0.00 97.68Device tps kB_read/s kB_wrtn/s kB_read kB_wrtn
mtdblock0 0.03 0.41 0.00 168 0
mtdblock1 0.03 0.41 0.00 168 0
mtdblock2 0.03 0.41 0.00 168 0
mtdblock3 0.03 0.41 0.00 168 0
mtdblock4 0.03 0.41 0.00 168 0
mtdblock5 0.03 0.41 0.00 168 0
mtdblock6 0.03 0.41 0.00 168 0
mtdblock7 0.03 0.41 0.00 168 0
mtdblock8 0.03 0.41 0.00 168 0
mtdblock9 0.03 0.41 0.00 168 0
mtdblock10 0.02 0.38 0.00 156 0
mtdblock11 0.02 0.38 0.00 156 0
mtdblock12 0.02 0.38 0.00 156 0
ubiblock0_1 0.15 9.66 0.00 3948 0
zram0 0.00 0.01 0.01 4 4
io也几乎都是空闲%idle 97.68
root@wireless-tag:/# uptime
23:03:15 up 4 min, 0 users, load average: 1.10, 0.67, 0.29
但是loadavg 1分钟统计显示1.10,结合前面r和b队列为0,说明系统有进程一直在等待运行
接着看一下进程列表:
root@wireless-tag:/# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 1.6 2596 1736 ? Ss 22:58 0:02 /sbin/procd
root 2 0.0 0.0 0 0 ? S 22:58 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 22:58 0:00 [ksoftirqd/0]
root 5 0.0 0.0 0 0 ? S< 22:58 0:00 [kworker/0:0H]
root 7 0.0 0.0 0 0 ? S 22:58 0:00 [rcu_preempt]
root 8 0.0 0.0 0 0 ? S 22:58 0:00 [rcu_sched]
root 9 0.0 0.0 0 0 ? S 22:58 0:00 [rcu_bh]
root 10 0.0 0.0 0 0 ? S 22:58 0:00 [migration/0]
root 11 0.0 0.0 0 0 ? S< 22:58 0:00 [lru-add-drain]
root 12 0.0 0.0 0 0 ? S 22:58 0:00 [watchdog/0]
root 13 0.0 0.0 0 0 ? S 22:58 0:00 [cpuhp/0]
root 14 0.0 0.0 0 0 ? S 22:58 0:00 [cpuhp/1]
root 15 0.0 0.0 0 0 ? S 22:58 0:00 [watchdog/1]
root 16 0.0 0.0 0 0 ? S 22:58 0:00 [migration/1]
root 17 0.0 0.0 0 0 ? S 22:58 0:00 [ksoftirqd/1]
root 18 0.0 0.0 0 0 ? S 22:58 0:00 [kworker/1:0]
root 19 0.0 0.0 0 0 ? S< 22:58 0:00 [kworker/1:0H]
root 20 0.1 0.0 0 0 ? S 22:58 0:00 [kdevtmpfs]
root 21 0.0 0.0 0 0 ? S< 22:58 0:00 [netns]
root 22 0.0 0.0 0 0 ? S 22:58 0:00 [kworker/u4:1]
root 173 0.0 0.0 0 0 ? S 22:58 0:00 [oom_reaper]
root 174 0.0 0.0 0 0 ? S< 22:58 0:00 [writeback]
root 176 0.0 0.0 0 0 ? S 22:58 0:00 [kcompactd0]
root 177 0.0 0.0 0 0 ? S< 22:58 0:00 [crypto]
root 178 0.0 0.0 0 0 ? S< 22:58 0:00 [bioset]
root 180 0.0 0.0 0 0 ? S< 22:58 0:00 [kblockd]
root 201 0.0 0.0 0 0 ? S< 22:58 0:00 [watchdogd]
root 282 0.0 0.0 0 0 ? S 22:58 0:00 [kworker/0:1]
root 296 0.0 0.0 0 0 ? S 22:58 0:00 [kswapd0]
root 297 0.0 0.0 0 0 ? S< 22:58 0:00 [vmstat]
root 384 0.0 0.0 0 0 ? D 22:58 0:00 [ehci_monitor] ----->注意状态为D
root 400 0.0 0.0 0 0 ? S 22:58 0:00 [urdma_tx_thread
root 414 0.0 0.0 0 0 ? S 22:58 0:00 [kworker/1:1]
root 419 0.0 0.0 0 0 ? S 22:58 0:00 [kworker/0:2]
root 502 0.1 0.0 0 0 ? S 22:58 0:00 [ubi_bgt0d]
root 503 0.0 0.0 0 0 ? S< 22:58 0:00 [bioset]
root 508 0.0 0.0 0 0 ? S< 22:58 0:00 [kworker/0:1H]
root 538 0.0 0.0 0 0 ? S< 22:59 0:00 [kworker/1:1H]
root 551 0.0 0.0 0 0 ? S 22:59 0:00 [ubifs_bgt0_2]
root 809 0.0 1.4 2144 1540 ? S 22:59 0:00 /sbin/ubusd
root 812 0.0 1.8 3144 1924 ttyS0 Ss 22:59 0:00 /bin/ash --login
root 859 0.0 0.0 0 0 ? S 22:59 0:00 [ubi_bgt1d]
root 885 0.0 0.0 0 0 ? S 22:59 0:00 [ubifs_bgt1_0]
root 986 0.0 0.0 0 0 ? S< 22:59 0:00 [bioset]
root 996 0.0 0.0 0 0 ? S< 22:59 0:00 [cfg80211]
root 1003 0.0 0.0 0 0 ? S 22:59 0:00 [kworker/u4:2]
root 1226 0.0 1.3 2320 1376 ? S 22:59 0:00 /sbin/logd -S 64
root 1247 0.0 1.4 2780 1560 ? S 22:59 0:00 /sbin/rpcd -s /v
root 1395 0.0 1.5 2396 1664 ? S 22:59 0:00 /sbin/netifd
root 1888 0.0 1.3 2708 1416 ttyS0 R+ 23:10 0:00 ps -aux
发现一个状态为D的内核线程ehci_monitor
进程状态: O:进程正在处理器运行 S:休眠状态(sleeping) R:等待运行(runable)R Running or runnable (on run queue) 进程处于运行或就绪状态 I:空闲状态(idle) Z:僵尸状态(zombie) T:跟踪状态(Traced) B:进程正在等待更多的内存页 D:不可中断的深度睡眠
D状态标示不可中断,同时又是内核线程,说明该线程没有捕获任何信号,不能被中断,一直在CPU运行队列中 ,但是该线程又不占用CPU(前面cpu 100% idle),说明该线程没有在干活。此时我们可以认为,该线程的实现有点”问题“,不干活又一直要运行,可能是在等待什么条件或者检查什么状态亦或其他什么很机密的东西;总之,该线程的状态处理有待改善。
既然已经定位到了内核线程名,那么就没有什么比查看代码来得更直接的了,通过查看代码发现该线程就是在干一个活,总结起来就是每隔100ms查询一个条件,如下:
while(1) { if(check_status) do.... msleep(100); }
该线程没有捕获任何信号,同时又没有改变运行状态,唯有一个msleep会引起调度,最终状态就是D,不可中断;
1. 设置线程状态为INTERRUPTIBLE
2. 使用schedule_timeout来显示的调度
while(1)
{set_current_state(TASK_INTERRUPTIBLE);
if(check_status)
do....
schedule_timeout(HZ)
}
修改之后结果:
root@wireless-tag:/# uptime
23:51:52 up 0 min, 0 users, load average: 0.16, 0.05, 0.01
root@wireless-tag:/# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 5.9 1.5 2596 1652 ? Ss 23:51 0:02 /sbin/procd
root 2 0.0 0.0 0 0 ? S 23:51 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 23:51 0:00 [ksoftirqd/0]
root 4 0.0 0.0 0 0 ? S 23:51 0:00 [kworker/0:0]
root 5 0.0 0.0 0 0 ? S< 23:51 0:00 [kworker/0:0H]
root 6 0.0 0.0 0 0 ? S 23:51 0:00 [kworker/u4:0]
root 7 0.0 0.0 0 0 ? S 23:51 0:00 [rcu_preempt]
root 8 0.0 0.0 0 0 ? S 23:51 0:00 [rcu_sched]
root 9 0.0 0.0 0 0 ? S 23:51 0:00 [rcu_bh]
root 10 0.0 0.0 0 0 ? S 23:51 0:00 [migration/0]
root 11 0.0 0.0 0 0 ? S< 23:51 0:00 [lru-add-drain]
root 12 0.0 0.0 0 0 ? S 23:51 0:00 [watchdog/0]
root 13 0.0 0.0 0 0 ? S 23:51 0:00 [cpuhp/0]
root 14 0.0 0.0 0 0 ? S 23:51 0:00 [cpuhp/1]
root 15 0.0 0.0 0 0 ? S 23:51 0:00 [watchdog/1]
root 16 0.0 0.0 0 0 ? S 23:51 0:00 [migration/1]
root 17 0.0 0.0 0 0 ? S 23:51 0:00 [ksoftirqd/1]
root 18 0.0 0.0 0 0 ? S 23:51 0:00 [kworker/1:0]
root 19 0.0 0.0 0 0 ? S< 23:51 0:00 [kworker/1:0H]
root 20 2.0 0.0 0 0 ? S 23:51 0:00 [kdevtmpfs]
root 21 0.0 0.0 0 0 ? S< 23:51 0:00 [netns]
root 22 0.0 0.0 0 0 ? S 23:51 0:00 [kworker/u4:1]
root 173 0.0 0.0 0 0 ? S 23:51 0:00 [oom_reaper]
root 174 0.0 0.0 0 0 ? S< 23:51 0:00 [writeback]
root 176 0.0 0.0 0 0 ? S 23:51 0:00 [kcompactd0]
root 177 0.0 0.0 0 0 ? S< 23:51 0:00 [crypto]
root 178 0.0 0.0 0 0 ? S< 23:51 0:00 [bioset]
root 180 0.0 0.0 0 0 ? S< 23:51 0:00 [kblockd]
root 201 0.0 0.0 0 0 ? S< 23:51 0:00 [watchdogd]
root 282 1.3 0.0 0 0 ? S 23:51 0:00 [kworker/0:1]
root 296 0.0 0.0 0 0 ? S 23:51 0:00 [kswapd0]
root 297 0.0 0.0 0 0 ? S< 23:51 0:00 [vmstat]
root 384 0.0 0.0 0 0 ? S 23:51 0:00 [ehci_monitor] ----> S态
root 400 0.0 0.0 0 0 ? S 23:51 0:00 [urdma_tx_thread
root 414 0.5 0.0 0 0 ? S 23:51 0:00 [kworker/1:1]
root 419 0.0 0.0 0 0 ? S 23:51 0:00 [kworker/0:2]
root 422 0.0 0.0 0 0 ? S< 23:51 0:00 [bioset]
root@wireless-tag:/# vmstat -w 1
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 76568 3600 11308 0 0 0 0 51 103 4 6 90 0 0
0 0 0 76568 3600 11308 0 0 0 0 56 57 0 0 100 0 0
0 0 0 76584 3600 11308 0 0 0 0 43 56 0 0 100 0 0
0 0 0 76584 3600 11308 0 0 0 0 43 53 0 0 100 0 0
0 0 0 76584 3600 11308 0 0 0 0 44 59 0 0 100 0 0
结果显示很“完美”
关于内核线程的使用以及线程状态切换和维护,后面有时间再补充一篇博文,以便更强有力的说明CPU使用率和loadavg这两个参数的意义。
同时我们也能得出结论:CPU够不够用,系统压力大不大,不能单纯的只看使用率或者loadavg,需要两个相结合来分析。