Linux 性能调优与追踪完整篇:ftrace、perf、eBPF从采样到落地验证

CPU 被打满却说不清热点、延迟尖刺只能「重启试一下」、上线后回归全靠猜------缺的不是参数列表,而是 可复现的观测路径 :从 tracepoint/kprobe 到采样火焰图,再到改参与回归对比。本文把 ftrace、perf_event、eBPF/bpftrace、常见调优开关与排障顺序合成一篇闭环。


源码锚点

路径 作用
kernel/trace/ftrace.c ftrace 核心、function tracer
kernel/trace/trace.c tracefs 环形缓冲与输出
include/linux/ftrace.h ftrace API
kernel/events/core.c perf_event 子系统
kernel/kprobes.c kprobe 动态插桩
kernel/bpf/ eBPF 验证器、地图、运行时
kernel/trace/bpf_trace.c BPF 与 tracing 衔接
fs/tracefs/ / debugfs 用户态控制面(挂载点因发行版而异)
tools/perf/ 用户态 perf 工具
Documentation/trace/Documentation/bpf/ 官方追踪与 BPF 文档

ftrace 控制面(示意):

bash 复制代码
# 通常需要 root;路径可能是 /sys/kernel/tracing
mount | grep tracefs
cd /sys/kernel/tracing
echo function > current_tracer
echo do_sys_openat2 > set_ftrace_filter   # 示例符号以本机为准
echo 1 > tracing_on
cat trace | head
echo 0 > tracing_on

perf 采样骨架:

bash 复制代码
perf record -F 99 -g -- ./app
perf report
# 或系统范围
perf top
perf record -a -g -- sleep 10

调用链

观测数据从内核到用户态

#mermaid-svg-VUehsEsGWDM6kxoH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VUehsEsGWDM6kxoH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VUehsEsGWDM6kxoH .error-icon{fill:#552222;}#mermaid-svg-VUehsEsGWDM6kxoH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VUehsEsGWDM6kxoH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VUehsEsGWDM6kxoH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VUehsEsGWDM6kxoH .marker.cross{stroke:#333333;}#mermaid-svg-VUehsEsGWDM6kxoH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VUehsEsGWDM6kxoH p{margin:0;}#mermaid-svg-VUehsEsGWDM6kxoH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster-label text{fill:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster-label span{color:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster-label span p{background-color:transparent;}#mermaid-svg-VUehsEsGWDM6kxoH .label text,#mermaid-svg-VUehsEsGWDM6kxoH span{fill:#333;color:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .node rect,#mermaid-svg-VUehsEsGWDM6kxoH .node circle,#mermaid-svg-VUehsEsGWDM6kxoH .node ellipse,#mermaid-svg-VUehsEsGWDM6kxoH .node polygon,#mermaid-svg-VUehsEsGWDM6kxoH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VUehsEsGWDM6kxoH .rough-node .label text,#mermaid-svg-VUehsEsGWDM6kxoH .node .label text,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape .label,#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape .label{text-anchor:middle;}#mermaid-svg-VUehsEsGWDM6kxoH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VUehsEsGWDM6kxoH .rough-node .label,#mermaid-svg-VUehsEsGWDM6kxoH .node .label,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape .label,#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape .label{text-align:center;}#mermaid-svg-VUehsEsGWDM6kxoH .node.clickable{cursor:pointer;}#mermaid-svg-VUehsEsGWDM6kxoH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VUehsEsGWDM6kxoH .arrowheadPath{fill:#333333;}#mermaid-svg-VUehsEsGWDM6kxoH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VUehsEsGWDM6kxoH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VUehsEsGWDM6kxoH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VUehsEsGWDM6kxoH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VUehsEsGWDM6kxoH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VUehsEsGWDM6kxoH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VUehsEsGWDM6kxoH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster text{fill:#333;}#mermaid-svg-VUehsEsGWDM6kxoH .cluster span{color:#333;}#mermaid-svg-VUehsEsGWDM6kxoH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VUehsEsGWDM6kxoH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VUehsEsGWDM6kxoH rect.text{fill:none;stroke-width:0;}#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape p,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VUehsEsGWDM6kxoH .icon-shape .label rect,#mermaid-svg-VUehsEsGWDM6kxoH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VUehsEsGWDM6kxoH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VUehsEsGWDM6kxoH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VUehsEsGWDM6kxoH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 静态
动态函数
PMU 采样
可编程
感兴趣事件
观测手段
tracepoint
kprobe / ftrace filter
perf_event
eBPF 程序
ring buffer / perf mmap
BPF map / ringbuf
用户态工具读取
报告 / 火焰图 / 指标

