通过perf测试进程的内存带宽

perf的基本原理

Perf 是内置于 Linux 内核源码树中的性能剖析(profiling)工具。它基于事件采样原理,以性能事件为基础,支持针对处理器相关性能指标与操作系统相关性能指标的性能剖析,可用于性能瓶颈的查找与热点代码的定位。

以监测“cycles”事件为例,perf的工作过程如下:
首先,perf 会通过系统调用sys_perf_event_open在内核中注册一个监测“cycles”事件的性能计数器。内核根据perf提供的信息在PMU(Performance Monitoring Unit)上初始化一个硬件性能计数器(PMC:Performance Monitoring Counter)。PMC随着CPU周期的增加而自动累加。在PMC溢出时,PMU触发一个PMI(Performance Monitoring Interrupt)中断。内核在PMI中断的处理函数中保存PMC的计数值,触发中断时的指令地址(Register IP:Instruction Pointer),当前时间戳以及当前进程的PID,TID,comm等信息。我们把这些信息统称为一个采样(sample)。内核会将收集到的sample放入用于跟用户空间通信的Ring Buffer。用户空间里的perf分析程序采用mmap机制从Ring Buffer中读入采样,并对其解析。perf根据pid,comm等信息可以找到对应的进程。根据IP与ELF文件中的符号表可以查到触发PMI中断的指令所在的函数。

根据上述的perf采样原理可以得知,perf假设两次采样之间,即两次相邻的PMI中断之间系统执行的是同一个进程的同一个函数。这种假设会带来一定的误差,当读者感觉perf给出的结果不准时,不妨提高采样频率,perf会给出更加精确的结果。

perf list简介

事件可以分为三种:

  1. Hardware Event由PMU部件产生,在特定的条件下探测性能事件是否发生以及发生的次数。比如cache命中。
  2. Software Event是内核产生的事件,分布在各个功能模块中,统计和操作系统相关性能事件。比如进程切换,tick数等。
  3. Tracepoint Event是内核中静态tracepoint所触发的事件,这些tracepoint用来判断程序运行期间内核的行为细节,比如slab分配器的分配次数等。

性能事件的属性

硬件性能事件由处理器中的PMU提供支持。由于现代处理器的主频非常高,再加上深度流水线机制,从性能事件被触发,到处理器响应 PMI中断,流水线上可能已处理过数百条指令。那么PMI中断采到的指令地址就不再是触发性能事件的那条指令的地址了,而且可能具有非常严重的偏差。为了解决这个问题,Intel处理器通过PEBS机制实现了高精度事件采样。PEBS通过硬件在计数器溢出时将处理器现场直接保存到内存(而不是在响应中断时才保存寄存器现场),从而使得 perf能够采到真正触发性能事件的那条指令的地址,提高了采样精度。在默认条件下,perf不使用PEBS机制。用户如果想要使用高精度采样,需要在指定性能事件时,在事件名后添加后缀”:p”或”:pp”。
Perf在采样精度上定义了4个级别,如下表所示。

级别 描述
0 无精度保证
1 采样指令与触发性能事件的指令之间的偏差为常数(:p)
2 需要尽量保证采样指令与触发性能事件的指令之间的偏差为0(:pp)
3 保证采样指令与触发性能事件的指令之间的偏差必须为0(:ppp)
性能事件的精度级别

目前的X86处理器,包括Intel处理器与AMD处理器均仅能实现前 3 个精度级别。

除了精度级别以外,性能事件还具有其它几个属性,均可以通过”event:X”的方式予以指定。

标志 属性
u 仅统计用户空间程序触发的性能事件
k 仅统计内核触发的性能事件
h 仅统计Hypervisor触发的性能事件
G 在KVM虚拟机中,仅统计Guest系统触发的性能事件
H 仅统计 Host 系统触发的性能事件
p 精度级别
性能事件的属性

参考资料:

  1. Linux 的系统级性能剖析工具‐perf