火焰图是对层次数据的可视化。 我们通常可以将性能分析工具采集到的调用栈信息以火焰图的方式进行可视化。 从而直观且准确地观察到频繁调用的代码路径。

perf

perf 是 Linux 系统上的性能分析工具。 perf 可以周期性地产生中断,在中断处理中获取并记录当前调用栈信息。

安装 perf

dnf install perf

perf --version

BCC

BCC(BPF Compiler Collection)是用于创建内存跟踪与操作程序的工具包,依赖 eBPF。 我们这里只需要使用它提供的 offcputime 工具,用于采集 off-CPU 的时间与堆栈信息。

dnf install bcc

/usr/share/bcc/tools/offcputime --help

如果执行报错说找不到内核头文件,就需要安装正确版本的 kernel-devel 依赖包:

dnf install kernel-devel-"$(uname -r)"

FlameGraph 工具

FlameGraph 以 perf 采集到的调用栈数据为输入,生成火焰图。

不需要安装,直接 clone 即可:

git clone https://github.com/brendangregg/FlameGraph.git

CPU 火焰图

https://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html

CPU 火焰图用于分析 CPU 繁忙的原因,通过调用栈分析找到热点代码路径。 一般是以固定频率对运行中的程序状态进行采样,将采集到的数据转化为火焰图。 通常的采样分析可以创建定时中断,每次中断时采集当前的 PC 寄存器、函数地址、调用栈等信息。 注意一下,CPU 火焰图是用于 on-CPU 分析的,分析的范围是程序花费的 CPU 时间,不涉及 I/O、锁、换页等阻塞时间。

首先我们把工作路径切到 clone 下来的 FlameGraph 里面。

cd FlameGraph

然后可通过 perf record 命令采集调用栈数据,下面提供的命令会将采集结果输出到 perf.data 中:

perf record -F <frequency> -a -g -p <pid> -- <cmd>
perf record -F 99 -a -g -p "$(pgrep -x mysqld -u <username>)" -- mysql -e "select * from <some-table>"
perf record -F 99 -a -g -p "$(pgrep -x mysqld -u <username>)" -- sleep 30"

最后通过 FlameGraph 工具生成火焰图。 示例中输出的文件名是 mysqld-on-cpu.svg。 这个 .svg 文件可直接用浏览器打开。

perf script | ./stackcollapse-perf.pl > out.perf-folded
cat out.perf-folded | ./flamegraph.pl > mysqld-on-cpu.svg

Off-CPU 火焰图

https://www.brendangregg.com/offcpuanalysis.html

Off-CPU 分析是指通过通过 off-CPU 的时间与调用栈信息确定线程阻塞的原因,它的分析范围是程序花费在等待 I/O、锁、换页等阻塞的时间。

线程离开 CPU 的原因很多,除了主动等待 I/O 与锁之外,还有一些与线程本身无关的原因,比如中断处理,在 CPU 资源紧张情况下的上下文切换等。

首先工作路径仍然是 FlameGraph 的项目目录:

cd FlameGraph

然后通过 offcputime 命令测量阻塞时间与调用栈信息:

/usr/share/bcc/tools/offcputime -df -p `pgrep -x mysqld -u <username>` 30 > out.stacks

最后使用 FlameGraph 工具生成冷火焰图:

./flamegraph.pl --color=io --title="Off-CPU Time Flame Graph" --countname=us < out.stacks > mysqld-off-cpu.svg