HN 日本語サマリー

← 一覧へ戻る
プログラミング

GPUがメモリに書き込む際に何が起こるか

What happens when a GPU writes memory (blog.doubleword.ai)

9 pointsby ibobev0 コメント

要約

この記事では、GPUの命令であるSTG.Eがグローバルメモリにデータを書き込むプロセスを詳細に追跡します。命令がワープから発行され、LSU、Coalescer、L1キャッシュ、クロスバーを経てL2キャッシュに到達するまでの各段階での処理と、L2キャッシュでのデータの保持、そして最終的にDRAMへの書き戻し(エビクション)のメカニズムについて解説しています。

全文翻訳

前回の投稿では、LDG.E命令がRTX 4090のL1、トランスレーション、クロスバーを経てL2スライス、そしてDRAMへとどのように進むかを追跡しました。リクエストはその結果を取得し、ウェイステーションを戻ってワープに結果を返し、カーネルの実行を続行しました。そのカーネルはベクター加算を実行するものでした。同じカーネルは、両方のベクターの要素をロードした後、それらを加算し、結果をストアします。 /*00c0*/ IMAD.WIDE R6, R6, R7, c[0x0][0x170] ; // &c[i] /*00d0*/ FADD R9, R4, R3 ; // a[i] + b[i] /*00e0*/ STG.E [R6.64], R9 ; // c[i] = ... /*00f0*/ EXIT ; STG.Eは、計算された合計をグローバルメモリに書き戻す責任を持つ命令です。この記事では、STG.Eを同じウェイステーションを通して追跡し、各ステップで何が起こるかを解明します。以前と同様に、この情報はすべて公開されているわけではありません。公開されていない場合は、新しい実験を行います。状況設定:LDG.Eはワープに戻り、FADDはR4とR3の内容をR9に加算しました。そして今、そのレジスタの内容をストアする必要があります。ワープはそのサブパーティション内で適格となり、そのレーンはSTG.Eの実行を開始します。 ワープから発行されたSTG.E [R6.64], R9は、レジスタR9の32ビットデータを、R6とR7の64ビットアドレスにグローバルストアします。LDG.Eではレジスタファイルの2行を読みましたが、STG.Eでは3行読む必要があります。ストアするデータのアドレスを構成する2行と、データそのものです。その後、命令はロード/ストアユニットに発行されます。LSUはオペコード(これらのアドレスへのストア)、アクティブなレーンの32ビットマスク、および計算された32個のアドレスを送信します。 SMはどのくらいの頻度でストアを発行できるか? 1つのワープは、レーンの発行数に関係なく、約6.1サイクル(2.6GHzで2.3ns)ごとにレジスタ/LSU/Coalescer/L1を新しいSTG.E命令でプッシュできます。SMの出口は、サイクルあたり32バイトのストア(またはロード)を維持できるため、すべてのワープが発行している場合、ここでボトルネックになります。次の停止はCoalescerです。その仕事は、32個の4バイトアクセスを受け取り、それを達成可能な最小限の32バイトセクター数に変換することです。私たちのカーネルは128バイトの連続データを書き込むため、それは4セクター、つまり1ラインになります。ロードは常にセクターあたり32バイトをプルし、LSUで結果がフィルタリングされて、SASSが実際に要求したものをレジスタに書き込みます。ストアの場合、各セクターリクエストはバイトマスクとともに発行され、この命令が書き込んでいるセクターのどのバイトを示します。4つのセクター、4つのマスク、および128バイトのデータがL1に進みます。 L1を通過する 4つのセクターはL1キャッシュに到達します。前回、L1キャッシュはSMあたり4ウェイセットアソシアティブで、仮想インデックス、仮想タグ付けされていることを示しました。ラインが存在するかどうかに関わらず、セクター、マスク、データはL2に直接進みます。L1はライトスルーです。ストアがセット内にスペースを必要とする場合、古いスロットは厳密なLRU順に道を譲ります。L1の下では、ストアの仮想アドレスが変換され、4つのセクターがクロスバーを横切ってラインを所有するL2スライスに移動します。 L2に到着する リクエストはクロスバーを介して36個のL2スライスの1つに送信されます。スライスは、前回リバースエンジニアリングしたのと同じ物理アドレスの関数によって選択されます。ラインのアドレス、最大4つのセクターのデータ、およびそれらのセクターのマスクを運びます。ストアはラインごとに1つのリクエストを発行します。スライス内では、各キャッシュは16ウェイセットアソシアティブで、1024セットがあり、物理アドレスによってハッシュされます。ラインが既に存在する場合、バイトは各セクターのマスクによって選択され、スロットに書き込まれ、セクターはダーティとしてマークされます。ラインが存在しない場合、スライスはそれを見つけるためのスロットを見つける必要があります。それを行うには、他のラインのバイトをDRAMに追い出す必要があるかもしれません。場所が見つかると、バイトがスロットに書き込まれ、マスクはセクターのどのバイトが有効かを記録します。バイトがスロットに入ると、スライスはSMに確認応答をクロスバー経由で返します。確認応答後、4つのセクターはそのスロットにダーティとしてマスクの下に配置されます。 書き込みの完了 確認応答はクロスバーを介してストアを送信したSMに戻ります。ストアを発行したワープはとっくに先に進んでいます。実際、ここではカーネル全体が終了しています。そのため、確認応答はLSUに到達し、そこで消費されます。実際、このカーネルでは、データはDRAMに到達しません!元の投稿のカーネルは、これらの書き込まれた結果をcudaMemcpyDeviceToHostで読み取り、L2からPCIeバスを経由してホストDRAMに直接取得します。それ自体が興味深いスレッドであり、別の機会に追跡する価値があります。ハードウェアは現在、L2にダーティなデータを保持しています。STG.E命令を完了しました。それが意味を持つためには、後続のカーネルからのデータへのポインタは、そこでデータを見つける必要があります。しかし、それはキャッシュ内のダーティな状態であり、まだDRAMにヒットしていません。どのようにしてそこに行くのでしょうか?いつ旅行するのでしょうか? ストア命令のその後 L2はチップのすべてのトラフィックのシリアライゼーションポイントとして機能しますが、ある時点でスペースがなくなると、何かを追い出す必要があります。データはL2にあります。私たちのカーネルの後、別のカーネルが来ます。そのカーネルはデータを読み取るか、書き込むか、私たちのラインを欲しがるか、他のラインを欲しがるかもしれません。そのカーネルが実行されるにつれて、私たちのデータはDRAMに移動する必要があります。 データがDRAMに到達する方法 私たちのデータの各ラインは、2ビットの「再参照予測値」(RRPV)とともに格納されます。これは000、111、または222に設定されます。低い数値は、キャッシュがラインをすぐに再利用すると考えていることを意味します。私たちのキャッシュラインは111にあり、挿入されたばかりです。各ラインには「ダーティマスク」があり、L2がこのバージョンのラインが存在する唯一の場所であるかどうかを示します。私たちのラインはすべて完全にダーティです。各ラインには、最後の使用と最後のストアのカウンターもあります。ラインに対する新しいロードまたはストアが入ってきます。何が起こるのでしょうか? レジデントヒットの場合:ロードが私たちのラインの1つを探して入ってくると、それを取得します。ラインのRRPVは000に設定されます。ストアが入ってきてラインにヒットした場合、そのセクターがラインにヒットし、「ダーティマスク」が更新されます。 ミスの場合:L2は、ミスした値をキャッシュにロードする必要があります。それを行うには、犠牲者を見つける必要があります。置換ポリシーは次のように機能します。まず、セット内のすべての16ウェイをスキャンして、RRPV=2のもの(つまり、キャッシュが再利用しないと考えているもの)を探します。それらが見つからない場合は、すべてのRRPV値をインクリメントし、再度スキャンします。RRPV=2の値の中から、最も最近使用されていないものを選択します。次に、犠牲者に何をするかを決定します。犠牲者がダーティである場合(つまり、L2が唯一存在する場所であり、それを追い出すとすぐにDRAMと通信する必要がある場合)、まだキャッシュから追い出しませんが、クリーニングを開始します。唯一の方法は、ダーティセクターをメモリコントローラーに渡してDRAMに書き戻すことです。ラインはセットのFIFO書き込みバッファに入り、読み取り可能になります。次に、クリーンな犠牲者を探してウェイを再度スキャンします。1つ見つけると、それを追い出し、そのウェイを奪います。新しいラインはそのウェイにスロットインされ、RRPVは1に設定されます。 セットをクリーンに保つ 説明したポリシーは、ガバナンスを制御します。