概要:シングルスレッドプログラムで(命令レベルの)並列処理を見つけて活用することは、純粋にハードウェアで実行され、CPUコアによって実行されます。 そして、大規模な並べ替えではなく、数百の命令のウィンドウでのみです。
シングルスレッドプログラムはマルチコアCPUの利点を享受しませんが、シングルスレッドタスクから時間を奪う代わりに他のものを他のコアで実行できる点が異なります。
OSは、すべてのスレッドの命令を、互いを待たないように編成します。
OSは、スレッドの命令ストリームの内部を調べません。スレッドをコアにスケジュールするだけです。
実際、各コアは、次に何をすべきかを判断する必要があるときに、OSのスケジューラー機能を実行します。スケジューリングは分散アルゴリズムです。マルチコアマシンをよりよく理解するには、各コアを個別にカーネルを実行していると考えてください。マルチスレッドプログラムのように、カーネルは、1つのコアのコードが他のコアのコードと安全に対話して共有データ構造(実行可能なスレッドのリストなど)を更新できるように記述されています。
とにかく、OSは、マルチスレッドプロセスを手動でマルチスレッドプログラムを記述することによって明示的に公開する必要があるスレッドレベルの並列性を活用するマルチスレッドプロセスの支援に関与しています。(または、OpenMPなどを使用した自動並列化コンパイラーによる)。
次に、CPUのフロントエンドは、各コアに1つのスレッドを配布することにより、これらの命令をさらに整理し、オープンサイクル間で各スレッドから独立した命令を配布します。
CPUコアは、停止されていない場合(タイマー割り込みなどの次の割り込みまでスリープ状態)、1つの命令ストリームのみを実行しています。多くの場合、これはスレッドですが、カーネル割り込みハンドラー、またはカーネルが処理および割り込みまたはシステムコールの後に単に前のスレッドに戻る以外のことを行うことを決定した場合は、雑多なカーネルコードでもあります。
ハイパースレッディングまたはその他のSMT設計では、物理CPUコアは複数の「論理」コアのように機能します。クアッドコア付きハイパースレッド(4c8t)CPUとプレーン8コアマシン(8c8t)のOSの観点からの唯一の違いは、HT対応OSがスレッドをスケジュールして物理コアを分離することですtは互いに競います。ハイパースレッディングを知らなかったOSは、8コアしか表示しません(BIOSでHTを無効にしない限り、4コアしか検出しません)。
「フロントエンド」という用語は、マシンコードをフェッチし、命令をデコードし、それらをコアのアウトオブオーダー部分に発行するCPUコアの部分を指します。各コアには独自のフロントエンドがあり、コア全体の一部です。フェッチする命令は、CPUが現在実行しているものです。
コアのアウトオブオーダー部分では、入力オペランドの準備ができ、空き実行ポートがある場合、命令(またはuop)が実行ポートにディスパッチされます。これはプログラムの順序で発生する必要はないため、OOO CPUが単一スレッド内で命令レベルの並列性を活用する方法です。
あなたのアイデアで「コア」を「実行ユニット」に置き換えれば、あなたは正解に近いでしょう。はい、CPUは独立した命令/ uopsを並列に実行ユニットに配布します。(しかし、実際にはCPUの命令スケジューラー、別名リザベーションステーションが実行準備が整った命令を選択するときに「フロントエンド」と言ったので、用語の混同があります)。
順不同の実行では、ILPは非常にローカルなレベルでのみ検出され、2つの独立したループ間ではなく、最大200命令までです(短い場合を除く)。
たとえば、これと同等のasm
int i=0,j=0;
do {
i++;
j++;
} while(42);
Intel Haswellで1つのカウンターをインクリメントするだけで、同じループとほぼ同じ速度で実行されます。 i++
唯一の以前の値に依存しi
ながら、j++
唯一の以前の値に依存しますj
ので、2つの依存関係の鎖はプログラムの順序で実行されているすべての幻想を壊すことなく、並列に実行することができます。
x86では、ループは次のようになります。
top_of_loop:
inc eax
inc edx
jmp .loop
Haswellには4つの整数実行ポートがあり、すべてに加算器ユニットがあるため、inc
すべて独立している場合、1クロックあたり最大4 命令のスループットを維持できます。(latency = 1の場合、4つのinc
命令のみを実行してスループットを最大化するために4つのレジスタのみが必要です。これをvector-FP MULまたはFMAと比較してください。また、各ベクトルは256bで、8つの単精度浮動小数点数を保持できます)。
分岐分岐はボトルネックでもあります。分岐分岐のスループットは1クロックにつき1に制限されているため、ループは反復ごとに少なくとも1クロック全体を常に必要とします。パフォーマンスを低下させることなく、ループ内にもう1つの命令を配置できます。ただし、読み取り/書き込みも行う場合、eax
またはedx
依存関係チェーンを長くする場合を除きます。ループ内にさらに2つの命令(または1つの複雑なマルチuop命令)を入れると、アウトオブオーダーコアへのクロックあたり4 uopしか発行できないため、フロントエンドでボトルネックが発生します。(4つのuopの倍数ではないループで何が起こるかについての詳細は、このSO Q&Aを参照してください:ループバッファとuopキャッシュは面白くします。)
より複雑な場合、並列処理を見つけるには、命令のより大きなウィンドウを調べる必要があります。(たとえば、すべて互いに依存する10個の命令のシーケンスがあり、次に独立した命令がある場合があります)。
リオーダーバッファ容量は、アウトオブオーダーウィンドウサイズを制限する要因の1つです。Intel Haswellでは、192 uopです。(また、レジスタ名の変更容量(レジスタファイルサイズ)とともに、実験的に測定することもできます。)ARMなどの低電力CPUコアは、アウトオブオーダー実行を行う場合、ROBサイズがはるかに小さくなります。
また、CPUをパイプライン化する必要があることに注意してください。そのため、実行中の命令よりもかなり先に命令をフェッチしてデコードする必要があります。フェッチサイクルを逃した後にバッファを補充するのに十分なスループットが必要です。ブランチがどの方向に進んだかわからない場合、どこからフェッチすればよいかわからないため、ブランチは扱いにくいです。これが、分岐予測が非常に重要な理由です。(そして、現代のCPUが投機的実行を使用する理由:分岐がどの方向に進むかを推測し、その命令ストリームのフェッチ/デコード/実行を開始します。予測ミスが検出されると、最後の既知の正常な状態にロールバックし、そこから実行します。)
CPU内部について詳しく知りたい場合は、Stackoverflow x86タグwikiにリンクがあります。AgnerFogのmicroarch ガイド、David KanterのIntelおよびAMD CPUの図を含む詳細な記事へのリンクなどがあります。彼のIntel Haswellマイクロアーキテクチャの記事から、これはHaswellコアのパイプライン全体の最終図です(チップ全体ではありません)。
これは、単一の CPUコアのブロック図です。クアッドコアCPUには、チップ上にこれらの4つがあり、それぞれ独自のL1 / L2キャッシュ(L3キャッシュ、メモリコントローラー、およびシステムデバイスへのPCIe接続を共有)を備えています。
私はこれが圧倒的に複雑であることを知っています。Kanterの記事では、たとえば、実行ユニットやキャッシュとは別にフロントエンドについて説明するために、この部分も示しています。