【perf】perf工具的使用生成火焰图
文章目录
- 1. What is perf?
- 2. perf使用
- 2.1 perf的子工具集
- 2.2 常用指令
- perf list
- 指令格式
- 参数
- perf中事件分类
- 使用示例
- perf stat
- 指令格式
- 参数
- perf top
- 指令格式
- 参数
- 交互式界面操作
- 使用示例
- perf record
- 指令格式
- 参数
- 使用示例
- perf report
- 指令格式
- 参数
- 交互式界面操作
- 使用示例
- perf diff
- 命令格式
- 参数
- 使用示例
- 输出字段说明
- perf script
- 指令格式
- 参数
- 使用示例
- 输出字段说明
- 3. 火焰图
- 3.1 火焰图生成原理
- 3.2 生成火焰图步骤
- 1. 安装依赖工具
- 2. 使用perf record记录性能数据
- 3. 导出数据为文本格式
- 4. 生成火焰图
- 参考内容
1. What is perf?
perf是Linux系统中的一个性能分析工具,它基于事件采样原理,以性能事件为基础,支持针对处理器相关性能指标与操作系统相关性能指标的性能剖析,常用于性能瓶颈的查找和热点代码的定位。
基本原理:对被检测对象进行采样,最简单的是根据tick中断进行采样,即在tick中断内触发采样点,在采样点中判断程序当时的上下文。
事件主要有以下三种:
- Hardware Event : 是由PMU硬件产生的事件,比如cache命中。当需要了解程序对硬件特性的使用情况时,需要对这些事件进行采样;
- Software Event : 是内核软件产生的事件,比如进程切换、tick数等;
- Tracepoint Event : 是内核中的静态tracepoint所触发的事件,这些tracepoint用于判断程序运行期间内核的行为细节,比如slab分配器的分配次数等。
P.S. CPU周期是默认的性能事件。
2. perf使用
2.1 perf的子工具集
1 annotate 解析perf record生成的perf.data文件,显示被注释的代码2 archive 根据数据文件记录的build-id,将所有被采样到的elf文件打包,利用此压缩包,可以在任何机器上分析数据文件中记录的采样数据3 bench perf中内置的benchmark,目前包含两套针对调度器和内存管理子系统的benchmark4 buildid-cache 管理perf的buildid缓存,每个elf文件都有一个独一无二的buildid,perf用buildid来关联性能数据与elf文件5 buildid-list 列出数据文件中记录的所有buildid6 diff 对比两个数据文件的差异,能够给出每个符号(即函数)在热点分析上的具体差异7 evlist 列出数据文件perf.data中所有性能事件8 inject 该工具读取perf record工具记录的事件流,并将其定向到标准输出,在被分析代码中的任何一点,都可以向事件流中注入其他事件9 kmem 针对内核内存(slab)子系统进行追踪测量的工具10 kvm 用来追踪测试运行在kvm虚拟机上的guest OS11 list 列出当前系统支持的所有性能事件,包括硬件性能事件、软件性能事件,以及检查点12 lock 分析内核中的锁信息,包括锁的竞争情况、等待延迟等13 mem 内存存取情况14 record 收集采样信息,并将其记录在数据文件中,随后可通过其他工具对数据文件进行分析15 report 读取perf record创建的数据文件,并给出热点分析结果16 sched 针对调度器子系统的分析工具17 script 执行perf或python编写的功能扩展脚本、生成脚本框架、读取数据文件中的数据信息等18 stat 执行某个命令,收集特定进程的性能概况,包括CPI、cache不命中率等19 test perf对当前软硬件平台进行健全性测试,可用此工具测试当前的软硬件平台是否能支持perf的所有功能20 timechart 针对测试期间系统行为进行可视化的工具21 top 类似linux中的top命令,对系统性能进行实时分析22 trace 关于syscall的工具23 probe 用于定义动态检查点
2.2 常用指令
perf list
指令格式
perf list [options] [event_category]
参数
--no-desc : 仅列出事件名称,不显示描述信息
--debug : 显示调试信息,如事件解析过程
--details : 显示事件的详细元数据(如PMU配置)
-j : json格式输出列表
-v : 显示冗余信息,如事件来源
perf中事件分类
- 硬件事件 Hardware Events:由cpu性能监控单元(PMU)直接提供的底层硬件事件
- cycles :cpu时钟周期数
- instructions :执行的指令数
- cache-misses:缓存失效次数
- branch-misses:分支预测失败次数
- 软件事件Software Events:由内核通过软件模拟的事件
- cpu-clock:cpu时钟时间
- task-clock:任务占用cpu时间
- context-switches:上下文切换次数
- page-faults:缺页异常次数
- 内核PMU事件 Kernel PMU Events:特定于内核性能监控单元的事件,通常和cpu微架构有关
- ref-cycles:不受频率调整影响的参考周期数(用于稳定性测试)
- stalled-cycles-frontend:前端流水线停滞周期数
- 跟踪点事件Tracepoint Events:静态内核跟踪点(static tracepoints),用于监控内核行为
- 格式为
tracepoint:<子系统>/<事件名>
,例如:- sched:sched_switch:进程切换事件
- block:block_rq_issue:块设备I/O请求事件
- sched:sched_switch:进程切换事件
- 格式为
- 动态探针事件 Dynamic Tracing:通过perf probe动态插入的探针事件
- 格式为
probe:<函数名>
或probe:<模块>:<函数名>
,例如:- probe:vfs_read:监控虚拟文件系统的vfs_read函数
- probe:libc:malloc:监控libc库的malloc函数
- 格式为
- 用户空间事件 User Events:用户程序通过pref_event_open接口注册的自定义事件(需代码集成)
- 其他事件
- Breakpoint Events:硬件断点事件,如内存访问断点
- Power Events:电源管理相关事件,如power、energy-cores
使用示例
perf list # 列出所有事件# 按类别过滤事件
perf list hw # 仅列出硬件事件
perf list sw # 仅列出软件的事件
perf list tracepoint # 仅列出跟踪点事件
perf list pmu # 列出pmu事件
perf list probe # 列出动态探针事件# 搜索特定事件
perf list 'sched:*' # 列出调度子系统所有跟踪点事件
perf list 'blokc:*' # 列出块设备相关事件
perf list 'mem:*' # 列出内存相关事件
perf list 'cache-misses' # 搜索包含'cache-misses'的事件
perf stat
指令格式
perf stat 可以查看程序的运行情况,执行该命令时收集性能统计信息.
命令结构:
perf stat [options] <command> # 监控指定指令的执行过程
perf stat [options] -p <pid> # 监控指定进程
perf stat [options] -a # 全局监控所有CPU
perf stat [options] -- <command> # 避免参数冲突时使用“--”分隔
参数
# ---------- 基础控制参数 ---------
-e <event> : 指定监控的事件,多个事件采用逗号分隔
-a : 监控所有CPU核心
-p <pid> : 监控指定进程的实时事件
-C <cpu-list> : 监控指定cpu,示例:-C 0,2 监控cpu0和2
-r <n> : 重复运行命令n次并计算平均值
-o <file> : 将结果保存到文件
--interval-print <ms> : 每隔ms毫秒就输出一次统计# ----------- 事件分组 -------------
-G <group> : 将事件分组统计。例如-G cache,统计所有缓存事件
--per-core : 按cpu核心分组显示结果
--per-socket : 按cpu插槽(物理cpu)分组显示结果# ---------- 输出控制 -------------
-d : 显示详细事件,包括L1/L2/L3缓存、TLB等
-B : 以更紧凑的格式输出(适合脚本解析)
--verbose : 显示调试信息,比如事件解析细节
--no-aggr : 不聚合所有cpu的统计,按核心单独显示
--pre <cmd> : 在监控前执行指定命令,如初始化环境
--post <cmd> : 在监控后执行执行命令,如清理环境# ---------- 高级统计 ----------------
--metric-only : 仅显示指标, 如IPC、缓存命中率等
--pre-thread : 按线程统计事件,需要指定-p <pid>
--scale : 自动缩放数值单位,K/M/G
--timeout <ms> : 监控超时时间,单位ms
关于事件定义:
# 事件语法
-e <event>[:modifiers] # 事件名 + 可选修饰符# 事件类型
硬件事件:cycles,cache-misses等
软件事件:cpu-clock,page-faults等
内核PMU事件:ref-cycles
自定义事件:perf list查看所有支持的事件# 修饰符
u : 仅监控用户空间事件
k : 仅监控内核空间事件
h : 仅监控Hypervisor事件
G : 全局事件(跨进程共享)
H : 主机端事件(虚拟化环境)# 示例:
perf stat -e cycles,instructions,cache-misses:u ./result.out # 监控用户空间的缓存失效
perf top
指令格式
perf top [options]
参数
# ------ 基础控制参数 -------
-e <event> # 指定监控的事件,默认为cycles
-p <pid> # 监控指定进程
-C <cpu-list> # 监控指定cpu
-K # 隐藏内核空间符号(仅显示用户空间函数)
-U # 隐藏用户空间符合,仅显示内核空间函数
--no-children # 不显示子函数调用占比
--call-graph <type> # 设置调用图类型(fp:帧指针;dwarf:调试信息;lbr:硬件记录)
-F <频率> # 设置采样频率;例如 -F 100表示每秒采样100次
-g # 记录调用链(生成火焰图时常用)# -------- 输出控制 -----------
-d <s> # 界面刷新间隔,默认2s
-n # 显示样本数量,不是百分比
--stdio # 非交互模式,直接输出到终端
--sort <字段> # 按照字段排序,例如symbol、overhead
--fields <字段> # 自定义显示字段,例如symbol、overhead
--percent-limit <数值> # 仅显示占比超过指定百分比的事件,例如 --percent-limit 0.5# -------- 高级分析 -----------
--branch-history # 显示历史分支(需要CPU支持LBR)
--demangle-kernel # 解析内核符号名称,显示可读函数名
--objdump <path> # 指定反汇编工具路径(用于汇编代码分析)
交互式界面操作
在perf top的实时界面中,支持以下快捷键:
h : 显示帮助菜单
q : 退出
Enter : 选中符号,查看其调用链详情
E : 展开所有调用链
C : 折叠所有调用链
+/- : 调整符号显示的百分比阈值
k : 显示内核符号
u : 显示用户空间符号
z : 高亮当前选中的符号
使用示例
perf top -p <pid> # 按照pid监控指定进程的热点函数
perf top -e cache-missed # 实时显示缓存失效最多的函数
perf top -g --call-graph dwarf # 记录调用链,生成火焰图时使用# 生成火焰图
perf top
回显字段含义说明:
overhead : 事件占比(百分比)
Shared Object : 所属模块,如[kernel],[libc.so.6]
Symbol : 函数或符号名称
Dso : 动态共享对象(模块或程序名)
![[Pasted image 20250420191525.png]]
perf record
指令格式
perf record [options] <command> # 记录命令执行期间的性能数据
perf record [options] -p <pid> # 记录指定进程的性能数据
perf record [options] -a # 全局记录所有cpu的性能数据
参数
# --------- 基础控制参数 ------------
-e <event> # 指定监控的事件
-F <频率> # 设置采样频率
-g # 记录调用链,生成火焰图必备
-p <pid> # 监控指定进程
-a # 全局监控所有cpu
-C <cpu-list> # 监控指定cpu
-o <file> # 输出文件名,默认perf.data
--call-graph <type> # 调用链记录方式:fp/dwarf/lbr# --------- 事件与过滤 -------------
-c <次数> # 每发生n次事件采样一次。替代-F,比如-c 100
--filter <filter> # 事件过滤器,如监控特定地址范围
-b # 启用分支栈采样(需cpu支持)# ----------- 输出与调试 -------------
-v # 显示详细信息
-s # 按线程单独记录样本
-k <时钟> # 指定时钟源,如mono/monotonic_raw
--timestamp # 记录时间戳
--switch-events # 记录上下文切换事件# ----------- 其他 ----------
--pid-map <file> # 指定pid映射文件(容器环境)
--namespaces # 记录命名空间信息
--aux # 启用aux区域跟踪(用于Intel PT)
--tail-synthesize # 在记录结束时合成事件
使用示例
perf record -F 100 ./my_proj # 记录命令my_proj的cycles事件,采样频率为100
perf record -g --call-graph dwarf ./my_proj # 记录调用链,使用dwarf调试信息
perf record -e cache-misses -p 311 # 监控pid为311的进程,采样缓存失效事件
perf record -e instrutions -a # 全局监控所有cpu的指令数事件
perf record -o mydata.data ./my_proj # 将记录保存到mydata.data文件中
perf report
指令格式
perf report [options] # 分析perf.data(默认文件名)
perf report -i <file> # 分析指定文件
参数
# ----------- 输入控制参数 --------------
-i <file> # 指定输入文件,默认是perf.data
--force # 强制读取文件,忽略版本不兼容警告
--kallsyms <path> # 指定内核符号表路径,默认为/proc/kallsyms
--vmlinux <path> # 指定内核调试符号文件,解析内核符号# ------- 输出控制参数 -------------
--stdio # 命令行模式输出(非交互式)
--tui # 启用交互式文本界面(默认)
--gtk # 使用GTK图形界面(需要编译支持)
--header # 显示文件头信息(事件、命令行等)
--sort <字段> # 按字段排序(如pid,comm,dso等)
--fields <字段> # 自定义显示字段(如overhead,symbol)
--percent-limit <数值> # 仅显示占比超过指定百分比的事件# ------=----- 分析模式 ----------------
-g <type> # 生成调用链(graph、callee或none)
--branch-history # 显示分支历史(需记录分支数据)
--objdump <path> # 指定反汇编工具路径(查看汇编代码)
--demangle # 解析C++符号名称
--source # 显示源码与汇编代码(需调试信息)# ------------- 过滤与统计 ----------
-C <cpu> # 仅显示指定cpu的样本
-p <pid> # 仅显示指定进程的样本
-s <字段> # 按字段聚合统计(如symbol或dso)
--filter <规则> # 过滤样本(比如comm="my_program")
交互式界面操作
perf report 的 TUI界面中,支持以下快捷键:
Enter : 展开选中符号的调用链
ESC : 返回上一级调用链
h : 显示帮助菜单
q : 退出
E : 展开所有调用链
C : 折叠所有调用链
+/- : 调整显示的百分比阈值
a : 显示注解(注释热点代码)
d : 过滤当前符号
t : 切换显示模式(百分比/样本数)
/ : 搜索符号或模块名
使用示例
perf report # 默认分析perf.data
perf report --stdio # 非交互式输出(适合脚本处理)
perf report -C 0,1 # 仅显示cpu 0和1的样本
perf report --sort symbol # 按符号名聚合统计
perf report -g graph # 显示函数调用链
perf report --source # 显示源码与汇编代码(需编译时保留调试信息)
perf diff
perf diff用于比较两个或多个perf.data文件的性能分析结果,帮助开发者快速识别优化前后的性能差异。
核心功能:
- 对比性能数据:比较不同运行场景下的事件统计,如cpu周期、缓存命中率等
- 识别热点变化:找出函数或代码路径的性能改进或退化
- 多文件支持:支持同时对比多个数据文件(如基线版本和优化版本)
使用步骤:
- 生成基准数据
perf record -o perf.data.base -- ./my_program_base # 生成基准数据perf.data.base
- 生成对比数据
perf record -o perf.data.optimized -- ./my_program_optimized # 生成优化后的数据perf.data.optimized
- 执行对比
perf diff perf.data.base perf.data.optimized
命令格式
perf diff [options] <file1> <file2> ... # 对比多个文件
perf diff [options] # 对比当前目录的perf.data文件
参数
-b 或 --baseline <file> # 指定基准文件,默认第一个文件为基准
-c 或 --compute <方式> # 差异计算方式:delta/ratio/wdiff,默认为delta
-q 或 --quiet # 仅显示显著差异,隐藏无变化的条目
-m 或 --modules # 按模块(动态库/内核模块)聚合差异
-s 或 --sort <字段> # 按字段排序,如delta/ratio/overhead
--percent-limit <数值> # 仅显示差异超过指定百分比的事件
-C 或 --cpu <cpu> # 仅对比指定cpu的样本
-p 或 --pid <pid> # 仅对比指定进程的样本
使用示例
perf diff -b perf.data.base perf.data.optimized # 指定基准文件
perf diff -s delta perf.data.base perf.data.optimized # 按差异百分比排序
perf diff --percent-limit 5.0 # 仅显示差异超过5%的条目
perf diff perf.data.v1 perf.data.v2 perf.data.v3 # 对比多组数据
输出字段说明
Overhead : 差异的百分比,正值为性能退化,负值为优化
Baseline : 基准文件的样本数或事件计数
Comparison : 对比文件的样本数或事件计数
Delta : 绝对值差异(对比文件 - 基准文件)
Symbol : 函数或符号名称
perf script
perf script的核心功能:
- 数据导出:将perf.data中的性能数据(如采样事件、调用链、时间戳等)转换为可读文本;
- 灵活过滤:按进程、CPU、时间范围等条件筛选数据;
- 自定义输出:指定输出的字段格式(如csv、json),方便后续处理
- 脚本扩展:结合perl或python脚本实现自动化分析
指令格式
perf script [options] # 默认读取perf.data
perf script -i <file> # 指定输入文件
参数
-i <file> # 指定输入文件
-F <字段> # 自定义输出字段(如time、event等)
-S <脚本> # 使用perl或python脚本解析数据
-f <格式> # 指定输出格式
--ns # 显示纳秒级时间戳
-C <cpu> # 仅显示指定cpu的样本
-p <pid> # 仅显示指定进程的样本
--time <start, end> # 按时间范围过滤样本(单位为秒)
-k <vmlinux> # 指定内核符号文件
-g # 显示调用链
--demangle # 解析C++符号名
--header # 显示文件头信息(事件类型、命令行等)
使用示例
perf script > output.txt # 导出所有数据为文本
perf script flamegraph.pl > flame.svg # 生成火焰图数据
perf script -g # 显示每个样本的完整调用链
输出字段说明
COMM : 进程名
PID : 进程id
TID : 线程id
TIME : 时间戳s
EVENT : 事件类型,如cycles
IP : 指令指针地址
SYM : 符号(函数名)
DSO : 动态共享对象(模块或程序名)
3. 火焰图
火焰图是一种用户可视化程序性能分析数据的工具。它的核心原理是通过采样捕获程序运行时的函数调用栈,并将这些调用栈按层级聚合,最终以直观的图形展示cpu时间的分布。
3.1 火焰图生成原理
- 采样
- perf以固定频率中断程序运行,记录当前的函数调用栈;
- 每个样本包含从底层函数到当前执行点(如某个具体函数)的完整调用链
- 聚合与折叠
- 将大量样本按调用栈的层级结构合并统计,相同的调用路径会合并为一个条目;
- e.g. 函数A调用函数B,函数B调用函数C,则这个三个函数的调用链会被合并统计
- 可视化
- 将聚合后的数据转换为svg图像,每个矩形代表一个函数:
- 宽度:表示该函数在采样中的出现频率,即cpu时间占比;
- 层级:火焰图的层级结构
- 将聚合后的数据转换为svg图像,每个矩形代表一个函数:
3.2 生成火焰图步骤
1. 安装依赖工具
克隆FlameGraph工具库:
git clone https://github.com/brendangregg/FlameGraph.git
2. 使用perf record记录性能数据
注意要加-g参数:
perf record -F 99 -g -- <command> #
# 示例
perf record -F 99 -a -g -- sleep 30 # 监控所有cpu的cycles事件30s
3. 导出数据为文本格式
将perf.data转换为可处理的文本;
perf script > output.perf
4. 生成火焰图
使用flamegraph工具链处理数据:
# 折叠调用栈(统计相同路径)
stackcollapse-perf.pl < output.perf > output.folded
# 生成svg火焰图
flamegraph.pl output.folded > flamegraph.svg# 命令简化,一步完成
perf script | stackcollapse-perf.pl | flamegraph.pl > flamegraph.svg
参考内容
- Linux 性能分析工具perf使用 - -零 - 博客园
- 从小白到精通:揭秘perf工具的全部功能与操作技巧-CSDN博客