1. ホーム
  2. c++

[解決済み】インラインアセンブリ言語はネイティブC++コードより遅いですか?

2022-04-13 19:09:02

質問

インラインアセンブリ言語と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;
}

次に、このプログラムを5回実行し、プロセッサのサイクル(時間ともいえる)を求めます。その都度、上記の関数を1つだけ呼び出す。

そして、その結果がこちらです。

アセンブリバージョンの機能。

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++に集中し、アセンブリ言語のことは忘れるべきだということでしょうか?

解決方法は?

はい、ほとんどの場合、そうです。

まず第一に、低レベル言語(この場合はアセンブリ)は高レベル言語(この場合はC++やC)よりも常に高速なコードを生成するという間違った仮定から出発しています。そんなことはない。C言語のコードはJavaのコードより常に速いのでしょうか?いいえ、プログラマという別の変数が存在するからです。コードの書き方やアーキテクチャの詳細に関する知識は、(今回のケースであなたが見たように)性能に大きく影響するのです。

あなたは 常に ハンドメイドのアセンブリコードの方がコンパイルされたコードより優れている例を出すが 通常 架空の例であったり、1つのルーチンであったり 500.000行以上のC++コードのプログラム)。私は、コンパイラは95%の確率でより良いアセンブリコードを生成すると思いますし たまに、ごくまれにですが。 アセンブリコードを書く必要があるのは、ごく一部の短い期間だけです。 使用頻度が高い , パフォーマンスクリティカル ルーチンや、お気に入りの高級言語が公開していない機能にアクセスしなければならない場合などです。この複雑さに触れてみたいですか?読む この素晴らしい答えは SOに掲載されています。

なぜ、これなのか?

まず第一に、コンパイラは私たちが想像もつかないような最適化を行うことができるからです( この短いリスト で行います。 (いつ 日数が必要な場合があります ).

アセンブリでコーディングする場合、きちんと定義された関数と、きちんと定義された呼び出しインターフェイスを作る必要があります。しかし、これらの関数は プログラム全体の最適化 プロシージャ間最適化 このような として レジスタ割り当て , 定数伝搬 , 共通部分式の削除 , 命令スケジューリング といった、複雑でわかりにくい最適化( ポリトープモデル など)。について RISC アーキテクチャの研究者は、何年も前にこのことを気にしなくなりました(たとえば、命令スケジューリングは非常に難しく 手作業で調整 ) そして、最近の CISC CPUは非常に長い パイプライン もあります。

複雑なマイクロコントローラの場合は、さらに システム なぜなら、コンパイラが最終的なコードをより良く(そして保守しやすく)作成するからです。

コンパイラは時々 自動的に一部のMMX/SIMDx命令を使用します。 を使用しないと、単純に比較できません(他の回答者は、すでにあなたのアセンブリコードを非常によくレビューしています)。 ループの場合だけですが、これは ループ最適化の短いリスト であるもののうち 一般的に コンパイラでチェックする(C#のプログラムでスケジュールが決まっているのに、自分でできると思うか?) アセンブリで何かを書くのであれば、最低限、ある程度の 簡単な最適化 . 配列の教科書的な例としては サイクルを展開する (そのサイズはコンパイル時に判明しています)。それを実行して、もう一度テストを実行してください。

また、最近では、別の理由でアセンブリ言語を使う必要があることも本当に珍しくなっています。 CPUの種類も豊富 . 全部をサポートしたいですか?それぞれに固有の マイクロアーキテクチャ と、いくつかの 特定命令セット . 機能ユニットの数が異なるので、それらをすべて維持するようにアセンブリ命令を配置する必要があります。 忙しい . C言語で記述する場合は PGO が、アセンブリでは、その特定のアーキテクチャに関する豊富な知識が必要になります(そして 別のアーキテクチャのためにすべてを考え直し、やり直す。 ). 小さな作業であれば、コンパイラ 通常 の方が優れており、複雑なタスクの場合は 通常 仕事が報われない(と コンパイラ かもしれない より良くする とにかく)です。

もしあなたが座って自分のコードを見てみると、おそらくアセンブリに変換するよりもアルゴリズムを再設計する方がより多くのものを得られることがわかるでしょう(これを読んでください SOの素晴らしい記事 アセンブリ言語に頼る前に、高レベルの最適化(とコンパイラへのヒント)を効果的に適用することができます。また、多くの場合、イントリンシックスを使用することで、求めているパフォーマンスを得ることができ、コンパイラはその最適化のほとんどを実行することができることを言及する価値があるでしょう。

このように、5~10倍速いアセンブリコードを作ることができたとしても、顧客に次のことを好むかどうかを尋ねるべきです。 <強い 支払う の1週間分 <強い あなたの時間 または 50ドル速いCPUを買う . 特にLOBアプリケーションでは)極端な最適化は必要ない場合がほとんどです。