後藤弘茂のWeekly海外ニュース

AMDの新GPUアーキテクチャ「Graphics Core Next」の秘密



●方向が揃ってきたNVIDIAとAMDのGPUアーキテクチャ

 AMDの新GPU「Radeon HD 7900(Tahiti:タヒチ)」は、Radeon HD 2000(R6xx)系以来、5年振りにプロセッサアーキテクチャを一新した。新アーキテクチャは単純に「GCN(Graphics Core Next)」と呼ばれている。AMDのGCNアーキテクチャは、プロセッサの基本の構造だけを見ると、NVIDIAのGeForce GTX 4/5(Fermi:フェルミ)や、IntelのLarrabee(現在はKnightsシリーズ)とよく似ている。いずれも、16レーンのベクタユニットを備えており、プレディケーションによるコントロールフロー制御ができる。

 ベクタユニットの基本構造が共通化したことは、3社のベクタプロセッシングへの足並みが、部分的にではあるが揃ったと言える。もっとも、IntelはPCクラスの製品には、旧来からの内蔵GPUコアを発展させたコアを提供しており、アーキテクチャが分断されている。

 Tahiti(Radeon HD 7900)の構造は、各プロセッシングクラスタ内部とGPU全体の構造のどちらも、NVIDIAのFermiとよく似ている。プロセッシングクラスタ内部には、16レーンのベクタユニットが複数個実装され、GPU全体は多数のプロセッシングクラスタに分割されている。個々のクラスタは個別に動作し、メモリとは双方向のクロスバースイッチとリード&ライトが可能なキャッシュ階層で結ばれている。下はTahitiの全体図と、FermiのGF100/GF110の全体図だ。

Tahitiの全体図
PDF版はこちら
GF100/110の全体図
PDF版はこちら

 TahitiとFermiがよく似ているのは偶然ではない。また、AMDがマネをしたという話でもない。GPUアーキテクチャを汎用コンピューティングに向けて最適化すると、自然に似通ったアプローチにたどり着くというだけの話だ。また、両社のアーキテクチャには、まだ大きな差異がいくつかあり、それは設計思想の違いを反映している。

 ただし、大枠では、AMDも汎用コンピューティングへとGPU設計を最適化し始めたことは確かだ。これまでは、汎用コンピューティングへの最適化を急ピッチで続けるNVIDIAと、グラフィックスへの最適化にこだわるAMDという際立った違いがあった。しかし、今後は、同じ土俵での戦いとなる。

 また、NVIDIAとAMDのGPUの性格やふるまいが、今後はある程度似通ったものになって行くことも意味している。GPUを汎用に使うヘテロジニアス(Heterogeneous:異種混合)コンピューティングへの道のりが、また一歩進んだ。

●中央化していた命令ユニットを各プロセッサクラスタに分散

 Tahiti(Radeon HD 7900)の全体構造を見ると、従来のAMD GPUとの間に、大きな断絶があることに気がつく。下の図は、AMDの旧世代のRadeon HD 6970(Cayman)の全体図だ。Caymanの図中で大きく目立つのは、Caymanでは各プロセッサに対する命令を発行するディスパッチユニットだ。図中で金色になっている部分でAMDは「Ultra-Threaded Dispatch Processor」と呼んでいた。

Caymanの全体図
PDF版はこちら

 Caymanは実質的にデュアルコアGPUで、2系統のグラフィックスエンジンとシェーダコア群を持っている。そのため、命令ディスパッチユニットも2系統に分かれており、2個の命令ユニットそれぞれが、12個のプロセッサクラスタであるSIMDエンジンに命令を発行していた。各SIMDエンジン毎に命令シーケンサが2系列あり、交互に命令発行を行なっていたため、1命令ユニット毎に合計で24個の命令シーケンサが保持されている。2つに分かれてはいるものの、中央の命令ユニットが各SIMDエンジンを制御する集中制御方式だ。

 それに対して、Tahitiの全体図には、従来の中央制御の命令ユニットが見当たらない。ワークディストリビュータが、各エンジンに対するタスクの分配を行なうが、実際の命令のハンドリングは中央制御ではなくなっている。命令ハンドリングの機能は、Tahiti(Radeon HD 7900)ではプロセッサクラスタである「コンピュートユニット(Compute Unit:CU)」に分離されている。

 簡単に言えば、CaymanまでのAMD GPUは、中央の命令ユニットがプロセッサを制御する中央官制方式、Tahitiは、各プロセッサの命令ユニットが独立して命令制御する分散方式だ。命令の発行やスケジューリングなどの制御は、クラスタ単位で制御され、中央はタスクを割り当てるだけとなる。この変更は、Tahitiでの、プロセッサの設計思想の変更と大きく絡んでいる。

