perf 是 Linux 下的一个性能分析工具,它可以利用处理器提供的性能计数器(Performance Counters)来监控系统和进程的各种事件。包括但不限于 CPU 周期、指令计数、缓存命中和失效情况等。此外,perf 也能够通过系统的 tracepoints,kprobes 和 uprobes 来追踪内核函数调用和用户空间的函数调用。
perf 的原理
perf 使用了 Linux 内核中的 Performance Counters for Linux (PCL) 子系统,这个子系统提供了硬件抽象层来访问 CPU 性能计数器。通过监听这些计数器,perf 能够监视不同类型的事件,例如:
CPU 周期
缓存引用与缓存未命中
上下文切换
CPU 迁移
分支预测未命中
当开启函数调用跟踪时,perf 可以使用 uprobes(用户空间探针)来挂钩到用户空间程序的任何函数上,并且使用 kprobes 来挂钩到内核空间的函数。它通过在目标函数的入口点注入断点指令(例如 INT 3 中断指令),当程序执行到这一点时会触发异常,从而允许 perf 记录函数调用事件。
示例
假设我们有如下 C++ 程序:
cpp
#include
#include <unistd.h>
void foo() {
std::cout << “Inside foo()” << std::endl;
}
int main() {
std::cout << “Inside main()” << std::endl;
foo();
sleep(2); // 系统调用
return 0;
}
保存为 example.cpp,编译并生成 example:
g++ -g example.cpp -o example
接着,我们可以使用 perf 来记录这个程序运行时的函数调用栈。首先,需要确保你有权限收集系统级的性能数据:
sudo sysctl -w kernel.perf_event_paranoid=1
然后,运行 perf 记录程序的运行情况:
sudo perf record -g ./example
这条命令启动了 perf 工具,-g 参数指示 perf 收集调用图数据(即函数调用关系)。perf 将会记录该程序的所有系统调用和用户空间的函数调用,并将这些信息保存到当前目录下的一个名为 perf.data 的文件中。
运行完成后,可以使用以下命令查看结果:
sudo perf report
perf report 会读取 perf.data 文件,展示一个交互式界面,列出所有采集到的事件和调用栈。在这里,你应该能看到 main 函数的调用,foo 函数的调用,以及 sleep 系统调用。
请注意,使用 perf 需要一定的权限,通常需要 root 权限或相应的能力设置。此外,如果你想完整地追踪函数调用,你可能需要确保编译你的程序时带有足够的调试信息(例如 -g 选项)。