【问题标题】:Do (sampling) profilers still "lie" these days?这些天(采样)分析器是否仍然“撒谎”?
【发布时间】:2018-09-15 15:04:00
【问题描述】:

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

现在,我刚刚阅读了这篇博文:

How profilers lie: The case of gprof and KCacheGrind

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

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

【问题讨论】:

  • 您的问题有点令人困惑,因为链接问题中的第二个示例涉及 callgrind,它绝对不是采样分析器:它在虚拟机下运行您的进程并且可以记录有关每条指令/基本块/功能/任何内容的信息。在这样做的过程中,它将一切都减慢了一个数量级,因此引入了自己的一系列问题和扭曲。但是,它不是采样分析器。

标签: performance profiling performance-testing sampling gprof


【解决方案1】:

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

事实上,即使是这样写的,具体问题实际上更像是gprof 混合使用检测和采样,然后尝试重建一个基于假设调用图的方式在有限的调用者/被调用者信息上,并将其与采样的时序信息相结合。

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

即使在过去也是如此,所以我认为可以公平地说,抽样分析器作为一个群体从未真正表现出这个问题。

当然,剖析器仍然可以通过多种方式撒谎。例如,获得精确到指令级别的结果是一个非常棘手的问题,因为现代 CPU 一次有 100 条指令在运行,可能跨越许多功能,以及复杂的性能模型,其中指令可能具有非常不同的上下文成本到它们的标称延迟和吞吐量值。即使是那些棘手的问题也可以通过“硬件辅助”得到帮助,例如在最近的 x86 芯片上使用PEBS support 以及后来的相关功能,这些功能可以帮助您以较少偏见的方式精确定位指令。

【讨论】:

    【解决方案2】:

    如果你注意到了,我为你引用的那篇文章贡献了几个 cmets,但这不仅仅是分析器给你的错误信息,而是人们自欺欺人地知道实际的性能是什么。

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

    举例说明:例如,您可以在某个地方调用一个看起来很无辜的小函数,该函数恰好调用了 9 码的系统代码,包括读取 .dll 以提取字符串资源以使其国际化。这可能会占用挂钟时间的 50%,因此在堆栈上需要挂钟时间的 50%。 “CPU-profiler”会向您展示吗?不,因为几乎所有这 50% 都在做 I/O。您是否需要许多堆栈样本才能知道精确到小数点后 3 位需要多少时间?当然不是。如果您只有 10 个样本,那么将在其中 5 个样本上,给予或接受。一旦你知道小程序是一个大问题,这是否意味着你不走运是因为其他人写的?如果你知道它正在查找的字符串是什么?它真的需要国际化,以至于你愿意为此付出两倍的速度吗?当您的真正问题是定性地了解什么需要时间时,您是否看到测量是多么无用?

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

    【讨论】:

    • 回答您的反问:我想了解我的代码的行为方式以及在多少时间内正在完成什么样的工作。在您的示例中,具有足够广泛信息收集的 CPU 分析器将向我显示哪些系统调用(以及这些调用的哪些常见部分参数组合)占用了大量时间 - 不仅如此,哪些代码行进行了这些系统调用;然后我可能会发现我花了一半的时间从文件中读取国际化字符串。知道了这一点,我要么收工,要么决定我想做...
    • ... 关于(例如将工作移到单独的线程中,或以某种方式缓存这些字符串等)
    • 并且“您是否需要很多堆栈样本才能知道精确到小数点后 3 位需要多少时间?” - 你误会了。我需要许多堆栈样本才能知道直到 first 个小数点为止不同堆栈状态所花费的时间,因为状态空间要大得多。
    • @einpoklum:@einpoklum:this link 可能有助于解释它在统计上是如何工作的。
    【解决方案3】:

    关于 gprof,是的,今天仍然如此。这是设计使然,以保持较小的分析开销。来自最新的documentation

    调用图中的一些数字是估计值,例如, 调用者和子程序中的孩子时间值和所有时间数字 行。

    配置文件中没有关于这些测量的直接信息 数据本身。相反,gprof 通过做出假设来估计它们 你的程序可能是真的,也可能不是。

    所做的假设是每次调用任何 函数 foo 与调用 foo 的人无关。如果 foo 使用 5 总共几秒钟,对 foo 的调用中有 2/5 来自 a,然后是 foo 假设为 a 的孩子时间贡献了 2 秒。

    关于 KCacheGrind,自撰写本文以来,几乎没有什么变化。您可以查看change log 并查看最新版本于 2013 年 4 月 5 日发布,其中包含不相关的更改。也可以参考文章下Josef Weidendorfer的cmets(Josef是KCacheGrind的author)。

    【讨论】:

    • 所以,我为你的答案 +1 了,因为它很好地回答了我的问题,但这太糟糕了。
    • @einpoklum 您可能想查看other profilers。特别是 AMD 的 AMD CodeXL 和英特尔的 VTune Amplifier XE。 Microsoft 还提供了许多工具。我已经使用过这些工具并且对它们非常满意。
    • 在我描述的意义上,您网站的示例是否更好?他们是采样分析器吗?
    • @einpoklum 是的。它们都支持基于采样的分析。然而,在某些情况下可以使用仪器。我在 VTune 上写了一个series of articles,我计划在不久的将来写一个关于 Visual Studio 内置分析器的类似系列。这里的问题是 gprof 和 KCacheGrind 真的很旧并且没有定期维护。但我提到的那些仍在维护中,而且更先进。这就是我使用它们的原因。
    • 但是,这种设计在大多数采样分析器中并不标准,甚至不常见。典型的采样分析可能会捕获样本上的整个调用堆栈(perf 会,如果您要求的话)。这完全避免了这个问题。
    猜你喜欢
    • 1970-01-01
    • 2012-03-23
    • 2018-09-30
    • 2013-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多