小编典典

内联汇编语言是否比本机 C++ 代码慢?

all

我试图比较内联汇编语言和 C++ 代码的性能,所以我写了一个函数,将两个大小为 2000 的数组相加 100000 次。这是代码:

#define TIMES 100000
void calcuC(int *x,int *y,int length)
{
    for(int i = 0; i < TIMES; i++)
    {
        for(int j = 0; j < length; j++)
            x[j] += y[j];
    }
}


void calcuAsm(int *x,int *y,int lengthOfArray)
{
    __asm
    {
        mov edi,TIMES
        start:
        mov esi,0
        mov ecx,lengthOfArray
        label:
        mov edx,x
        push edx
        mov eax,DWORD PTR [edx + esi*4]
        mov edx,y
        mov ebx,DWORD PTR [edx + esi*4]
        add eax,ebx
        pop edx
        mov [edx + esi*4],eax
        inc esi
        loop label
        dec edi
        cmp edi,0
        jnz start
    };
}

这是main()

int main() {
    bool errorOccured = false;
    setbuf(stdout,NULL);
    int *xC,*xAsm,*yC,*yAsm;
    xC = new int[2000];
    xAsm = new int[2000];
    yC = new int[2000];
    yAsm = new int[2000];
    for(int i = 0; i < 2000; i++)
    {
        xC[i] = 0;
        xAsm[i] = 0;
        yC[i] = i;
        yAsm[i] = i;
    }
    time_t start = clock();
    calcuC(xC,yC,2000);

    //    calcuAsm(xAsm,yAsm,2000);
    //    for(int i = 0; i < 2000; i++)
    //    {
    //        if(xC[i] != xAsm[i])
    //        {
    //            cout<<"xC["<<i<<"]="<<xC[i]<<" "<<"xAsm["<<i<<"]="<<xAsm[i]<<endl;
    //            errorOccured = true;
    //            break;
    //        }
    //    }
    //    if(errorOccured)
    //        cout<<"Error occurs!"<<endl;
    //    else
    //        cout<<"Works fine!"<<endl;

    time_t end = clock();

    //    cout<<"time = "<<(float)(end - start) / CLOCKS_PER_SEC<<"\n";

    cout<<"time = "<<end - start<<endl;
    return 0;
}

然后我运行该程序五次以获得处理器的周期,这可以看作是时间。每次我只调用上面提到的函数之一。

结果来了。

汇编版功能:

Debug   Release
---------------
732        668
733        680
659        672
667        675
684        694
Average:   677

C++版本功能:

Debug     Release
-----------------
1068      168
 999      166
1072      231
1002      166
1114      183
Average:  182

发布模式下的 C++ 代码几乎比汇编代码快 3.7 倍。为什么?

我猜我写的汇编代码没有GCC生成的那么有效。像我这样的普通程序员很难写出比编译器生成的对手更快的代码。这是否意味着我不应该相信自己亲手编写的汇编语言的性能,专注于
C++ 而忘记汇编语言?


阅读 81

收藏
2022-07-07

共1个答案

小编典典

是的,大多数时候。

首先,您从错误的假设开始,即低级语言(在这种情况下为汇编)总是会比高级语言(在这种情况下为 C++ 和 C)生成更快的代码。这不是真的。C 代码总是比
Java 代码快吗?不,因为还有另一个变量:程序员。您编写代码的方式和架构细节知识会极大地影响性能(正如您在本例中看到的那样)。

总是 可以制作一个示例,其中手工汇编代码比编译代码更好,但 通常 它是一个虚构的示例或单个例程,而不是500.000 多行 C++
代码的 真实程序)。 我认为编译器会产生 95% 的更好的汇编代码, 有时,只有极少数情况下,
您可能需要为少数、简短、高度使用性能关键的例程编写汇编代码,或者当您必须访问您最喜欢的高级语言的功能时不暴露。您想了解一下这种复杂性吗?在
SO 上阅读这个很棒的答案。

为什么这个?

首先,因为编译器可以进行我们甚至无法想象的优化(请参阅这个简短列表),并且它们会在
几秒钟内完成

当您在汇编中编码时,您必须使用定义良好的调用接口来制作定义良好的函数。然而,它们可以考虑整个程序优化和过程间优化,例如寄存器分配常量传播公共子表达式消除指令调度和其他复杂的、不明显的优化(例如Polytope
模型
)。很多年前,在RISC架构上,人们就不再担心这个问题了(例如,指令调度很难手动调整),现代CISC
CPU
流水线很长也。

对于一些复杂的微控制器,甚至 系统 库都是用 C 语言而不是汇编语言编写的,因为它们的编译器会生成更好(且易于维护)的最终代码。

编译器有时可以自己自动使用一些 MMX/SIMDx 指令,如果您不使用它们,您根本无法比较(其他答案已经很好地审查了您的汇编代码)。仅针对循环,这是编译器 通常*
检查的循环优化的简短列表(当您为 C#
程序确定了日程安排后,您认为您可以自己做吗?)如果您用汇编编写一些东西,我认为你至少要考虑一些简单的优化。数组的教科书示例是展开循环(其大小在编译时已知)。这样做并再次运行您的测试。
*

如今,由于另一个原因需要使用汇编语言也很少见:不同的 CPU
过多
。你想支持他们吗?每个都有特定的微体系结构和一些特定的指令集。它们有不同数量的功能单元,应安排组装说明以使它们保持
忙碌 。如果你用 C 语言编写,你可能会使用PGO,但在汇编中,你将需要对该特定架构有深入的了解(并 重新思考和重做其他架构的所有内容 )。对于小任务,编译器
通常 会做得更好,而对于复杂的任务,工作 通常 不会得到回报(并且无论如何编译器 可能
会做得更好
)。

如果你坐下来看看你的代码,你可能会发现重新设计你的算法比翻译成汇编获得更多(在 SO
上阅读这篇很棒的帖子
),有高级优化(和编译器提示),您可以在需要求助于汇编语言之前有效地应用。可能值得一提的是,经常使用内在函数可以获得所需的性能提升,并且编译器仍然能够执行大部分优化。

综上所述,即使您可以生成快 5 到 10 倍的汇编代码,您也应该询问您的客户是否愿意 支付 您一周的 时间购买速度快 50 美元的
CPU
。我们大多数人通常不需要极端优化(尤其是在 LOB 应用程序中)。

2022-07-07