0%

perf命令

Linux perf 命令:性能分析的瑞士军刀

perf 是 Linux 系统自带的性能分析工具,基于内核性能事件机制,可用于监控 CPU 使用率、缓存命中、函数调用开销、上下文切换等关键性能指标。它是排查程序性能瓶颈(如 CPU 密集、缓存失效、函数耗时过长)的核心工具,尤其适合分析 Java 等应用的底层运行情况。

perf 基本用法

命令格式

1
perf [子命令] [选项] [目标程序/进程ID]

perf 包含多个子命令,分别用于不同场景的性能分析,最常用的包括 stat(统计事件)、record(记录事件)、report(生成报告)等。

核心子命令

子命令 功能描述
perf stat 统计指定事件(如 CPU 周期、缓存命中)的发生次数和频率,适合快速定位性能瓶颈。
perf record 记录程序运行时的性能事件数据,生成二进制文件(默认 perf.data),用于后续分析。
perf report 解析 perf record 生成的文件,展示函数级别的性能开销分布(如 CPU 占用率)。
perf top 实时显示当前系统中消耗 CPU 最多的函数或指令,类似 top 但更深入。

常用场景与示例

perf stat:快速统计性能指标

perf stat 用于统计指定事件的发生情况,适合初步定位程序的性能特征(如是否 CPU 密集、缓存效率如何)。

基本用法
1
2
3
4
5
# 监控进程(如 Java 进程,PID 为 570864)的指定事件
perf stat -e <事件列表> -p <进程ID>

# 监控命令执行期间的事件(如执行 java -jar app.jar)
perf stat -e <事件列表> java -jar app.jar
常用事件(-e 选项)
  • cpu-clock:CPU 时钟周期,反映程序的 CPU 耗时。
  • task-clock:任务(进程)占用的 CPU 时间(单位:ms)。
  • cs:上下文切换次数(包括进程间切换和线程间切换),过多会导致性能下降。
  • cache-references:缓存访问次数。
  • cache-misses:缓存未命中次数(cache-misses / cache-references 反映缓存效率)。
  • instructions:CPU 执行的指令数(可计算 instructions / cycles 衡量指令效率)。
  • branches:分支指令数(如 iffor 跳转)。
  • branch-misses:分支预测失败次数(预测失败会导致流水线停顿)。
示例:监控 Java 进程
1
2
# 监控进程 570864 的 CPU 时钟、上下文切换、缓存命中情况
perf stat -e cpu-clock,task-clock,cs,cache-references,cache-misses -p 570864

输出示例:

1
2
3
4
5
6
7
8
9
性能计数器统计对于进程 ID 570864:

12345.67 msec cpu-clock # CPU 时钟周期(总耗时)
10234.56 msec task-clock # 进程占用的 CPU 时间(占比 ~83%)
1234 cs # 上下文切换次数
567890 cache-references # 缓存访问
45678 cache-misses # 缓存未命中(命中率 ~92%)

12.345678765 seconds time elapsed # 总 elapsed 时间

解读

  • cpu-clock 接近 time elapsed,说明程序是 CPU 密集型;
  • cs 数值过大(如每秒数万次),可能存在过多线程切换;
  • cache-misses 占比高(如 >20%),可能存在缓存使用效率低的问题(如频繁访问大数组导致缓存失效)。

perf top:实时查看 CPU 热点函数

perf top 实时显示当前系统中消耗 CPU 最多的函数,适合快速定位哪个函数或模块占用资源最多。

基本用法
1
2
3
4
5
# 实时监控,按 CPU 使用率排序(默认)
perf top

# 监控指定进程(只显示该进程的函数)
perf top -p <进程ID>
输出解读
1
2
3
4
5
6
Samples: 1K of event 'cpu-clock', Event count (approx.): 123456
Overhead Command Shared Object Symbol
15.23% java libjvm.so [.] _ZN13G1CollectedHeap15collectGarbageEbb
8.76% java libjvm.so [.] _ZN26G1ParallelWorkerThread3runEv
5.32% java app.jar [.] com.example.Service.process
...
  • Overhead:函数占用 CPU 的百分比;
  • Symbol:函数名(C++ 函数可能经过名称修饰,如 _ZN13G1CollectedHeap... 是 JVM G1 垃圾回收相关函数);
  • 若 Java 应用的热点函数多为 libjvm.so 中的 JVM 内部函数(如 GC 相关),可能说明 GC 频繁是瓶颈;若多为业务类(如 com.example.Service),则需优化业务代码。

perf record + perf report:深入分析函数调用开销

perf record 记录程序运行时的详细性能事件,perf report 生成可视化报告,适合深入分析函数级别的耗时分布。

基本流程
  1. 记录事件

    1
    2
    # 记录进程 570864 的性能事件(默认记录 CPU 周期)
    perf record -p 570864 -g # -g 记录函数调用栈,便于分析调用关系

    执行后按 Ctrl+C 停止,生成 perf.data 文件。

  2. 生成报告

    1
    perf report  # 解析 perf.data,交互式展示结果
报告解读

报告按函数 CPU 使用率排序,可查看每个函数的调用栈(因 -g 选项),例如:

1
2
3
4
5
-   30.0%  java  libjvm.so
- 20.0% _ZN13G1CollectedHeap15collectGarbageEbb
- 15.0% _ZN26G1ParallelWorkerThread3runEv
- 10.0% _ZN7VMThread3runEv
- 10.0% _ZN9Interpreter14invoke_methodEP10MethodDataP11JavaThread

通过调用栈可追踪性能开销的源头(如上述示例中 GC 线程占用大量 CPU,可能需要优化 JVM 内存配置)。

Java 应用分析注意事项

  1. 符号解析
    分析 Java 应用时,perf 可能无法直接显示 Java 方法名(默认显示 JVM 内部函数)。需通过以下方式让 perf 识别 Java 方法:
    • 启动 Java 时添加 -XX:+PreserveFramePointer(保留栈帧指针,便于 perf 解析调用栈);
    • 使用 perf report --demangle=java 尝试解析 Java 方法名。
  2. 结合 JVM 工具
    perf 侧重底层(CPU、缓存、系统调用),需结合 JVM 工具(如 jstackjstat)定位问题。例如:
    • perf 显示 GC 函数耗时多,用 jstat -gc <PID> 确认 GC 频率和耗时;
    • cs(上下文切换)多,用 jstack <PID> 查看线程状态(是否有大量 RUNNABLE 线程竞争 CPU)

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10