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

ピーク性能から実効性能へとフォーカスが変わったAMDのGPUアーキテクチャ



●演算ユニットの構成が変わったAMDのGPUアーキテクチャ

 AMDは、かつてはGPUのピーク演算パフォーマンスを謳っていた。NVIDIAの同世代GPUと比べると倍以上も高い演算性能で、ダイ当たりのパフォーマンス効率を強調した。これは、AMD GPUが、演算プロセッサに対して、命令制御などのユニットの比率が極端に低く、そのため、GPUにより多くの演算ユニットを詰め込み、ピーク性能を上げることができたからだ。

 しかし、AMDのそうしたアプローチは終わりを迎えつつある。なぜなら、AMDは、ピーク性能を引き上げるより、汎用コンピューティング時の実効性能を追求する方向へと転じたからだ。AMDはNVIDIAと比べると、依然としてグラフィックス寄りだが、新GPU「Radeon HD 7900」(Tahiti:タヒチ)ファミリでは、従来よりぐっと汎用コンピューティング寄りになった。その結果、トランジスタ数の増加の割には、演算ユニット数やピークパフォーマンスは上がっていない。しかし、汎用処理時の効率は、アーキテクチャ上は大きく改善された。

 Tahiti世代のグラフィックスコアのアーキテクチャは「GCN (Graphics Core Next)」と呼ばれる。GCNは、AMDが満を持して出した、汎用コンピューティングに最適化した新世代コアだ。GCNではプロセッサのクラスタ「CU (Compute Unit)」が、独立した最小単位となっている。GPUはスケーラブルに実装できるCU群と、グラフィックス専用のユニット群やメモリコントローラなどで構成される。

Radeon HD 7900の概要
※PDF版はこちら

 なお、下の全体図中ではコマンドプロセッサがグラフィックス用とコンピュート用の2系統描いてあるが、実際にはコンピュート用の機能拡張がされたと見られる。コマンドプロセッサは、GPU全体で実行するプログラムのハンドリングを受け持つ部分で、CPU的に表現すればハードウェアによるスレッドスケジューリングエンジンだ。AMDのFSA (Fusion System Architecture)構想で示された、タスクキューもこの部分に実装されている。

 CUは下の図のように、命令ユニットから実行ユニット、ロード/ストアユニット、キャッシュまでを備えたフルのプロセッサとなっている。従来のRadeon HD 6970(Cayman)でCUに当たる単位のユニットは「SIMD(Single Instruction, Multiple Data) Engine」だが、かなり構造が異なっている。

Compute Uniteのブロックダイヤグラム
※PDF版はこちら
GCN Compute Unitマルチエンジン統合型コンピューティングGPU

 CaymanのSIMD Engineは下の図のように16個のVLIW(Very Long Instruction Word)プロセッサで構成されていた。それに対して、GCNのCUは16レーンのベクタユニット4個で構成されている。CaymanのSIMDエンジンは32-bit単精度浮動小数点演算ユニットが各プロセッサに4ユニットで、16プロセッサの合計で64ユニットとなる。それに対して、GCNのCUは32-bit浮動小数点演算ユニットが各ベクタユニットに16ユニットで、4ベクタユニット合計で64ユニットとなる。

AMD Cayman SIMDエンジンとVLIW4プロセッサ

 ちなみに、Cayman以前のAMD GPUは、5演算ユニットのVLIWプロセッサ構成で、SIMD Engineは80個の演算ユニットを備えていた。こうして見ると、CaymanのSIMD Engineと、TahitiのCUは、どちらも単精度演算ユニット数は同じであるのに、その構成が異なることがわかる。

AMD VLIW4、VLIW5、CUの比較
※PDF版はこちら

●64レーンのベクタに相当するWavefrontが処理の基本

 この違いは、プロセッサをどう制御するかの違いであり、また、どれだけ多くのスレッドを同時に走らせるかの違いでもある。GCNのCUの方が、従来のVLIW4/5よりプロセッサをより小さな粒度で制御し、より多くのスレッドを走らせる。これは、汎用コンピューティング寄りの設計だ。

