1. 文档目的
本文介绍如何使用perf stat、perf top、perf sched 和 perf lock观察 Linux 进程的 CPU 使用、函数热点、调度延迟和锁竞争,从而判断进程的主要运行瓶颈。
1.1 perf 工具简介
perf是Linux 内核提供的性能分析工具集,主要通过硬件性能计数器、软件事件、tracepoint 和采样机制观察系统或进程的运行行为。它适合回答“CPU 时间花在哪里”、“程序是否真的在跑 CPU”、“线程是否被调度延迟”、“是否存在锁竞争”等问题。
perf top 看到的是 on-CPU 热点,对 I/O 等待、条件变量等待、队列阻塞等 off-CPU 问题并不敏感;perf lock 主要观察 Linux 内核锁事件,不能完整代表用户态 pthread_mutex 竞争;perf stat 只能给出方向性指标,通常需要结合业务吞吐、延迟、丢包率和采集时的负载条件一起判断。
推荐按照以下顺序排查:
perf stat -> perf top/perf record -> perf sched -> perf lock/futex
1.2 perf 排查流程图
2. 分析前准备
2.1 获取目标进程和线程
pid=$(pidof worker)ps -p ”$pid” -o pid,ppid,stat,psr,pcpu,pmem,etime,commps -T -p ”$pid” -o pid,tid,psr,stat,pcpu,comm
其中:
- STAT 中 R 表示运行或等待 CPU,S 表示可中断睡眠,D 表示不可中断睡眠。
如果进程长期处于 D 状态,应优先检查磁盘、网络文件系统、驱动或其他内核 I/O,单独使用 CPU 热点分析通常无法找到根因。
2.2 确认 perf 和事件支持情况
perf --versionsudo perf list
perf最好与当前运行内核版本匹配。不同发行版和 perf 版本支持的参数、硬件事件、tracepoint 可能不同,执行前可以使用 <命令> --help 确认。
生产环境建议先采集 10 到 30 秒,并观察采集本身带来的 CPU 和存储开销。
3. 使用 perf stat 判断瓶颈方向
3.1 基础采集
sudo perf stat -p ”$pid” -e \task-clock,context-switches,cpu-migrations,page-faults,cycles,instructions,\cache-references,cache-misses,branches,branch-misses -- sleep 30
也可以使用详细统计模式:
sudo perf stat -d -p ”$pid” -- sleep 30
针对单个关键线程采集:
sudo perf stat -t -- sleep 30
3.2 关键指标解释
IPC 的含义为:
IPC = instructions / cycles
IPC 没有适用于所有程序的统一正常值,应在相同硬件、相同流量和相同业务模型下进行对比。
3.3 初步判断
3.4 perf stat 瓶颈判断图
4. 使用 perf top 定位实时 CPU 热点
4.1 查看目标进程热点
sudo perf top -p ”$pid” -g
只观察用户态 CPU 周期:
sudo perf top -p ”$pid” -e cycles:u -g
如果需要稳定、可保存的结果,建议使用离线采样:
sudo perf record -F 99 -g -p ”$pid” -- sleep 30sudo perf report
4.2 常见热点解释
perf top主要显示正在 CPU 上运行的代码。线程如果大部分时间处于睡眠、I/O 等待或锁等待,可能不会形成明显的 CPU 热点,此时应继续使用 perf sched 或等待事件分析。
如果调用栈缺失,应检查:
5. 使用 perf sched 分析调度延迟
5.1 采集调度事件
sudo perf sched record -p ”$pid” -- sleep 30
部分旧版本不支持按 PID 过滤,可以采集全系统后再根据线程名和 PID 分析:
sudo perf sched record -a -- sleep 30
5.2 查看统计结果
sudo perf sched latencysudo perf sched timehistsudo perf sched map
6. 使用 perf lock 分析内核锁竞争
6.1 采集和查看内核锁事件
sudo perf lock record -p ”$pid” -- sleep 30sudo perf lock report
常见字段包括:
应优先检查 contended、wait total 和 wait max 较高的锁及其调用路径。
6.2 perf lock 的能力边界
perf lock主要分析Linux内核锁,不等同于完整的用户态 pthread_mutex 分析工具。用户态互斥锁在没有竞争时通常不会进入内核,因此不会被 perf lock 完整记录。
发生竞争的用户态锁通常会通过futex 进入内核,可以尝试采集 futex 系统调用:
sudo perf record -g \ -e syscalls:sys_enter_futex \ -e syscalls:sys_exit_futex \ -p ”$pid” -- sleep 30sudo perf report
先确认当前内核是否提供相应事件:
sudo perf list | grep -E 'lock|futex|sched'
如果 futex 等待明显,但调用栈无法定位到业务锁,还需要结合 eBPF、用户态探针或程序内的低开销锁统计。
注意事项
- Perf 采样本身存在开销,生产环境应控制采样频率和持续时间。
- perf.data 可能包含进程符号、调用栈等运行信息,应按生产数据安全规范处理。
- 大型 perf.data 文件应在分析完成后按要求归档或清理。
- 硬件事件可能受虚拟机、容器权限、内核参数和 PMU 能力限制。
- 不要只依据单个指标下结论,应结合业务吞吐、延迟和丢包结果判断。
- perf top 看不到完整的 off-CPU 等待,perf lock 也不能覆盖所有用户态锁。
- 本文命令中的参数应以目标服务器实际安装的 perf --help 输出为准。