【原创】CPU性能优化小记
CPU性能优化小记
一、现象
业务线反馈,单板只要一跑我们的通讯软件appA,CPU就变得很高,即使没有任何通讯,空跑时CPU利用率同样的高,难得业务会关注CPU性能,好久没更新博客了,小记一下(又是debug一两天,最后改一行代码解决的问题o(╯□╰)o)。
启动appA 前,top看一下CPU使用情况,如下,9%还算正常(有其他业务应用)。
Mem: 49320K used, 202284K free, 0K shrd, 0K buff, 27420K cached
CPU: 3.0% usr 6.0% sys 0.0% nic 91.0% idle 0.0% io 0.0% irq 0.0% sirq
Load average: 1.79 2.79 2.98 1/86 1721
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
1721 1376 root R 2272 0.9 0 1.6 top -d 1
917 1 root S 38936 15.4 0 1.1 ...
908 1 root S 38936 15.4 0 0.5 ...
915 1 root S 38936 15.4 0 0.5 ...
896 1 root S 38936 15.4 0 0.5 ...
914 1 root S 38936 15.4 0 0.5 ...
857 1 root S 4396 1.7 0 0.5 /usr/sbin/telnetd
3 2 root SW 0 0.0 0 0.5 [ksoftirqd/0]
1376 857 root S 2272 0.9 0 0.0 -sh
929 1 root S 2272 0.9 0 0.0 /sbin/getty -L ttyO2 115200 vt100
1 0 root S 2268 0.9 0 0.0 init
...
我们的应用启动后,CPU使用率很高,65%左右,是什么让CPU占用高?
$top -d1
Mem: 54604K used, 197000K free, 0K shrd, 0K buff, 27220K cached
CPU: 14.6% usr 38.5% sys 0.0% nic 36.2% idle 0.0% io 0.0% irq 10.5% sirq
Load average: 3.26 2.22 1.58 1/107 1470
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
1444 1376 root S 28008 11.1 0 5.8 {Thread_start} ./appA
3 2 root SW 0 0.0 0 4.0 [ksoftirqd/0]
1445 1376 root S 28008 11.1 0 2.9 {Task_OS_Timer} ./appA
1470 1376 root R 2272 0.9 0 2.3 top -d 1
917 1 root S 38936 15.4 0 1.7 ...
1450 1376 root S 28008 11.1 0 1.7 ...
896 1 root S 38936 15.4 0 1.1 ...
1449 1376 root S 28008 11.1 0 0.5 {CycleIO} ./appA
857 1 root S 4396 1.7 0 0.5 /usr/sbin/telnetd
......
TOP各指标含义
简单介绍下top各指标含义。top 命令显示了 us、sy、nic、idle 、io、hi、si 和 st 这几个指标(不同版本的top显示简写有所不同),各指标含义如下,这几个指标之和为 100。
us, user : time running un-niced user processes
sy, system : time running kernel processes
ni, nice : time running niced user processes
id, idle : time spent in the kernel idle handler
wa, IO-wait : time waiting for I/O completion
hi : time spent servicing hardware interrupts
si : time spent servicing software interrupts
st : time stolen from this vm by the hypervisor
| CPU指标 | 含义 |
|---|---|
| us | CPU执行用户代码消耗的CPU时间比例,这个比例越高,说明CPU的利用率越好,因为我们的目的就是为了让CPU将更多的时间用在执行用户代码上,如果这个指标过高影响了你的业务,那就需要去分析业务代码了。 |
| sy | CPU执行内核代码消耗的CPU时间比例,这个比例要越低越好,因为CPU不应该把时间浪费在执行内核函数上,如内核函数浪费了很多时间,那说明内核可能需要优化了。 |
| ni | Nice值被调大的线程执行用户态代码消耗的CPU百分比。对于非实时任务,通过调整线程的Nice值可以控制它的CPU时间,当我们增大一个线程的Nice值时,我们期望它可以少占用一些CPU时间,CPU利用率里的ni这个值就给我们一个参考指标来观察我们的调整效果。 运行一个进程后,它的默认Nice值为0,通过renice来增加该进程的Nice值(正数),该进程的CPU利用率就会在ni中显示,而减少进程的Nice值(负数)则不会在这里面显示。 |
| id | CPU空闲时间,我们通常说的整体CPU利用率就是(100-idl)这个值,也是其他几项的和。为了提升系统的资源利用率,目标就是尽量降低idl。 |
| wa | CPU阻塞在I/O上的时间,比如CPU从磁盘读取文件内容,由于磁盘I/O太慢,导致CPU不得不等待数据就绪,然后才能继续执行下一步操作,这就wai时间,这个值越高,说明I/O处理能力出现了问题。 |
| hi | CPU消耗在硬中断里的时间,正常情况下这个值都很低,因为中断的处理很快,即使有大量的硬件中断,也不会消耗很多的CPU时间。 |
| si | CPU消耗在软中断里的时间,系统中常见的软中断有网络收发包软中断、写文件落盘产生的软中断、高精度定时器软中断等。所以网络吞吐量较高的系统中,这个值也会高一些。 |
在上面这几项中,idle 和 wait 是 CPU 不工作的时间,其余的项都是 CPU 工作的时间。idle 和 wait 的主要区别是,idle 是 CPU 无事可做,而 wait 则是 CPU 想做事却做不了。你也可以将 wait 理解为是一类特殊的 idle,即该 CPU 上有至少一个线程阻塞在 I/O 时的 idle。
二、分析
由CPU: 14.6% usr 38.5% sys 0.0% nic 36.2% idle 0.0% io 0.0% irq 10.5% sirq可以看出,CPU 利用率飙高是由 sys 利用率和sirq利用率变高导致的,也就是说 sys 利用率会忽然飙高一下,比如在 usr 低于 15% 的情况下,sys 会高于 40%,同时sirq会高于10%,持续不到一秒后又恢复正常。
CPU 的 sys 利用率高,说明内核函数执行花费了太多的时间,同样,CPU 的 sirq利用率高,说明内核处理软中断执行花费了太多的时间,先对比应用启动前后系统各部分信息,看看能否推断出CPU执行哪部分的的内核函数花费的时间长。
启动应用前
我们先通过pidstat看看appA启动前,系统中每个进程usr、system、guest、wait各部分CPU使用情况:
$ pidstat 1 3 #每秒打印一次 打印3次
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
09:45:44 UID PID %usr %system %guest %wait %CPU CPU Command
09:45:44 0 47 0.00 0.96 0.00 0.00 0.96 0 kworker/0:1
09:45:44 0 894 2.88 3.85 0.00 0.00 6.73 0 cpu_mem_task
09:45:44 0 968 0.00 1.92 0.00 0.00 1.92 0 pidstat
09:45:44 UID PID %usr %system %guest %wait %CPU CPU Command
09:45:45 0 857 0.00 1.00 0.00 0.00 1.00 0 telnetd
09:45:45 0 881 0.00 1.00 0.00 0.00 1.00 0 xxxx
09:45:45 0 894 2.00 5.00 0.00 0.00 7.00 0 xxxx
09:45:45 0 968 1.00 2.00 0.00 0.00 3.00 0 pidstat
09:45:45 UID PID %usr %system %guest %wait %CPU CPU Command
09:45:46 0 3 0.00 1.00 0.00 0.00 1.00 0 ksoftirqd/0
09:45:46 0 894 1.00 6.00 0.00 0.00 7.00 0 xxxx
09:45:46 0 968 1.00 2.00 0.00 0.00 3.00 0 pidstat
可以看到,各进程正常,CPU使用率低,接下来通过mpstat 查看内核各部分详细。
]# mpstat --help
Usage: mpstat [ options ] [ <interval> [ <count> ] ]
Options are:
[ -A ] [ -n ] [ -T ] [ -u ] [ -V ]
[ -I { SUM | CPU | SCPU | ALL } ] [ -N { <node_list> | ALL } ]
[ --dec={ 0 | 1 | 2 } ] [ -o JSON ] [ -P { <cpu_list> | ALL } ]
- -A: 等同于-u -I ALL -P ALL
- -I:指定SUM CPU SCPU ALL四个参数,SUM表示每个处理器的中断总数,CPU表示每个核的每秒中断数量, SCPU表示每个核每秒的软中断数量。
- -P: 统计的CPU编号,一般用ALL
- -u: 输出列的信息
- -V: 查看版本号
- CPU利用率
每秒输出1次, 输出5次:
[root@/tmp]# mpstat 1 5
09:49:51 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
09:49:52 all 1.01 0.00 5.05 0.00 0.00 2.02 0.00 0.00 0.00 91.92
09:49:53 all 2.15 0.00 1.08 0.00 0.00 0.00 0.00 0.00 0.00 96.77
09:49:54 all 0.00 0.00 0.00 0.00 0.00 1.09 0.00 0.00 0.00 98.91
09:49:55 all 2.04 0.00 3.06 0.00 0.00 2.04 0.00 0.00 0.00 92.86
09:49:56 all 0.00 0.00 2.15 0.00 0.00 0.00 0.00 0.00 0.00 97.85
Average: all 1.05 0.00 2.32 0.00 0.00 1.05 0.00 0.00 0.00 95.58
- 软中断
软中断每秒输出1次, 输出6次:
# mpstat -I SCPU 1 6
09:51:22 CPU HI/s TIMER/s NET_TX/s NET_RX/s BLOCK/s BLOCK_IOPOLL/s TASKLET/s SCHED/s HRTIMER/s RCU/s
09:51:23 0 0.00 25.00 1.00 3.00 0.00 0.00 0.00 0.00 200.00 0.00
09:51:24 0 0.00 31.00 0.00 4.00 0.00 0.00 0.00 0.00 200.00 0.00
09:51:25 0 0.00 26.00 0.00 4.00 0.00 0.00 0.00 0.00 199.00 0.00
09:51:26 0 0.00 36.00 0.00 4.00 0.00 0.00 0.00 0.00 200.00 0.00
09:51:27 0 0.00 31.00 0.00 3.00 0.00 0.00 0.00 0.00 199.00 0.00
09:51:28 0 0.00 31.00 1.00 3.00 0.00 0.00 0.00 0.00 200.00 0.00
Average: 0 0.00 30.00 0.33 3.50 0.00 0.00 0.00 0.00 199.67 0.00
对应的软中断信息:
# cat /proc/softirqs
CPU0
HI: 0
TIMER: 7778445
NET_TX: 7244
NET_RX: 293406
BLOCK: 0
BLOCK_IOPOLL: 0
TASKLET: 1
SCHED: 0
HRTIMER: 522165833
RCU: 0
- 硬中断
处理器硬中断总数:
# mpstat -I SUM 1 6
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
09:54:50 CPU intr/s
09:54:51 all 3000.00
09:54:52 all 3151.00
09:54:53 all 3229.00
09:54:54 all 3129.00
09:54:55 all 3049.00
09:54:56 all 3210.00
Average: all 3127.79
每个硬中断产生速率:
# mpstat -I CPU 1 6
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
09:56:46 CPU 20/s 28/s 30/s 33/s 34/s 35/s 68/s 80/s 84/s 86/s 87/s 90/s 94/s 116/s 125/s 127/s 173/s 230/s 233/s 255/s 261/s Err/s
09:56:47 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3151.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 5.00 0.00 0.00 0.00 0.00 0.00
09:56:48 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3140.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 7.00 0.00 0.00 0.00 0.00 0.00
09:56:49 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3355.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6.00 0.00 0.00 0.00 0.00 0.00
09:56:50 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3031.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00
09:56:51 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3288.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6.00 0.00 0.00 0.00 0.00 0.00
09:56:52 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3155.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 6.00 0.00 0.00 0.00 0.00 0.00
Average: 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3186.67 0.00 2.00 0.00 0.00 0.00 0.00 0.00 5.67 0.00 0.00 0.00 0.00 0.00
对应的中断信息:
# cat /proc/interrupts
CPU0
84: 1583852200 INTC 68 gp_timer
86: 108 INTC 70 44e0b000.i2c
87: 483682 INTC 71 4802a000.i2c
90: 59 INTC 74 UART2
173: 701497 GPIO 29 eth0
230: 6 GPIO 22 button_int
233: 0 GPIO 25 fpga_int
255: 0 GPIO 15 mmc0
261: 0 GPIO 21 power_int
Err: 0
......
启动appA应用前,可以看出irq为84的中断gp_timer中断比较高, 3155次/S左右。
启动应用后
先启动应用,然后再看一下这些指标的变化。
# mpstat 1 5
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
10:10:45 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
10:10:46 all 7.95 0.00 18.18 0.00 0.00 3.41 0.00 0.00 0.00 70.45
10:10:47 all 6.17 0.00 16.05 0.00 0.00 1.23 0.00 0.00 0.00 76.54
10:10:48 all 4.94 0.00 17.28 0.00 0.00 2.47 0.00 0.00 0.00 75.31
10:10:49 all 8.05 0.00 17.24 0.00 0.00 4.60 0.00 0.00 0.00 70.11
10:10:50 all 11.76 0.00 12.94 0.00 0.00 2.35 0.00 0.00 0.00 72.94
Average: all 7.82 0.00 16.35 0.00 0.00 2.84 0.00 0.00 0.00 72.99
usr,sys 升高明显,soft有所升高,什么导致的sys升高?下面看硬中断处理信息:
# mpstat -I SUM 1 6
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
10:12:11 CPU intr/s
10:12:12 all 6571.00
10:12:13 all 6597.00
10:12:14 all 6574.00
10:12:15 all 6566.00
10:12:16 all 6592.00
10:12:17 all 6583.00
Average: all 6580.50
对比启动应用前3000/s,每秒中断产生次数增长了120%。继续查看哪些中断变高了?
# mpstat -I CPU 1 6
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
10:15:04 CPU 20/s 28/s 30/s 33/s 34/s 35/s 68/s 80/s 84/s 86/s 87/s 90/s 94/s 116/s 125/s 127/s 173/s 230/s 233/s 255/s 261/s Err/s
10:15:05 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6552.00 0.00 3.00 0.00 0.00 0.00 0.00 0.00 28.00 0.00 0.00 0.00 0.00 0.00
10:15:06 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6552.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.00 0.00 0.00 0.00 0.00 0.00
10:15:07 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6637.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 27.00 0.00 0.00 0.00 0.00 0.00
10:15:08 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6543.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.00 0.00 0.00 0.00 0.00 0.00
10:15:10 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6579.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 30.00 0.00 0.00 0.00 0.00 0.00
10:15:11 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6561.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.00 0.00 0.00 0.00 0.00 0.00
Average: 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6570.67 0.00 1.83 0.00 0.00 0.00 0.00 0.00 28.67 0.00 0.00 0.00 0.00 0.00
# mpstat -I SCPU 1 6
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
10:20:29 CPU HI/s TIMER/s NET_TX/s NET_RX/s BLOCK/s BLOCK_IOPOLL/s TASKLET/s SCHED/s HRTIMER/s RCU/s
10:20:30 0 0.00 41.58 0.00 9.90 0.00 0.00 0.00 0.00 2172.28 0.00
10:20:31 0 0.00 43.00 0.00 12.00 0.00 0.00 0.00 0.00 2187.00 0.00
10:20:32 0 0.00 38.00 0.00 11.00 0.00 0.00 0.00 0.00 2191.00 0.00
10:20:33 0 0.00 34.00 1.00 10.00 0.00 0.00 0.00 0.00 2190.00 0.00
10:20:34 0 0.00 37.00 0.00 11.00 0.00 0.00 0.00 0.00 2190.00 0.00
10:20:35 0 0.00 40.00 0.00 10.00 0.00 0.00 0.00 0.00 2184.00 0.00
Average: 0 0.00 38.94 0.17 10.65 0.00 0.00 0.00 0.00 2185.69 0.00
可以看irq为84的中断gp_timer中断相比应用启动前变为2倍, 3155.00次/S左右。相应的高精度定时器软中断HRTIMER从之前的200/S上升到2100/S,到此基本可以确定应用疯狂定时操作引起的,进一步看内核执行的函数来确认。
采集内核函数的方法
目前基本清楚因为定时器中断变高导致的内核函数执行时间变长,接下来采集 CPU 在 sys 飙高的瞬间所执行的内核函数,同时看看应用执行什么引起的定时器中断,再做相应的优化。采集内核函数的方法有很多,比如:
通过 perf( perf 是内核自带的性能剖析工具) 可以采集 CPU 的热点,看看 sys 利用率高时,哪些内核耗时的 CPU 利用率高;
通过 perf 的
call-graph功能可以查看具体的调用栈信息,也就是线程是从什么路径上执行下来的;通过 perf 的
annotate功能可以追踪到线程是在内核函数的哪些语句上比较耗时;通过 ftrace 的
function-graph功能可以查看这些内核函数的具体耗时,以及在哪个路径上耗时最大。针对一些瞬时sys 利用率高问题,还可以通过系统快照sysrq,把当前 CPU 正在做的工作记录下来,然后结合内核源码分析为什么 sys 利用率会高。
sysrq常用来分析内核问题的工具,用它可以观察当前的内存快照、任务快照,可以构造 vmcore 把系统的所有信息都保存下来,甚至还可以在内存紧张的时候用它杀掉内存开销最大的那个进程。
用 sysrq 来分析问题,首先需要使能 sysyrq,使能sysrq后没有任何开销,使能方式如下:
$ sysctl -w kernel.sysrq=1
sysrq 的功能被使能后,使用它的 -t 选项来把当前的任务快照保存下来,看看系统中都有哪些任务,以及这些任务都在干什么。使用方式如下:
$ echo t > /proc/sysrq-trigger
执行后,任务快照会被打印到内核缓冲区,这些任务快照信息通过
dmesg命令来查看:$ dmesg
内核采集分析
这里使用perf 对appA进程进行采样,输出内核整个调用链上的汇总信息。
# 采样10s后退出
$ perf record -a -g -p `pidof appA` -- sleep 10
采样完成后,继续执行 perf report命令,得到 perf 的汇总报告。

