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

PlayStation 4で採用されたAMDのGCNアーキテクチャ

AMDが一新したGPUアーキテクチャをPS4に採用

 PlayStation 4(PS4)が採用したAMDのGCN(Graphics Core Next)系GPUアーキテクチャの利点は、旧来のAMD GPUアーキテクチャより、多様な新しいタイプのシェーダや汎用コンピューティングプログラムでも性能を出せることだ。モダンなGPUアーキテクチャであり、これからしばらくの期間、ゲームプログラムを走らせるにふさわしいコアとなっている。

 難点は、全く新しいGPUコアアーキテクチャのためのドライバソフトウェア(コンパイラ)の成熟に時間がかかること。GPUはネイティブ命令セットを基本的には露出させず、リアルタイムコンパイラで中間言語からネイティブ命令に変換する。それによって、コアアーキテクチャの改革をソフトウェアから隠蔽している。しかし、そのために、コンパイラの負担は大きく、ハードウェア側のアーキテクチャが大きく変わった時は、成熟に膨大な労力が必要となる。PS4はOSは独自であっても、コンパイラ部分はPCと共通するので、この課題は存在する。ただし、PS4の市場投入には、まだ時間があり、AMDはコンパイラをさらに成熟させる余地がある。

 AMDは、Radeon HD 2000(R6xx)系から5年間、VLIW(Very Long Instruction Word)型のプロセッサをGPUコアに使ってきた。基本のアーキテクチャに拡張を重ねてきたが、昨年(2012年)からGCNへと、アーキテクチャを一新した。GCNは完全に新しいアーキテクチャで、内部構造が大きく変わったため、コンパイラも全く作り替える必要があった。GCNアーキテクチャは「Radeon HD 7900(Tahiti:タヒチ)」から始まり、今年にはディスクリートGPUのほとんどがGCNベースとなり、APUも低消費電力製品からGCNへと移行を始める。

PlayStation 4の概要
PDF版はこちら

 GCNについてもう一度整理すると、その特長は、「Structure of Arrays(SOA)」または「スカラ(Scalar)」と呼ばれる実行方式へとプロセッサアーキテクチャを切り替えたことにある。これは、現在のハイエンドGPUの進化の流れに沿っており、NVIDIAのアーキテクチャとも近い。

 もともと、GPUは頂点とピクセルのプロセッシングに適した4-wayのショートSIMDエンジンを多数備えていた。GPU的な表現では「vec4」と呼ぶ4-way SIMDでは、1命令を最大4個のワークアイテムに対して実行する。x86 CPUのSSEユニットとよく似た狭いSIMDユニットだ。

 PC向けGPUでは、この4-way SIMDプロセッサを複数個束ねて、同じSIMD命令を実行する構成を取っていた。つまり、4-way SIMDによって1頂点または1ピクセルに同じ命令を実行するだけでなく、4-way SIMDを並べることで、複数の頂点またはピクセルに対しても同じ命令を実行していた。それによって、命令ユニットに対する命令発行効率を高めて、スループットを上げることがGPUの基本的な技術方向性だった。ベクタマシンとしては「Array of Structures(AOS)」または「パックド(Packed)」と呼ばれる方式となる。

中間解だったAMDのVLIW GPUアーキテクチャ

 DirectX 9世代までは、このvec4または、vec4の発展形でvec4を分割して異なる2命令を実行させるスタイルでGPUは進化した。しかし、シェーダが進化するにつれて、プログラム中にスカラ命令が増えて来た。さらに、GPUコアの汎用コンピューティングへの利用が、その傾向を強めた。汎用コンピューティングでは、vec4では効率が非常に悪いケースがあり、GPUはこの問題に対応するために、プロセッサの構成を変え始めた。

 AMDの選択肢はVLIW(Very Long Instruction Word)側にプロセッサを構成し直し、4~5個の演算ユニットの各レーンが異なる命令を実行できるようにすることだった。対するNVIDIAはSOAスタイルに切り替えた。

