当前位置: 首页 > 知识库问答 >
问题:

Xcode Instruments的拆卸时间分析的可靠性

薛烈
2023-03-14

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

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

在这个问题上有什么参考资料吗?

共有2个答案

鲁德佑
2023-03-14

这是真的和已知的吗?

是的,这是英特尔 x86 上的分析工具的已知问题。我已经在 Linux perf_events和英特尔 VTune 中观察到了这一点(花费的时间可疑地分配给看似无辜的指令)。其他人也在其他地方报道过。

对收集到的结果进行更好、更真实的可视化,将汇总每个基本块内的所有样本,并演示与基本块相关联的结果值,而不是其单个指令。不是百分之百的傻瓜证明,但有一点更好和诚实,

或者我需要使用某些选项来获得可靠的结果?

我不知道新的评测硬件,即基于Intel Processor Trace的工具(从Broadwell开始提供,但在Skylake中进行了改进),而不是旧的PEBS,是否会提供更准确的数据。我想人们需要先试用这些工具。

陆阳曜
2023-03-14

首先,一些真正属于divss的计数可能会被记入后面的指令,这称为“滑动”。(有关更多详细信息,请参阅该注释线程的其余部分。)可能Xcode类似于Linuxperf,并使用修复的cpu_clk_unhalted。线程计数器用于循环>,而不是其中一个可编程计数器。这不是一个“精确”事件(PEBS),因此可能出现打滑。正如@BeeOnRope所指出的,您可以使用一个PEBS事件,该事件每周期进行一次滴答(如UOPS_RETIRED

但是计数器基本上用于流水线/无序执行的方式也解释了您所看到的大多数情况。或者可能;您没有显示完整的循环,因此我们无法像IACA那样在简单的管道模型上模拟代码,也无法使用硬件指南(如http://agner.org/optimize/和Intel优化手册。(你甚至还没有指定你有什么微体系结构。我想这是Mac上的Intel Sandybridge家族的一员)。

周期的计数通常向等待结果的指令收费,而不是通常对产生结果速度较慢的指令收费。流水线 CPU 不会停止,直到您尝试读取尚未准备好的结果。

无序执行使这变得非常复杂,但是当有一个非常慢的指令时,它通常仍然是正确的,就像缓存中经常错过的负载一样。当周期计数器溢出(触发中断)时,有许多指令在传输中,但只有一个可以是与该性能计数器事件关联的 RIP。它也是RIP,在中断后执行将恢复。

那么引发中断时会发生什么呢?请参阅Andy Glew对此的回答,该回答解释了英特尔P6微架构管道中的性能计数器中断的内部结构,以及为什么(在PEBS之前)它们总是延迟。Sandybridge家族在这方面与P6相似。

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

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

因此,周期计数的分布显示了哪些指令花费的时间最长,是调度程序中最早的未调度指令。(或者在前端暂停的情况下,CPU在尝试获取/解码/发出指令时暂停)。请记住,这通常意味着它会向您显示等待输入的指令,而不是生成这些指令的速度较慢的指令。

(嗯,这可能不对,我还没有测试这么多。我通常使用perf统计来查看微量标记中整个循环的总体计数,而不是具有perf记录的统计图。添加修改的延迟比 andps 高,所以如果我提出的模型是正确的,你会期望 andps 获得等待其 xmm5 输入的计数。

总之,一般的问题是,对于同时执行的多条指令,当循环计数器环绕时,硬件“责备”哪一条?

请注意,divss生成结果的速度很慢,但只是一条单uop指令(不像整数div在AMD和Intel上进行微码)。如果您没有瓶颈其延迟或未完全流水线的吞吐量,它不会比mulss慢,因为它也可以与周围的代码重叠。

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

考虑一个大循环,它瓶颈是吞吐量,而不是任何循环携带依赖项的延迟,并且每20条FP指令只需要divss运行一次。使用divssby a constant而不是带有倒数常量的mulss应该不会(几乎)造成性能上的差异。(实际上无序调度并不完美,较长的依赖链甚至在没有循环的情况下也会造成一些伤害,因为它们需要更多的指令来运行,以隐藏所有延迟并维持最大吞吐量。也就是说,无序核心要找到指令级并行性。)

无论如何,这里的重点是divss是一个单一的uop,它不获取循环事件的许多计数是有意义的,具体取决于周围的代码

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

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

> < Li > < p > < code > divss 不必等待其输入准备就绪。(在< code>divss之前的< code>movaps %xmm3,%xmm5有时需要一些周期,但< code>divss从不需要。)

我们可能接近 divs 吞吐量的瓶颈

divss之后,涉及xmm5的依赖链得到了一些计数。无序执行必须工作以同时保持多个独立的迭代。

< code > maxss /< code > movaps 循环携带的依赖链可能是一个严重的瓶颈。(尤其是在Skylake上,< code>divss吞吐量是每3个时钟一次,而< code>maxss延迟是4个周期。端口0和1的资源冲突会延迟maxss。)

movaps 的高计数可能是由于它遵循 maxss,在您显示的循环部分中形成了唯一的循环携带依赖关系。因此,Maxss在产生结果方面确实很慢是有道理的。但是,如果它真的是一个循环携带的dep链,这是主要的瓶颈,你会期望看到对maxs本身的大量依赖,因为它将等待上次迭代的输入。

但也许mov消除是“特殊的”,并且出于某种原因,所有计数都被计入movaps?在Ivybridge和更高版本的CPU上,寄存器副本不需要执行单元,而是在管道的发布/重命名阶段处理。

 类似资料:
  • AWS S3 Web控制台列出了已删除的存储桶。选择桶并尝试清空或删除它会导致“清空桶”或“删除桶”模式确认按钮静默失败。 如果您单击桶并尝试上传文件,您会收到一条错误消息,“找不到错误数据”。如果您尝试创建一个文件夹,您会得到,“错误无法创建带名称的文件夹”。"如果尝试更改和属性、权限或管理,也会收到错误消息。 如果您尝试使用相同的名称创建一个bucket(可能是为了覆盖旧的bucket),则会

  • 我得到了下面的C代码: 我用gcc 4.8.2(在Ubuntu 14下)为x86-64编译它,它产生了这样的代码: 有些事情我看不懂。 一开始,我们推送了 rbp,并将 rsp 保存在 rbp 中。然后在堆栈的顶部(在%rbp处),我们保存了rbp。那么低于 rbp 的所有内容都是可用空间。 但是,然后我们将来自 edi 和 esi 的传递参数放在 -0x14(%rbp) 及以下位置。 但是为什么

  • 问题内容: 到目前为止,我已经看到许多可拆分的示例,但是由于某种原因,当它变得更加复杂时,我无法使其正常工作。我有一个Movie对象,该对象实现了Parcelable。本书对象包含一些属性,例如ArrayLists。执行ReadTypedList时,运行我的应用程序会导致NullPointerException!我真的不在这里 评论类: 如果有人能让我走上正确的道路,我将不胜感激,我已经花了很多时

  • 问题内容: 我一直在使用此功能来生成时间戳。我在堆栈溢出的某个地方找到了它。 它一直没有问题,但是我得到了EXC_BAD_INSTRUCTION: 由于该应用程序的开发即将完成,这让我感到震惊,突然间看到它引起了EXC_BAD_INSTRUCTION。这正在模拟器中运行,但是我设置了有效的日期和时间。 任何想法或建议或不胜感激。下面是回溯。 问题答案: 您的代码将在所有32位平台(例如iPhone

  • 海蓝(navy blue)是最为大众所接受的颜色之一。采用这种颜色的色彩组合可解释成可靠、值得信赖的色彩。这类组合也带有不可置疑的权威感。警官、海军军官或法官都穿着深色、稳定的海军蓝,以便在值勤时表现出统率、支配的权威感。 当海军蓝用红和金色来强调时,会变得较不严肃,但仍表达出坚定、有力量的感觉。 补色色彩组合 原色色彩组合 单色色彩组合 21 65 17 65 33 1 65 67 70 65

  • 以下代码的时间复杂度分析和空间复杂度分析是什么: 给定一个非空字符串和一个包含非空单词列表的字典,确定是否可以被分段为一个或多个字典单词的空格分隔序列。