性能分析利器之perf浅析

源:http://walkerdu.com/2018/09/13/perf-event/
作为服务器后台开发,不仅仅要写业务逻辑,后台意味着高并发,稳定性,当你写了很多逻辑,发现性能有问题的时候,也要学会性能分析,进行性能优化, 也许你会接触很多性能分析工具:valgrind,gperftools,gprof, oprofile, 有时间慢慢一一介绍,在学习perf的过程中,也学习和加深了很多之前的知识,本文抛砖引玉,希望能帮助大家了解一些性能分析更深的一些东西 。
1. perf简介perf是一款linux内置的性能分析工具,随着内核发布,也被称为perf_events, perf tools, PCL(Performance Counters for Linux), 发布于Linux kernel version 2.6.31, perf是怎么工作的呢?perf如何使用?本文是来介绍一下 。
perf官方wiki的介绍是:Linux profiling with performance counters
Perf可以解决高级性能和故障排除,它可以分析(当然目前我也只是用来进行cpu性能分析):
  • 为什么内核消耗CPU高, 代码的位置在哪里?
  • 什么代码引起了CPU 2级cache未命中?
  • CPU是否消耗在内存I/O上?
  • 哪些代码分配内存,分配了多少?
  • 什么触发了TCP重传?
  • 某个内核函数是否正在被调用,调用频率多少?
  • 线程释放CPU的原因?
2. perf的event它可以利用CPU performance counters(性能计数器),tracepoints, kprobes和uprobes来进行应用程序的性能分析 。perf使用这些linux内核提供的tracing特性进行事件的采集和分析,perf使用的event主要有以下几种:
  • Hardware Events: CPU中的寄存器含有performance counters(性能计数器),用来统计 Hardware event,例如 cpu-cycles、instructions executed 、cache-misses、branch mispredicted等 。这些event构成了应用程序profiling的基础 。
  • Software Events: 基于内核计数器的低优先级events,例如, CPU migrations(处理器迁移次数), minor faults(soft page faults), major faults(hard page faults).
  • Tracepoints: 是散落在内核源代码中的一些 hook,用来调用probe函数,开启后,它们便可以在特定的代码被运行到时被触发,这一特性可以被各种 trace/debug 工具所使用 。Perf 就是该特性的用户之一 。假如您想知道在应用程序运行期间,内核内存管理模块的行为,便可以利用潜伏在 slab 分配器中的 tracepoint 。当内核运行到这些 tracepoint 时,便会通知 perf 。
  • Dynamic Tracing: probe函数(探针or探测函数),kprobe(kernel probe)内核态探针,用来创建和管理内核代码中的探测点 。Uprobes,user-probe,用户态探针,用来对用户态应用程序进行探测点的创建和管理,关于kprobe和uprobe可参考对应的内核文档
  • perf使用的event来源,如下图:来源:brendangregg

性能分析利器之perf浅析

文章插图
 
3. 安装两种安装方式
  • 通过包管理进行安装,perf工具在 linux-tools-common工具包里,通过包管理软件安装的时候还需要依赖linux-tools-kernelversion包
  • 源码编译:找到对应内核版本的源码包,在tools/perf目录下进行编译
4. 背景要想使用perf来分析应用程序,需要了解一些基础概念,例如符号表, frame pointer等信息
4.1 符号表
应用程序的符号表,用来将逻辑地址翻译成对应的函数和变量名,这样才能被程序员阅读和分析,没有符号表,profile的结果都是一些16进制的逻辑地址:
如下是perf report分析sshd进程的堆栈调用情况(来自brendangregg):
 
性能分析利器之perf浅析

文章插图
 
 
对于通过软件包安装的程序,通常都会有dubug package(-dbgsym)即带有符号表信息的程序,如果是源码安装的就需要编译时开启debug选项 。
通过使用openssh-server-dbgsym and libc6-dbgsym,sshd的perf report分析结果如下:
性能分析利器之perf浅析

文章插图
 
4.2 栈回溯(栈展开)
我们经常在编译的时候会开启frame pointers优化选项,即优化掉函数栈帧rbp,省略掉frame pointer是编译器一个很烂的优化,它会破坏debug, 更烂的是省略frame pointer一般是编译器默认的优化选项 。
没有frame pointer会使perf 无法获取完整的调用栈,如下示例:
性能分析利器之perf浅析

文章插图
 
例如上面代码正常不开启优化的编译,进行profile是可以看到call graph的,如下:
性能分析利器之perf浅析

文章插图
 
如果编译时开启-fomit-frame-pointer(这里因为测试代码简单,直接开优化的话就优化没了),就无法获取到call graph


推荐阅读