Linux 性能调优必备:perf 使用指南

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

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

本文目录如下:


  • 安装 perf

  • 基本使用

    • 列出可用事件

    • 记录性能数据

    • 分析性能数据

  • 使用示例

  • 其他功能

  • 高级用法

  • 注意事项

  • 可能遇到的问题

    • 问题1

    • 问题2


安装 perf

在大多数 Linux 发行版中,perf 工具通常包含在 linux-tools 包中。你可以使用相应的包管理器来安装它。例如,在基于 Debian 的系统上,可以使用以下命令:

sudo apt-get install linux-tools-common linux-tools-generic

在 Red Hat/CentOS 系统上:

sudo yum install perf

基本使用

列出可用事件

列出所有可用的性能事件。这些事件包括硬件事件(如 CPU 周期、缓存命中/未命中等)和软件事件(如上下文切换、系统调用等)。

perf list

记录性能数据

使用 perf record 命令来记录目标程序的性能数据。

perf record -g -a -F 99  sleep 6

-g 表示记录调用栈,-a 表示对所有 CPU 进行采样,-F 99 表示每秒采样 99 次,sleep 6 是要分析的程序。

这会生成一个 perf.data 文件,它包含了采集的性能数据,也可以用 -o 来指定生成的文件名。

可以指定要分析的事件类型,例如 CPU 时钟周期、缓存命中等。

perf record -e cpu-clock -a sleep 6

还支持跟踪点(tracepoints),这是一种在内核中预定义的事件,可以用来跟踪系统调用等。

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

(常用的)可选参数:

  1. -e:选择性能事件。可以是 CPU 周期、缓存未命中等。使用 perf list 命令来查看所有可用的事件。

  2. -a:记录整个系统的性能数据,而不仅仅是一个进程。这对于分析系统级的性能问题非常有用。

  3. -p:记录指定进程的性能数据。只关注某一个特定进程。

  4. -t:记录指定线程的性能数据。用于分析多线程程序中某个特定线程的性能。

  5. -o:指定输出文件名。默认情况下,perf 会将数据保存在当前目录下的 perf.data 文件中。

  6. -g:记录函数调用关系(调用栈)。这对于分析程序中函数调用和热点非常有帮助。

  7. -c:设置事件的采样周期。例如,每发生1000次事件采样一次。

  8. -F:设置事件的采样频率。例如,每秒采样1000次。

每个参数的使用取决于你的具体需求。例如,如果你想对整个系统进行性能分析,可以使用 -a 参数;如果你想专注于分析特定的进程或线程,可以使用 -p-t。同样,-g 对于理解程序的函数调用关系非常重要,尤其是在定位性能热点时。

在实际使用中,一开始可以只用 perf record ./your_program 来进行简单的性能记录,然后慢慢尝试添加不同的参数来满足更具体的需求。

分析性能数据

使用 perf report 来分析记录的数据:

perf report

可以用 -i 指定要分析的性能数据

这将展示一个交互式的报告,你可以使用键盘导航来查看不同的视图。

使用示例

下面是一个简单的 C++ 程序示例,它创建了一个 std::vector 并使用 push_backemplace_back 方法向其中添加元素。这个程序将允许你比较这两种方法在性能上的差异。

#include <iostream>
#include <vector>
#include <chrono>

class ComplexObject {
public:
    ComplexObject(int value) : value_(value) {
        //std::cout << "ComplexObject(" << value_ << ") constructedn";
    }
    ~ComplexObject() {
        //std::cout << "ComplexObject(" << value_ << ") destroyedn";
    }

    int value_;
};

int main() {
    std::vector<ComplexObject> vec;

    // 使用 push_back 添加元素
    auto start_push_back = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 10000000; ++i) {
        vec.push_back(ComplexObject(i));
    }
    auto end_push_back = std::chrono::high_resolution_clock::now();
    std::chrono::duration<doublestd::milli> push_back_time = end_push_back - start_push_back;
    std::cout << "Time taken by push_back: " << push_back_time.count() << " msn";

    // 清空 vector 以便重新测试 emplace_back
    vec.clear();

    // 使用 emplace_back 添加元素
    auto start_emplace_back = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 10000000; ++i) {
        vec.emplace_back(i);
    }
    auto end_emplace_back = std::chrono::high_resolution_clock::now();
    std::chrono::duration<doublestd::milli> emplace_back_time = end_emplace_back - start_emplace_back;
    std::cout << "Time taken by emplace_back: " << emplace_back_time.count() << " msn";

    return 0;
}

