SSE标量代码如何胜过AVX矢量代码

时间:2017-02-27 01:05:53

标签: c++ g++ vectorization avx2

我正在为双打做简单的打包添加,以比较linux上的标量和打包数据与haswell处理器的性能。

测试功能:

struct vector {
     __m256d v; // double v[3];
     // ctor
     vector operator+(const vector& rhs) const {
         return v + rhs.v;
     }
};
vector f(vector* varray, vector* varray2) {
    // varray and varray2 are two arrays of vectors of length 128
    vector ret;
    for (unsigned j = 0; j != 10000000; ++j) {
        for (unsigned i = 0; i != 128; ++i) {
            ret = ret + varray[i] + varray2[i];
        }
    }
    return ret;
}

以下f编译时使用-march=native -O2(尾随nop省略)我已直接验证主要功能call f

  400560:   c5 f9 57 c0             vxorpd xmm0,xmm0,xmm0
  400564:   4c 8d 56 18             lea    r10,[rsi+0x18]
  400568:   4c 8d 4a 18             lea    r9,[rdx+0x18]
  40056c:   48 89 f8                mov    rax,rdi
  40056f:   41 b8 80 96 98 00       mov    r8d,0x989680
  400575:   c5 f9 28 c8             vmovapd xmm1,xmm0
  400579:   c5 f9 28 d0             vmovapd xmm2,xmm0
  40057d:   48 81 c6 00 0c 00 00    add    rsi,0xc00
  400584:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]
  400588:   4c 89 d2                mov    rdx,r10
  40058b:   4c 89 c9                mov    rcx,r9
  40058e:   66 90                   xchg   ax,ax
  400590:   c5 eb 58 12             vaddsd xmm2,xmm2,QWORD PTR [rdx];***
  400594:   48 83 c2 18             add    rdx,0x18
  400598:   c5 eb 58 11             vaddsd xmm2,xmm2,QWORD PTR [rcx];***
  40059c:   48 83 c1 18             add    rcx,0x18
  4005a0:   c5 f3 58 4a f0          vaddsd xmm1,xmm1,QWORD PTR [rdx-0x10];***
  4005a5:   c5 fb 58 42 f8          vaddsd xmm0,xmm0,QWORD PTR [rdx-0x8];***
  4005aa:   c5 f3 58 49 f0          vaddsd xmm1,xmm1,QWORD PTR [rcx-0x10];***
  4005af:   c5 fb 58 41 f8          vaddsd xmm0,xmm0,QWORD PTR [rcx-0x8];***
  4005b4:   48 39 d6                cmp    rsi,rdx
  4005b7:   75 d7                   jne    400590 <f(vector*, vector*)+0x30>
  4005b9:   41 83 e8 01             sub    r8d,0x1
  4005bd:   75 c9                   jne    400588 <f(vector*, vector*)+0x28>
  4005bf:   c5 fb 11 10             vmovsd QWORD PTR [rax],xmm2
  4005c3:   c5 fb 11 48 08          vmovsd QWORD PTR [rax+0x8],xmm1
  4005c8:   c5 fb 11 40 10          vmovsd QWORD PTR [rax+0x10],xmm0
  4005cd:   c3                      ret

对于矢量代码,有两个简单的vaddpd

  4005d0:   ba 80 96 98 00          mov    edx,0x989680
  4005d5:   c5 f9 57 c0             vxorpd xmm0,xmm0,xmm0
  4005d9:   0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]
  4005e0:   b8 20 00 00 00          mov    eax,0x20
  4005e5:   0f 1f 00                nop    DWORD PTR [rax]
  4005e8:   c5 fd 58 04 07          vaddpd ymm0,ymm0,YMMWORD PTR [rdi+rax*1];***
  4005ed:   c5 fd 58 04 06          vaddpd ymm0,ymm0,YMMWORD PTR [rsi+rax*1];***
  4005f2:   48 83 c0 20             add    rax,0x20
  4005f6:   48 3d 00 10 00 00       cmp    rax,0x1000
  4005fc:   75 ea                   jne    4005e8 <f(vector*, vector*)+0x18>
  4005fe:   83 ea 01                sub    edx,0x1
  400601:   75 dd                   jne    4005e0 <f(vector*, vector*)+0x10>
  400603:   c3                      ret

表现是:

real    0m1.971s // sd
real    0m2.126s // pd

无论如何,经过大量的观察,与time同步,标量版本几乎总是(90%+)快于打包版本。

查询Agner的表格vaddpdvaddsd具有完全相同的延迟和吞吐量,那么三个vaddsd甚至更快的原因是什么?一个vaddpd? (或者我应该把重点放在哪里找出限制点?)

我知道有一些可以改进(测试)代码的东西,例如:展开,但是为了比较单向量和单标量指令性能而进行了详细说明。

0 个答案:

没有答案
相关问题