性能分析工具Perf

204 阅读5分钟

perf 工具使用详解

perf是linux系统内核自带的性能分析工具,用于监控系统性能,分析程序瓶颈。 可捕获硬件事件(cpu周期,缓存命中/未命中),也可定位i性能热点,支持用户态和内核态的全面分析。

原理:perf通过访问linux内核中的性能监控单元(PMU),采样和计数硬件事件,perf通过这些单元收集数据并分析性能。 PMU专门用于监控硬件性能。PMU捕捉的硬件事件包括指令执行,缓存命中/未命中,分支预测等。

性能热点:

CPU 占用: 程序的某些函数或代码片段可能会长时间占用 CPU 资源,导致程序整体变慢。比如,如果某个函数反复执行且时间长,它就可能是性能热点。

频繁的函数调用: 如果程序中某个函数调用频繁,而每次调用的时间又较长,可能导致该函数成为性能瓶颈。

内存访问: 频繁的内存访问,特别是未命中的缓存,会导致性能下降。性能热点可能出现在那些大量访问内存、并且没有利用 CPU 缓存的代码部分。

I/O 操作: 如果程序中有大量的 I/O 操作,尤其是磁盘或网络 I/O,它们也会成为性能热点,影响程序的整体执行速度。

分支预测失败: 程序的分支预测失败会增加 CPU 处理的负担,导致性能下降

一、perf 基础

1. perf 子命令概览

annotate      解析perf.data中的符号
bench         运行内核微基准测试
c2c           共享缓存行分析
data          数据文件操作
diff          比较两个数据文件
evlist        列出事件
ftrace        ftrace接口
inject        过滤或扩展性能数据
kallsyms      搜索运行内核的符号
kmem          内核内存分析
kvm           KVM虚拟机分析
list          列出所有事件
lock          分析锁事件
mem           内存访问分析
record        记录性能数据
report        生成性能报告
sched         调度器分析
script        读取perf.data并显示跟踪输出
stat          运行命令并收集性能计数器统计
test          运行完整性测试
timechart     生成时间图表
top           实时性能分析
trace         跟踪系统调用
probe         定义动态跟踪点

二、常用性能分析场景

1. 全局热点分析

sudo perf top

perf top.png

3. 记录和分析 (perf record/report)

# 记录性能数据
perf record -g -p <PID>  # -g 记录调用图
perf record -F 99 -g -- <command>  # 99Hz采样频率

# 生成报告
perf report
perf report -n  # 显示样本数量
perf report --stdio  # 文本模式

# 火焰图生成
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg

三、实际案例分析

案例1:CPU使用率高

# 1. 找到高CPU进程
top

# 2. 分析该进程的热点
perf top -p <PID>

# 3. 记录详细数据
perf record -g -p <PID> sleep 10

# 4. 生成报告
perf report

案例2:系统调用频繁

# 1. 跟踪系统调用
perf trace -p <PID>

# 2. 统计系统调用
perf stat -e 'syscalls:sys_enter_*' -p <PID> sleep 5

# 3. 分析特定系统调用
perf trace -e nanosleep -p <PID>

案例3:锁竞争

# 1. 监控锁事件
perf lock record <command>
perf lock report

# 2. 分析自旋锁
perf stat -e 'sched:sched_process*,lock:*' -a sleep 5

五、perf与其他工具集成

  1. 火焰图生成

    git clone https://github.com/brendangregg/FlameGraph
    export PATH=$PATH:path/to/FlameGraph
    perf script | stackcollapse-perf.pl | flamegraph.pl > perf.svg
    
  2. 与BPF集成

    perf stat -e 'probe:xxx' -a sleep 5
    

六、Perf 数据分析报告

perf.png 这份 perf 数据展示了 zkos_log_engine 进程的性能热点分布,主要集中在 DLT (Diagnostic Log and Trace) 日志处理相关的函数调用上。

总体分析

  • 总样本数: 1K 个 CPU cycles 事件
  • 总周期数: ≈385,593,030
  • 主调用路径: _startmainzkos::log::BackendDlt::Loopdlt_daemon_handle_event

热点分布

  1. 主热点路径 (99.31%): zkos::log::BackendDlt::Loop (99.31%) └── dlt_daemon_handle_event (98.07%) ├── dlt_daemon_process_user_messages (31.68%) │ ├── dlt_daemon_process_user_message_log (22.41%) │ │ ├── dlt_daemon_client_send_message_to_all_client (19.87%) │ │ │ └── dlt_daemon_client_send (18.70%) │ │ │ └── dlt_daemon_logstorage_write (17.73%) │ │ │ ├── dlt_logstorage_write (12.71%) │ │ │ ├── strcmp (3.89%) │ │ │ └── __GI___memset_generic (0.60%) │ │ └── strncmp (0.62%) └── [其他分支] (66.39%)

  2. 关键性能消耗点:

    • dlt_logstorage_write12.71%
    • strcmp3.89%
    • dlt_daemon_process_user_message_log22.41%

详细问题分析

1. 日志存储写入性能瓶颈

dlt_logstorage_write 及其子函数共消耗约 17.73% 的 CPU 时间,是最大的性能热点。

  • 子函数分析:
    • dlt_logstorage_prepare_and_write_on_msg (1.25%)
      • dlt_logstorage_sync_on_msggzflush (0.67%) - 可能是压缩同步操作
    • dlt_logstorage_prepare_and_write_on_cache (1.11%)
      • dlt_logstorage_write_msg_cache (0.63%) - 缓存写入操作
    • zklog_get_config (1.80%) - 日志配置获取

优化建议:

  • 检查日志写入频率和批量写入的可能性
  • 评估压缩算法(gzip)的性能影响
  • 检查日志缓存大小和刷新策略

2. 字符串操作开销

  • strcmp3.89%
  • strncmp0.62%
  • __GI___memset_generic0.60%

优化建议:

  • 检查高频字符串比较的场景,考虑使用哈希或字典优化
  • 评估是否可以使用更高效的内存比较方式
  • 对于固定格式的日志消息,可以考虑预先解析或结构化处理

3. 消息处理路径

dlt_daemon_process_user_message_log22.41%,其中主要消耗在消息发送和存储环节。

优化建议:

  • 检查消息广播给所有客户端的必要性,可能实现过滤机制
  • 评估消息分发机制,考虑使用更高效的事件驱动模型
  • 检查日志级别设置,减少不必要的日志处理

后续分析建议

  1. 使用 perf annotate 对热点函数进行指令级分析
  2. 收集更多样本(如10K)提高数据准确性
  3. 结合 perf stat 查看整体系统指标
  4. 检查是否有锁竞争或I/O等待问题