宋宝华: 用off-cpu火焰图进行Linux性能分析

在《宋宝华:火焰图:全局视野的Linux性能剖析》一文中,我们主要看了on-cpu火焰图,理解了系统的CPU的走向的分析。但是,很多时候,单纯地看on-cpu的情况(什么代码在耗费CPU),并不能解决性能问题,因为有时候性能差的原因瓶颈不一定在CPU上面,而是在off-cpu的时间,比如:
进程进入系统调用执行io动作,io动作的延迟
进程等待mutex锁的时间
内存被交换,swap的时间
内存不够的时候,执行直接内存回收的时间
进程被抢占调度走、或者时间片用完被调度走的时间(runqueue太大)等等等。
基本上,off-cpu的状态图如下(图片来自:
宋宝华: 用off-cpu火焰图进行Linux性能分析_第1张图片
比如一个http服务器,登录的用户多了后,如果普遍觉得上网慢,瓶颈可能出现在网络慢、硬盘读取慢、mutex竞争等。
这种情况下,on-cpu可能不是问题,主要的问题可能是在off-cpu的部分了。
off-cpu分析,对性能问题的调优也至关重要。
下面我们写一个最简单的程序
宋宝华: 用off-cpu火焰图进行Linux性能分析_第2张图片
gcc编译它,可以获得a.out。假设我们追求的性能目标是:每秒钟打印地hello world越多越好,证明这个进程越能服务更多的打印请求。
当然现实生活中的程序比这个要复杂1万倍,但是这个例子不妨碍我们说明原理。
实验环境:
Ubuntu-18.10,内核版本4.18,apt install安装bpfcc-tools - tools for BPF Compiler Collection (BCC)工具包,以及git clone了
https://github.com/brendangregg/FlameGraph
下面我们采集一个它的off-cpu时间:

barry@barryUbuntu:~$ sudo offcputime-bpfcc  -K -p `pgrep -nx a.out`
Tracing off-CPU time (us) of PID 5593 by kernel stack... Hit Ctrl-C to end.

按下ctrl-c停下来后,我们看到2个主要的off-cpu的栈回溯是:
宋宝华: 用off-cpu火焰图进行Linux性能分析_第3张图片
一个发生在usleep()调用的hrtimer_nanosleep -> do_nanosleep系统调用;
一个发生在printf()的时候,进入sys_write系统调用后,tty_writen_tty_write等待一个mutex的代码上面。
这个时候,我们可以进一步查看Linux内核的代码
https://lxr.missinglinkelectronics.com/linux+v4.18/drivers/tty/n_tty.c#L2285
我们认为延迟应该是出现在这个地方:
宋宝华: 用off-cpu火焰图进行Linux性能分析_第4张图片

sudo offcputime-bpfcc -df -p `pgrep -nx a.out` 30 > out.stacks

接下来,我们进入clone下来的FlameGraph项目目录,用flamegraph.pl绘制火焰图:
./flamegraph.pl --color=io --title="Off-CPU Time Flame Graph" --countname=us ~/out.stacks > output.svg
用看图片的工具打开output.svg
宋宝华: 用off-cpu火焰图进行Linux性能分析_第5张图片
从图上也可以看到,off-cpu的2个主要原因一个是nanosleep,一个是write系统调用进入后n_tty_write里面要拿mutex。
点击write的路径,可以局部放大这部分栈回溯:
宋宝华: 用off-cpu火焰图进行Linux性能分析_第6张图片
与我们前面的文本分析的结果是一致的。如果我们想优化性能,一个是可以消除usleep,第二个是分析为什么mutex_lock要等这么久,有什么空间可以提高。

本文是一篇关于off-cpu火焰图的入门引导性文章,如果您对此感兴趣,可以进一步参考:
http://www.brendangregg.com/offcpuanalysis.html

你可能感兴趣的:(perf)