Radeon HD 2000シリーズにおける命令実行の仕組み
PDF版はこちら
VLIW5アーキテクチャでの命令発行
PDF版はこちら
Radeon HD 5870のSIMD
PDF版はこちら

 VLIWでは、ドライバに含まれるリアルタイムコンパイラが並列実行できる命令を抽出して、1つの超長命令の中に組み込む。例えば、連続した命令A/B/C/Dの間に依存性がなく、並列に実行できる場合は、VLIWの命令スロットに命令A/B/C/Dを納めて、1個のVLIW命令にしてしまう。また、VLIWプロセッサは16個で1クラスタとして、16個のVLIWプロセッサが同じVLIW命令をSIMD実行するアーキテクチャとした。

 AMDのVLIW方式における実行プログラムは、依然として4-wayのパックドデータが主流で、スカラ命令がある程度含まれる場合を想定したものだったと見られる。従来のグラフィックスプログラムでも効率がよく性能が出る上に、スカラ命令もある程度速いという発想だ。ハードウェアによるスケジューリングも軽く済むため、命令ユニットを単純化できる。そのため、GPUコアのダイ面積当たりの生パフォーマンスが高くなる。VLIW時代のAMD GPUがNVIDIA GPUに対して、生パフォーマンスで常に優位に立っていたのはそのためだ。ちなみに、NVIDIAはモバイルGPUでは、Tegra 4/4iでVLIW方式のGPUコアを採用している。NVIDIAも、中間解としてはVLIWが優れていることを認めた格好だ。

Tegra 4のGPUコア
PDF版はこちら

 しかし、シェーダの進化とGPUの使い方の変化は、そうした想定で設計したVLIWの対応できる範囲を超えつつある。AMDのVLIWプロセッサでは、特に汎用プログラムでVLIWスロットを埋めることができず、パフォーマンス効率がガクっと落ちることも多かった。そのため、AMDはGPUコアを根底から改良することにした。それがGCNだった。

広いベクタの中でコントロールフローを制御

 PS4が採用するAMDのGCNでは、ベクタユニットは16-wayと広い。DirectX 9世代までのvec4やこれまでのVLIWとは異なり、狭い4-wayでのパック化が必要ない。GCNでは、例えばピクセル処理なら、RGBAの4カラーデータのパックは崩して16個のピクセル全てのデータを順番に処理して行く。例えば16ピクセルの中のRに対して命令を実行し、次に16個のGに対して命令を実行する。

GPUの命令実行の仕組み
PDF版はこちら

 従来のVLIWの場合も、ピクセルカラーデータのように初めからデータがパックされたデータでは効率がよかった。しかし、パックをうまく揃えることができない場合は、いきなり効率が落ちる。スカラ命令では、効率は最悪の場合、4分の1に落ちてしまう。それに対して、GCNではストールしない限り効率が落ちない。そのため、GPUコア自体の汎用性が高まる。正確には、多様なアプリケーションで一定の性能を期待できるようになる。

VLIWアーキテクチャの特徴

 ただし、広いSIMDでは、スレッド毎に命令フローが条件分岐するような場合は、問題が生じてしまう。同じ命令を実行できなくなるからだ。対策として、マスクレジスタを使ったプレディケーションを行なうのが一般的で、PS4が採用するGCNでもその手法を取っている。

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

 各SIMDのレーンのスレッド毎に、命令を実行するかしないか(または演算の結果をレジスタに書き込むか書き込まないか)をマスクレジスタによって選択する。そのため、見かけ上、各レーンが個別に条件分岐するように見せることができる。NVIDIAはこれをSIMT(Single Instruction, Multiple Thread)と呼んでいる。

 ちなみに、現在のモバイルGPUとPC向けGPUの違いの1つはここにある。PowerVR Series5やMali-600などのモバイルGPUは、個々のピクセルや頂点単位でPC(Program Counter)を持ち、個々に分岐できる。この点は、PC向けGPUと大きく違う。これは、そもそも画面解像度の違いやタイリングによる小さな描画面積といった違いがあったためだ。

モバイル系GPUのコントロールフロー
PDF版はこちら

PS4はCU(Compute Unit)を18個搭載

 GCNでは、GPUは「コンピュートユニット(Compute Unit:CU)」と呼ばれるプロセッサクラスタで構成される。PS4では、18個のCUを備えている。コンピュートユニットは、演算ユニット、ロード/ストア&テクスチャユニット、キャッシュ&ローカルスクラッチパッドメモリ、命令ユニットを備えた、フルのプロセッサだ。CUが最大4個束ねられて大きなクラスタを構成しており、クラスタ内のCUはL1命令キャッシュとL1スカラデータキャッシュを共有する。

