プログラミングを始めて以来、無駄なブランチを避けるためにあらゆる場所で読んでいます。
それは問題ありませんが、私がこれを行う必要がある理由を説明している記事はありません。 [〜#〜] cpu [〜#〜] が分岐命令をデコードし、ジャンプすることを決定した場合、正確にはどうなりますか?そして、他の指示(加算など)よりも遅くなる「もの」とは何ですか?
分岐命令は、他のどの命令よりも本質的に遅くはありません。
ただし、ブランチを避けるべきだと聞いた理由は、最近のCPUは パイプラインアーキテクチャ に従っているためです。これは、同時に実行されている複数の順次命令があることを意味します。ただし、パイプラインを完全に利用できるのは、サイクルごとにメモリから次の命令を読み取ることができる場合のみです。つまり、which命令を知る必要があります。読む。
条件付き分岐では、通常、どのパスが使用されるかを事前に知りません。したがって、これが発生すると、CPUは決定が解決されるまで停止し、分岐命令の背後にあるパイプライン内のすべてを破棄する必要があります。これにより、使用率が低下し、パフォーマンスが低下します。
これが、 分岐予測 や 分岐遅延)のようなものである理由です。スロット 存在します。
CPUはパイプラインを採用して命令を実行するため、前の命令がある段階で実行されている場合(たとえば、レジスタから値を読み取る場合)、次の命令は同時に実行されますが、別の段階で実行されます(たとえば、デコード)。ステージ)。非制御命令でも問題ありませんが、jmp
やcall
などの制御命令を実行すると複雑になります。
CPUは、jmp
命令を実行するときに次の命令がどうなるかわからないため、 分岐予測 手法を使用して、分岐命令が実行されるかどうかを予測します(たとえば、分岐ループスニペット内の命令は、おそらく命令フローをループヘッドに戻します)。
ただし、このような予測が失敗すると、 分岐予測ミス と呼ばれ、実行パフォーマンスに影響します。分岐後のパイプラインは破棄する必要があるため、正しい命令からやり直してください。
Oliは、分岐が高価である理由を非常によく説明しました。パイプラインと分岐予測です。ただし、最近のコンパイラはコードを最適化し、1つの最適化は分岐を減らすため、この問題についてあまり心配する必要はないことを付け加えておきます。
MicrosoftコンパイラでのC++最適化の詳細を読むことができます ここ -プロファイルガイドオプティマイザは、ランタイム情報(つまり、コードのどの部分が最も使用されているか)を使用してコードを最適化します。スピードアップは20%の範囲です。
操作の1つは、「条件付き分岐最適化」です。たとえば、ほとんどの場合iが6であると仮定すると、これはより高速です。
if (i==6)
{
//...
}
else
{
switch (i)
{
case 1: //
case 2: //
//...
}
}
より:
switch (i)
{
case 1: //
//...
case 6: //
case 7: //
}
他の最適化に関するブログ投稿は次のとおりです。 http://bogdangavril.wordpress.com/2011/11/02/optimizating-your-native-program/