perf+火焰图使用
使用
# 安装perf
yum install perf -y
# 下载绘图工具
git clone https://github.com/brendangregg/FlameGraph.git
# 采集数据(perf record表示记录,-F99表示每秒99次,-p3887是进程号,即对哪个进程进行分析,-g表示记录调用栈,sleep 30则是持续30秒)
perf record -F99 -p3887 -g -- sleep 30
# 生成火焰图
perf script -i perf.data &> perf.unfold
./FlameGraph/stackcollapse-perf.pl perf.unfold &> perf.folded
./FlameGraph/flamegraph.pl perf.folded > perf.svg
火焰图的含义
- 火焰图是基于 stack 信息生成的 SVG 图片, 用来展示 CPU 的调用栈。 y 轴表示调用栈, 每一层都是一个函数.
- 调用栈越深, 火焰就越高, 顶部就是正在执行的函数, 下方都是它的父函数. x 轴表示抽样数, 如果一个函数在 x 轴占据的宽度越宽,
- 就表示它被抽到的次数多, 即执行的时间长. 注意, x 轴不代表时间, 而是所有的调用栈合并后, 按字母顺序排列的.
- 火焰图就是看顶层的哪个函数占据的宽度最大. 只要有 “平顶”(plateaus), 就表示该函数可能存在性能问题。 颜色没有特殊含义,
- 因为火焰图表示的是 CPU 的繁忙程度, 所以一般选择暖色调.
火焰图类型
常见的火焰图类型有 On-CPU,Off-CPU,还有 Memory,Hot/Cold,Differential 等等。它们有各自适合处理的场景。
火焰图类型 | 横轴含义 | 纵轴含义 | 解决问题 | 采样方式 |
---|---|---|---|---|
on-cpu火焰图 | cpu占用时间 | 调用栈 | 找出cpu占用搞的问题函数;分析代码热路径 | 固定频率采样cpu调用栈 |
off-cpu火焰图 | 阻塞时间 | 调用栈 | i/o、网络等阻塞场景导致的性能下降;锁竞争、死锁导致的性能下降问题 | 固定频率采样阻塞事件调用栈 |
内存火焰图 | 内存申请/释放函数调用次数 | 调用栈 | 内存泄漏问题;内存占用高的对象/申请内存多的函数;虚拟内存或物理内存泄漏问题 | 有四种方式:跟踪malloc/free;跟踪brk;跟踪mmap;跟踪页错误 |
Hot/Cold火焰图 | on-cpu和off-cpu综合展示 | 调用栈 | 需要结合cpu占用以及阻塞分析的场景;off-cpu火焰图无法直观判断的场景 | on-cpu火焰图和off-cpu火焰图结合 |
On-CPU
如果是 CPU 则使用 On-CPU 火焰图
# 使用perf采集(perf record表示记录,-F99表示每秒99次,-p3887是进程号,即对哪个进程进行分析,-g表示记录调用栈,sleep 30则是持续30秒)
perf record -F 99 -p 34631 -g -- sleep 120
# 生成火焰图
perf script | ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl > zeromq-req-rep.svg
Off-CPU
如果是 IO 或锁则使用 Off-CPU 火焰图.
# 使能sched_schedstats统计(root)
echo 1 > /proc/sys/kernel/sched_schedstats
# 使用perf采集
perf record -e sched:sched_stat_sleep -e sched:sched_switch -e sched:sched_process_exit -p 43777 -g -o perf.data.raw sleep 10
perf inject -v -s -i perf.data.raw -o perf.data
# 通过perf分别记录sched:sched_stat_sleep、sched:sched_switch、sched:sched_process_exit三种事件,这三种事件分别表示:进程主动放弃 CPU 而进入睡眠的等待事件、进程由于I/O和锁等待等原因被调度器切换而进入睡眠的等待事件、进程的退出事件。
# 生成火焰图
perf script -F comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace | awk '
NF > 4 { exec = $1; period_ms = int($5 / 1000000) }
NF > 1 && NF <= 4 && period_ms > 0 { print $2 }
NF < 2 && period_ms > 0 { printf "%s\n%d\n\n", exec, period_ms }' | \
./FlameGraph/stackcollapse.pl | \
./FlameGraph/flamegraph.pl --countname=ms --title="Off-CPU Time Flame Graph" --colors=io > offcpu.svg