Compute Unitのアーキテクチャ
PDF版はこちら
Compute Unitのアーキテクチャの概要

 GCNの図の中で、ベクタ演算ユニットは青い16本の円柱で示してある。ベクタユニットはSIMD(Single Instruction, Multiple Data)プロセッサで、4つのベクタにはSIMD 0からSIMD3までの名前が振られている。各ベクタプロセッサが、それぞれ64KBのベクタレジスタを備えている。レジスタが相対的に大きいのは、GPUではレジスタを大きく取ってマルチスレッディングを行なうことで、メモリアクセスレイテンシを隠蔽するからだ。

 CU全体で、16KBのL1データキャッシュと64KBの「ローカルデータシェアメモリ(Local Data Share Memory)」と呼ばれるスクラッチパッドメモリを共有する。このほかにロード/ストアとテクスチャユニットがあり、さらに1個のスカラユニットがある。ちょっと面白いのは、ロード/ストアとテクスチャフリタリング兼用のユニットと命令ポートは別に、データのエクスポートのパスと命令ポートがあることだ。DirectX 10以降のGPUは、シェーダエクスポートと呼ぶストアパスをロジカルには備えているが、AMDアーキテクチャの場合は、それが物理的にも割り付けられている。実は、NVIDIAもある程度似たような構造で、ロード/ストアのパスとテクスチャフェッチのパスが分かれている。

 4つのベクタユニットは、構造的には、それぞれ独立して別なスレッドを実行する。実際にはAMD GPUでは、「Wave」と呼ぶ64スレッドのバッチ単位で処理を行なう。Waveの先頭の64スレッド分の命令が、Wavefront(ウエーブフロント)として実行ユニットに送られる。CU内の物理的ユニットのベクタ長は16レーンだが、論理的なベクタ長は64レーン分となる。2のべき乗なのは、グラフィックス処理では2のべき乗が切りが良い単位だからだとAMDは説明していた。

 各ベクタユニットは、それぞれ異なるWavefrontを実行する。いったん、特定のベクタユニットに割り当てられたWavefrontの命令が、別なベクタユニットに発行されることはない。言ってみれば、4-wayのマルチスレッディングマシンとなっている。さらに、それぞれのベクタユニットに対しては、複数のWaveがプールされており、各Wavefrontの命令が実行できるものから発行される。下のようなイメージとなっている。

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

 WavefrontはPC(Program Counter)を共有し、同じ命令が実行される。このように、実行する単位は64スレッドなのに、ベクタユニット自体は16レーンなので、各ベクタユニットは4サイクルかけて1個のWavefrontの1命令を実行する。この仕組みは、後で説明するGCNの命令発行の仕組みと密接に結びついている。

4個のベクタユニットに4サイクル毎に命令発行

 CU内では、まず、図中の一番上の命令フェッチアービトレーションユニット(Instruction Fetch Arbitration)が命令を命令キャッシュからフェッチする。命令ユニットは、実際には4ユニットに分かれている。図中で「SIMDx Program Counter & Instruction Buffer」となっている4ユニットがそれで、各ユニットが、それぞれ特定のWaveの命令ストリームをフェッチする。実際にはマルチスレッド動作なので、各ユニットが多数のWaveの命令ストリームをフェッチしてバッファしている。通常は10以上のWaveの命令とステイトをバッファする。

命令フェッチとバッファ

 GCNのCUで立ち上げることができるWavefrontの数は、ベクタレジスタによって制約される。GPUではプログラムが使うことができるレジスタ数は固定されておらず、中間コードからGPUのネイティブコードへの変換時に動的にレジスタが割り当てられる。そのため、1スレッドに多くのレジスタを割り当てると、立ち上げることができるWavefront数が減少する。

 各ベクタユニットに付属するレジスタは、64KBで、256-byte(2,048-bit)長のレジスタが256本。1 Wavefrontの64スレッドがそれぞれ単精度32-bitのデータを取るので256-byte(2,048-bit)長となる。もし、各Wavefront毎に32レジスタなら、立ち上げることができるWavefront数は、各ベクタユニット毎に8となる。16レジスタなら16 Wavefrontだ。各Wave毎に、プログラムカウンタも備える。

 4個の命令ユニットからの命令は、スケジュールされ実行できる命令からイシューされる。命令イシューユニットからは、各サイクル最大5命令が発行される。命令発行ポートは全部で7つ。ただし、肝心の4個のSIMDベクタユニット群に対する命令発行ポートは、たった1つしかない。これは、1つのWavefrontの命令発行に4サイクルかかるからだ。

 SIMDベクタユニットに対して発行されるベクタ命令については、各ベクタユニットに対して、それぞれ4サイクルに1回ずつ発行される。各ベクタユニットは、64スレッドのWavefrontの命令を4サイクルかけて実行するため、4つのベクタユニット群に対する命令発行ポートは1個で済む。下の図のような仕組みとなる。