调优闭环分层

#mermaid-svg-hqHuOnUWouyZb6O2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hqHuOnUWouyZb6O2 .error-icon{fill:#552222;}#mermaid-svg-hqHuOnUWouyZb6O2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hqHuOnUWouyZb6O2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hqHuOnUWouyZb6O2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hqHuOnUWouyZb6O2 .marker.cross{stroke:#333333;}#mermaid-svg-hqHuOnUWouyZb6O2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hqHuOnUWouyZb6O2 p{margin:0;}#mermaid-svg-hqHuOnUWouyZb6O2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster-label text{fill:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster-label span{color:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster-label span p{background-color:transparent;}#mermaid-svg-hqHuOnUWouyZb6O2 .label text,#mermaid-svg-hqHuOnUWouyZb6O2 span{fill:#333;color:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .node rect,#mermaid-svg-hqHuOnUWouyZb6O2 .node circle,#mermaid-svg-hqHuOnUWouyZb6O2 .node ellipse,#mermaid-svg-hqHuOnUWouyZb6O2 .node polygon,#mermaid-svg-hqHuOnUWouyZb6O2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hqHuOnUWouyZb6O2 .rough-node .label text,#mermaid-svg-hqHuOnUWouyZb6O2 .node .label text,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape .label,#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-hqHuOnUWouyZb6O2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hqHuOnUWouyZb6O2 .rough-node .label,#mermaid-svg-hqHuOnUWouyZb6O2 .node .label,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape .label,#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape .label{text-align:center;}#mermaid-svg-hqHuOnUWouyZb6O2 .node.clickable{cursor:pointer;}#mermaid-svg-hqHuOnUWouyZb6O2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hqHuOnUWouyZb6O2 .arrowheadPath{fill:#333333;}#mermaid-svg-hqHuOnUWouyZb6O2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hqHuOnUWouyZb6O2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hqHuOnUWouyZb6O2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hqHuOnUWouyZb6O2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hqHuOnUWouyZb6O2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hqHuOnUWouyZb6O2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster text{fill:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 .cluster span{color:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hqHuOnUWouyZb6O2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hqHuOnUWouyZb6O2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape p,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hqHuOnUWouyZb6O2 .icon-shape .label rect,#mermaid-svg-hqHuOnUWouyZb6O2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hqHuOnUWouyZb6O2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hqHuOnUWouyZb6O2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hqHuOnUWouyZb6O2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 验证
假设与改动
观测
定义问题
延迟? CPU? IO? 唤醒?
建立 baseline
perf / top / iostat
ftrace / trace-cmd
bpftrace / BCC
调度/内存/IO/驱动参数
代码热点修复
同负载复测
回滚开关


重点知识

1. 先定性,再选工具

症状 先看 深挖
CPU 高 perf top/record -g 符号、锁、软中断
延迟尖刺 cyclictest、调度/中断追踪 irqsoff/preemptirqsoff、唤醒链
IO 等 iostatperf block 事件 电梯、队列深度、FS 回写
内存 /proc/meminfopsi reclaim、oom、cgroup 限制

没有 baseline(同负载下的延迟/CPU/带宽数字)就改 sysctl,属于盲调。

2. ftrace:低成本看清调用与关闭抢占

  • function / function_graph:看谁调用谁、耗时轮廓。
  • irqsoff / preemptoff:关中断/关抢占过久(驱动里常见)。
  • sched / wakeup:任务为何睡、被谁唤醒。
bash 复制代码
trace-cmd record -e sched:sched_switch -e sched:sched_wakeup sleep 5
trace-cmd report | head

注意:过滤不当时开销与 trace 体积会爆;生产先短时、窄 filter。

3. perf:PMU 采样与火焰图

perf_event 把硬件计数器/软件事件接到统一接口;perf record 采样调用栈,适合「CPU 花在哪」。

bash 复制代码
# 权限相关
sysctl kernel.perf_event_paranoid
# 常见:cache-misses、cycles、page-faults
perf stat -e cycles,cache-misses,page-faults -- ./app

解读要点:采样有偏差;内联/缺符号会「糊」;先保证 vmlinux/debuginfod 或至少 kallsyms 可读。

4. eBPF:验证后可编程观测