额。。。屏幕太小、ARM 串口来打印,这打印很难看。
火焰图分析
针对 perf 汇总数据的展示问题,Brendan Gragg 发明了火焰图,通过矢量图的形式,更直观展示汇总结果。

(图片来自 Brendan Gregg 博客)
横轴表示采样数和采样比例。一个函数占用的横轴越宽,就代表它的执行时间越长。同一层的多个函数,则是按照字母来排序。
纵轴表示调用栈,由下往上根据调用关系逐个展开。换句话说,上下相邻的两个函数中,下面的函数,是上面函数的父函数。这样,调用栈越深,纵轴就越高。
另外,要注意图中的颜色,并没有特殊含义,只是用来区分不同的函数。
火焰图是动态的矢量图格式,所以它还支持一些动态特性。比如,鼠标悬停到某个函数上时,就会自动显示这个函数的采样数和采样比例。而当你用鼠标点击函数时,火焰图就会把该层及其上的各层放大,方便你观察这些处于火焰图顶部的调用栈的细节。
如果我们根据性能分析的目标来划分,火焰图可以分为下面这几种。
- on-CPU 火焰图:表示 CPU 的繁忙情况,用在 CPU 使用率比较高的场景中。
- off-CPU 火焰图:表示 CPU 等待 I/O、锁等各种资源的阻塞情况。
- 内存火焰图:表示内存的分配和释放情况。
- 热 / 冷火焰图:表示将 on-CPU 和 off-CPU 结合在一起综合展示。
- 差分火焰图:表示两个火焰图的差分情况,红色表示增长,蓝色表示衰减。差分火焰图常用来比较不同场景和不同时期的火焰图,以便分析系统变化前后对性能的影响情况。
如何生成火焰图?首先,下载几个能从 perf record 记录生成火焰图的工具,这些工具都放在 https://github.com/brendangregg/FlameGraph 。
$ git clone https://github.com/brendangregg/FlameGraph
$ cd FlameGraph
安装好工具后,要生成火焰图,其实主要需要三个步骤:
- 执行
perf script,将perf record的记录转换成可读的采样记录; - 执行
stackcollapse-perf.pl脚本,合并调用栈信息; - 执行
flamegraph.pl脚本,生成火焰图。
如果你的机器安装了完整的系统,通过管道简化这三个步骤的执行如下:
$ perf script -i /root/perf.data | ./stackcollapse-perf.pl --all | ./flamegraph.pl > hsys.svg
因为我的目标系统是在ARM busybos上,先在目标机器上执行步骤1,在将中间文件上传到X86系上完成步骤2和3。
$ perf script -i perf.data > perf-temp
$ tftp -p 192.168.1.55 -l perf-temp
X86机器上完成步骤2和3.
$ cat perf-temp| ./stackcollapse-perf.pl --all | ./flamegraph.pl > hsys.svg
使用浏览器打开hsys.svg如下。

