普通C ++代码比内联汇编程序快10倍。为什么?

时间:2015-09-03 21:26:29

标签: c++ performance assembly

这两个代码片段做同样的事情:将两个float数组一起添加并将结果存回到它们中。

内联汇编程序:

void vecAdd_SSE(float* v1, float* v2) { 
    _asm {
        mov esi, v1
        mov edi, v2
        movups xmm0, [esi]
        movups xmm1, [edi]
        addps xmm0, xmm1
        movups [esi], xmm0
        movups [edi], xmm0
    }
}

普通C ++代码:

void vecAdd_Std(float* v1, float* v2) {
    v1[0] = v1[0]+ v2[0];
    v1[1] = v1[1]+ v2[1];
    v1[2] = v1[2]+ v2[2];
    v1[3] = v1[3]+ v2[3];

    v2[0] = v1[0];
    v2[1] = v1[1];
    v2[2] = v1[2];
    v2[3] = v1[3];
}

C ++代码的反汇编(在调试模式下进行反汇编,因为由于某种原因我无法在发布模式下查看反汇编):

 void vecAdd_Std(float* v1, float* v2) {
 push        ebp  
 mov         ebp,esp  
 sub         esp,0C0h  
 push        ebx  
 push        esi  
 push        edi  
 lea         edi,[ebp-0C0h]  
 mov         ecx,30h  
 mov         eax,0CCCCCCCCh  
 rep stos    dword ptr es:[edi]  

    v1[0] = v1[0]+ v2[0];
 mov         eax,4  
 imul        ecx,eax,0  
 mov         edx,4  
 imul        eax,edx,0  
 mov         edx,dword ptr [v1]  
 mov         esi,dword ptr [v2]  
 movss       xmm0,dword ptr [edx+ecx]  
 addss       xmm0,dword ptr [esi+eax]  
 mov         eax,4  
 imul        ecx,eax,0  
 mov         edx,dword ptr [v1]  
 movss       dword ptr [edx+ecx],xmm0  
    v1[1] = v1[1]+ v2[1];
 mov         eax,4  
 shl         eax,0  
    v1[1] = v1[1]+ v2[1];
 mov         ecx,4  
 shl         ecx,0  
 mov         edx,dword ptr [v1]  
 mov         esi,dword ptr [v2]  
 movss       xmm0,dword ptr [edx+eax]  
 addss       xmm0,dword ptr [esi+ecx]  
 mov         eax,4  
 shl         eax,0  
 mov         ecx,dword ptr [v1]  
 movss       dword ptr [ecx+eax],xmm0  
    v1[2] = v1[2]+ v2[2];
 mov         eax,4  
 shl         eax,1  
 mov         ecx,4  
 shl         ecx,1  
 mov         edx,dword ptr [v1]  
 mov         esi,dword ptr [v2]  
 movss       xmm0,dword ptr [edx+eax]  
 addss       xmm0,dword ptr [esi+ecx]  
 mov         eax,4  
 shl         eax,1  
 mov         ecx,dword ptr [v1]  
 movss       dword ptr [ecx+eax],xmm0  
    v1[3] = v1[3]+ v2[3];
 mov         eax,4  
 imul        ecx,eax,3  
 mov         edx,4  
 imul        eax,edx,3  
 mov         edx,dword ptr [v1]  
 mov         esi,dword ptr [v2]  
 movss       xmm0,dword ptr [edx+ecx]  
 addss       xmm0,dword ptr [esi+eax]  
 mov         eax,4  
 imul        ecx,eax,3  
 mov         edx,dword ptr [v1]  
 movss       dword ptr [edx+ecx],xmm0  

    v2[0] = v1[0];
 mov         eax,4  
 imul        ecx,eax,0  
 mov         edx,4  
 imul        eax,edx,0  
 mov         edx,dword ptr [v2]  
 mov         esi,dword ptr [v1]  
 mov         ecx,dword ptr [esi+ecx]  
 mov         dword ptr [edx+eax],ecx  
    v2[1] = v1[1];
 mov         eax,4  
 shl         eax,0  
 mov         ecx,4  
 shl         ecx,0  
 mov         edx,dword ptr [v2]  
 mov         esi,dword ptr [v1]  
 mov         eax,dword ptr [esi+eax]  
 mov         dword ptr [edx+ecx],eax  
    v2[2] = v1[2];
 mov         eax,4  
 shl         eax,1  
 mov         ecx,4  
 shl         ecx,1  
 mov         edx,dword ptr [v2]  
 mov         esi,dword ptr [v1]  
 mov         eax,dword ptr [esi+eax]  
 mov         dword ptr [edx+ecx],eax  
    v2[3] = v1[3];
 mov         eax,4  
 imul        ecx,eax,3  
 mov         edx,4  
 imul        eax,edx,3  
 mov         edx,dword ptr [v2]  
 mov         esi,dword ptr [v1]  
 mov         ecx,dword ptr [esi+ecx]  
 mov         dword ptr [edx+eax],ecx  

}

现在我对函数进行了时间测量,并注意到内联汇编程序代码大约需要10倍(在发布模式下)。 有人知道为什么吗?

2 个答案:

答案 0 :(得分:19)

在我的机器上(VS2015 64位模式),编译器内联vecAdd_Std并生成

00007FF625921C8F  vmovups     xmm1,xmmword ptr [__xmm@4100000040c000004080000040000000 (07FF625929D60h)]  
00007FF625921C97  vmovups     xmm4,xmm1  
00007FF625921C9B  vcvtss2sd   xmm1,xmm1,xmm4  

测试代码

int main() {
    float x[4] = {1.0, 2.0, 3.0, 4.0};
    float y[4] = {1.0, 2.0, 3.0, 4.0};

    vecAdd_Std(x, y);

    std::cout << x[0];
}

答案 1 :(得分:5)

你真的没有调用执行一个 SSE指令的函数,是吗?设置xmm寄存器涉及非平凡的开销,并且您将值从内存复制到寄存器并返回,这将比实际计算花费更长的时间。

我不会惊讶地发现编译器内联函数的C ++版本,但对于包含内联汇编的函数却没有(不能,真的)这样做。