第13章 perf:先确定问题像 CPU 和调用栈,再让 perf 上场

perf 适合在问题已经收窄后补采样证据,不适合在问题尚未定义时充当起手工具。

本页目录

perf 很强,但它不是默认起手工具

第 13 章先把 perf 放回正确位置。它最擅长的,是 CPU 视角下的热点、调用栈和硬件事件。

如果问题还没缩小到这一层,perf 很容易给你一张很漂亮、但解释链并没有闭合的图。

perf 最适合回答什么

下面这些问题,更适合让 perf 上场:

  • CPU 时间主要花在哪
  • 哪段调用栈最热
  • 某类硬件事件是不是异常集中
  • on-CPU 视角下最值得继续看的代码路径是什么

这类问题里,perf 的价值很高。

perf 最不适合直接回答什么

下面这些问题,perf 通常不够:

  • 线程到底在等什么
  • 完整请求路径是怎么走的
  • 因果链是怎么连起来的
  • 某段等待为什么形成

如果你拿 perf 去直接回答这些问题,结论很容易飘。

别把热点直接当根因,也别让火焰图替你收口结论

最常见的错法有四种:

  • 火焰图一出来,就直接宣布根因
  • 把 on-CPU 样本当成整体时间分布
  • 明明问题更像等待,还继续死磕 perf
  • 已经知道 perf 解释不动了,还不愿意换工具

这些错法都把“热点”直接翻译成“根因”。

什么时候该停下 perf,换别的证据

出现下面这些情况时,继续深挖 perf 的收益通常已经不高:

  • 你已经知道哪里热了,但不知道为什么慢
  • 你怀疑主要时间其实花在等待上
  • 你需要的是请求路径和因果关系
  • 热点和整体症状一直接不起来

这时候该换 tracing、off-CPU 证据或更细的路径证据。

一个最典型的错法:火焰图很好看,但会议还在原地打转

现场里很常见:perf 跑完,火焰图也有了,热点函数也能点出来,结果会议里的争论一点没少。

这通常说明现在缺的不是“更细的热点”,而是别的证据:

  • 等待证据
  • 请求路径证据
  • 前后对照证据

如果还留在 perf 里打转,只会越来越像在看漂亮图。

先把热点、问题链和停手点写清

先写清 perf 只回答哪三类问题

以后上 perf 前,先确认自己问的是不是这三类:

  1. CPU 时间花在哪。
  2. 哪段调用栈最热。
  3. 哪类硬件事件异常集中。

如果问的不是这三类,先别急着上。

真正落命令时,还要死守一条顺序底线:先 perf stat,后 perf recordperf record 会疯狂往 perf.data 落盘,本身就可能制造巨大的存储 I/O 干扰;先用开销更低的 perf stat 摸清事件频率,才能判断后面的采样值不值得做。

热点接不上整体症状时,就及时换证据

一旦出现“热点很清楚,但解释不动整体慢”,就别继续往火焰图里钻。先换路径、等待或因果链证据。

如果你已经落到了 PMC 级别的硬件事件,还要再防一种更隐蔽的假热点:指令滑移(skid)。不带精确修饰符去抓底层事件,样本地址很可能会往后漂,最后把完全无关的下游代码点成热点;这类场景至少要考虑 cycles:ppp 这类更精确的事件修饰。

perf 结果默认先当缩小方向,不当最终结论

perf 最稳的用法,是先缩小方向,再决定后面补什么,不是直接拿它当裁判。

火焰图回答不动时,再看内核路径

第 13 章解决的是“perf 该回答什么”。第 14 章接着解决“当问题已经落到内核路径里时,Ftrace 该怎么上场”。