从下往上看,沿着调用栈中最宽的函数来分析执行次数最多的函数。看到的结果跟的 perf report 类似,但直观了很多,这几团系统调用的火焰,就是我们关注的地方。
可以看到,应用发起的几个系统调用后,内核sys_rt_sigtimedwait、sys_mq_timedsend、sys_mq_timedreceive分别占总执行时间的22.69%、(13.71%+6.15%)、(8.53%+8.89%)。

到这里,找出了内核执行最频繁的函数调用堆栈,而这个堆栈中的各层级函数,就是潜在的性能瓶颈来源。对比同一cpu高版本内核,该问题并不明显,如果想深入了解linux时间子系统,请移步时间子系统-蜗窝科技。看来内核是动不了,不好下手,那回到应用看看。
三、解决
既然已经清楚原因是应用定时相关操作引起的,回到应用排查相关代码。
这个应用是一个协议栈,整个协议栈有多个不同优先级的实时线程,每个线程负责各部分通讯处理,其中两个线程为整个协议栈提供timers处理机制,线程Thread_start向操作系统注册一个周期timer,该周期timer的间隔就是协议栈软件timer的基准时间,线程A周期等待操作系统timer超时信号。
当超时信号到达时,线程Thread_start遍历所有上层应用注册的timer,判断时间是否到期,如果该timer到期,通过消息队列mq将该timer发送给另一个线程OS_timer进行timer处理,线程OS_timer接收到该timer后,执行该timer注册的超时回调函数callbalk_timeout。
排查后发现,问题出在线程Thread_start向操作系统注册的这个周期timer,它的触发间隔为500us,由于触发频率太高,导致操作系统处理定时器软硬中断消耗大部分CPU,表现就是系统cpu飙高,但是检索整个协议栈,并没有发现上层应用注册小于1ms的timer,协议栈根本用不到这么小基准的timer。
所以,解决的办法很简单,就修改一行代码,将线程Thread_start向操作系统注册的周期timer间隔500us调整为1ms,问题解决。
优化后,时钟软硬中断降低。系统sys CPU利用率下降,如下:
$ pidstat 1 5 -p `pidof appA` #目标应用指标
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
17:32:45 UID PID %usr %system %guest %wait %CPU CPU Command
17:32:46 0 1112 8.91 0.99 0.00 0.00 9.90 0 appA
17:32:47 0 1112 3.00 8.00 0.00 0.00 11.00 0 appA
17:32:48 0 1112 8.00 3.00 0.00 0.00 11.00 0 appA
17:32:49 0 1112 10.00 1.00 0.00 0.00 11.00 0 appA
$mpstat -A 1 1 #系统整体详细指标
Linux 3.12.10 08/22/22 _armv7l_ (1 CPU)
17:35:24 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
17:35:25 all 1.20 0.00 10.84 0.00 0.00 0.00 0.00 0.00 87.95
17:35:25 0 1.20 0.00 10.84 0.00 0.00 0.00 0.00 0.00 87.95
17:35:24 CPU intr/s
17:35:25 all 6821.69
17:35:25 0 6820.48
17:35:24 CPU 20/s 28/s 30/s 33/s 34/s 35/s 68/s 80/s 84/s 86/s 87/s 90/s 94/s 116/s 125/s 127/s 173/s 230/s 233/s 255/s 261/s Err/s
17:35:25 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6792.77 0.00 3.61 0.00 0.00 0.00 0.00 0.00 24.10 0.00 0.00 0.00 0.00 0.00
17:35:24 CPU HI/s TIMER/s NET_TX/s NET_RX/s BLOCK/s BLOCK_IOPOLL/s TASKLET/s SCHED/s HRTIMER/s RCU/s
17:35:25 0 0.00 30.12 1.20 13.25 0.00 0.00 0.00 0.00 1443.37 0.00
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
Average: all 1.20 0.00 10.84 0.00 0.00 0.00 0.00 0.00 87.95
Average: 0 1.20 0.00 10.84 0.00 0.00 0.00 0.00 0.00 87.95

