単一のスレッドは複数のコアでどのように実行されますか?


61

私は、シングルスレッドが複数のコアでどのように実行されるかを高レベルで理解しようとしています。以下は私の理解です。私はそれが正しいとは思わない。

Hyper-threadingの私の読書に基づいて、OSはすべてのスレッドの命令を、それらが互いに待機しないように編成しているようです。次に、CPUのフロントエンドは、各コアに1つのスレッドを配布することにより、これらの命令をさらに整理し、オープンサイクル間で各スレッドから独立した命令を配布します。

そのため、スレッドが1つしかない場合、OSは最適化を行いません。ただし、CPUのフロントエンドは、独立した命令セットを各コアに分配します。

https://stackoverflow.com/a/15936270によると、特定のプログラミング言語が作成するスレッドは多かれ少なかれありますが、それらのスレッドで何をすべきかを判断する際には無関係です。OSとCPUがこれを処理するため、使用されるプログラミング言語に関係なくこれが発生します。

ここに画像の説明を入力してください

明確にするために、単一のコアで複数のスレッドを実行するのではなく、複数のコアで実行される単一のスレッドについて尋ねています。

要約の何が問題になっていますか?スレッドの命令は複数のコアにどこでどのように分割されますか?プログラミング言語は重要ですか?これは広範なテーマであることを知っています。私はそれについて高レベルの理解を望んでいます。


6
単一のソフトウェアスレッドに対する一連の命令は、多くのコアで実行できますが、一度に実行することはできません。
-Kroltan

1
ソフトウェアスレッド(OSスケジューラを含む)とハードウェアスレッドまたはハイパースレッディング(1つのコアを2つのように動作させるCPU機能)を混在させています。
ウゴレン

2
20人のドライバーと4つのトラックがあります。1人のドライバーが2台のトラックで荷物を配達できるのはどうしてですか?1台のトラックに複数のドライバーがいる可能性はありますか?両方の質問に対する答えは同じです。交代してください。
エリックリッパー

回答:


84

オペレーティングシステムは、実行に適格なスレッドにCPUのタイムスライスを提供します。

コアが1つしかない場合、オペレーティングシステムは、タイムスライスの間、そのコアで実行する最も適格なスレッドをスケジュールします。タイムスライスが完了した後、または実行中のスレッドがIOでブロックされたとき、またはプロセッサが外部イベントによって中断されたとき、オペレーティングシステムは次に実行するスレッドを再評価します(同じスレッドを再度選択するか、別のスレッドを選択できます)。

実行の適格性は、公平性と優先度と準備状況のバリエーションで構成され、この方法により、さまざまなスレッドがタイムスライスを取得します。

複数のコアNがある場合、オペレーティングシステムは、最も適格なNスレッドをコアで実行するようにスケジュールします。

プロセッサアフィニティは、効率性の考慮事項です。CPUが以前とは異なるスレッドを実行するたびに、キャッシュは前のスレッドに対しては温かいが、新しいスレッドに対しては冷たいため、少し遅くなる傾向があります。したがって、多数のタイムスライスにわたって同じプロセッサで同じスレッドを実行することは、効率上の利点です。

ただし、オペレーティングシステムは異なるCPU上で1つのスレッドタイムスライスを自由に提供し、異なるタイムスライス上のすべてのCPUを循環させることができます。ただし、@ gnasher729が言うように、複数のCPUで1つのスレッドを同時に実行することはできません。

ハイパースレッディングは、単一の拡張 CPUコアが2つ以上の異なるスレッドの同時実行をサポートできるハードウェアの方法です。(このようなCPUは、追加のフルコアよりもシリコンリアルステートで低コストで追加のスレッドを提供できます。)この強化されたCPUコアは、CPUレジスタ値など、他のスレッドの追加の状態をサポートする必要があり、調整状態と動作も備えていますスレッドを統合することなく、そのCPU内で機能ユニットを共有できるようにします。

ハイパースレッディングは、ハードウェアの観点からはプログラマーの観点からは技術的に挑戦的ですが、実行モデルはより複雑なものではなく、追加のCPUコアの実行モデルにすぎません。したがって、オペレーティングシステムは追加のCPUコアを認識しますが、いくつかのハイパースレッドスレッドが1つのCPUコアのキャッシュアーキテクチャを共有しているため、新しいプロセッサアフィニティの問題がいくつかあります。


