Linux性能分析工具 - perf 和火焰图

说明

  • perf(Performance Event)是Linux 2.6.31版本后,内核自带的强力性能分析工具。
  • 火焰图是一种图表,将perf抓取的数据生成火焰图,可以使数据更直观,方便分析。

和其它工具比较

  • Linux C/C++平台性能分析工具有很多,例如:gperftools(Google开发的profile工具)等,相比其它工具,perf有以下优点:
  1. 更贴近底层(内核和硬件),抓取到的信息更详细,可以抓取到系统层级甚至硬件层级数据,Linux原生工具(内核自带),与内核配和工作更紧密,可以利用硬件设备PMU获取一些硬件事件。
  2. 功能更强大,即可分析应用层,也可分析内核。

工作原理

  • 性能分析原理:perf对运行中的进程按一定频率进行中断采样,获取当前执行的函数名及调用栈,如果大部分的采样点都落在同一个函数上,则表明该函数执行的时间较长或该函数被频繁调用,可能存在性能问题。
  • 数据来源:使用现代处理器中的特殊硬件PMU(Performance Monitor Unit,性能监视单元)获取硬件事件和内核计数器以及tracepoint统计软件性能数据。
  1. tracepoints
  • tracepoints是散落在内核源码中的一些hook,它们可以在特定的代码被执行到时触发,这一特定可以被各种trace/debug工具所使用。

嵌入式移植

内核配置

  • 需要在内核dts中配置pmu硬件,不然采样不到数据。
* 一款risc_v C906B平台上的配置
pmu:pmu{
	interrupt-parent = <&cpu0_intc>;
	interrupts = <17>;
	compatible = "thead,c900_pmu";
};
  • 内核配置
CONFIG_PERF_EVENTS=y     //perf事件
CONFIG_HW_PERF_EVENTS=y  //perf 硬件事件
CONFIG_KALLSYMS=y        //内核符号表信息,数据包含函数名信息

编译

  • 工具源码在内核源码根目录下的:tools/perf/
  • 一款risc_v C906平台上编译命令:
make CROSS_COMPILE=riscv64-unknown-linux-gnu- ARCH=rv64imafdcvxthead LDFLAGS="-static"
  • perf编译时会自动检测一些系统特性(第三方库和系统功能)来关闭和打开一些功能以生成可正确运行的程序,如下表:(OFF表示不支持,on表示支持)
Auto-detecting system features:
...                         dwarf: [ OFF ]
...            dwarf_getlocations: [ OFF ]
...                         glibc: [ on  ]
...                          gtk2: [ OFF ]
...                      libaudit: [ OFF ]
...                        libbfd: [ OFF ]
...                        libelf: [ OFF ]
...                       libnuma: [ OFF ]
...        numa_num_possible_cpus: [ OFF ]
...                       libperl: [ OFF ]
...                     libpython: [ OFF ]
...                      libslang: [ OFF ]
...                     libcrypto: [ OFF ]
...                     libunwind: [ OFF ]
...            libdw-dwarf-unwind: [ OFF ]
...                          zlib: [ OFF ]
...                          lzma: [ OFF ]
...                     get_cpuid: [ OFF ]
...                           bpf: [ on  ]

应用层符号表支持

  • 分析应用层app,想要打印出具体的函数名而不是函数地址,需要perf支持识别进程符号表信息,该功能依赖elfutil开源库,elfutil依赖zlib开源库。
  • 注意:要获得进程函数名信息,应用层app需要带符号表信息
  1. zlib/elfutil 移植
  • zlib库比较简单没有其它依赖,编译也几乎不会遇到问题;elfutil依赖zlib开源库,移植时可能会遇到较多问题,具体问题和处理可在网上找到,找不到的见招拆招。
  1. 更新系统特性
  • 移植好zlib/elfutil开源库后,重新编译perf,有时perf自动检测到的系统特性表(如上)依然没有变化,需要手动更新下,如下:
cd tools/build/feature # cd到内核 tools/build/feature目录

# 仿照以下命令编译生成 test-dwarf.bin,test-libelf.bin,test-zlib.bin
make CFLAGS="-Wbad-function-cast -Wdeclaration-after-statement -Wformat-security -Wformat-y2k -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wno-system-headers -Wold-style-definition -Wpacked -Wredundant-decls -Wshadow -Wstrict-aliasing=3 -Wstrict-prototypes -Wswitch-default -Wswitch-enum -Wundef -Wwrite-strings -Wformat -DHAVE_PERF_REGS_SUPPORT -O6 -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 -I/opt/libelf/include -L/opt/libelf/lib -ldw -lelf" LDFLAGS="-Wl,-z,noexecstack " CROSS_COMPILE=aarch64-linux- test-dwarf.bin
# 编译失败会生成 test-dwarf.make.output,查看可以判断失败原因
  • 再重新编译perf 即可识别到。
  • 引用

perf 使用

  • perf支持很多功能,例如
perf top

分析应用层app

  1. perf需要先对目标进程进行采样:
./perf record -F 1000 -p [进程pid] -g
* -F指定采样的频率为1000Hz,即一秒钟采样1000次
* -p指定要采样的进程ID
* -g表示记录调用栈信息
  • perf会将采集到的性能数据写入当前目录下的perf.data文件中。
  1. 查看/分析采样数据
./perf report -n
  • 上述命令会读取perf.data并统计每个调用栈的百分比,且按照从高到低的顺序排列, 但是可读性不是很好, 因此需要借助火焰图生成工具。

火焰图

  • 火焰图(Flame Graph)由系统性能大牛Brendan Gregg提出的动态追踪技术而发扬光大,用于将性能分析工具生成的数据可视化处理。
  1. 工具下载
wget https://github.com/brendangregg/FlameGraph/archive/master.zip
unzip master.zip
  • 工具都是一些脚本,不需要编译。
  1. 对采样数据文件进行解析以生成堆栈信息
./perf script > cpu.unfold
* 在perf.data 目录下执行
  1. 对perf.unfold进行符号折叠
./stackcollapse-perf.pl cpu.unfold > cpu.folded
  1. 生成SVG格式的火焰图
./flamegraph.pl cpu.folded > cpu.svg

火焰图说明

Linux性能分析工具 - perf 和火焰图_第1张图片

  • 纵轴表示调用栈,每一层都是一个函数,也是其上一层的父函数,最顶部就是采样时正在执行的函数,调用栈越深,火焰就越高。
  • 横轴表示抽样数,并不是表示执行时间。若一个函数的宽度越宽,则表示它被抽到的次数越多,所有调用栈会在汇总后,按字母序列排列在横轴上。

你可能感兴趣的:(#,Linux,内核知识,linux,性能分析)