对比上面的火焰图,看到sys_rt_sigtimedwait、sys_mq_timedsend、sys_mq_timedreceive明显降低.
| sys_rt_sigtimedwait | sys_mq_timedsend | sys_mq_timedreceive | |
|---|---|---|---|
| 前 | 22.69% | 19.86%(13.71%+6.15%) | 17.51%(8.53%+8.89%) |
| 后 | 14.94% | 9.84%(5.84%+4%) | 11.47%(5.67%+5.8%) |
真是debug一两天,最后改一行代码解决问题o(╯□╰)o)。。。
【原创】CPU性能优化小记的更多相关文章
- [原创]Java性能优化权威指南读书思维导图
[原创]Java性能优化权威指南读书思维导图 书名:Java性能优化权威指南 原书名:Java performance 作者: (美)Charlie Hunt Binu John 译者: 柳飞 ...
- [原创]Java性能优化权威指南读书思维导图4
[原创]Java性能优化权威指南读书思维导图4
- [原创]Java性能优化权威指南读书思维导图3
[原创]Java性能优化权威指南读书思维导图3
- [原创]Java性能优化权威指南读书思维导图2
[原创]Java性能优化权威指南读书思维导图2
- [Unity优化] Unity CPU性能优化
前段时间本人转战unity手游,由于作者(Chwen)之前参与端游开发,有些端游的经验可以直接移植到手游,比如项目框架架构.代码设计.部分性能分析,而对于移动终端而言,CPU.内存.显卡甚至电池等硬件 ...
- Linux性能优化从入门到实战:07 CPU篇:CPU性能优化方法
性能优化方法论 动手优化性能之前,需要明确以下三个问题: (1)如何评估性能优化的效果? 确定性能的量化指标.测试优化前的性能指标.测试优化后的性能指标. 量化指标的选择.至少要从应用程序 ...
- CPU性能优化干货总结
一.背景 部门成立专项组,对数智平台和站务系统做性能优化,其中目标之一为降低服务端硬件成本,即在32G内存.CPU银牌的配置下,能支撑1万+发客量.要达到此目标,需通过压力测试并配合监控系统,以QPS ...
- CPU性能优化
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11521331.html CPU性能指标 根据指标找工具 根据工具查指标 top.vmstat 和 pi ...
- 《Linux 性能优化实战—倪朋飞 》学习笔记 CPU 篇
平均负载 指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,即平均活跃进程数 可运行状态:正在使用CPU或者正在等待CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态 (Run ...
- Linux性能优化实战CPU篇之总结(四)
一.分析CPU瓶颈 1,性能指标 a>CPU使用率 CPU使用率描述了非空闲时间占总CPU时间的百分比,根据CPU上运行任务的不同可以分为:用户CPU.系统CPU.等待I/O CPU.软中断和硬 ...
随机推荐
- JUC(四)多线程锁
目录 多线程锁 Synchronized锁的八种情况 公平锁和非公平锁 可重入锁 synchronized Lock 死锁 检查死锁 多线程锁 Synchronized锁的八种情况 以一个手机类为例, ...
- Redis报错MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on
1.错误信息 org.redisson.client.RedisException: MISCONF Redis is configured to save RDB snapshots, but is ...
- 笔记:C++学习之旅---面向对象程序的设计1
笔记:C++学习之旅---面向对象程序的设计1 面向对象的主要特征 1.抽象 2.封装 3.继承 4.多态 抽象:将程序的每一部分都看作一个抽象的对象,即程序有一组抽象的对象组成的更复杂点,这些对象根 ...
- C# 编译异常CS0433
编译后遇到nuget版本冲突: error CS0433: 类型"ShellFile"同时存在于"Microsoft.WindowsAPICodePack.Shell, ...
- [OpenCV-Python] 4 图像读取
文章目录 OpenCV-Python: II OpenCV 中的 Gui 特性 4 图片 4.1 读入图像 4.2 显示图像 4.3 保存图像 4.4 总结一下 OpenCV-Python: II O ...
- 【Redis】Cluster集群
一.Redis Cluster 工作原理 在引入哨兵机制后,解决了Redis主从架构Master故障时的主从切换问题,保证了Redis服务可用性.但依旧无法解决单机节点出现的写入性能瓶颈(网卡速率.单 ...
- Python获取jsonp数据
使用python爬取数据时,有时候会遇到jsonp的数据格式,由于不是json的,所以不能直接使用json.loads()方法来解析,需要先将其转换为json格式,再进行解析.在前面讲了jsonp的原 ...
- CD的认知与学习
cd命令的作用 ●ls可以理解成当前而cd是切换到那一层 ls查看当前目录下的所有文件(不包含隐藏): ls /查看/下的所有文件 cd 切换到哪个文件下 pwd命令的作用 通过ls来验证当前的工作目 ...
- 2022-10-30:给你一个长度为 n 的整数数组 rolls 和一个整数 k 。 你扔一个 k 面的骰子 n 次,骰子的每个面分别是 1 到 k , 其中第 i 次扔得到的数字是 rolls[i]
2022-10-30:给你一个长度为 n 的整数数组 rolls 和一个整数 k . 你扔一个 k 面的骰子 n 次,骰子的每个面分别是 1 到 k , 其中第 i 次扔得到的数字是 rolls[i] ...
- 2021-11-01:寻找重复数。给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数
2021-11-01:寻找重复数.给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设 nums 只有 一个重复的整数 ...