ハイパースレッドコア上で実行される2つのスレッドは、それぞれが独自のフルコアを使用する場合の半分の速度で実行されると単純に考えるかもしれません。ただし、1つのスレッドの実行はスラックサイクルでいっぱいであり、他のハイパースレッドスレッドがそれらのスレッドの一部を使用できるため、必ずしもそうではありません。さらに、非スラックサイクル中であっても、1つのスレッドが他のスレッドとは異なる機能ユニットを使用しているため、同時実行が発生する可能性があります。ハイパースレッディング用の強化されたCPUには、それをサポートするために、特に使用頻度の高い特定の機能ユニットがいくつかあります。


3
「したがって、同じプロセッサ上で多数のタイムスライスにわたって同じスレッドを実行することは、効率上の利点です。」連続したタイムスライスである必要はないでしょうか。そうしないと、キャッシュは他のスレッドによって消去されてしまいますか?素敵な説明のために+1。
jpmc26

2
@Luaan:HTはしばしば良いですが、状況はあなたが説明するほど単純ではありません。フロントエンドの問題の帯域幅(Intelではクロックあたり4 uop、Ryzenでは6 uop)は、スレッド間で均等に共有されます(ストールしない限り)。それがボトルネックであれば、HTがまったく役に立たないと言ったように。負荷、ALU、およびストアが混在している場合、Skylakeが適切に調整されたループでそれに近づくことは珍しくありません...トランジスタは安価です(そして、一度にすべてを切り替えることができないか、CPUが溶けます)。その現代のx86 CPUは、複製され、多くの実行ユニットを(養うことができ、フロントエンドよりも実行ポートを持っている...
ピーター・コルド

2
...複数のポートで)...これは無駄に思えるかもしれませんが、多くの場合、ループは一度に1種類のALU実行ユニットのみを使用するため、すべての重複があるということは、実行中のコードの種類に関係なく、その指示のためのポート。したがって、ほとんどのコードにはフロントエンド帯域幅を占有する負荷やストアがあり、残りは実行ユニットを飽和させるのに十分ではないことが多いため、HTの恩恵を受けた理由はそれほど一般的ではありません。
ピーターコーデス

2
@Luaan:また、Intel CPUでは、整数とFP /ベクトル実行ユニットは同じ実行ポートを共有します。たとえば、FP FMA / mul / addユニットはポート0/1にあります。しかし、整数乗数もport1にあり、単純な整数opは4つの実行ポートのいずれかで実行できます(私の答えの図)。問題の帯域幅を使用している2番目のスレッドは、実行ユニットと競合していなくても両方とも速度が低下しますが、キャッシュとの競合が厳しくないと、多くの場合、純スループットが向上します。x264 / x265(ビデオエンコーダー)などの適切に調整されたハイスループットコードでさえ、HTのSkylakeで約15%のメリットがあります。
ピーターコーデス

3
@luaanピーターが言ったことに加えて、「それがHTの背後にある最初の理由」というあなたの主張は間違っています。HTの背後にある最初の理由は、NetBurstマイクロアーキテクチャがパイプラインを極端に延長し(クロック速度を上げるため)、分岐の予測ミスやその他のパイプラインのバブルパフォーマンスを完全に損なうことでした。HTは、この大きな高価なチップの実行ユニットがパイプライン内のバブルのためにアイドル状態であった時間を最小限に抑えるIntelのソリューションの1つでした。他のスレッドからのコードを挿入し、それらのホールに実行できます。
コーディグレー

24

複数のコアで同時に実行される単一のスレッドのようなものはありません。

ただし、1つのスレッドからの命令を並行して実行できないという意味ではありません。それを可能にする命令パイプライン化アウトオブオーダー実行と呼ばれるメカニズムがあります。各コアには、単純な命令では使用されない多くの冗長リソースがあるため、複数のそのような命令を一緒に実行できます(次の命令が前の結果に依存しない限り)。ただし、これは単一のコア内でも発生します。

ハイパースレッディングは、このアイデアの一種の極端な変形であり、1つのコアが1つのスレッドからの命令を並行して実行するだけでなく、2つの異なるスレッドからの命令を組み合わせてリソース使用をさらに最適化します。