GCNにおけるベクタユニットの動作
PDF版はこちら

 命令によっては、Wavefrontの64スレッドの命令を発行するのに4サイクルではなく、8サイクルまたは16サイクルかかる命令もある。しかし、4サイクル以下にはならないので、ベクタ命令については1個の命令発行ポートで、4個のベクタユニットをフルに回すだけの命令発行ができる。ベクタユニットだけに注目すると、GCNのCUは4個のプロセッサをまとめたような作りになっている。これは、命令発行効率のためだ。

利点の多いGCNアーキテクチャ

 GCNでは、従来のVLIWに対して、原理的にはドライバのリアルタイムコンパイラの負担が減り、デバッグも容易になり、幅広いプログラムの効率が上がり、何よりもパフォーマンスの予測がしやすくなる。アーキテクチャ的には、今風の新しいシェーダアルゴリズムや汎用コンピューティングの性能を引き上げることができる。SCEがPS4に載せたのは、こうしたブランドニューのGPUコアアーキテクチャだ。

GCNへの変化

 GCNの場合は、コンパイラは基本的にはGPUネイティブ命令に変換する程度で、あとは通常の最適化しか必要がない。複雑なVLIW命令のパックが必要ない。実行形態としては、各スレッドは完全にスカラプロセッサで実行されるので、プログラミングする側の考え方もシンプルにできる。

 そして、GPUコア全体では、従来より多くのWavefrontを走らせることができる。AMDの各世代のGPUを比較すると、VLIW型の時代のクラスタだったSIMD Engineと、GCNのCUでは、実行ユニットの数自体はそれほど変わっていない。ところが、同時に走らせることができるWavefrontとスレッドの数は大きく異なる。

AMD GPUエンジンの比較
PDF版はこちら
アーキテクチャの違いによるWavefrontとスレッドの違い
PDF版はこちら

 従来のAMD GPUでは1個のSIMD Engineにつき、演算ユニット群側では、各サイクル1個のWavefrontしか走らない。それに対して、新アーキテクチャGCNでは、1個のCUの中で各サイクル4 Wavefrontで64スレッドがベクタユニットで並列に走る。旧来のVLIWプロセッサ時代は、Wavefrontの中の命令並列性で、多くの演算ユニットを稼働させなければならなかった。それに対して、GCNではスレッドの並列性だけなので、ずっと効率を上げやすくなった。

命令ユニットの構造が大きく変わったGCN

 GPU全体の構造で、GCNが旧来のVLIW世代のAMD GPUと大きく異なるのは、命令ユニットの位置だ。下はPS4のGPUコアに実行ユニットの数的に近いと見られる、「Radeon HD 7870/7850(Pitcairn)」の構成だ。GPU全体を制御するワークディストリビュータが、ワークを各CUに割り当てる。実際の命令スケジューリングや命令発行は、各CUの中の命令ユニットが行なう。

Radeon HD 7870の概要
PDF版はこちら

 それに対して、VLIW時代のAMD GPUでは、中央制御の命令ユニットがある。GPU全体またはGPUの半分を受け持つ命令ユニットが、各SIMD Engineの実行する命令やスレッディングを直接制御する仕組みだった。命令制御方式の変更は、CU単位での粒度の小さな、きめ細かいスレッド管理を可能にしている。

 PS4が採用するGCNは、AMD GPUの歴史の中では大きな飛躍で、より柔軟で高度なプロセッシングを可能にする。グラフィックス的には、これからのシェーダーの時代に対応している。その点は、同じAMD設計ベースでも、VLIWアーキテクチャを採用するゲーム機に対しての利点になる。次世代のゲーム機としてのPS4にはふさわしいGPUコアだ。

 ただし、トレードオフもある。それは、トランジスタ当たりの実行ユニット数がVLIW系アーキテクチャよりも減ることだ。命令ユニットのオーバーヘッドがより大きくなり、全体に演算系以外のリソースが増えた。その分、同程度のダイに載せることができる演算リソースが減る。これは、実行効率が上がることで相殺されるが、旧来のグラフィックスを同じプロセス技術のGCNとVLIWで走らせた場合は、GCNが不利になる場合もあるだろう。このあたりは、未来を見てハードウェアを設計するかどうかの思想の違いでもある。

AMD GPUのダイサイズ/ユニット数比較
PDF版はこちら

(後藤 弘茂 (Hiroshige Goto)E-mail