流程:编写(或 bpftrace 一行)→ verifier 保证安全 → 加载 → 挂到 kprobe/tracepoint/XDP 等 → map/ringbuf 汇总。

bash 复制代码
# 示例:统计 syscall 次数(语法随 bpftrace 版本微调)
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'

约束:

  • 无 verifier 通过则无法加载------这是特性不是障碍;
  • 生产控制 attach 范围与采样率,避免自扰动;
  • 权限:通常需要 CAP_BPF/CAP_PERFMON 或 root(视内核与发行版)。

5. kprobe 与开销意识

kprobe 可动态插到几乎任意内核函数,但:

  • 热路径高频命中会显著扰动;
  • 部分函数不可探测或随版本改名;
  • 优先用稳定 tracepoint,kprobe 作补充。

6. 配置与安全

bash 复制代码
# 追踪文件系统
mount -t tracefs tracefs /sys/kernel/tracing
# BPF 文件系统(部分工具需要)
mount -t bpf bpf /sys/fs/bpf
说明
kernel.perf_event_paranoid 控制非特权 perf 能力
debugfs/tracefs 权限 避免无关用户读内核地址信息
生产追踪 限时、限事件、有回滚

7. 从观测到改参:几类高频旋钮(先测后改)

领域 示例入口 说明
调度 schedutil、CPU 亲和、nice/cgroup cpu 先确认是否真 CPU 饱和
内存 vm.swappinessvfs_cache_pressure、cgroup 限制 配合 PSI/meminfo
网络 somaxconn、队列、NAPI/中断开销 ss/perf 再改
块 IO 调度器、队列深度、ionice 先分清读/写/刷新
驱动 线程化 IRQ、合并工作、避免关中断过久 irqsoff 验证

原则:一次只改一类变量 ,保留开关与回滚命令。容器/ cgroup 场景下,宿主机 sysctl 与容器限额要分开看。

8. 常见坑

结果 处理
无符号表 火焰图全是地址 安装 debug 包 / 带 vmlinux
同时开太多 tracer 机器变慢、数据失真 单次一种目的
只调参不复测 「好像好了」 固定负载脚本对比
把平均当尾延迟 P99 仍炸 看直方图/百分位
在生产长期开 function tracer 吞吐断崖 限时、窄 filter、事后关闭

Checklist

  • 调优前有书面 baseline(负载描述 + 关键指标)
  • 能说明 ftrace / perf / eBPF 各自擅长的问题类型
  • 会用 perf record -g + report 定位用户/内核热点
  • 会在 tracefs 上做一次窄过滤的 function 追踪并关闭
  • 优先选用 tracepoint,明白 kprobe 的开销与版本风险
  • 知道 perf_event_paranoid 与 tracefs 挂载对工具的影响
  • 每次改动可回滚,并用同一负载复测验证

小结

内核已经把观测做成可组合管线:事件源 → 缓冲/映射 → 用户态分析。调优的设计意图不是堆参数,而是用 ftrace/perf/eBPF 把假设证伪或证实。顺序固定为:定性 → 选工具 → 短时窄范围采集 → 改一处 → 对比 baseline。

相关推荐
sunoo-2291 小时前
【网络编程 + 数据库】select 与 epoll 核心区别详解 + SQLite 入门到 C 接口全攻略
linux·网络·数据库·vscode·学习·sqlite
zbyyd1 小时前
Linux 系统编程 :select/epoll 多路复用与 SQLite 数据库实战
linux·数据库·sqlite
虎王物联1 小时前
Docker BuildKit多阶段构建:IoT固件交叉编译流水线实战
运维·物联网·ci/cd·docker·容器·物联网嵌入式
Mortalbreeze1 小时前
深入理解 Linux IO 模型(二):多路复用——select
linux·运维·服务器·网络·tcp/ip
养生技术人1 小时前
Oracle OCP认证考试题目详解082系列第17题
运维·数据库·sql·oracle·ocp
Mrs_DongDong1 小时前
华为云 Windows 服务器远程桌面自定义端口排障指南
服务器·windows·华为云
koi77u1 小时前
嵌入式学习———sqlite数据表
linux·数据库·学习·sqlite
SamChan901 小时前
PDF翻译服务端到端基准测试:4款主流方案的吞吐量、延迟、内存占用对比
服务器·网络·python·ai·pdf·wpf
笑梦无境1 小时前
nginx安装(5)
linux·运维·nginx