関連するウィキペディアのエントリ:命令のパイプライン化順不同の実行


3
同時に実行することはできませんが、並行して実行できますか?これらは同じものではありませんか?
-Evorlor

10
@Evorlorここで重要なことは、コアと実行ユニットの違いです。単一のスレッドは1つのコアでのみ実行できますが、プロセッサは動的解析を使用して、コアによって実行される命令が相互に依存せず、これらを異なる実行ユニットで同時に実行できるようにします。1つのコアに複数の実行ユニットがある場合があります。
user1937198

3
@Evorlor:異常なCPU は、単一スレッドの命令ストリーム内の命令レベルの並列処理を見つけて活用できます。たとえば、ループカウンタを更新する命令は、ループが実行する他の作業の一部から独立していることがよくあります。または、a[i] = b[i] + c[i]ループでは、各反復が独立しているため、異なる反復からのロード、追加、およびストアを一度に実行できます。命令がプログラムの順序で実行されるという幻想を保持する必要がありますが、たとえば、キャッシュでミスしたストアは、スレッドを遅延させません(ストアバッファーのスペースがなくなるまで)。
ピーターコーデス

3
@ user1937198:「動的分析」というフレーズは、JITコンパイラに適しています。異常なCPUは実際には分析しませ。これは、デコードされて発行された命令を実行し、入力を準備する貪欲なアルゴリズムに似ています。(順不同の並べ替えウィンドウは、いくつかのマイクロアーキテクチャリソースによって制限されます。たとえば、Intel SandybridgeのReOrderバッファサイズは168 uopsです。ROBサイズの実験的な測定も参照してください)。すべてがハードウェアステートマシンで実装され、クロックあたり4 uopを処理します。
ピーターコーデス

3
@Luaanええ、それは興味深いアイデアでしたが、AOTコンパイラはまだそれを十分に活用するほど賢くはありません。また、Linus Torvalds(およびその他)は、パイプラインの内部の多くを公開することが将来の設計に大きな制約になると主張しています。たとえば、ISAを変更せずにパイプライン幅を実際に増やすことはできません。または、通常の方法で依存関係を追跡し、2つのVLIWグループを並行して発行するCPUを構築しますが、EPICのCPUの複雑さの利点は失われますが、欠点もあります(コンパイラーが満たせない場合、発行帯域幅が失われます)単語)。
ピーターコーデス

22

概要:シングルスレッドプログラムで(命令レベルの)並列処理見つけて活用することは、純粋にハードウェアで実行され、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の記事では、たとえば、実行ユニットやキャッシュとは別にフロントエンドについて説明するために、この部分も示しています。


2
「シングルスレッドプログラムでの(命令レベルの)並列処理の検索と利用は、純粋にハードウェアで行われます」これは、ILPがコンパイラまたはプログラマによって完全に決定されるVLIWではなく、ハードウェア間で協調的に行われる従来のISAにのみ適用されることに注意してくださいおよびソフトウェア。
ハディブライス

1
@ user7813604:はい。ハイパースレッディングは、単一のスレッドを並列化できません。逆に、1つのコアで複数のスレッドを実行し、スレッドごとのパフォーマンスを低下させますが、全体的なスループットを向上させます。
ピーター

1
@ user7813604:ILPの重要なポイントは、各命令が順番に実行されているという錯覚を維持しながら、どの命令を並列に実行できるかを見つけることです。レイテンシが1より大きい場合、スカラーパイプラインCPUは依存関係のために時々ストールする必要がありますが、スーパースカラーCPUではさらに大きな問題です。
ピーター

1
@ user7813604:はい、私の答えは文字通りそれを例として使用しています。たとえば、Haswellはinc、4つの整数ALU実行ユニットに対して、同じクロックサイクルで最大4つの命令を実行できます。
ピーター

1
@ user7813604:はい、ILPはどれだけ並列に実行できるかです。実際のCPUでは、単一のコア(Intelで最大4ワイドのスーパースカラーなど)内で実際に並列実行することにより、ILPを見つけて活用する能力が制限されます。この答えは、例を使ってそれを説明しようとします。
ピーター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.