来自阿格纳雾的“优化装配”指南的12.7节:一个循环示例。讨论示例代码的段落之一是:
..。对奔腾M的分析:.每时钟3次,13次,每4.33c退休时间重复一次。 循环中有一个依赖链。延迟为:内存读取2次,乘法5次,减法3次,内存写入3次,共13个时钟周期。这是停用时间的三倍,但它不是循环携带的依赖,因为每个迭代的结果被保存到内存中,而不是在下一个迭代中重用。无序执行机制和流水线使得每个计算都可以在前面的计算完成之前开始。唯一的循环携带依赖链是
add eax,16,它的延迟仅为1。
## Example 12.6b. DAXPY algorithm, 32-bit mode
[...] ; not shown: initialize some regs before the loop
L1:
movapd xmm1, [esi+eax] ; X[i], X[i+1]
mulpd xmm1, xmm2 ; X[i] * DA, X[i+1] * DA
movapd xmm0, [edi+eax] ; Y[i], Y[i+1]
subpd xmm0, xmm1 ; Y[i]-X[i]*DA, Y[i+1]-X[i+1]*DA
movapd [edi+eax], xmm0 ; Store result
add eax, 16 ; Add size of two elements to index
cmp eax, ecx ; Compare with n*8
jl L1 ; Loop back我不明白为什么依赖链不增加整个吞吐量。我知道只有找到最严重的瓶颈才是最重要的。在考虑依赖链之前发现的最坏的瓶颈是融合域uop吞吐量,每次迭代4.33次。我不明白为什么依赖链不是比这更大的瓶颈。
add eax, 16 -> cmp eax, ecx -> jl L1必须在执行cmp之前执行加法,而cmp必须在jl之前执行。PS:后面的段落将奔腾M的最大瓶颈确定为解码,将其限制为每6c迭代一次,因为128 B向量ops每解码两个uop。有关分析的其余部分,请参阅Agner的指南,以及Core2、FMA4推土机和沙桥的分析+调优。
发布于 2016-04-21 03:15:31
mulpd insns。在这里,单个指令的延迟根本不是问题,而是依赖链。每一次迭代都有一个单独的13c依赖链,包括load、mulpd、subpd、store。无序执行是允许多个迭代的uop同时运行的原因。cmp / jl依赖于来自该迭代的add,但下一个迭代中的add不依赖于cmp。推测执行和分支预测意味着控制依赖项(条件分支和间接跳转/调用)不是数据依赖链的一部分。这就是为什么来自一个迭代的指令可以在前一个迭代的jl退出之前开始运行。
相比之下,cmov是一个数据依赖项,而不是一个控件依赖项,因此,无分支循环往往具有循环携带的依赖链。如果分支预测得好的话,这往往比分支的速度慢。
每个循环迭代都有一个独立的cmp/jl依赖链,就像FP依赖链一样。我不明白为什么依赖链没有增加整个吞吐量。
我不知道这句话是什么意思。我想我能弄清楚你的其他混淆词和措辞。(例如,“链依赖”而不是“依赖链”)。看看我对你问题的编辑,其中一些可能也有助于你的理解。
https://stackoverflow.com/questions/36739118
复制相似问题