深度解析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简介
事件可以分为三种:
- Hardware Event由PMU部件产生,在特定的条件下探测性能事件是否发生以及发生的次数。比如cache命中。
- Software Event是内核产生的事件,分布在各个功能模块中,统计和操作系统相关性能事件。比如进程切换,tick数等。
- 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 | 精度级别 |
参考资料: