インラインアセンブリ言語はネイティブC++コードよりも遅いですか? 質問する

インラインアセンブリ言語はネイティブC++コードよりも遅いですか? 質問する

インライン アセンブリ言語と C++ コードのパフォーマンスを比較しようとしたので、サイズ 2000 の配列 2 つを 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;
}

Then I run the program five times to get the cycles of processor, which could be seen as time. Each time I call one of the function mentioned above only.

And here comes the result.

Function of assembly version:

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

Function of C++ version:

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

The C++ code in release mode is almost 3.7 times faster than the assembly code. Why?

I guess that the assembly code I wrote is not as effective as those generated by GCC. It's hard for a common programmer like me to wrote code faster than its opponent generated by a compiler.Does that mean I should not trust the performance of assembly language written by my hands, focus on C++ and forget about assembly language?

ベストアンサー1

Yes, most times.

First of all you start from wrong assumption that a low-level language (assembly in this case) will always produce faster code than high-level language (C++ and C in this case). It's not true. Is C code always faster than Java code? No because there is another variable: programmer. The way you write code and knowledge of architecture details greatly influence performance (as you saw in this case).

You can always produce an example where handmade assembly code is better than compiled code but usually it's a fictional example or a single routine not a true program of 500.000+ lines of C++ code). I think compilers will produce better assembly code 95% times and sometimes, only some rare times, you may need to write assembly code for few, short, highly used, performance critical routines or when you have to access features your favorite high-level language does not expose. Do you want a touch of this complexity? Read this awesome answer here on SO.

Why this?

First of all because compilers can do optimizations that we can't even imagine (see this short list) and they will do them in seconds (when we may need days).

When you code in assembly you have to make well-defined functions with a well-defined call interface. However they can take in account whole-program optimization and inter-procedural optimization such as register allocation, constant propagation, common subexpression elimination, instruction scheduling and other complex, not obvious optimizations (Polytope model, for example). On RISC architecture guys stopped worrying about this many years ago (instruction scheduling, for example, is very hard to tune by hand) and modern CISC CPUs have very long pipelines too.

For some complex microcontrollers even system libraries are written in C instead of assembly because their compilers produce a better (and easy to maintain) final code.

Compilers sometimes can automatically use some MMX/SIMDx instructions by themselves, and if you don't use them you simply can't compare (other answers already reviewed your assembly code very well). Just for loops this is a short list of loop optimizations of what is commonlyコンパイラによってチェックされます(C#プログラムのスケジュールが決まっているときに自分でできると思いますか?)アセンブリで何かを書く場合は、少なくともいくつかは考慮する必要があると思います。シンプルな最適化配列の教科書的な例はサイクルを解きほぐす(サイズはコンパイル時に判明します)。それを実行して、テストを再度実行します。

最近では、別の理由からアセンブリ言語を使用する必要はほとんどありません。多種多様なCPUすべてをサポートしますか?それぞれに固有のマイクロアーキテクチャいくつかの特定の命令セット機能ユニットの数が異なり、組み立て手順はそれらすべてを保持するように整理する必要があります。忙しいC言語で書く場合は、PGOしかし、アセンブリでは、特定のアーキテクチャに関する深い知識が必要になります(そして別のアーキテクチャのためにすべてを再考し、やり直す)。小さなタスクの場合、コンパイラはいつものより良く、複雑なタスクにも対応いつもの仕事は報われない(そしてコンパイラ5月もっと頑張るともかく)。

座ってコードを見てみると、アセンブリに翻訳するよりもアルゴリズムを再設計する方が多くのメリットがあることに気づくでしょう(これを読んでくださいSOの素晴らしい投稿)、アセンブリ言語に頼る前に効果的に適用できる高レベルの最適化 (およびコンパイラへのヒント) があります。組み込み関数を使用すると、必要なパフォーマンスの向上が得られ、コンパイラはほとんどの最適化を実行できることは言及する価値があるでしょう。

とはいえ、5~10倍高速なアセンブリコードを生成できる場合でも、顧客に次のことを希望するかどうかを尋ねる必要があります。支払う1週間のあなたの時間または50ドル速いCPUを購入する多くの場合、極端な最適化は (特に LOB アプリケーションでは) ほとんどのユーザーにとって必要ありません。

おすすめ記事