我正在为双打做简单的打包添加,以比较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的表格vaddpd
和vaddsd
具有完全相同的延迟和吞吐量,那么三个vaddsd
甚至更快的原因是什么?一个vaddpd
? (或者我应该把重点放在哪里找出限制点?)
我知道有一些可以改进(测试)代码的东西,例如:展开,但是为了比较单向量和单标量指令性能而进行了详细说明。