性能不精确的调用图报告

Perf Imprecise Call-Graph Report

最近的 Intel 处理器提供了一项硬件功能(a.k.a., Precise Event-Based Sampling (PEBS))来访问 精确 一些关于 CPU 状态的信息采样 CPU 个事件(例如 e)。这是 Intel 64 and IA-32 Achitecture's Software Developer's Manual: Volume 3 的摘录:

18.15.7 Processor Event-Based Sampling (PEBS)

The debug store (DS) mechanism in processors based on Intel NetBurst microarchitecture allow two types of information to be collected for use in debugging and tuning programs: PEBS records and BTS records.

基于同参考的Chapter 17x86-64架构的DS格式如下: BTS Buffer 记录最后 N 执行的分支(N 取决于微架构),而 PEBS Buffer 记录以下寄存器: IIUC,设置了一个计数器,每个事件(e)的发生都会增加它的值。当计数器溢出时,将向这两个缓冲区添加一个条目。最后,当这些缓冲区达到一定大小时(BTS Absolute MaximumPEBS Absolute Maximum),将产生中断并将两个缓冲区的内容转储到磁盘。这会定期发生。 --call-graph dwarf 回溯数据似乎也在同一个处理程序中提取,对吗?

1) 这是否意味着 LBRPEBS (--call-graph --lbr) 状态完美匹配?

2) --call-graph dwarf 输出怎么样,它不是 PEBS 的一部分(在上面的参考中似乎很明显)? (有些RIP/RSP不匹配回溯)

准确地说,这里是一个LKML Thread,其中Milian Wolff表明第二个问题是,NO .但是我不完全明白原因是什么?

第一个问题的答案也是,NO(在跟帖后面的留言中表达为Andi Kleen ), 完全看不懂

3) 这是否意味着整个 DWARF 调用图信息已完全损坏?

上面的线程没有显示这一点,在我的实验中我没有看到任何 RIP 不匹配回溯。换句话说,我可以相信回溯的多数吗?

我不喜欢 LBR 方法,它本身可能不精确。它还限制了回溯的大小。虽然,here 是解决大小问题的补丁。但这是最近的,可能是假的。


更新:

  1. 您引用的手册部分谈论的是 BTS,而不是 LBR:它们不是一回事。 Later in that same thread 你引用 Andi Kleen 似乎表明 LBR 快照时间实际上是 PMI(运行处理程序的中断)的时刻而不是 PEBS 时刻。所以我认为所有三种堆栈方法都有相同的问题。

  2. DWARF 堆栈捕获肯定与 PEBS 条目不完全对应。 PEBS 事件在运行时由硬件记录,然后仅在一段时间后 CPU 被中断,此时堆栈被展开。如果 PEBS 缓冲区配置为只保存一个条目,这两个东西至少应该 close 如果幸运的话,PEBS IP 将在 same function 在处理程序运行时仍然位于堆栈的顶部。那样的话,堆栈基本上是正确的。由于 perf 在顶部向您显示了实际的 PEBS IP,加上捕获的帧下方的帧,因此在这种情况下最终可以正常工作。

  3. 如果运气不好,函数将在 PEBS 捕获和处理程序之间发生变化 运行。在这种情况下,您会得到一个没有意义的弗兰肯堆栈:顶层函数可能无法从第二个顶层函数(或其他函数)调用。它并没有完全损坏:只是除了顶部框架之外的所有内容都来自捕获 PEBS 堆栈后的某个点,而顶部框架来自 PEBS,或类似的东西。出于同样的原因,这也适用于 --call-graph fp

很可能您从未见过无效 IP,因为 perf 显示了 PEBS 示例中的 IP(这是整个线程的主题)。我想如果你查看原始样本,你可以看到 PEBS IP 和处理程序 IP,你可以看到它们通常不匹配。

总的来说,您可以相信“时间”或“周期”分析的回溯,因为它们在某种意义上是执行时间的准确采样表示:只是它们不对应于 PEBS 时刻,而是对应于某个时间后来(但为什么后来的时间比 PEBS 时间更糟)。基本上对于这种类型的分析,你根本不需要 PEBS。

如果您正在使用不同类型的事件,并且您想要对事件发生的位置进行细粒度的统计,这就是 PEBS 的用途。您通常不需要堆栈跟踪:只需顶部框架就足够了。如果您想要堆栈跟踪,请使用它们,但要知道它们来自稍后的某个时刻,或者使用 --lbr (if that works).