●NVIDIAのSMに似たGCNのCU(Compute Unit)の構造

 AMDがTahitiから採用したGCNアーキテクチャでは、GPUは「コンピュートユニット(Compute Unit:CU)」と呼ばれるプロセッサクラスタで構成される。コンピュートユニットは、演算ユニット、ロード/ストア&テクスチャユニット、キャッシュ&ローカルスクラッチパッドメモリ、命令ユニットを備えた、フルのプロセッサだ。下の図がCU(Compute Unit)の全体だ。

CUの全体図
PDF版はこちら

 ここで面白いのは、TahitiのCU(Compute Unit)が、NVIDIAのFermiアーキテクチャでのプロセッサクラスタであるSM(Streaming Multiprocessor)とよく似ていることだ。下は、FermiのGeForce GTX 560 Ti(GF114)系のSMのブロック図だ。どちらも16レーンのベクタユニットを複数個備え、命令ユニットから複数のスレッドの命令を同時に発行する。基本の構造は、よく似ている。

GF104のSM
PDF版はこちら

 旧来のAMD GPUでは中央にあった命令ユニットは、GCNのCU(Compute Unit)では、CUに備えられている。命令の流れを追うと、まず、図中の一番上の命令フェッチアービトレーションユニット(Instruction Fetch Arbitration)が、4個のCUで共有するL1命令キャッシュから命令をフェッチする。

 次に、フェッチした命令を、4個の命令バッファに振り分ける。図中で「SIMDx Program Counter & Instruction Buffer」となっている4ユニットがそれだ。AMD GPUでは、Wavefrontと呼ぶ64スレッドのバッチ単位で処理を行なう。つまり、物理的ユニットなベクタ長は16レーンだが、論理的なベクタ長は64レーン分となる。命令ユニットの、命令バッファとプログラムカウンタは、64スレッドの束であるWavefront単位で制御する。

 それぞれのWavefrontは、同じプログラムを実行する場合も、プログラムの進行は揃わない。そのため、各Wavefront毎に、プログラムカウンタが必要となる。また、CU(Compute Unit)は多数のWavefrontを立ち上げて、動的に切り替えるため、多くのプログラムカウンタが必要となる。

●Bulldozerに少し似ているGCNのマルチWavefrontアーキテクチャ

 命令ユニットの中の4個のバッファユニットは、それぞれ4個のベクタ演算ユニットに対応している。ベクタ演算ユニットは、図中では青い16本の円柱で示されており、SIMD 0からSIMD3までの名前が振られている。SIMD 0~3の4個のベクタ演算ユニットは、それぞれSIMD 0~3までの専用の命令シーケンサが制御する特定のWavefrontの命令を実行する。

 例えば、SIMD 0で実行しているWavefrontが、SIMD 1に移るといったことはない。そもそも、ベクタレジスタ自体が各ベクタユニットに付属しており、レジスタを相互参照ができないため、物理的に実行中のWavefrontの移動はできないという。SIMD 0でバッファしているWavefrontの命令は、必ず、SIMD 0ユニットに発行される。

 つまり、命令スケジューリング的には、CUは4個の分離したベクタユニットと、それに対応する命令ユニットを束ねたものとなっている。CPU的な例えをすれば、4個のCPUコアを1つに束ねたような姿だ。

CUでの命令スケジューリング
PDF版はこちら

 この構造は、AMDのBulldozer(ブルドーザ)アーキテクチャのマルチスレッドCPUと比べるとわかりやすい。BulldozerのCPUモジュールは、2個のスレッドを同時に走らせることができる。2個の整数演算ユニットはそれぞれスレッドが占有し、他のユニットは2スレッドで共有する。

 GCNのCUも似たような構造を取っており、4個のベクタ演算ユニットは、並列に走る4個のWavefrontがそれぞれ占有するが、他のユニットは共有する。その意味では、GCNのCU(Compute Unit)は、マルチコア的な構造を持っていると言える。ただし、実際には、GCNは、4個のWavefrontだけでなく、より多くのWavefrontをインフライトで走らせることができる。レジスタ数が許す限りのWavefrontを立ち上げることが可能で、ベクタレジスタは256本なので、例えば、各スレッドにつき32本のベクタレジスタを割り当てるなら、各ベクタユニット毎に8Wavefrontを同時に走らせることが可能だ。

マルチスレッディングのアーキテクチャ比較
PDF版はこちら

 GCNのCU(Compute Unit)では、命令ユニットの内部の4ブロックに分かれた命令バッファ&プログラムカウンタによって、4グループのWavefront群がプールされる。そして、プールされたWavefrontの中から、命令発行アービトレーションユニット(Instruction Issue Arbitration)が実行できる命令を調停して、各ユニットに発行する。

 命令発行ユニットは、1サイクルに最大5命令を発行できる。発行されるそれぞれの命令は、異なるWavefrontの命令となる。そのため、スーパースカラCPUのように、同時に発行する命令の依存性を細かくチェックする必要がない。CPUのような複雑な命令制御機構を持たなくても、比較的シンプルな命令ユニットで、多くの命令を並列に発行できる。

