我试图理解英特尔x86-64上SSE的不同MOV指令。
根据this,当你在两个寄存器之间移动数据时,你应该使用对齐的指令(MOVAPS,MOVAPD和MOVDQA),使用你正在操作的类型的正确指令。在将寄存器移入内存时使用MOVUPS/MOVAPS,反之亦然,因为类型在移入/移出内存时不会影响性能。
那么,有没有理由使用MOVDQU和MOVUPD呢?我在链接上得到的解释是错误的吗?
发布于 2018-02-11 04:42:12
摘要:我不知道最近有任何x86体系结构在使用“错误的”加载指令(即,加载指令后面跟着来自相反域的指令)时会产生额外的延迟。
以下是关于旁路延迟的Agner has to say说明,旁路延迟是在CPU中的不同执行域之间移动时可能导致的延迟(有时这些延迟是不可避免的,但有时它们可能是由于使用了这里所讨论的指令的“错误”版本而导致的):
Nehalem上的
数据旁路延迟在Nehalem上,执行单元分为五个“域”:
整型域处理通用寄存器中的所有操作。整数向量(SIMD)域处理向量寄存器中的整数操作。Fp域处理XMM和x87寄存器中的浮点操作。加载域处理所有内存读取。存储域会处理所有内存存储。当一个域中的操作的输出用作另一个域中的输入时,存在1或2个时钟周期的额外延迟。表8.2列出了这些所谓的旁路延迟。
对于在错误类型的数据上使用加载和存储指令,仍然没有额外的旁路延迟。例如,对整数数据使用MOVHPS可以方便地读取或写入XMM寄存器的上半部分。
最后一段的重点是我的,也是关键部分:旁路延迟不适用于Nehalem加载和存储指令。直观地说,这是有道理的:加载和存储单元专用于整个内核,并且必须以适合任何执行单元的方式提供结果(或将其存储在PRF中)-与ALU的情况不同,转发不存在相同的问题。
现在不再关心Nehalem了,但在Sandy Bridge/Ivy Bridge,Haswell和Skylake的部分中,你会发现域名与Nehalem的讨论相同,总体上延迟较少。因此,可以假设加载和存储不会受到基于指令类型的延迟的行为仍然存在。
我们也可以测试它。我写了一个这样的基准测试:
bypass_movdqa_latency:
sub rsp, 120
xor eax, eax
pxor xmm1, xmm1
.top:
movdqa xmm0, [rsp + rax] ; 7 cycles
pand xmm0, xmm1 ; 1 cycle
movq rax, xmm0 ; 1 cycle
dec rdi
jnz .top
add rsp, 120
ret
这将使用movdqa
加载值,对其执行整型域操作(pand
),然后将其移至通用寄存器rax
,以便在下一个循环中将其用作movdqa
地址的一部分。我还创建了其他3个与上面相同的基准测试,只是用movdqu
,movups
和movupd
替换了movdqa
。
Skylake-client (i7-6700HQ,最新微码)上的结果:
** Running benchmark group Vector unit bypass latency **
Benchmark Cycles
movdqa [mem] -> pxor latency 9.00
movdqu [mem] -> pxor latency 9.00
movups [mem] -> pxor latency 9.00
movupd [mem] -> pxor latency 9.00
在每种情况下,往返延迟都是相同的:9个周期,正如预期的那样:6+1+2个周期分别用于加载、pxor
和movq
。
所有这些测试都是在uarch-bench中添加的,以防您想在任何其他架构上运行它们(我对结果很感兴趣)。我使用命令行:
./uarch-bench.sh --test-name=vector/* --timer=libpfc
发布于 2018-02-09 23:15:56
请注意,您引用的有关SSE移动性能的链接已相当陈旧,可能仅适用于较老一代的英特尔硬件。我了解到,最近的微架构提高了性能,例如,在用于实际对齐数据的情况下,未对齐加载指令的性能。总而言之,简短的基准测试是适用于您拥有的特定硬件的有效信息的最佳来源。
https://stackoverflow.com/questions/40854819
复制相似问题