web-dev-qa-db-ja.com

条件付き移動が分岐予測エラーに対して脆弱ではないのはなぜですか?

この投稿(StackOverflowの回答) (最適化セクションで)を読んだ後、条件付きの移動が分岐予測エラーに対して脆弱ではない理由を知りました。 cond moveに関する記事はこちら(PDF by AMD) で見つけました。また、condのパフォーマンス上の利点を主張しています。動きます。しかし、これはなぜですか?見えません。そのASM命令が評価される時点では、先行するCMP命令の結果はまだわかっていません。

70

予測ミスしたブランチは高価です

最新のプロセッサは通常、うまくいけば各サイクルで1〜3命令を実行します(前の命令またはメモリから到着するこれらの命令のデータ依存性を待機していない場合)。

上記のステートメントは、タイトなループに対して驚くほどよく保持されますが、サイクルが来たときに命令が実行されるのを防ぐことができる追加の依存関係を盲目にするべきではありません。 15〜20サイクル前。

プロセッサはブランチに遭遇したときに何をすべきですか?両方のターゲットのフェッチとデコードはスケーリングされません(さらに分岐が続く場合、指数関数的な数のパスを並行してフェッチする必要があります)。そのため、プロセッサは投機的に2つのブランチのうち1つだけをフェッチしてデコードします。

これが、予測ミス分岐が高価な理由です。効率的な命令パイプラインのために通常は見えない15〜20サイクルかかります。

条件付き移動は決して高価ではありません

条件付き移動は予測を必要としないため、このペナルティはありません。通常の命令と同じデータ依存性があります。実際、条件付き移動には、通常の命令よりも多くのデータ依存関係があります。これは、データ依存関係に「条件真」と「条件偽」の両方のケースが含まれるためです。 r1r2に条件付きで移動する命令の後、r2の内容は、r2の以前の値とr1の両方に依存しているようです。よく予測された条件分岐により、プロセッサはより正確な依存関係を推測できます。しかし、データの依存関係は、到着するまでに時間が必要な場合、通常、到着するのに1〜2サイクルかかります。

メモリからレジスタへの条件付き移動は時々危険な賭けになることに注意してください。メモリから読み取られた値がレジスタに割り当てられないような条件である場合、メモリで何も待たないことになります。しかし、命令セットで提供される条件付き移動命令は、通常、レジスタ間で登録されるため、プログラマー側でのこの間違いを防ぎます。

61
Pascal Cuoq

命令パイプライン がすべてです。最新のCPUは命令をパイプラインで実行するため、実行フローがCPUによって予測可能な場合、パフォーマンスが大幅に向上します。

cmov

    add     eax, ebx
    cmp     eax, 0x10
    cmovne  ebx, ecx
    add     eax, ecx

そのASM命令が評価される時点では、先行するCMP命令の結果はまだわかっていません。

おそらく、CPUは、cmov命令とcmp命令の結果に関係なく、cmovに続く命令がすぐに実行されることを認識しています。したがって、次の命令は事前に安全にフェッチ/デコードできますが、ブランチの場合はそうではありません。

次の命令はcmovが実行される前に実行することさえできます(私の例ではこれは安全です)

ブランチ

    add     eax, ebx
    cmp     eax, 0x10
    je      .skip
    mov     ebx, ecx
.skip:
    add     eax, ecx

この場合、CPUのデコーダーがje .skipプリフェッチ/デコード命令を1)次の命令から続行するか、2)ジャンプターゲットから続行するかを選択する必要があります。 CPUは、この前方条件分岐が発生しないと推測するため、次の命令mov ebx, ecxはパイプラインに入ります。

数サイクル後、je .skipが実行され、分岐が行われます。やばい!パイプラインには、実行すべきではないランダムなジャンクが保持されています。 CPUは、キャッシュされているすべての命令をフラッシュし、.skip:

それは、予測フローのパフォーマンスの低下です。これは、実行フローを変更しないため、cmovでは発生しません。

43
Martin

実際、結果はまだわかっていない可能性がありますが、他の状況(特に依存関係チェーン)で許可されている場合、CPUはcmovに続く命令を並べ替えて実行できます。分岐は含まれていないため、これらの命令はどのような場合でも評価する必要があります。

この例を考えてみましょう:

cmoveq edx, eax
add ecx, ebx
mov eax, [ecx]

cmovに続く2つの命令はcmovの結果に依存しないため、cmov自体が保留中であっても実行できます(これは順不同の実行)。実行できなくても、フェッチおよびデコードできます。

分岐バージョンは次のとおりです。

    jne skip
    mov edx, eax
skip:
    add ecx, ebx
    mov eax, [ecx]

ここでの問題は、制御フローが変化し、cpuが十分に賢くなく、分岐が取得されたと誤って予測された場合、スキップされたmov命令を「挿入」できるかどうかを確認できないことです-代わりに、実行したすべてを破棄しますブランチの後、ゼロから再起動します。これがペナルティの原因です。

17
Jester

これらをお読みください。 Fog + Intelでは、CMOVを検索するだけです。

Linus Torvaldによる2007年頃のCMOVに対する批判
Agner Fogのマイクロアーキテクチャの比較
Intel®64およびIA-32アーキテクチャ最適化リファレンスマニュアル

簡単に言えば、正しい予測は「無料」ですが、条件分岐の予測ミスはHaswellで14〜20サイクルかかります。ただし、CMOVは決して無料ではありません。それでもCMVはトーバルズが暴言を吐いたときよりもずっと良いと思う。これまでに答えられたすべてのプロセッサーで、常に正しいものはありません。

3
Olsonist

この図は、[Peter Puschner et al。]スライドからのもので、シングルパスコードに変換し、実行を高速化する方法を説明しています。

enter image description here

0
COLD ICE