Linux性能分析工具 - perf 和火焰图
linux 性能分析工具 perf 和火焰图
·
说明
- perf(Performance Event)是Linux 2.6.31版本后,内核自带的强力性能分析工具。
- 火焰图是一种图表,将perf抓取的数据生成火焰图,可以使数据更直观,方便分析。
和其它工具比较
- Linux C/C++平台性能分析工具有很多,例如:gperftools(Google开发的profile工具)等,相比其它工具,perf有以下优点:
- 更贴近底层(内核和硬件),抓取到的信息更详细,可以抓取到系统层级甚至硬件层级数据,Linux原生工具(内核自带),与内核配和工作更紧密,可以利用硬件设备PMU获取一些硬件事件。
- 功能更强大,即可分析应用层,也可分析内核。
工作原理
- 性能分析原理:perf对运行中的进程按一定频率进行中断采样,获取当前执行的函数名及调用栈,如果大部分的采样点都落在同一个函数上,则表明该函数执行的时间较长或该函数被频繁调用,可能存在性能问题。
- 数据来源:使用现代处理器中的特殊硬件PMU(Performance Monitor Unit,性能监视单元)获取硬件事件和内核计数器以及tracepoint统计软件性能数据。
- 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需要带符号表信息。
- zlib/elfutil 移植
- zlib库比较简单没有其它依赖,编译也几乎不会遇到问题;elfutil依赖zlib开源库,移植时可能会遇到较多问题,具体问题和处理可在网上找到,找不到的见招拆招。
- 更新系统特性
- 移植好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
- perf需要先对目标进程进行采样:
./perf record -F 1000 -p [进程pid] -g
* -F指定采样的频率为1000Hz,即一秒钟采样1000次
* -p指定要采样的进程ID
* -g表示记录调用栈信息
- perf会将采集到的性能数据写入当前目录下的perf.data文件中。
- 查看/分析采样数据
./perf report -n
- 上述命令会读取perf.data并统计每个调用栈的百分比,且按照从高到低的顺序排列, 但是可读性不是很好, 因此需要借助火焰图生成工具。
火焰图
- 火焰图(Flame Graph)由系统性能大牛Brendan Gregg提出的动态追踪技术而发扬光大,用于将性能分析工具生成的数据可视化处理。
- 工具下载
wget https://github.com/brendangregg/FlameGraph/archive/master.zip
unzip master.zip
- 工具都是一些脚本,不需要编译。
- 对采样数据文件进行解析以生成函数调用栈信息
./perf script > cpu.unfold
* 在perf.data 目录下执行
- 对perf.unfold进行符号折叠
./stackcollapse-perf.pl cpu.unfold > cpu.folded
- 生成SVG格式的火焰图
./flamegraph.pl cpu.folded > cpu.svg
火焰图说明
- 纵轴表示调用栈,每一层都是一个函数,也是其上一层的父函数,最顶部就是采样时正在执行的函数,调用栈越深,火焰就越高。
- 横轴表示抽样数,并不是表示执行时间。若一个函数的宽度越宽,则表示它被抽到的次数越多,所有调用栈会在汇总后,按字母序列排列在横轴上。
更多推荐
已为社区贡献1条内容
所有评论(0)