gpt4 book ai didi

xcode - Xcode Instrument 的反汇编时间分析的可靠性

转载 作者:行者123 更新时间:2023-12-04 08:47:23 24 4
gpt4 key购买 nike

我已经使用 Instrument 的时间分析器分析了我的代码,并放大了反汇编,这是其结果的片段:

Instrument Screenshot

我不希望 mov指令占用 23.3% 的时间,而 div指令采取几乎没有。
这让我相信这些结果是不可靠的。
这是真的吗?还是我只是遇到了 Instruments 错误?或者我需要使用一些选项来获得可靠的结果吗?

有没有关于这个问题的引用资料?

最佳答案

首先,可能有些计数确实属于 divss正在向以后的指示收费,which is called a "skid" . (有关更多详细信息,另请参阅该评论线程的其余部分。)大概 Xcode 类似于 Linux perf ,并使用固定的 cpu_clk_unhalted.thread专柜cycles而不是可编程计数器之一。这不是“精确”事件 (PEBS),因此可能会打滑。 As @BeeOnRope points out ,您可以使用每个周期滴答一次的 PEBS 事件(如 UOPS_RETIRED < 16 )作为固定周期计数器的 PEBS 替代品,从而消除对中断行为的一些依赖。

但是计数器从根本上用于流水线/乱序执行的方式也解释了您所看到的大部分内容。或者它可能;你没有显示完整的循环,所以我们不能像 IACA 那样在一个简单的管道模型上模拟代码,或者手动使用硬件指南,如 http://agner.org/optimize/和英特尔的优化手册。 (而且您甚至还没有指定您拥有什么微体系结构。我猜它是 Mac 上英特尔 Sandybridge 系列的某个成员)。

计数 cycles通常对等待结果的指令收费 ,通常不是产生结果很慢的指令。 在您尝试读取尚未准备好的结果之前,流水线 CPU 不会停止。

乱序执行使这一点变得非常复杂,但是当有一条非常慢的指令时,通常仍然如此,例如经常在缓存中未命中的加载。当cycles计数器溢出(触发中断),有许多指令在运行,但只有一个可以是与该性能计数器事件关联的 RIP。它也是中断后恢复执行的 RIP。

那么当中断发生时会发生什么?见 Andy Glew's answer关于这一点,它解释了英特尔 P6 微体系结构管道中性能计数器中断的内部原理,以及为什么(在 PEBS 之前)它们总是被延迟。 Sandybridge-family 在这方面类似于 P6。

我认为英特尔 CPU 上的性能计数器中断的合理心理模型是它丢弃任何尚未被分派(dispatch)到执行单元的微指令。但是已经被分派(dispatch)的 ALU uop 已经通过管道退出(如果没有任何年轻的 uop 被丢弃)而不是被中止,这是有道理的,因为 sqrtpd 的最大额外延迟约为 16 个周期。 ,并且刷新存储队列很容易花费比这更长的时间。 (已经退休的挂起商店不能回滚)。关于尚未退役的负载/存储的 IDK;至少负载可能会被丢弃。

我的猜测是基于这样一个事实,即很容易构建不显示 divss 的任何计数的循环。当 CPU 有时等待它产生输出时。如果它在没有退出的情况下被丢弃,它将是恢复中断时的下一条指令,因此(除了skids)您会看到很多计数。

因此, cycles的分布counts 显示哪些指令花费最多时间是调度程序中最旧的尚未调度的指令 . (或者在前端停顿的情况下,CPU 尝试获取/解码/发出哪些指令时停顿)。请记住,这通常意味着它会向您显示正在等待输入的指令,而不是生成它们的指令很慢。

(嗯, 这可能不正确 ,我还没有测试这么多。我通常使用 perf stat 在微基准测试中查看整个循环的总体计数,而不是使用 perf record 的统计配置文件. addssmulss 的延迟高于 andps ,所以如果我建议的模型是正确的,你会期望 andps 获得等待其 xmm5 输入的计数。)

总之,普遍的问题是,一次执行多个指令,当 cycles 时,哪个是硬件“责备”柜台环绕?

请注意 divss产生结果很慢,但只是一个单 uop 指令(与整数 div 不同,后者在 AMD 和 Intel 上微编码)。如果您没有在延迟或未完全流水线化的吞吐量方面遇到瓶颈,it's not slower than mulss 因为它也可以与周围的代码重叠。

( divss/divps 不是完全流水线化的。例如在 Haswell 上,一个独立的 divps 可以每 7 个周期启动一次。但每个只需要 10-13 个周期来产生它的结果。所有其他执行单元都是完全流水线化的;能够在每个周期对独立数据开始新的操作。)

考虑一个大循环,它对吞吐量造成瓶颈,而不是任何循环携带的依赖项的延迟,并且只需要 divss每 20 条 FP 指令运行一次。使用 divss由一个常量代替 mulss与倒数常数应该(几乎)没有性能差异。 (实际上,乱序调度并不完美,即使没有循环执行,更长的依赖链也会对某些人造成伤害,因为它们需要更多的指令在运行以隐藏所有延迟并维持最大吞吐量。即对于输出-of-order 核心以找到指令级并行性。)

无论如何,这里的重点是divss是一个单一的 uop 并且它没有为 cycles 获得很多计数是有意义的。事件,取决于周围的代码。

您会看到缓存未命中加载的相同效果:加载本身通常仅在必须等待寻址模式中的寄存器时才获得计数,并且依赖链中使用加载数据的第一条指令获得大量计数.

您的个人资料结果可能告诉我们什么 :

  • divss不必等待其输入准备就绪。 (movaps %xmm3, %xmm5 之前的 divss 有时需要一些周期,但 divss 永远不会。)
  • 我们可能会在 divss 的吞吐量上接近瓶颈
  • 涉及xmm5的依赖链之后 divss正在得到一些计数。乱序执行必须同时保持多个独立迭代。
  • maxss/movaps循环携带的依赖链可能是一个重要的瓶颈。 (特别是如果您在 Skylake 上,其中 divss 吞吐量是每 3 个时钟一个,但 maxss 延迟是 4 个周期。端口 0 和 1 的资源冲突将延迟 maxss。)

  • movaps 的高计数可能是由于以下 maxss ,在您显示的循环部分中形成唯一的循环携带依赖项。因此, maxss 是合理的产生结果确实很慢。但如果它真的是一个循环承载的 dep 链是主要瓶颈,你会期望在 maxss 上看到很多计数。本身,因为它将等待上次迭代的输入。

    但也许 mov-elimination 是“特殊的”,并且由于某种原因所有计数都被收取到 movaps ?在 Ivybridge 和更高版本的 CPU 上, register copies doesn't need an execution unit, but instead are handled in the issue/rename stage of the pipeline .

    关于xcode - Xcode Instrument 的反汇编时间分析的可靠性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48369347/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com