这些天(抽样)分析器仍然 "lie" 吗?

Do (sampling) profilers still "lie" these days?

我对分析本机代码的大部分有限经验是在 GPU 上而不是在 CPU 上,但我在未来看到了一些 CPU 分析...

现在,我刚读完这篇博客 post:

How profilers lie: The case of gprof and KCacheGrind

关于分析器如何测量以及它们向您显示的内容,如果您有兴趣区分不同的调用路径和在它们中花费的时间,这可能不是您所期望的。

我的问题是:今天(5 年后)仍然如此吗?也就是说,sampling 分析器(即那些不会严重减慢执行速度的分析器)是否仍然像 gprof 过去那样(或没有 --separate-callers=N 的 callgrind)?或者现在的分析器是否习惯于在采样时记录整个调用堆栈?

关于gprof,是的,今天依然如此。这是设计使然,以保持小的分析开销。来自 up-to-date documentation:

Some of the figures in the call graph are estimates—for example, the children time values and all the time figures in caller and subroutine lines.

There is no direct information about these measurements in the profile data itself. Instead, gprof estimates them by making an assumption about your program that might or might not be true.

The assumption made is that the average time spent in each call to any function foo is not correlated with who called foo. If foo used 5 seconds in all, and 2/5 of the calls to foo came from a, then foo contributes 2 seconds to a’s children time, by assumption.

关于 KCacheGrind,自撰写本文以来几乎没有变化。可以查看KCacheGrind的change log and see that the latest version was published in April 5, 2013, which includes unrelated changes. You can also refer to Josef Weidendorfer's comments under the article (Josef is the author)。

如果您注意到了,我对您引用的 post 发表了一些评论,但这不仅仅是分析器给您提供了错误的信息,而是人们自欺欺人地了解性能到底是什么。

你的目标是什么?是为了 A) 找出如何使程序尽可能快吗?或者是 B) 测量各种功能所花费的时间,希望这会导致 A? (提示 - 它没有。)Here's a detailed list of the issues.

举例说明:例如,您可以在某处调用一个很小的 ​​innocent-looking 小函数,该函数恰好调用九码系统代码,包括读取 .dll 以提取字符串资源以实现国际化它。这可能会占用 wall-clock 时间的 50%,因此在堆栈中占 wall-clock 时间的 50%。 "CPU-profiler" 会给你看吗?不,因为实际上这 50% 的人都在做 I/O。您是否需要很多堆栈样本才能知道精确到小数点后三位到底花费了多少时间?当然不是。如果您只有 10 个样本,则将在其中的 5 个样本上,给予或接受。一旦您知道极小的例程是一个大问题,这是否意味着您运气不好,因为它是别人写的?如果您知道它正在查找的字符串是什么怎么办?它真的需要国际化,以至于您愿意为此付出两倍的速度吗?当您真正的问题是定性地理解什么需要时间时,您知道测量是多么无用吗?

我可以继续举这样的例子...

不,许多现代采样分析器不会出现关于 gprof 所描述的问题。

事实上,即使在写下这些内容时,具体问题实际上更像是 gprof 混合使用仪器和采样然后尝试重建 假设 基于有限 caller/callee 信息的调用图,并将其与采样的时序信息相结合。

现代采样分析器,例如 perf、VTune 和各种针对不编译为本机代码的语言的特定语言分析器,可以捕获每个样本的完整调用堆栈,从而提供准确的时间关于那个问题。或者,您可以在不收集调用堆栈的情况下进行采样(这会大大降低采样成本),然后在没有任何 caller/callee 信息的情况下呈现信息,这仍然是准确的。

即使在过去,这在很大程度上也是正确的,所以我认为可以公平地说,采样分析器作为一个整体从未真正表现出该问题。

当然,侧写者仍然可以通过多种方式撒谎。例如,让结果精确到指令级别是一个非常棘手的问题,因为现代 CPU 有 100 条指令同时运行,可能跨越许多功能,以及复杂的性能模型,其中指令可能具有非常不同的上下文成本到他们的标称延迟和吞吐量值。即使是棘手的问题也可以通过 "hardware assist" 来解决,例如最近的 x86 芯片 PEBS support 和后来的相关功能,可以帮助您以更不偏不倚的方式确定指令。