2、性能分析工具链:perf工具使用、ftrace追踪、eBPF基础、火焰图生成与解读
说到性能分析,我见过太多人一上来就拍脑袋猜瓶颈。说实话,这跟闭着眼修车没什么区别。真正的驱动开发老手,手里都有一套趁手的工具链。今天我就把这套「四件套」——perf、ftrace、eBPF、火焰图,掰开揉碎了讲给你听。
2.1 perf:内核自带的性能计数器
perf 是我用得最多的工具,没有之一。它基于硬件性能计数器和内核事件,能告诉你 CPU 在干嘛、缓存命中率多少、上下文切换有多频繁。
2.1.1 基本用法
# 统计CPU周期和指令数
perf stat ./my_driver_test
# 采样分析热点函数
perf record -F 99 -g ./my_driver_test
perf report
我个人习惯先用 perf stat 看宏观数据。如果发现 context-switches 特别高,那大概率是锁竞争或者中断太多。嗯,这里要注意:采样频率 -F 99 是经验值,太高会影响被测程序行为。
perf top 可以实时查看当前系统热点函数,适合快速定位「谁在吃CPU」。
2.1.2 驱动开发中的实战场景
我曾经调试一个网卡驱动,发现吞吐量上不去。用 perf stat 一看,cache-misses 高达 40%。再配合 perf record -e cache-misses 采样,发现是 DMA 描述符的缓存布局有问题。调整数据结构对齐后,性能直接翻倍。
| perf事件 | 含义 | 驱动场景 |
|---|---|---|
| cycles | CPU周期 | 计算密集型驱动 |
| cache-misses | 缓存未命中 | 数据结构布局优化 |
| context-switches | 上下文切换 | 中断/锁竞争分析 |
| page-faults | 缺页异常 | 内存映射驱动 |
2.2 ftrace:内核的瑞士军刀
ftrace 是内核内置的追踪器。说白了,它能记录函数调用、中断、调度等几乎所有内核活动。我常说,ftrace 是「内核的 strace」。
2.2.1 快速上手
# 挂载tracefs
mount -t tracefs tracefs /sys/kernel/tracing
# 设置追踪函数
echo function > /sys/kernel/tracing/current_tracer
echo my_driver_function > /sys/kernel/tracing/set_ftrace_filter
echo 1 > /sys/kernel/tracing/tracing_on
cat /sys/kernel/tracing/trace
你想想看,当你的驱动莫名其妙卡住时,ftrace 能精确告诉你「哪个函数调用了哪个函数,花了多少时间」。我曾经用它抓到一个中断处理函数里意外调用了 printk,导致系统响应延迟暴增。
echo 0 > tracing_on。
2.2.2 高级用法:function_graph
echo function_graph > current_tracer
echo __schedule > set_graph_function
cat trace
这个模式会以缩进方式显示函数调用链,特别适合分析调度延迟。我调试一个实时驱动时,就是靠它发现了一个优先级反转问题。
2.3 eBPF:新时代的性能神器
eBPF 是近几年内核社区最火的技术。它允许你在内核中安全地运行沙箱程序,动态追踪任何你想看的东西。说白了,就是给内核装了个「可编程探针」。
2.3.1 基础概念
- kprobe:动态内核函数探针
- tracepoint:静态内核事件点
- perf_event:硬件性能事件
- XDP:高速网络数据包处理
2.3.2 实战:用bpftrace追踪驱动
# 统计某个驱动函数的调用次数
bpftrace -e 'kprobe:my_driver_ioctl { @[comm] = count(); }'
# 追踪内存分配路径
bpftrace -e 'kprobe:kmalloc /comm == "my_driver"/ { printf("%s %d\n", comm, arg0); }'
我记得有一次,客户反馈驱动在特定场景下内存泄漏。用 eBPF 追踪 kmalloc 和 kfree 的配对情况,半小时就定位到了问题——一个错误路径上忘了释放 DMA 缓冲区。
bpftrace 开始,它语法简单,类似 awk。等熟悉了再学 libbpf 和 CO-RE(一次编译,到处运行)。
2.4 火焰图:让性能问题一目了然
火焰图是 Brendan Gregg 的杰作。它把采样数据可视化,让你一眼看出「CPU 时间都烧在哪了」。我每次做性能优化,第一件事就是生成火焰图。
2.4.1 生成流程
# 1. 采样
perf record -F 99 -a -g -- sleep 30
# 2. 生成火焰图
git clone https://github.com/brendangregg/FlameGraph
perf script | ./FlameGraph/stackcollapse-perf.pl > out.perf-folded
./FlameGraph/flamegraph.pl out.perf-folded > perf.svg
2.4.2 如何解读
- X轴:采样总数,不代表时间顺序
- Y轴:调用栈深度
- 颜色:通常随机分配,橙色/红色表示热点
- 宽块:说明这个函数占用了大量CPU
你想想看,如果火焰图顶部有个又宽又平的块,那大概率是自旋锁或者忙等待。我曾经看到一个驱动在中断上下文里做 msleep,火焰图上直接显示一个巨大的 schedule_timeout 块。
off-CPU 火焰图。
2.5 知识体系总览
下面这张图是我自己总结的工具链关系。你看,perf 负责「宏观统计」,ftrace 负责「函数级追踪」,eBPF 负责「自定义探针」,火焰图负责「可视化呈现」。四者配合,没有解不开的性能问题。
说实话,这套工具链我用了快十年。每次遇到棘手的性能问题,都是它们帮我找到突破口。你刚开始用可能会觉得命令太多,没关系,先从 perf stat 和 perf record 开始,慢慢你就会发现——性能分析,其实没那么玄乎。