●GPUによって大きく異なるマルチスレッディングの実装 NVIDIAは、次世代GPU「GeForce 8800(G80)」を発表した。G80はさまざまな新テクノロジ、新アプローチを取り込んでいるが、その中で目立たないながらも重要なのはマルチスレッディング機能の拡充だった。Shader時代のGPUにとってマルチスレッディングはキーテクノロジだからだ。 マルチスレッディングは、GPUのパフォーマンスを大きく左右する。特にUnified-Shader型アーキテクチャになると、マルチスレッディングがGPU性能のカギとなる。条件分岐などを多用する高度なシェーダプログラムや、物理シミュレーションのような非グラフィックス処理のプログラムでは、マルチスレッディングが特にそうだ。 GPUでマルチスレッディングが重要となるのは、GPU内部がプログラマブルな演算ユニットであるProgrammable Shader中心の構成になったためだ、プログラマブルな演算ユニットは、固定機能のパイプラインと異なり、効率的に稼働させることが難しい。演算ユニットを効率的に稼働させるために、CPUと同様にマルチスレッディングが必要になる。しかも、GPUのソフトウェア環境は、依存性のないタスクを無数に持つため、マルチスレッド化による効用が大きい。 プログラマブルプロセッサ化したGPUでは、メモリアクセスのレイテンシや命令フローの乱れがボトルネックとなる。CPU同様に、スレッディングによってメモリレイテンシやコントロールフローのレイテンシを隠蔽する必要がある。
しかし、GPUベンダーは、まだマルチスレッディングについて試行錯誤を繰り返している最中で、GPUによって実装がかなり異なっている。そして、実装方式によって、GPUの効率が大きく異なる。NVIDIAの過去のGPUが条件分岐に弱かったのも、Xbox 360 GPU(Xenos)がピーク性能をまだ発揮できていないのも、全てこのスレッディングの実装に起因している。つまり、Shader GPUのアーキテクチャの最大のカギは、この部分にある。 また、マルチスレッディングは、GPU全体のアーキテクチャやShaderの内部構造に大きく関わる。Shaderアーキテクチャに関しては、スレッディングをどうやっているかがわからないと、基本的な部分が見えてこない。 しかし、G80のマルチスレッディングを説明するには、まず、GPUの“マルチスレッディング”自体について説明する必要がある。そもそも、GPUでの「マルチスレッド」という単語は、CPUのマルチスレッドとは全く異なる意味を指している。さらに、GPUのマルチスレッディングは、しばしば異なる機能を指す場合がある。つまり、人やGPUメーカーによって、違う機能をマルチスレッディングと呼んでいる。そのため、スレッドという時に、それが何を指すのか、注意する必要がある。 また、GPUのマルチスレッディングについては、きちんとした説明がほとんどされていない。AMD(旧ATI)がRadeon X1800(R520)の発表時に多少公開した程度で、ドキュメントもほとんどないので、GPUベンダーの技術陣からインタビューで聞き出すしかないのが実情だ。しかも、GPUベンダーでもマーケティングサイドのスタッフだと、マルチスレッディングについてほとんど知識を持っていない。こうしたことが複合して、GPUのマルチスレッディングは非常にわかりにくくなっている。 ●3つのレイヤでコンテクストをスイッチするGPU では、現在わかっている限りのGPUのマルチスレッディングを整理してみよう。まず、GPUで言うスレッディング/スイッチングは、3つの異なるレイヤに分かれる。 (1)GPU全体のコンテクストのスイッチング (1)のコンテクストスイッチングのハードウェア化は、GPUで走るプログラムをノーコストまたは低コストにスイッチする機能だ。複数のコンテキストを保持しておくことで、シェーダプログラムやレンダーステイトの切り替えを高速にする。完全にコンテクストをハードウェアで保持すると、CPUのハードウェアコンテキストスイッチングと非常に似通ったものになる。CPU的な意味での(ファイングレインまたはコースグレイン)マルチスレッディングはこの機能となる。 また、GPUによってはShader群に対して複数のコンテクストのオブジェクトを同時に割り当て、並列に実行させることができる。その場合は、実質的にCPUのサイマルテニアスマルチスレッディング(Simultaneous Multithreading)と同じ機能となる。しかし、一般にGPU業界ではこの機能はマルチスレッディングとは呼ばない。ハードウェアコンテクストスイッチングが、最も一般的な呼び方だ。 (2)のShaderのスレッディングが、GPUのマルチスレッディングと呼ばれることが多い。これは、Shader(またはShader群)に対して割り当てるバッチの切り替えとなる。 GPUの場合、同じプログラムを使って、膨大な数のオブジェクト(ピクセルや頂点など)のプロセッシングを行なう。個々のオブジェクトのプロセッシングは独立した「スレッド」となっている。オブジェクト1個1個を個別に制御すると、膨大なコントロールが必要になってしまうため、通常のGPUは、オブジェクトを一定数まとめたバッチにする。 GPUでは、このバッチを「スレッド」と呼ぶことも多い。その場合、Shader(またはShader群)に対してスレッドとして複数のオブジェクトが割り当てられる。Shaderは、スレッドの中のオブジェクトを後述する方法で処理する。一般に、GPUではGPU内のShaderをクラスタ化して、各クラスタに対してそれぞれスレッドを割り当てて、複数スレッドに対する処理を並列化する。また、各Shaderがメモリ待ちでストールすると、スレッドを切り替えるマルチスレッディングを行なう。AMDの場合、マルチスレッディングと呼んでいるのはこの仕組みのことだ。 (3)のカスケード実行は、ストリームプロセッサであるGPUに特徴的な方式だ。各スレッドの中の個々のオブジェクトに対するプロセッシングを効率的に切り替える。そのために、一般的なGPUでは、プログラムをカスケード式に実行している。例えば、1つのスレッドにピクセル0からnまでのピクセルが含まれている場合は次のようになる。 Shaderはピクセル0からピクセルnまでの、それぞれのオブジェクトに対してカスケード式にプログラムを実行して行く。実行するプログラムには、命令(Inst)0から命令nまでの多数の命令が含まれる。Shaderは、最初に、ピクセル0の命令0を実行し、次にピクセル1の命令0を実行と、順番に同じ命令を実行し、ピクセルnまでを終える。命令0の実行を全てのピクセルに対して終えたら、再びピクセル0に戻って、今度は命令1を実行する。ピクセル0の命令1、ピクセル1の命令1……と実行し、ピクセルnの命令1までを実行する。あとは同じことの繰り返しだ。
Shaderは、プログラム中の命令を順番に実行し、処理するオブジェクトがスライドして行くイメージだ。目的は、これも(2)のShaderスレッディングと同じでメモリアクセスレイテンシの隠蔽だ。ややこしいのは、NVIDIAが3つ目のカスケード実行を、しばしばマルチスレッディングと呼んでいることだ。AMDもカスケード実行しているが、スレッディングと呼ぶことはない。 ●処理単位毎に階層化してスイッチする こうした3レベルのGPUのスイッチングは、かなりややこしいようだが、実際には切り替える単位の問題だと考えると話は簡単だ。つまり、次の3レベルでGPUは切り替えを行なっている。 (1)GPUコンテクストスイッチング=GPUで走るプログラムの切り替え 階層に従って、切り替えるコンテクストの単位も変わってくる。一番下のカスケード実行は、単純にカスケードさせるだけなので、もっともライトウエイトなスイッチングとなる。
こうした複合構造になるのは、グラフィックス処理では同じプログラムで、何千何万ものオブジェクトに対してプロセッシングを行なうからだ。GPUで走るプログラム自体も切り替えるが、ひとつのプログラムで処理するオブジェクトも切り替える。でも、オブジェクトはあまりに多いので、オブジェクトをスレッド(バッチ)単位にまとめておいて切り替えを行なう。さらに、スレッドの中にも多くのオブジェクトが含まれるので、そのオブジェクトはカスケード実行で簡易に切り替える。 今のGPUは、入れ子構造のように、スイッチングが重なった構造となっている。GPUがこうした方式を取るのは、階層的にスイッチした方が、膨大な数のオブジェクトのプロセッシングを管理するのが楽だからだ。CPUのように、少数のシーケンシャルなプログラムを実行するプロセッサとは基本的にスレッディングの考え方が異なる。 さらにややこしいのは、実際のGPUでは上の3つのレベルのスイッチングが相互に複雑に入り組んでいることだ。例えば、コンテクストスイッチして異なるプログラムのバッチを、異なるShaderクラスタに割り当てて、同時に走らせるといった並列化を行っている。独立して考えることができない。 また、一見無関係に見える要素も、スレッディングに大きく関わっている。例えば、Shaderで条件分岐命令を実行する場合の効率は、スレッドの単位で大きく左右される。 GPUはストリーム型の処理に最適なアーキテクチャに偏重している。そのため、命令レベルでの並列化はあまり行なわない。また、命令レベルの並列化のためのハードウェアもほとんど備えない。その代わり、処理するオブジェクトをスイッチことで並列化を図っている。その結果、GPUのパフォーマンス効率は、このスイッチングの効率に大きく左右される。 特に重要なのは、非グラフィックスアプリケーションだ。グラフィックスアプリケーションでは、プログラムの振る舞いはほぼ一定している。オブジェクト同士には依存性がなく、プロセッサ同士の連携は不要で、処理対象のオブジェクトが多数あるため、スループットだけが重要でレイテンシは許容できる。また、メモリのリード&ライトの多くは連続性があり、バーストで連続的に転送できる。 しかし、非グラフィックスアプリケーションになると、そうは行かない。オブジェクト同士に依存性があるケースがあり、レイテンシが非常に重要な処理が出てくる。また、メモリへの頻繁なランダムアクセスが必要がアプリケーションもある。そうすると、オブジェクトの切り替えを高速かつ効率的にできないと、ムダが生じてパフォーマンスが削がれてしまう。 そのため、NVIDIAはより汎用的なコンピューティングを念頭に置いたG80では、特にマルチスレッディングの機能を重視する必要があった。 □関連記事 (2006年11月14日) [Reported by 後藤 弘茂(Hiroshige Goto)]
【PC Watchホームページ】
|
|