命令バッファリングとフェッチ

 では、どうやってAMDはプロセッサを制御しているのか。GCNのCUでは、命令ユニットが4グループのプログラムカウンタ群と命令バッファ群を備えている。それぞれの命令バッファが、10以上の「Wave」の命令とステイトをバッファする。Waveは64個のワークアイテム(スレッド)をバンドルしたバッチで、1つのプログラムカウンタを共有する。つまり、64スレッドが基本的には同じ命令を実行する、64レーンのベクタとなっている。Waveの先頭の64スレッド分の命令が、Wavefrontとして実行ユニットに送られる。

 Waveが命令ストリームで、Wavefrontが命令ストリームの中の命令の波という位置づけだ。命令ストリームが波(Wave)のように実行ユニットに押し寄せ、1つ1つの命令が波頭(Wavefront)という表現だ。だが、実際にはAMDでも用語使い分けは厳密ではなく、通常は、Waveも含めてWavefrontと呼んでいる。この仕組みは、NVIDIAも同様で、NVIDIAでは32スレッドのバッチを「Warp」と呼んでいる。

CUのアーキテクチャ

 各ベクタユニットに対して10個のWavefrontなら、合計で40 Wavefrontが立ち上がることになる。各Wavefrontは64スレッドのバッチなので、合計で2,560スレッドとなる。ちなみに、GPUではプログラムが使うことができるレジスタ数は固定されていない。ネイティブコードへの変換時に動的に割り当てられるため、スレッド当たりのレジスタ数は変わる。1スレッドに多くのレジスタを割り当てると、立ち上げることができるスレッド/Wavefront数が減る仕組みだ。

 ベクタユニット側のベクタレジスタは、256-byte長のレジスタが256本なので、10のWavefrontを立ち上げると、計算上は1スレッド当たり25レジスタとなる。実際にはもっと切りのよい数字で制御しているはずだが、レジスタが大きくても立ち上げるスレッド数が多いため、1スレッド当たりのレジスタ数はそれほど多くならない。1スレッド当たりのレジスタを16本にした場合は、各ベクタユニット当たり16 Wavefrontで合計スレッド数は4,096になる計算だ。立ち上げ可能なスレッド数は極めて多いと推定される。

●シェーダプログラムの進化に応じてGPU構造を変革

 AMDがGCNで、プロセッサの構造を変えたのは、より柔軟で扱いやすいエンジンにするためだ。そもそも、GPUは頂点とピクセルのプロセッシングに適した4レーン程度のショートSIMDエンジンを多数備えていた。個々のSIMDエンジンは、元来は1命令を3~4個のワークアイテムに対して実行し、複数のSIMDエンジンも同じ命令を実行する。全体の構成としては、「Array of Structures (AOS)」型のパックドのアプローチを取っていた。

AOS vs SOA
※PDF版はこちら

 ところが、グラフィックスのシェーダプログラムが進化するにつれて、ショートSIMDで処理することができないスカラ命令が増えて来た。さらに、GPUコアの汎用コンピューティングへの利用が、その傾向を強めた。そこで、GPUはこの問題に対応するために、プロセッサの構成を変え始めた。NVIDIAは、完全な「Structure of Arrays (SOA)」(=スカラ)型へと切り替えた。それに対して、AMDはVLIW (Very Long Instruction Word)側にプロセッサを構成し直し、4~5個の演算ユニットの各レーンが異なる命令を実行できるようにした。また、VLIWプロセッサは16個で1クラスタとして、16個のVLIWプロセッサが同じVLIW命令をSIMD実行するアーキテクチャとした。

GPUプログラムの変化とGPUの対応の違い
※PDF版はこちら

 VLIWでは、コンパイラによって並列実行できる命令をあらかじめ1つの超長命令の中に組み込む。例えば、連続した命令A、B、C、Dの間に依存性がなく、並列に実行できる場合は、VLIWの命令スロットに命令A、B、C、Dを納めて、1個のVLIW命令にしてしまう。PC向けx86 CPUは、ハードウェアで命令を並べ変えて並列に実行するが、AMD GPUは似たようなことをコンパイラで命令を並べ変えることで実現する。

 この方法の利点は、グラフィックスのようにデータが3~4エレメント揃っている場合も効率的に実行できる上に、命令をVLIWにパック化することで、スカラ中心のコードでも効率的に実行できること。NVIDIAのようなスカラ型(SOA)型と比べると、ハードウェアによるスケジューリングがずっと軽くすむため、命令ユニットを単純化できる。

●従来アーキテクチャの複雑で非効率な点を改革

 AMDの従来のVLIW型アーキテクチャを、もう少し詳しく見ると下の図のように推定される。

