使用perf可以抓取指定执行情况的数据,然后基于抓取的数据可以制作火焰图,这样就能够很容易地进行分析了。
当然一些应用程序也提供了一些手段来生成火焰图,这里使用perf则是在系统层面而非应用层面来查询更加底层的一些异常情况。
# perf record -C 32 -g -- sleep 10抓取CPU32上的执行指定,-g记录调用关系,sleep 10表示抓取10s。执行结束之后就会将数据写入到一个名为perf.data的文件当中。通过这个命令就可以在cpu usage上升的节点上捕捉到引起使用率上升的函数。
perf的工作机制
perf的工作是基于event的。执行perf list就可以看到大量的event以及其类型。
常用的有三类:
- hardware event:处理器相关的event
- software event:内存代码中定义的event,比如进程上下文切换event,缺页中断event
- tracepoints event:这个的数量是非常多的,实现方式和software event类似,内核当中的很多函数都注册了event。已经是linux内核tracing的标准接口了,很多工具例如ftrace、ebpf都会用到。
perf使用event有两种方式:计数与采样。
计数
使用perf stat就是对event进行计数。
# perf stat -e page-faults -- sleep 1使用-e指定event,并指定查询的时间段。
采样
文章最开始的示例就是采样,即perf record命令。
使用-e参数可以指定采样的event,不指定的话默认就是Hardware event cycles。
默认采集所有的event的话,数据量是相当庞大的,因此采样可以按照次数和频率来减少采集的event的数量。
-c count:每发生count次就记录一次-F freq:每秒采集freq次
容器使用perf注意事项
由于容器是共享宿主机的内核的,而perf版本和内核是一致的,因此容器如果要使用perf工具的话,最好是从宿主机对应内核版本的perf编译而来。
Perf 通过系统调用 perf_event_open() 来完成对 perf event 的计数或者采样。不过 Docker 使用 seccomp(seccomp 是一种技术,它通过控制系统调用的方式来保障 Linux 安全)会默认禁止 perf_event_open()。因此启动容器的时候需要允许这个系统调用在容器中使用,参数是”—security-opt seccomp=unconfined”
需要允许容器在没有 SYS_ADMIN 这个 capability的情况下,也可以让 perf 访问这些 event。那么现在我们需要做的就是,在宿主机上设置出 echo -1 > /proc/sys/kernel/perf_event_paranoid,这样普通的容器里也能执行 perf 了。
perf的常用使用方式,在采样的时候,加上-g带上函数调用关系,多核的机器加上-a抓取所有cpu。然后抓取的结果会保存在perf.data文件当中,使用perf script将perf.data文件转为分析脚本,然后用FlameGraph读取这个脚本,生成火焰图。
# perf record -a -g -- sleep 60
# perf script > out.perf
# git clone --depth 1 https://github.com/brendangregg/FlameGraph.git
# FlameGraph/stackcollapse-perf.pl out.perf > out.folded
# FlameGraph/flamegraph.pl out.folded > out.sv