assembly - AVX VMOVDQA 比两个 SSE MOVDQA 慢?

标签 assembly sse bignum arbitrary-precision avx

当我正在研究快速 ADD 循环 ( Speed up x64 assembler ADD loop ) 时,我正在使用 SSE 和 AVX 指令测试内存访问。要添加,我必须读取两个输入并产生一个输出。因此,我编写了一个虚拟例程,将两个 x64 值读入寄存器并将一个值写回内存,而不执行任何操作。这当然没什么用,我只是为了基准测试才这么做的。

我使用展开的循环,每个循环处理 64 字节。它由 8 个 block 组成,如下所示:

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 个 block ,如下所示:

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 位)。我有 2 个这样的 block :

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 位字(即两倍 8 kb 的输入和一次 8kb 的输出)上运行三种不同的方法时,我得到了奇怪的结果。以下每个时序都是将两次 64 字节输入处理为 64 字节输出。

  • x64 寄存器方法运行时间约为 15 个周期/64 字节
  • SSE2 方法的运行速度约为 8.5 个周期/64 字节
  • AVX 方法的运行时间约为 9 个周期/64 字节

我的问题是:为什么 AVX 方法比 SSE2 方法慢(尽管不是很多)?我预计它至少会达到同等水平。使用 YMM 寄存器会花费这么多额外时间吗?内存已对齐(否则您会得到 GPF)。

有人对此有解释吗?

最佳答案

在 Sandybridge/Ivybridge 上,256b AVX 加载和存储在加载/存储中被分解为两个 128b 操作 [正如 Peter Cordes 所说,这些不完全是微操作,但需要两个周期才能清除端口]执行单元,因此没有理由期望使用这些指令的版本会更快。

为什么速度变慢了?我想到了两种可能性:

  • 对于基址 + 索引 + 偏移寻址,128b 加载的延迟为 6 个周期,而 256b 加载的延迟为 7 个周期(英特尔优化手册中的表 2-8)。尽管您的基准测试应该受到吞吐量的约束,而不是延迟,但较长的延迟意味着处理器需要更长的时间才能从任何问题(管道气泡或预测失误或中断服务或...),这确实有一些影响。

  • 在同一文档的 11.6.2 中,英特尔建议 256b 加载的缓存行和页交叉的惩罚可能比 128b 加载的更大。如果您的加载并非全部 32 字节对齐,这也可以解释您在使用 256b 加载/存储操作时所看到的速度减慢的原因:

Example 11-12 shows two implementations for SAXPY with unaligned addresses. Alternative 1 uses 32 byte loads and alternative 2 uses 16 byte loads. These code samples are executed with two source buffers, src1, src2, at 4 byte offset from 32- Byte alignment, and a destination buffer, DST, that is 32-Byte aligned. Using two 16- byte memory operations in lieu of 32-byte memory access performs faster.

关于assembly - AVX VMOVDQA 比两个 SSE MOVDQA 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13975546/

相关文章:

c - 'switch' 比 'if' 快吗?

assembly - Intel x86 汇编语法中寄存器上的括号

c - 这种悲伤教导的奇怪行为的原因是什么?

c++ - Clang 格式用撇号打破了大数字的分隔

c - 如何用C写这个

assembly - 理解和分析汇编代码

c++ - SSE:如何将 _m128i._i32[4] 减少到 _m128i._i8

c - SSE加载和添加

bigdecimal - 无法使用大数字作为参数从 web3 调用合约函数

ruby - Ruby 1.8.7 中的求幂返回错误答案