AMD GPUのGCNアーキテクチャでの命令発行
※PDF版はこちら

 まず、CPU上で動作するドライバソフトウェアのリアルタイムコンパイラのフロントエンドが、中間コードの命令をGPUのネイティブ命令に変換する。そうして生成された命令から、コンパイラ内で並列に実行できる命令の並びを抽出し、VLIWスケジューラ部分がVLIW命令の中にパックする。VLIW5アーキテクチャでは、フローコントロール命令を含めて6個の命令スロットがあり、うまく命令をはめ込めば、最大6命令を1サイクルで実行できる。グラフィックス処理で、例えば、ピクセルのRGBAの4値のデータが来た場合は、それぞれに同じ命令を実行するため、VLIW命令スロットのうちBCDEの4スロットは同じ命令で埋めればいい。

 この方式の問題点は一目瞭然で、コンパイラによる複雑なスケジューリングと、VLIWへのパック効率にある。特にスカラ命令が続く場合、うまく並列化できなければ、命令スロットを空けるしかなく、プロセッサの稼働率はぐっと落ちてしまう。そして、汎用コンピューティングでは、スカラ命令が多いケースも少なくはないという。

 それに対してGCNの新アーキテクチャでは、ベクタユニットはStructure of Arrays型となり、16スレッドを並列に実行する形態へと変わった。4個のベクタユニットは、それぞれ異なるWavefrontの命令を実行する。そのため、命令間の依存性をチェックする必要はない(スレッド間のバリア同期とアトミックオペレーションで制御する)。

 このアプローチの利点は、まず、コンパイラの複雑性を取り去った点にある。上の図のように、コンパイラが行なうのは、基本的にはGPUネイティブ命令に変換する程度で、あとは通常の最適化しか必要がない。実行形態としては、各スレッドは完全にスカラプロセッサで実行されるので、プログラミングする側の考え方もシンプルにできる。

 「スケジューリングをずっと簡単にしたため、コンパイラがずっとシンプルになり、デバッグも容易になり、ツールの開発も簡単になった。そして、もっと重要な点は、プログラマがハードウェアを理解してパフォーマンスを予測することが簡単になった」とAMDは説明している。

 また、プロセッサの稼働率も上がる。特に大きいのは、ベクタとスカラのどちらの命令でもプロセッサの稼働率が高くなる点で、パフォーマンスのばらつきが小さくなる。これもパフォーマンス最適化の面では利点だ。

ベクタユニットについて非VLIWのベクタエンジン

●より多くのWavefront&スレッドを走らせるAMDの新アーキテクチャ

 AMDの改革は、GPU全体で見ると、より多くのスレッド/Wavefrontを走らせることも意味する。従来のAMD GPUの場合は、1個のSIMD Engineにつき各サイクル、VLIWユニット側では1個のWavefront、16個のスレッドしか走っていない(テクスチャやロード/ストアは別)。それに対して、新アーキテクチャGCNでは、1個のCUの中で各サイクル4 Wavefrontで64スレッドが並列に走る。

AMDプロセッサの構造
※PDF版はこちら

 つまり、これまでのAMD GPUのプロセッサ(SIMD Engine)は、シングルWavefrontのマシンだった。それが、GCNのプロセッサ(CU)では、4個のWavefrontが並列に走るマルチWavefrontマシンに変わった。

 チャートにすると、演算ユニット当たりのスレッド数とWavefront数が増えたことがわかる。そもそも、VLIW5からVLIW4へと切り替えた2011年頭の段階で、演算ユニットに対するスレッド数が25%増えた。それがGCNになり、さらに4倍に増えた。逆を言えば、GPUを制御する粒度が小さくなり、よりきめ細かな制御ができるようになったとも言える。

AMDプロセッサ
※PDF版はこちら

 ちなみに、旧来のGPUでは、スレッド数を増やすことは、メモリアクセスレイテンシを隠蔽することが主目的だったが、今回は違う。Wavefront当たりの、割り当てユニットの粒度を減らすことが主目的だ。メモリレイテンシについては、AMDも、NVIDIAと同様に、内部メモリを増やすことで、レイテンシを短縮する方向へと転じた。ちなみに、CPUのキャッシュは時間的局所性を利用するためだが、従来のGPUのキャッシュは空間的局所性に寄っていた。これもAMDは変えつつある。