[解決済み】インラインアセンブリ言語はネイティブ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;
}
次に、このプログラムを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アプリケーションでは)極端な最適化は必要ない場合がほとんどです。
関連
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】致命的なエラー LNK1169: ゲームプログラミングで1つ以上の多重定義されたシンボルが発見された
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】Visual C++で "Debug Assertion failed "の原因となる行を見つける。
-
[解決済み】エラー:free(): 次のサイズが無効です(fast)。
-
[解決済み】デバッグアサーションに失敗しました
-
[解決済み】'std::cout'への未定義の参照
-
[解決済み] B "の印刷が "#"の印刷より劇的に遅いのはなぜですか?
-
[解決済み] なぜC++はPythonよりもstdinからの行の読み込みが遅いのですか?
-
[解決済み] Collatz予想の検証を行うC++のコードは、なぜ手書きのアセンブリよりも高速に動作するのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++でint型に無限大を設定する
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】C++でユーザー入力を待つ【重複あり
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み] Collatz予想の検証を行うC++のコードは、なぜ手書きのアセンブリよりも高速に動作するのでしょうか?
-
[解決済み] 最後の手段としてのパフォーマンス最適化戦略【終了しました
-
[解決済み】なぜアセンブリで書かれたプログラムが増えないのか?[クローズド]
-
[解決済み] レジスタを自分自身とXORする目的は何ですか?重複