●Structure of Arrays(SOA)とArray of Structures(AOS)

 GCNの実行ユニットの核となるのは、4個の16レーンベクタユニットだ。GPUはベクタユニットを中心に構成されるが、この部分がGCNと従来のAMD GPUで大きく異なる。アーキテクチャ面での最も大きな変化は「Structure of Arrays(SOA)」方式へ転換したことだ。ベクタ演算をSOAにすることで、汎用コンピューティングでのパフォーマンスとプログラム性を上げようとしている。

 ベクタユニットの使い方には2つの方法がある。「Array of Structures(AOS)」または「パックド(Packed)」と呼ばれる方式と、「Structure of Arrays(SOA)」または「スカラ(Scalar)」と呼ばれる方式だ。下の図のように、ベクタユニット上で、どのような並び方でデータを扱うかが異なる。

AOSとSOAの比較
PDF版はこちら

 図の例は、16レーンのベクタユニットで、64個のデータを処理する場合だ。ベクタユニットに含まれる16個の演算ユニットは、SIMD(Single Instruction, Multiple Data)型で、16個のユニットが同じ命令を16個の異なるデータに対して実行する。CPUは、4レーン(単精度浮動小数点演算の場合)のSSEか、8レーンのAVX(Advanced Vector Extensions)だが、現在のGPUでは16レーン程度が一般的だ。

 図の例では、16個のピクセルデータを処理することを想定している。各ピクセルがRGBの3カラーデータとアルファデータを持つため、1ピクセルにつきRGBAの4データとなっている。16ピクセル分のRGBAで、データは合計で64個となる。ベクタユニットは16レーンなので、4サイクルで実行できる。

 AOSの場合は、RGBAの4データのパックを4個並べて16レーンを埋める。つまり、各サイクルに、4ピクセルを同時に処理する。RGBAのデータパックは崩さない。

 それに対して、Structure of Arrays(SOA)では、RGBAの4データのパックを崩してしまう。16個のピクセル全てのデータを順番に処理して行く。例えば16ピクセルの中のRに対して命令を実行し、次に16個のGに対して命令を実行する。

●SOAへと流れるGPUアーキテクチャ

 こうして見ると、AOSとSOAは、どちらも同じように効率的に見える。ところが、場合によっては効率が大きく変わる可能性がある。それは、AOSでは、データのパックをうまく揃えなければならないからだ。例えば、データが頂点のXYZの3値だった場合には16レーンにうまく収まらない。下の図がその例だ。

AOSにXYZの3値を収めた場合
PDF版はこちら

 この場合、AOSでは、XYZの3データの後にブランクスロットを入れるなどの工夫が必要で、その場合は16レーンで4頂点しか処理できない。演算ユニットは4分の1が遊ぶことになり、75%の稼働率に落ちてしまう。ベクタユニットをAOSに最適化して4レーン毎に分割していた場合は、この方法しかなく、効率が悪化する。

 それに対してSOAの場合は、どんな場合も100%の稼働率を得ることができる。もちろん、16スレッドが揃った場合の話だ。SOAでは、各スレッドのXYZの3データを各サイクルに順番に実行するだけなので、ムダが生じない。AOSでは、16頂点の演算に4サイクルかかるのに、SOAだと3サイクルで済んでしまう。効率もスピードも、SOAに分がある。もし、1スレッドに1データだけの場合は、さらにAOSとSOAの効率の差が開く。

 もちろん、トレードオフもある。SOAでは、SOAの構造に合わせてデータの並べ変えをする必要がある。データは、メモリ上でAOSに適した並び方をしている場合が多い。それを並べ変えてレジスタに収納する必要がある。しかし、データ並び替えのオーバーヘッドがあっても、演算が多い場合はSOAが有利となる。

 SOAでは16レーンで16スレッド全てに同じ命令を実行する必要がある。そのため、スレッドによって命令フローが分岐するような場合は、問題が生じてしまう。そのため、SOAを前提とする広幅のベクタユニットでは、マスクレジスタを遣ったプレディケーションを行なうのが一般的だ。

ベクタ条件分岐
PDF版はこちら

 プレディケーションでは、各レーンのスレッド毎に、命令を実行するかしないか(または演算の結果をレジスタに書き込むか書き込まないか)をマスクレジスタによって選択できる。そのため、レーン上のスレッドに分岐が発生しても、対応できる。

 NVIDIAは、GPUアーキテクチャをユニファイド型に変更したGeForce 8(G80)世代から、SOAアーキテクチャを取った。IntelのLarrabeeでは、SOAに最適なアーキテクチャをとった。それに対して、AMDは異なるアプローチで、短いベクタユニットを16個、SIMD(Single Instruction, Multiple Data)で動作させる方法を取った。しかし、GCNでは、NVIDIAやIntelのように、SOAに合わせた16レーンベクタユニットへと変更した。その理由は、汎用コンピューティング時の効率を高めるためだ。今回のAMDのアーキテクチャ変更のキーポイントはそこにある。次の記事で説明したい。