编程新手该如何调优程序?程序员必备性能调优利器——火焰图

本文主要分享火焰图使用技巧,介绍 systemtap 的原理机制,如何使用火焰图快速定位性能问题原因,同时加深对 systemtap 的理解 。
让我们回想一下,曾经作为编程新手的我们是如何调优程序的?通常是在没有数据的情况下依靠主观臆断来瞎蒙,稍微有些经验的同学则会对差异代码进行二分或者逐段调试 。这种定位问题的方式不仅耗时耗力,而且还不具有通用性,当遇到其他类似的性能问题时,需要重复踩坑、填坑,那么如何避免这种情况呢?
俗语有曰:兵欲善其事必先利其器,个人认为,程序员定位性能问题也需要一件“利器” 。如同医生给病人看病,需要依靠专业的医学工具(比如 X 光片、听诊器等)进行诊断,最后依据医学工具的检验结果快速精准的定位出病因所在 。性能调优工具(比如 perf / gprof 等)之于性能调优就像 X 光之于病人一样,它可以一针见血的指出程序的性能瓶颈 。
但是常用的性能调优工具 perf 等,在呈现内容上只能单一的列出调用栈或者非层次化的时间分布,不够直观 。这里我推荐大家配合使用火焰图,它将 perf 等工具采集的数据呈现得更为直观 。
初识火焰图火焰图(Flame Graph)是由 linux 性能优化大师 Brendan Gregg 发明的,和所有其他的 profiling 方法不同的是,火焰图以一个全局的视野来看待时间分布,它从底部往顶部,列出所有可能导致性能瓶颈的调用栈 。
编程新手该如何调优程序?程序员必备性能调优利器——火焰图

文章插图
 
火焰图整个图形看起来就像一个跳动的火焰,这就是它名字的由来 。
火焰图有以下特征(这里以 on-cpu 火焰图为例):
  • 每一列代表一个调用栈,每一个格子代表一个函数
  • 纵轴展示了栈的深度,按照调用关系从下到上排列 。最顶上格子代表采样时,正在占用 cpu 的函数 。
  • 横轴的意义是指:火焰图将采集的多个调用栈信息,通过按字母横向排序的方式将众多信息聚合在一起 。需要注意的是它并不代表时间 。
  • 横轴格子的宽度代表其在采样中出现频率,所以一个格子的宽度越大,说明它是瓶颈原因的可能性就越大 。
  • 火焰图格子的颜色是随机的暖色调,方便区分各个调用信息 。
  • 其他的采样方式也可以使用火焰图, on-cpu 火焰图横轴是指 cpu 占用时间,off-cpu 火焰图横轴则代表阻塞时间 。
  • 采样可以是单线程、多线程、多进程甚至是多 host,进阶用法可以参考附录进阶阅读 。
火焰图类型常见的火焰图类型有 On-CPU,Off-CPU,还有 Memory,Hot/Cold,Differential 等等 。他们分别适合处理什么样的问题呢?
这里笔者主要使用到的是 On-CPU、Off-CPU 以及 Memory 火焰图,所以这里仅仅对这三种火焰图作比较,也欢迎大家补充和斧正 。
编程新手该如何调优程序?程序员必备性能调优利器——火焰图

文章插图
 
火焰图分析技巧
  1. 纵轴代表调用栈的深度(栈桢数),用于表示函数间调用关系:下面的函数是上面函数的父函数 。
  2. 横轴代表调用频次,一个格子的宽度越大,越说明其可能是瓶颈原因 。
  3. 不同类型火焰图适合优化的场景不同,比如 on-cpu 火焰图适合分析 cpu 占用高的问题函数,off-cpu 火焰图适合解决阻塞和锁抢占问题 。
  4. 无意义的事情:横向先后顺序是为了聚合,跟函数间依赖或调用关系无关;火焰图各种颜色是为方便区分,本身不具有特殊含义
  5. 多练习:进行性能优化有意识的使用火焰图的方式进行性能调优(如果时间充裕)
如何绘制火焰图?要生成火焰图,必须要有一个顺手的动态追踪工具,如果操作系统是 Linux 的话,那么通常通常是 perf 或者 systemtap 中的一种 。其中 perf 相对更常用,多数 Linux 都包含了 perf 这个工具,可以直接使用;SystemTap 则功能更为强大,监控也更为灵活 。网上关于如何使用 perf 绘制火焰图的文章非常多而且丰富,所以本文将以 SystemTap 为例 。
SystemTap 是动态追踪工具,它通过探针机制,来采集内核或者应用程序的运行信息,从而可以不用修改内核和应用程序的代码,就获得丰富的信息,帮你分析、定位想要排查的问题 。SystemTap 定义了一种类似的 DSL 脚本语言,方便用户根据需要自由扩展 。不过,不同于动态追踪的鼻祖 DTrace ,SystemTap 并没有常驻内核的运行时,它需要先把脚本编译为内核模块,然后再插入到内核中执行 。这也导致 SystemTap 启动比较缓慢,并且依赖于完整的调试符号表 。


推荐阅读