为什么SSE对齐读取+ shuffle比某些CPU上的未对齐读取慢,而对其他CPU没有?

时间:2014-04-22 07:11:49

标签: performance optimization x86 sse simd

在尝试优化我的有限差分代码所需的未对齐读取时,我更改了这样的未对齐加载:

__m128 pm1 =_mm_loadu_ps(&H[k-1]);

进入这个对齐的read + shuffle代码:

__m128 p0   =_mm_load_ps(&H[k]);
__m128 pm4  =_mm_load_ps(&H[k-4]);
__m128 pm1  =_mm_shuffle_ps(p0,p0,0x90);   // move 3 floats to higher positions
__m128 tpm1 =_mm_shuffle_ps(pm4,pm4,0x03); // get missing lowest float
       pm1  =_mm_move_ss(pm1,tpm1);        // pack lowest float with 3 others

其中H是16字节对齐的; H[k+1]H[k±3]movlhps&也有类似的变化movhlps的{​​{1}}优化(here是循环的完整代码。)

我发现在我的Core i7-930上,阅读H[k±2]的优化似乎很有成效,而为H[k±3]添加下一个优化会减慢我的循环(以百分比为单位)。在±1±1优化之间切换并未改变结果。

同时,在Core 2 Duo 6300和Core 2 Quad上,两种优化(±3±1)都提升了性能(提高了几十个百分点),而Core i7-4765T则提升了性能这些减慢了(以百分比为单位)。

在Pentium 4上,所有尝试优化未对齐读取的行为,包括那些±3 / movlhps的读取都会导致速度减慢。

为什么不同的CPU会如此不同?是因为代码大小的增加使循环可能不适合某些指令缓存?或者是因为某些CPU对未对齐的读取不敏感,而其他CPU则更敏感?或者某些CPU上的shuffle这样的动作很慢?

2 个答案:

答案 0 :(得分:5)

每两年,英特尔推出一种新的微体系结构。执行单元的数量可以改变,先前只能在一个执行单元中执行的指令可以在较新的处理器中具有2或3个。指令的延迟可能会改变,就像添加shuffle执行单元一样。

英特尔详细介绍了他们的优化参考手册,这里是链接,下面我复制了相关章节。

http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf

部分 3.5.2.7浮点/ SIMD操作数

  

来自存储器指令的MOVUPD执行两次64位加载,但需要额外的μops来调整地址并将负载组合到一个寄存器中。使用MOVSD XMMREG1,MEM可以获得相同的功能; MOVSD XMMREG2,MEM + 8; UNPCKLPD XMMREG1,XMMREG2,它使用更少的μops,可以更有效地打包到跟踪缓存中。已经发现后一种替代方案在某些情况下提供了几个百分点的性能改进。它的编码需要更多的指令字节,但这对于奔腾4处理器来说很少是个问题。 MOVUPD的商店版本复杂而且速度慢,因此应始终使用具有两个MOVSD和UNPCKHPD的序列。

     

汇编/编译器编码规则44。(ML影响,L一般性)使用MOVSD XMMREG1,MEM,而不是使用MOVUPD XMMREG1,MEM作为未对齐的128位负载; MOVSD XMMREG2,MEM + 8; UNPCKLPD XMMREG1,XMMREG2。如果附加寄存器不可用,则使用MOVSD XMMREG1,MEM; MOVHPD XMMREG1,MEM + 8.

     

汇编/编译器编码规则45。(M impact,ML generality)使用MOVSD MEM,XMMREG1,而不是使用MOVUPD MEM,XMMREG1作为存储。 UNPCKHPD XMMREG1,XMMREG1;相反,MOVSD MEM + 8,XMMREG1。

部分 6.5.1.2数据调整

  

从SoA到AoS格式的混合数据可以应用于许多应用领域,包括3D几何,视频和成像。可以调整两种不同的调配技术来处理浮点和整数数据。例6-3说明了一个使用SHUFPS,MOVLHPS,MOVHLPS指令的混合函数。

enter image description here

enter image description here

  

示例6-3中的技术(使用SHUFPS加载16个字节并复制XMM寄存器的一半)优于在较新的微架构上使用MOVLPS / MOVHPS加载每个向量的一半的替代方法。这是因为使用MOVLPS / MOVHPS加载8个字节可能会产生代码依赖性并降低执行引擎的吞吐量。例6-3和例6-4的性能考虑通常取决于每个微体系结构的特性。例如,在Intel Core微体系结构中,执行SHUFPS往往比PUNPCKxxx指令慢。在增强型英特尔酷睿微体系结构中,由于128位混洗执行单元,SHUFPS和PUNPCKxxx指令均以1周期吞吐量执行。然后,下一个重要的考虑因素是只有一个端口可以执行PUNPCKxxx,而MOVLHPS / MOVHLPS可以在多个端口上执行。由于3个端口用于执行SIMD指令,因此两种技术的性能均优于先前微架构的英特尔酷睿微体系结构。由于128位shuffle单元,这两种技术在增强型英特尔酷睿微体系结构方面进一步改进。

答案 1 :(得分:2)

在较旧的CPU上,未对齐的负载会产生很大的性能损失 - 它们会产生两个总线读取周期,然后在两个读取周期后会有一些额外的修复。这意味着未对齐的负载通常比对齐的负载慢2倍或更慢。然而,对于更新的CPU(例如Core i7),未对准负载的代价几乎可以忽略不计。因此,如果您需要支持旧CPU和新CPU,您可能希望以不同方式处理未对齐的负载。