在这个例子中,ComplexObject 类有一个构造函数,它接受一个整数参数并存储它。构造函数和析构函数都会输出一条消息,以便我们可以看到对象的创建和销毁。我们将创建 1000 万个这样的对象,并比较 push_backemplace_back 的性能。

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

要编译和运行这个程序,我们需要一个支持 C++11 或更高版本的编译器。在命令行中使用以下命令:

g++ -std=c++11 -o vector_test vector_test.cpp
./vector_test

(可以通过 -g 选项添加调试信息,-O0 禁用了优化,以便更容易分析代码行为。)

这将编译程序并运行生成的 vector_test 可执行文件。

现在,我们将使用 perf 来分析这个程序的性能。首先,确保你有足够的权限来运行 perf。然后,使用以下命令来记录性能数据:

perf record ./vector_test

运行结束后,使用 perf report 查看性能报告:在报告中,你能会看到不同函数的调用次数、执行时间等信息。

Linux 性能调优必备:perf 使用指南

进入交互界面后,

  • 可以通过键盘的上下左右键移动,回车键选择并进入一个函数或代码区块,“q” 键退出 perf report 的交互界面。
  • “h” 或 “?” 键:显示帮助菜单,列出所有可用的键盘快捷键和它们的功能。

其他功能

perf 提供了许多其他工具,如 perf stat(显示程序运行时的性能统计信息),perf top(实时显示性能热点),perf annotate(显示源代码级别的性能分析)等。

  1. 实时性能监控:

使用 perf top 查看实时性能数据:

perf top

这类似于 top 命令,但提供了更详细的性能信息。

  1. 使用注解(Annotate):

对特定函数或代码行进行性能分析:

perf annotate <function_name>

这将显示该函数内部的详细 CPU 周期分布。

  1. 事件计数:

统计特定事件(例如缓存未命中)的发生次数:

perf stat -e cache-misses ./my_program

高级用法

  • 使用 perf 与调试符号:

    为了获得更详细的信息(例如函数名和源代码行号),确保你的程序带有调试符号。

  • CPU Cache 分析:

    分析缓存使用情况,了解缓存未命中等事件。

  • 硬件计数器:

    利用 CPU 的硬件计数器来分析诸如分支预测错误等底层事件。

  • 跟踪系统调用:

    使用 perf trace 跟踪系统调用及其耗时。

  • 脚本接口

    perf 提供了脚本接口,可以用来生成自定义报告。

注意事项

  • 在使用 perf 之前,你可能需要调整 perf_event_paranoidkptr_restrict 设置,以允许非特权用户使用性能分析功能。

  • perf 的功能非常强大,这里只是介绍了一些基本用法。要深入了解 perf,建议阅读官方文档和手册页(man perfman perf-record等)。

  • 官方文档:Perf 的官方文档通常包含在 Linux 内核源码中,可以在 Linux 内核的 Documentation/perf 目录下找到。你也可以在 Linux 发行版的官方文档网站上查找 Perf 的相关信息。

可能遇到的问题

问题1

ubuntu@VM-4-2-ubuntu:~/repos/tmp$ perf record ./a.out
Error:
Access to performance monitoring and observability operations is limited.
Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open
access to performance monitoring and observability operations for processes
without CAP_PERFMON, CAP_SYS_PTRACE or CAP_SYS_ADMIN Linux capability.
More information can be found at 'Perf events and tool security' document:
https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html
perf_event_paranoid setting is 4:
-1: Allow use of (almost) all events by all users
Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
>= 0: Disallow raw and ftrace function tracepoint access
>= 1: Disallow CPU event access
>= 2: Disallow kernel profiling
To make the adjusted perf_event_paranoid setting permanent preserve it
in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>)

