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
(常用的)可选参数:
-
-e
:选择性能事件。可以是 CPU 周期、缓存未命中等。使用 perf list
命令来查看所有可用的事件。 -
-a:记录整个系统的性能数据,而不仅仅是一个进程。这对于分析系统级的性能问题非常有用。
-
-p
:记录指定进程的性能数据。只关注某一个特定进程。 -
-t
:记录指定线程的性能数据。用于分析多线程程序中某个特定线程的性能。 -
-o
:指定输出文件名。默认情况下,perf 会将数据保存在当前目录下的 perf.data
文件中。 -
-g:记录函数调用关系(调用栈)。这对于分析程序中函数调用和热点非常有帮助。
-
-c
:设置事件的采样周期。例如,每发生1000次事件采样一次。 -
-F
:设置事件的采样频率。例如,每秒采样1000次。
每个参数的使用取决于你的具体需求。例如,如果你想对整个系统进行性能分析,可以使用 -a
参数;如果你想专注于分析特定的进程或线程,可以使用 -p
或 -t
。同样,-g
对于理解程序的函数调用关系非常重要,尤其是在定位性能热点时。
在实际使用中,一开始可以只用 perf record ./your_program
来进行简单的性能记录,然后慢慢尝试添加不同的参数来满足更具体的需求。
分析性能数据
使用 perf report
来分析记录的数据:
perf report
可以用 -i
指定要分析的性能数据
这将展示一个交互式的报告,你可以使用键盘导航来查看不同的视图。
使用示例
下面是一个简单的 C++ 程序示例,它创建了一个 std::vector
并使用 push_back
和 emplace_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<double, std::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<double, std::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_back
和 emplace_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
查看性能报告:在报告中,你能会看到不同函数的调用次数、执行时间等信息。

进入交互界面后,
-
可以通过键盘的上下左右键移动,回车键选择并进入一个函数或代码区块,“q” 键退出 perf report 的交互界面。 -
“h” 或 “?” 键:显示帮助菜单,列出所有可用的键盘快捷键和它们的功能。
其他功能
perf
提供了许多其他工具,如 perf stat
(显示程序运行时的性能统计信息),perf top
(实时显示性能热点),perf annotate
(显示源代码级别的性能分析)等。
-
实时性能监控:
使用 perf top
查看实时性能数据:
perf top
这类似于 top
命令,但提供了更详细的性能信息。
-
使用注解(Annotate):
对特定函数或代码行进行性能分析:
perf annotate <function_name>
这将显示该函数内部的详细 CPU 周期分布。
-
事件计数:
统计特定事件(例如缓存未命中)的发生次数:
perf stat -e cache-misses ./my_program
高级用法
-
使用 perf 与调试符号:
为了获得更详细的信息(例如函数名和源代码行号),确保你的程序带有调试符号。
-
CPU Cache 分析:
分析缓存使用情况,了解缓存未命中等事件。
-
硬件计数器:
利用 CPU 的硬件计数器来分析诸如分支预测错误等底层事件。
-
跟踪系统调用:
使用
perf trace
跟踪系统调用及其耗时。 -
脚本接口:
perf 提供了脚本接口,可以用来生成自定义报告。
注意事项
-
在使用
perf
之前,你可能需要调整perf_event_paranoid
和kptr_restrict
设置,以允许非特权用户使用性能分析功能。 -
perf
的功能非常强大,这里只是介绍了一些基本用法。要深入了解perf
,建议阅读官方文档和手册页(man perf
,man 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 内核为了安全起见而设置的一个限制,以防止未授权的用户访问可能包含敏感信息的性能数据。
要解决这个问题,你有几个选项:
-
临时调整 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
-
永久调整 perf_event_paranoid 设置:
如果你想要永久更改这个设置,你可以在 /etc/sysctl.conf 文件中添加或修改相应的行。
例如:
kernel.perf_event_paranoid=-1
或者,如果你只想允许用户空间事件:
kernel.perf_event_paranoid=0
然后运行 sudo sysctl -p
来应用更改。
-
使用具有适当能力的进程: 如果你有权限,你可以使用具有 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
来收集性能数据时,如果无法解析内核样本,你将无法得到有关内核函数和模块的详细信息。为了解决这个问题,你可以采取以下步骤:
-
临时调整 kptr_restrict 设置:
你可以临时更改 kptr_restrict 的值,以允许 perf 工具访问内核指针。这可以通过运行以下命令来完成:
sudo sysctl -w kernel.kptr_restrict=0
这将设置 kptr_restrict 为 0,允许所有用户访问内核指针。
-
永久调整 kptr_restrict 设置:
如果你想要永久更改这个设置,可以在 /etc/sysctl.conf 文件中添加或修改相应的行:
kernel.kptr_restrict=0
然后运行 sudo sysctl -p
来应用更改。
-
使用 vmlinux 文件:
如果你的系统上有 vmlinux 文件,perf 工具可以使用它来解析内核样本。通常,这个文件位于 /boot 目录下。确保 vmlinux 文件与当前运行的内核版本相匹配。如果 vmlinux 文件不存在或过时,你可能需要更新它。
-
考虑安全性:
降低 kptr_restrict 的值会降低系统的安全性。在生产环境中,你应该权衡性能监控的需求与系统安全的需求。如果你不确定如何操作,或者这是在一个生产系统上,最好咨询系统管理员。
原文始发于微信公众号(楚人留香):Linux 性能调优必备:perf 使用指南
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/236995.html