web-dev-qa-db-ja.com

それでも条件をチェックする必要がある場合、分岐予測はどのように機能しますか?

https://stackoverflow.com/q/11227809/55569 からブランチ予測に関する一般的な回答を読んでいましたが、何か混乱している点があります。

  • あなたが正しく推測した場合、それは続きます。
  • 間違ったと思った場合、船長は停止し、後退し、スイッチを入れるように叫びます。その後、他のパスで再起動できます。

毎回正しいと思うなら、電車は止まる必要はありません。

間違って推測しすぎると、列車は停止、バックアップ、再起動に多くの時間を費やします。

しかし、これは私が得ないものです:あなたの推測が正しいか間違っていたかを知っているあなたはしなければなりません条件チェックを行うとにかく。では、どちらの方法でも同じ条件チェックを行っている場合、分岐予測はどのように機能しますか?

私が言いたいのは、とにかく同じ条件チェックを行っているので、分岐予測がまったく分岐予測がないこととまったく同じではないということです。 (明らかに私は間違っていますが、わかりません)

33
Omega

もちろん状態は毎回チェックされます。しかし、それがチェックされるときまでに、それはCPUパイプラインのはるか上にあります。その間、他の命令もパイプラインに入り、さまざまな実行段階にあります。

通常、条件の直後に条件付き分岐命令が続きます。条件付き分岐命令は、条件がTRUEと評価された場合に分岐するか、条件がFALSEと評価された場合にフォールスルーします。これは、条件がTRUEとFALSEのどちらに評価されるかに応じて、条件命令と分岐命令の後にパイプラインにロードできる2つの異なる命令ストリームがあることを意味します。残念ながら、条件命令と分岐命令をロードした直後は、CPUは条件が何に評価されるかまだわかりませんが、パイプラインにデータをロードし続ける必要があります。したがって、条件が何に評価されるかについての推測に基づいて、2つの命令セットのいずれかを選択します。

後で、条件命令がパイプラインを上るとき、それは評価される時です。その時、CPUはその推測が正しいか間違っているかを調べます。

推測が正しいことが判明した場合、分岐は正しい場所に行き、正しい命令がパイプラインにロードされました。推測が間違っていることが判明した場合、条件付き分岐命令の後にパイプラインにロードされたすべての命令が間違っていたため、それらを破棄する必要があり、命令のフェッチを正しい場所から再度開始する必要があります。

修正

StarWeaverのコメントに応じて、単一の命令を実行するためにCPUが何をしなければならないかを理解するには、次のようにします。

MOV AX,[SI+10]のような単純なものを考えてみてください。これは、人間が単純に「SIプラス10のWordでAXをロードする」と考えるものです。大まかに言って、CPUは次のことを行う必要があります。

  1. pC(「プログラムカウンタレジスタ」)の内容をアドレスバスに送ります。
  2. データバスから命令オペコードを読み取ります。
  3. pCをインクリメントします。
  4. オペコードをデコードして、それをどうするかを判断します。
  5. pCの内容をアドレスバスに送ります。
  6. データバスから命令オペランド(この場合は10)を読み取ります。
  7. pCをインクリメントします。
  8. オペランドとSIを加算器に供給します。
  9. 加算器の結果をアドレスバスに出力します。
  10. データバスからAXを読み取ります。

これはなんと10ステップです。これらの手順の一部は、パイプライン化されていないCPUでも最適化されます。たとえば、CPUはほとんど常に次の手順と並行してPCをインクリメントします。これは、PCが非常に特別なレジスターであるため、簡単に実行できます。他のジョブには使用されないため、この特定のレジスタにアクセスするためにCPUの異なる部分間で競合が発生する可能性はありません。しかし、それでも、そのような単純な命令には8つのステップが残されており、CPUに代わってある程度の高度化をすでに想定していることに注意してください。たとえば、このための追加のステップ全体は必要ないと想定しています。結果を読み取る前に実際に加算を実行する加算器。加算器の出力は、中間の内部アドレッシングレジスタに格納する必要なく、直接アドレスバスに送信できると想定しています。

ここで、MOV AX, [DX+SI*4+10]などのより複雑なアドレス指定モードと、実際にCPU内でループを実行して結果を計算するMUL AX, operandなどのさらに複雑な命令が存在することを考慮してください。

つまり、ここでの私のポイントは、「原子レベル」のメタファーは、CPU命令レベルには適していないということです。実際のロジックゲートレベルまで下げたくない場合は、パイプラインステップレベルに適している可能性があります。

19
Mike Nakis

GPSのない遠征のようなものだと考えてください。あなたは交差点に来て、曲がる必要があると思いますが、完全にはわかりません。それで、あなたはターンをします、しかしあなたの乗客に地図をチェックするように頼んでください。たぶん、あなたはあなたがどこにいるのかについて議論し終えるまでに、道を3マイル下っています。もしあなたが正しかったなら、あなたが曲がる前に立ち止まって議論した場合よりも3マイル離れています。あなたが間違っていた場合、あなたは振り向かなければなりません。

CPUパイプラインも同じように機能します。彼らが状態を確認できるようになるまでに、彼らはすでに道を進んでいます。違いは、3マイル戻る必要がないということです。つまり、試しても害はありません。

31
Karl Bielefeldt

私が理解しているように、分岐予測は、チェックする必要のある条件が、高価または進行中の何かの結果を必要とする場合に最も役立ちます。

順不同の実行などの場合は、分岐予測を使用して、パイプラインの空のスポットを埋め始めることができます。そうでなければ、CPUはそれを使用できません。何らかの理由でパイプラインにアイドルサイクルが存在しない状況では、はい、分岐予測に利益はありません。

しかし、ここでの鍵は、CPUが予測されたブランチの1つに対して作業を開始していることです。これは、条件自体をまだ評価できないことができないためです。

2
Dogs

ショートフォーム:

一部のCPUは、古い命令を完了する前に新しい命令で作業を開始できます。これらは、分岐予測を使用するCPUです。

擬似コードの例:

int globalVariable;
int Read(int* readThis, int* readThat)
{
    if ((globalVariable*globalVariable % 17) < 5)
       return *readThis;
    else
       return *readThat;
}

上記のコードは条件をチェックし、結果に基づいて、メモリロケーションaddThisに格納された値またはreadThatに格納された値を返す必要があります。分岐予測で条件がtrueであると予測された場合、CPUはaddThisステートメントを評価するために必要な計算を実行しながら、メモリロケーションifに格納された値を既に読み取ります。これは簡単な例です。

1
Peter

はい、条件はいずれかの方法でチェックされます。ただし、分岐予測の利点は、条件チェックの結果を待つ代わりに作業を行えることです。

エッセイを書く必要があり、それがトピックAまたはトピックBに関するものであるとします。以前のエッセイから、先生はトピックAがBよりも好きで、より頻繁に選択していることがわかります。彼の決定を待つ代わりに、最初のトピックについてのエッセイを書き始めることができます。現在、2つの結果が考えられます。

  1. あなたは間違ったトピックについてエッセイを始め、これまでに書いたものを落とさなければなりません。あなたは他のトピックについて書き始める必要があり、それはあなたが待っていたのと同じ時間の努力です。
  2. あなたは正しく推測し、あなたはすでに仕事を終えました。

最近のCPUは、IO応答または他の計算の結果を待っているため、ほとんどの時間アイドリングしています。この時間は、将来の作業に使用できます。

このアイドル時間に行っていることを却下しなければならない場合でも、プログラムが選択するパスを推測する機能があれば、より効果的です。そして、最近のCPUにはこの機能があります。

1
Otomo