参考:深入探索 perf CPU Profiling 实现原理,perfwiki,系统级性能分析工具perf的介绍与使用
perf 是由 Linux 官方提供的系统性能分析工具 。我们通常说的 perf 实际上包含两部分:
- perf 命令,用户空间的应用程序,是内核子系统 perf_events 的前端工具。
- perf_events ,Linux 内核中的一个子系统。
perf_events是Linux 2.6.31版本引入的内核子系统,可以提供多种来源的事件的性能计数器,供用户空间软件 perf 使用,完成性能分析(Performance profiling)。perf 和 perf_events 最初支持硬件计数器(performance monitoring counters,PMC),后来扩展到下列的多种事件源的支持。
perf_events 4类事件源:
-
Hardware Events::由CPU 性能计数器(performance counters)以及其内部的 Performance Monitoring Unit (PMU)获取,用来统计 Hardware event,例如 cpu-cycles、instructions executed 、cache-misses、branch mispredicted、周期数(the number of cycles)、退役指令(instructions retired), 缓存未命中(L1 cache misses L1 )等。这些 event 因每种处理器类型和型号而异。
注:Last Branch Record(LBR)是Intel CPU中最先引入的一个功能,记录最近执行过的分支指令,可以用来分析分支指令的执行情况,在perf list中,branch相关的功能也被划分到PMU分类,认为LBR的相关数据是通过PMU来获取的。
-
Software Events: 基于内核计数器的低优先级events, 例如, context-switches,CPU migrations(处理器迁移次数), minor faults(soft page faults),major faults(hard page faults)。
-
Tracepoints::由内核的 ftrace 实现的跟踪点事件,是散落在内核源代码中的一些 hook,用来调用probe函数。开启后,它们便可以在特定的代码被运行到时被触发,这一特性可以被各种 trace/debug 工具所使用。Perf 就是该特性的用户之一。假如您想知道在应用程序运行期间,内核内存管理模块的行为,便可以利用潜伏在 slab 分配器中的 tracepoint。当内核运行到这些 tracepoint 时,便会通知 perf。仅仅适用于2.6.3以及之后的 linux 内核。除了内核中的tracepoint,还有用户态中的,USDT(User-level statically-defined tracing)。
-
Dynamic Tracing: probe函数(探针or探测函数),kprobe(kernel probe)内核态探针,用来创建和管理内核代码中的探测点。Uprobes,user-probe,用户态探针,用来对用户态应用程序进行探测点的创建和管理,关于kprobe和uprobe可参考对应的内核文档。
下图显示了 perf 命令和 perf_events 的关系,以及 perf_events 支持的事件源。下面的分类和linux perf wiki上的perf_envent分类有些许不同,主要在与tracepoint的定义,下图包含了Static Tracing以及Dynamic Tracing。
图片来源:深入探索 perf CPU Profiling 实现原理
我们可以通过命令perf list
来查看perf支持的事件类型,但perf list
不能完全显示所有支持的事件类型,需要sudo perf list
。
同时还可以显示特定模块支持的perf事件:hw/cache/pmu都是硬件相关的;tracepoint基于内核的ftrace;sw(software)实际上是内核计数器。
下边列出一些sudo perf list
的输出例子:
1branch-instructions OR branches [Hardware event]2context-switches OR cs [Software event]3cpu-clock [Software event]4L1-dcache-load-misses [Hardware cache event]5L1-dcache-loads [Hardware cache event]6branch-instructions OR cpu/branch-instructions/ [Kernel PMU event]7block:block_bio_backmerge [Tracepoint event]
下图是很有名的brendan gregg的博客中的分类,他写了很多关于性能分析的书籍和博客。
图片来源:www.brendangregg.com/blog/2015-02-27/linux-profiling-at-netflix…、www.brendangregg.com/perf.html
原理
CPU 和其他硬件设备通常提供用于观测性能数据的 PMC。简单来说,PMC 就是 CPU 上的可编程寄存器,可通过编程对特定硬件事件进行计数。通过 PMC 可以监控和计算 CPU 内部各种事件,比如 CPU 指令的执行效率、CPU caches 的命中率、分支预测的成功率等微结构级别的性能信息。利用这些数据分析性能,可以实现各种性能优化。
perf 命令通过 perf_event_open(2) 系统调用访问 PMC,配置想要捕获的硬件事件。PMC 可以在两种模式下使用:
- Counting(计数模式),只报告Hardware Event、Software Events、PMU计数等。相关命令perf stat。开销几乎为零。
- Sampling(采样模式),当发生一定数量的事件后,会触发一个中断,以便捕获系统的状态信息。perf将事件数据缓存到一块buffer中,然后异步写入到perf.data文件中。使用perf report等工具进行离线分析。可用于采集代码路径。
- bpf:Kernel 4.4+新增功能,可以提供更多有效filter和输出总结。
下面详细介绍一下 Sampling 模式:
Perf 通过系统调用 sys_perf_event_open 陷入到内核中,内核根据 perf 提供的信息在PMU(Performance Monitoring Unit)上初始化一个硬件性能计数器(PMC: Performance Monitoring Counter)。PMC随着指定硬件事件的发生而自动累加。如果不触发溢出中断,则就是counting模式,例如 perf stat模式。
在PMC 溢出时,PMU触发一个PMI(Performance Monitoring Interrupt)中断。内核在PMI 中断的处理函数中保存PMC的计数值,触发中断时的指令地址,当前时间戳以及当前进程的PID、TID、comm 等信息。我们把这些信息统称为一个采样(sample)。内核会将收集到的sample放入用于跟用户空间通信的Ring Buffer。用户空间里的perf分析程序采用mmap机制从ring buffer中读入采样,并对其解析。
下图从系统调用和数据结构的层面展示了用户空间如何获取PMU信息的流程。还有一张类似的图,是来自阿里的pdf中的,被其他博客转载,或者重绘后使用,其大体内容和下图是一致的。pdf地址:类似图
图片来源:plantegg.github.io/2021/05/16/Perf_IPC%E4%BB%A5%E5%8F%8ACPU%E5%8…
使用
关于 perf 的详细使用,参考:系统级性能分析工具perf的介绍与使用