AVX VMOVDQA比两个SSE MOVDQA慢吗?

18
当我在处理快速ADD循环(如何提速x64汇编ADD循环)时,我使用SSE和AVX指令测试内存访问。为了执行加法操作,我需要读取两个输入并产生一个输出。因此,我编写了一个虚拟程序,将两个x64值读入寄存器中,并将其中一个写回内存,而没有进行任何操作。显然,这是无用的,只是为了进行基准测试。

我使用展开的循环每次处理64字节,它由8个类似于以下块的块组成:

mov rax, QWORD PTR [rdx+r11*8-64]
mov r10, QWORD PTR [r8+r11*8-64]
mov QWORD PTR [rcx+r11*8-64], rax

然后我将其升级为SSE2。现在我使用4个类似于此的块:

movdqa xmm0, XMMWORD PTR [rdx+r11*8-64]
movdqa xmm1, XMMWORD PTR [r8+r11*8-64]
movdqa XMMWORD PTR [rcx+r11*8-64], xmm0

后来我使用了AVX(每个寄存器256位)。我有两个这样的块:

vmovdqa ymm0, YMMWORD PTR [rdx+r11*8-64]
vmovdqa ymm1, YMMWORD PTR [r8+r11*8-64]
vmovdqa YMMWORD PTR [rcx+r11*8-64], ymm0

到目前为止,还没有什么特别惊人的地方。有趣的是基准测试结果:当我在1k + 1k = 1k 64位字(即两次8kb的输入和一次8kb的输出)上运行三种不同的方法时,得到了奇怪的结果。以下每个时间都是处理两个64字节输入以生成64字节输出的时间。
  • x64寄存器方法大约需要15个周期/64字节
  • SSE2方法大约需要8.5个周期/64字节
  • AVX方法大约需要9个周期/64字节
我的问题是:为什么AVX方法比SSE2方法慢(虽然不是很多)?我预计它至少应该与SSE2方法相当。使用YMM寄存器是否会增加太多额外的时间?内存已对齐(否则会出现GPF)。是否有人能解释这个现象?

3
在当前的架构上,我记得AVX内存访问在某些情况下会被分成2个独立的128位访问。也许这就是你在这里遇到的问题所在。当你开始进行实际计算时,AVX的真正好处就体现出来了,因为你可以像使用SSE一样并行进行两倍的计算。 - Jason R
啊,有趣。你对此有什么指示吗?快速搜索发现了这个,但他们声称内存路径为完整的256位:http://www.lostcircuits.com/mambo//index.php?option=com_content&task=view&id=99&Itemid=1&limit=1&limitstart=6 - cxxl
3
在混合使用旧版(非VEX)SSE指令和AVX指令时要小心,不清楚这是否与其余基准测试代码相关,但您可能应该意识到此问题。请参阅此链接以避免AVX和SSE的转换惩罚:http://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties - Paul R
1
我不太喜欢你在SSE和AVX版本中使用的8个乘法器,你需要使用16和32个(但你不能在寻址中这样做),当然要减少循环次数。你的基准测试代码是否正确考虑了这一点? - Jester
@Paul R:感谢您的评论,但是惩罚是在从一个指令集切换到另一个指令集时支付的。但是我的整个AVX循环只使用AVX和常规指令,没有SSE / FP。 - cxxl
没问题 - 我只是想确保你的 AVX 基准测试代码中没有任何遗留的 SSE 指令。 - Paul R
1个回答

15
在Sandybridge/Ivybridge上,256字节的AVX加载和存储被拆分为两个128字节操作[正如Peter Cordes所指出的那样,这些不完全是µops,但需要两个周期来清除端口以进行操作]在加载/存储执行单元中,因此没有理由认为使用这些指令的版本会更快。
为什么它会更慢?有两种可能性:
1.对于基址+索引+偏移寻址,128字节负载的延迟为6个时钟周期,而256字节负载的延迟为7个时钟周期(Intel优化手册中的表2-8)。虽然你的基准测试应该受到吞吐量而不是延迟的限制,但更长的延迟意味着处理器需要更长时间才能从任何故障恢复(管道气泡或预测错误或中断服务等),这确实会产生一些影响。
2.在同一文档的11.6.2中,英特尔建议对于256字节负载和128字节负载相比,在缓存行和页面交叉的惩罚可能更大。如果你的负载不都是32字节对齐的,这也可能解释当使用256字节负载/存储操作时观察到减速的原因:
例如11-12展示了两个使用非对齐地址的SAXPY实现。 另外,使用两个16字节内存操作代替32字节内存访问可以更快地执行这些代码样本。

5
请注意,这并不适用于哈斯维尔处理器。自从我最初写下这个答案以来,该处理器已经发布。 - Stephen Canon
1
它不是2个uops,但在执行单元中执行两个半部分需要2个周期。 AGU仅在第一个周期上需要,并且在第二个周期上是免费的(例如计算存储地址),这就是为什么SnB / IvB设计师没有感到需要包括单独的存储地址端口。 Haswell有一个,因为它可以在单个周期内进行256b传输。 无论如何,1个uop或否之间的区别在于管道的4个uop /周期吞吐量。 - Peter Cordes
2
未对齐的加载/存储不可能是问题,因为操作员使用了vmovdqa,它会在未对齐时出错。尽管如此,包括该段仍然可以使答案更好。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接