Perf 工具深度解析
Perf(Performance Counters for Linux)是 Linux 系统的性能分析工具,基于内核的 perf_event
子系统,通过硬件性能计数器(PMC)、软件事件和跟踪点(tracepoints)实现全方位性能监控。
一、工作原理与实现机制
1. 核心组件
组件 | 作用 |
---|---|
硬件性能计数器 | 利用 CPU 的 PMU(Performance Monitoring Unit)统计指令周期、缓存命中/失效等事件。 |
软件事件 | 内核插桩统计上下文切换、缺页异常等软件行为(如 context-switches )。 |
跟踪点 | 静态内核探针(如 sched:sched_switch ),记录特定代码路径的执行信息。 |
kprobes/uprobes | 动态内核/用户空间探针,支持自定义函数级跟踪。 |
2. 数据采集流程
+----------------+ +-------------------+ +-----------------+
| 配置事件 | ----> | perf_event_open() | ----> | 内核事件子系统 |
| (cycles, cache | | (系统调用) | | (PMU/软件计数器) |
| misses, etc.) | +-------------------+ +-----------------+
+----------------+ |v
+------------------+ mmap() +--------------+
| 用户空间工具 | <------------- | 环形缓冲区 |
| (perf record/stat)| | (存储样本) |
+------------------+ +--------------+
3. 关键机制
- 环形缓冲区:采样数据通过无锁环形缓冲(避免系统调用开销)传递到用户空间。
- 采样模式:
- 计数模式:累计事件发生次数(
perf stat
)。 - 中断采样:事件达到阈值时触发中断,记录指令指针/IP(
perf record
)。
- 计数模式:累计事件发生次数(
- 符号解析:通过
/proc/kallsyms
或 ELF 文件将地址映射为函数名。
二、命令大全与使用示例
1. 常用命令总结
命令 | 功能 | 常用选项 |
---|---|---|
perf stat | 统计事件发生的绝对次数 | -e (指定事件), -p (PID), -a (全局) |
perf record | 采样并保存数据到 perf.data | -g (调用栈), -F (采样频率), -o (输出文件) |
perf report | 解析 perf.data 生成报告 | --stdio (文本报告), -n (显示样本数) |
perf top | 实时显示热点函数 | -e (事件), -K (隐藏内核符号) |
perf list | 列出支持的事件 | --details (显示事件详情) |
perf script | 导出采样数据为脚本格式 | -i (输入文件), -F (自定义字段) |
perf trace | 类似 strace ,跟踪系统调用 | -p (PID), -e (过滤系统调用) |
perf annotate | 汇编代码级注解 | --stdio (文本模式), -s (符号) |
2. 详细示例
Perf 典型使用场景及命令详解
2.1 CPU 性能分析
场景 | 命令示例 | 说明 |
---|---|---|
CPU 热点函数分析 | perf top -e cycles -p <PID> | 实时查看进程的热点函数 |
调用链分析 | perf record -F 99 -g -p <PID> -o perf.data; perf report --stdio | 记录调用栈并生成文本报告 |
多核负载均衡分析 | perf stat -e sched:sched_migrate_task -a sleep 10 | 监控任务在 CPU 核间的迁移情况 |
IPC 指标分析 | perf stat -e cycles,instructions -p <PID> -- sleep 5 | 计算指令/周期比 (IPC = instructions/cycles) |
示例:CPU 瓶颈诊断
# 1. 查找 CPU 占用最高的进程
perf top# 2. 对高负载进程 (PID 1234) 进行采样
perf record -F 997 -g -p 1234 -o cpu_hotspot.data -- sleep 30# 3. 生成带调用栈的报告
perf report -i cpu_hotspot.data --stdio --no-children
输出片段:
# Overhead Command Shared Object Symbol
# ........ ....... ................ ................................
#62.15% nginx nginx [.] ngx_http_process_request|---ngx_http_process_request| |--45.32%-- ngx_http_core_content_phase| ngx_http_proxy_handler| || |--38.71%-- ngx_http_upstream_connect| | __connect
2.2 内存子系统分析
场景 | 命令示例 | 说明 |
---|---|---|
缓存命中率分析 | perf stat -e cache-references,cache-misses <command> | 统计 L1/L2/L3 缓存效率 |
内存带宽分析 | perf stat -e uncore_imc_0/cas_count_read/,uncore_imc_0/cas_count_write/ | 监控 DDR 内存读写带宽 (需 Intel PMU) |
缺页异常分析 | perf stat -e page-faults,minor-faults,major-faults -p <PID> | 区分次/主缺页异常 |
示例:内存敏感型应用优化
# 1. 检测缓存效率
perf stat -e \L1-dcache-load-misses,LLC-load-misses,dTLB-load-misses \./memory_intensive_app# 2. 输出结果35,421,632 L1-dcache-load-misses # 12.45% of all L1-dcache hits 8,765,432 LLC-load-misses # 3.21% of all LL-cache hits1,234,567 dTLB-load-misses # 0.45% of all dTLB cache hits
2.3 I/O 性能分析
场景 | 命令示例 | 说明 |
---|---|---|
块设备 I/O 延迟 | perf record -e block:block_rq_issue,block:block_rq_complete -a | 跟踪块设备请求生命周期 |
文件系统操作跟踪 | perf record -e ext4:*,xfs:* -a | 捕获特定文件系统事件 |
系统调用分析 | perf trace -e 'read,write,openat' -p <PID> | 监控文件相关系统调用 |
示例:磁盘 I/O 瓶颈诊断
# 1. 跟踪块设备事件
perf record -e block:block_rq_issue -e block:block_rq_complete -a# 2. 生成延迟报告
perf script | awk '/block_rq_issue/{ts[$5]=$4}/block_rq_complete/{if(ts[$5])printf "%.2f ms\n", ($4-ts[$5])*1000}'
输出:
8.23 ms # I/O 请求延迟
12.45 ms
5.67 ms
2.4 网络性能分析
场景 | 命令示例 | 说明 |
---|---|---|
网络协议栈跟踪 | perf record -e skb:kfree_skb -e net:net_dev_xmit -a | 监控丢包和发送事件 |
TCP 函数跟踪 | perf probe --add tcp_v4_connect; perf record -e probe:tcp_v4_connect | 动态跟踪 TCP 连接建立 |
网络延迟分析 | perf trace -e sendto,recvfrom -p <PID> -T | 跟踪网络收发系统调用时间戳 |
示例:网络丢包分析
# 1. 创建丢包检测探针
sudo perf probe --add 'kfree_skb reason'# 2. 记录丢包事件
sudo perf record -e probe:kfree_skb -aR -o net_drop.data# 3. 分析丢包原因
sudo perf script -i net_drop.data | awk '{print $5}' | sort | uniq -c | sort -nr
输出:
1423 TCP: Too many orphaned sockets890 NETDEV WATCHDOG: enp0s3 transmit timeout321 ICMP: Destination unreachable
2.5 锁与同步分析
场景 | 命令示例 | 说明 |
---|---|---|
锁竞争分析 | perf record -e lock:lock_acquire -e lock:lock_release -g -p <PID> | 跟踪锁获取/释放事件 |
调度延迟分析 | perf sched record -p <PID>; perf sched latency | 分析任务调度延迟 |
中断分析 | perf record -e irq:irq_handler_entry -e irq:irq_handler_exit -a | 跟踪中断处理时间 |
示例:锁竞争诊断
# 1. 记录锁事件
perf record -e lock:lock_acquire -e lock:lock_release -g -p 5678 -o locks.data# 2. 生成竞争报告
perf lock report -i locks.data --combine-locks --sort contended
输出:
Name acquired contended avg wait (ns)
----------------------------------------------------------
&sb->s_type->i_lock 14235 4231 15234&rq->lock 8765 2109 8765mm->page_table_lock 6543 987 5432
2.6 火焰图生成
perf record -F 99 -a -g -- sleep 30
perf script > out.perf
./FlameGraph/stackcollapse-perf.pl out.perf > out.folded
./FlameGraph/flamegraph.pl out.folded > flame.svg
2.7 Perf 工作流程图
2.8 高级技巧
-
PEBS 精确采样
perf record -e cycles:pp -c 1000000 -p <PID> # 每100万周期采样一次
-
事件分组统计
perf stat -e '{cycles,instructions,branch-misses}' -r 5 ./program
-
时间戳跟踪
perf record -e sched:sched_switch -T -a -- sleep 10 perf script --ns
-
跨进程跟踪
perf record -e 'sched:sched_wakeup,sched:sched_switch' -a
-
用户空间探针
perf probe -x /path/to/bin 'func_name' perf record -e probe_bin:func_name -a
三、Perf 使用流程图
四、高级技巧
- 事件修饰符:
u
:仅用户空间,如perf stat -e cycles:u
k
:仅内核空间
- 精确采样:
perf record -e cycles:pp -p 1234 # 使用 PEBS 精确采样
- 多事件分析:
perf stat -e cycles,instructions,cache-references,cache-misses ls
五、注意事项
- 权限要求:部分事件需要
CAP_PERFMON
或root
权限。 - 符号表:用户程序需编译时添加
-g
选项(保留调试符号)。 - 内核版本:不同内核版本支持事件可能不同(
perf list
查看)。
通过灵活组合命令,Perf 可定位 CPU 瓶颈、内存延迟、I/O 问题等,是 Linux 性能调优的核心工具。