【问题标题】:Intel intrinsics assembly code英特尔内在汇编代码
【发布时间】:2016-07-13 02:35:40
【问题描述】:

我正在考虑一个简单的问题——加快计算两个双精度数组的分量乘积。我注意到,与循环中的顺序乘法相比,使用 AVX 命令我只能获得大约 20% 的加速。

我决定检查这两种情况的延迟,并对加载操作的汇编代码感到困惑:

### __m256d pd;
### pd = _mm256_load_pd(a);
    movq      -112(%rbp), %rax    //Pushing the pointer to the stack                              
    vmovapd   (%rax), %ymm0       //Pushing 32 bytes from memory to ymm                                 
    vmovapd   %ymm0, -80(%rbp)    //What is                              
    vmovapd   -80(%rbp), %ymm0    //happening here?                         
    vmovapd   %ymm0, -48(%rbp)    //Quite slow down, since vmovapd cost ~ vmulpd                          

以上是以下 C 代码的程序集的一部分:

inline int test(double * a) {
    __m256d pd;
    pd = _mm256_load_pd(a);
    return 1;
}

在__m256_load_pd的描述中说是这样完成的:

dst[255:0] := MEM[mem_addr+255:mem_addr]
dst[MAX:256] := 0

即以相反的顺序?但是这两行汇编代码有什么关系呢?

【问题讨论】:

  • 你在编译时禁用了优化,所以 gcc 使代码变得很慢。通过优化,test() 编译为仅return 1,因为从未使用过pd。如果 20% 的加速是使用 -O0,然后尝试使用 -O3。如果您希望代码快速运行,则必须启用优化。
  • AT&T 语法在寄存器名称上使用 op src2,src1,dest% 装饰器,而 Intel 语法使用 op dest, src1, src2。 Intel手册的伪代码根本不是asm,只是描述了操作。
  • 20% 的加速是使用 icpc 的 -O3 标志的结果。
  • 英特尔的 C++ 编译器是否已经自动矢量化了您的标量代码?理解/解释微基准测试结果的唯一有用方法是查看优化的 asm。最好来自-march=native,因此自动矢量化器不限于 SSE2 作为基线。
  • 我也指定了 -no-vec 标志。感谢您指出-march=native

标签: assembly simd intrinsics avx


【解决方案1】:

除了编译标志之外,如果没有更多上下文,很难回答这个问题。根据运行的线程数和 double 数组的大小,您的问题可能是内存受限,即性能受到内存访问的限制。

非常大的数据 你想看看Stream 基准。使用 AVX 内部函数将有助于软件和硬件预取以及数据对齐,这可能解释了 +20%。无论如何,您将受到内存限制(将数据从系统内存加载到 L1 缓存),并且与 AVX 操作相比,连续执行操作将无关紧要,并且可能被并行发生的数据加载所隐藏(感谢预取的魔力)。

二级缓存中的数据 根据并发线程的数量,可能会以更高的速度馈送数据。但是,对数据执行 mul 对数据的计算不够复杂,无法在内存编组成本上占主导地位。

一级缓存中的数据 对于这种情况,您可能会看到性能有所提高,但可能还会出现其他意外,例如 L1 缓存负载引起的执行依赖性和延迟。但是,在 256 位寄存器中加载对齐的数据可能是性能最好的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 2012-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多