根据你提供的错误信息,你的系统上的 perf_event_paranoid 设置为 4,这意味着除了具有特定 Linux 能力的进程外,所有用户都无法使用性能监控和可观察性操作。这是 Linux 内核为了安全起见而设置的一个限制,以防止未授权的用户访问可能包含敏感信息的性能数据。

要解决这个问题,你有几个选项:

  1. 临时调整 perf_event_paranoid 设置:

    你可以临时降低 perf_event_paranoid 的值,以允许当前用户使用 perf 工具。

    例如,你可以将值设置为 -1(最不安全,允许所有用户使用所有事件),或者设置为 0(允许所有用户使用除原始跟踪点和 ftrace 函数跟踪点之外的所有事件)。

使用以下命令临时更改设置:

sudo sysctl -w kernel.perf_event_paranoid=-1

或者,如果你只想允许使用用户空间事件:

sudo sysctl -w kernel.perf_event_paranoid=0

  1. 永久调整 perf_event_paranoid 设置:

    如果你想要永久更改这个设置,你可以在 /etc/sysctl.conf 文件中添加或修改相应的行。

例如:

kernel.perf_event_paranoid=-1

或者,如果你只想允许用户空间事件:

kernel.perf_event_paranoid=0

然后运行 sudo sysctl -p 来应用更改。

  1. 使用具有适当能力的进程: 如果你有权限,你可以使用具有 CAP_PERFMON、CAP_SYS_PTRACE 或 CAP_SYS_ADMIN 能力的进程来运行 perf 工具。这通常意味着你需要以 root 用户身份运行 perf,或者为特定用户或组设置这些能力。

请注意,降低 perf_event_paranoid 的值可能会增加系统安全风险,因为它允许更多类型的性能监控。在生产环境中,你应该谨慎考虑这种权衡,并确保只有信任的用户和进程能够访问这些性能数据。

问题2

Kernel address maps (/proc/{kallsyms,modules}) were restricted.   │
│ │
│Check /proc/sys/kernel/kptr_restrict before running 'perf record'.│
│ │
│As no suitable kallsyms nor vmlinux was found, kernel samples │
│can't be resolved. │
│ │
│Samples in kernel modules can't be resolved as well. │
│ │
│ │
│ │
│Press any key... │
└───────────────────────

错误信息表明,

由于 /proc/sys/kernel/kptr_restrict 设置的值,内核符号(kallsyms)和模块的地址映射被限制了。这通常是为了提高系统安全性,防止内核指针被用户空间程序访问,因为这些指针可能包含敏感信息。

当你尝试使用 perf record 来收集性能数据时,如果无法解析内核样本,你将无法得到有关内核函数和模块的详细信息。为了解决这个问题,你可以采取以下步骤:

  1. 临时调整 kptr_restrict 设置:

你可以临时更改 kptr_restrict 的值,以允许 perf 工具访问内核指针。这可以通过运行以下命令来完成:

sudo sysctl -w kernel.kptr_restrict=0

这将设置 kptr_restrict 为 0,允许所有用户访问内核指针。

  1. 永久调整 kptr_restrict 设置:

如果你想要永久更改这个设置,可以在 /etc/sysctl.conf 文件中添加或修改相应的行:

kernel.kptr_restrict=0

然后运行 sudo sysctl -p 来应用更改。

  1. 使用 vmlinux 文件:

如果你的系统上有 vmlinux 文件,perf 工具可以使用它来解析内核样本。通常,这个文件位于 /boot 目录下。确保 vmlinux 文件与当前运行的内核版本相匹配。如果 vmlinux 文件不存在或过时,你可能需要更新它。

  1. 考虑安全性:

降低 kptr_restrict 的值会降低系统的安全性。在生产环境中,你应该权衡性能监控的需求与系统安全的需求。如果你不确定如何操作,或者这是在一个生产系统上,最好咨询系统管理员。


原文始发于微信公众号(楚人留香):Linux 性能调优必备:perf 使用指南

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/236995.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!