perf 是内置于 Linux 内核源码树中的性能剖析(profiling)工具。

它基于事件采样原理,以性能事件为基础,支持针对处理器相关性能指标与操作系统相关性能指标的性能剖析。常用于性能瓶颈的查找与热点代码的定位。


1. 安装 perf

在大多数 Linux 发行版中,perf 工具包含在 linux-tools 包中。可以通过包管理器安装:

  • Debian/Ubuntu:
sudo apt-get install linux-tools-common linux-tools-generic
  • Red Hat/CentOS:
sudo yum install perf
2. 基本使用
列出可用事件

列出所有可用的性能事件(包括硬件和软件事件):

perf list

在这里插入图片描述

记录性能数据

记录目标程序的性能数据。例如,以99Hz频率对所有CPU采样并记录调用栈信息6秒:

perf record -g -a -F 99 sleep 6

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以指定特定事件类型来分析,如CPU时钟周期、缓存命中等:

perf record -e cpu-clock -a sleep 6

在这里插入图片描述

跟踪点用于跟踪系统调用等预定义事件:

perf record -e 'syscalls:sys_enter_*' -a sleep 6

在这里插入图片描述

perf record 的可选参数

参数描述示例备注
-e选择性能事件。可以是 CPU 周期、缓存未命中等。使用 perf list 命令来查看所有可用的事件。perf record -e cpu-clock ./your_program适用于指定要监控的性能事件类型
-a记录整个系统的性能数据,而不仅仅是一个进程。这对于分析系统级的性能问题非常有用。perf record -a sleep 6允许对整个系统的性能进行剖析
-p <pid>记录指定进程的性能数据。只关注某一个特定进程。perf record -p 12345 sleep 6<pid> 是目标进程的进程ID
-t <tid>记录指定线程的性能数据。用于分析多线程程序中某个特定线程的性能。perf record -t 12345 sleep 6<tid> 是目标线程的线程ID
-o <file>指定输出文件名。默认情况下,perf 会将数据保存在当前目录下的 perf.data 文件中。perf record -o my_output.data ./your_program自定义性能数据的存储位置
-g记录函数调用关系(调用栈)。这对于分析程序中函数调用和热点非常有帮助。perf record -g ./your_program提供了函数调用链的信息,有助于理解代码执行路径
-c <count>设置事件的采样周期。例如,每发生1000次事件采样一次。perf record -c 1000 ./your_program控制基于计数器的采样频率
-F <frequency>设置事件的采样频率。例如,每秒采样1000次。perf record -F 1000 ./your_program控制基于时间的采样频率

使用建议

  • 系统级分析:如果你希望对整个系统进行性能分析,可以使用 -a 参数。
  • 特定进程/线程分析:对于专注于分析特定的进程或线程的情况,分别使用 -p-t 参数。
  • 函数调用关系:当需要理解程序的函数调用关系,尤其是在定位性能热点时,-g 参数非常重要。
  • 简单开始:在实际使用中,一开始可以只用 perf record ./your_program 来进行简单的性能记录,然后根据具体需求添加不同的参数。
分析性能数据

使用 perf report 分析记录的数据,默认读取当前目录下的 perf.data 文件。可使用 -i 指定其他文件。


3. 使用示例

一个简单的 C++ 程序比较 push_backemplace_back 的性能差异。编译和运行后,使用 perf 工具进行性能分析。

在这里插入图片描述

由于 emplace_back 避免了对象的复制,所以在这种情况下,它会显示出更好的性能。

在这里插入图片描述

  • push_back 的性能热点

  • ComplexObject::ComplexObject(int) 被频繁调用,且每次调用都伴随着内存分配和初始化。

  • 构造函数和析构函数的调用占用了大量 CPU 时间(例如,ComplexObject::ComplexObject(int) 占比 4.12%,ComplexObject::~ComplexObject() 占比 2.94%)。

  • std::vector::push_back 涉及到更多的复制或移动操作,这可能导致更高的开销。

在这里插入图片描述

  • ComplexObject::ComplexObject(int) 占比 4.71%,表示构造函数被频繁调用。
  • std::vector<ComplexObject, std::allocator<ComplexObject> >::~vector() 占比 3.53%,表示析构函数也被频繁调用。
  • void std::vector<ComplexObject, std::allocator<ComplexObject>>::push_back(ComplexObject const&) 占比 2.94%,这可能涉及到对象的复制或移动操作。

emplace_back 的性能优势

  • emplace_back 直接在向量中构造对象,减少了临时对象的创建和销毁,从而降低了构造函数和析构函数的调用次数。
  • 这种方式避免了不必要的复制或移动操作,因此通常会更快。
4. 其他功能
  • 实时性能监控: 使用 perf top 查看实时性能热点。
  • 注解(Annotate): 对特定函数或代码行进行源代码级别的性能分析。
  • 事件计数: 使用 perf stat 统计特定事件的发生次数。
5. 高级用法
  • 调试符号: 确保程序带有调试符号以获得更详细的信息。
  • CPU Cache 分析: 分析缓存使用情况。
  • 硬件计数器: 分析底层事件如分支预测错误。
  • 系统调用跟踪: 使用 perf trace 跟踪系统调用。
  • 脚本接口: 生成自定义报告。
6. 注意事项

调整 /proc/sys/kernel/perf_event_paranoid/proc/sys/kernel/kptr_restrict 设置,允许非特权用户使用性能分析功能。

7. 可能遇到的问题
问题1: perf_event_paranoid 设置限制

根据错误信息,可能需要降低 perf_event_paranoid 设置值,以允许当前用户使用 perf 工具。可以临时或永久调整此设置。

问题2: kptr_restrict 设置导致内核样本无法解析

由于 kptr_restrict 设置,内核符号被限制访问。可以临时或永久调整此设置,或者确保有匹配的 vmlinux 文件用于解析内核样本。

注意:调整这些设置可能会带来安全风险,应谨慎操作,并考虑生产环境中的安全性需求。

点击阅读全文
Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