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

スケーラブルに展開するNVIDIAのG80アーキテクチャ




●詳細が明らかになったG80のマイクロアーキテクチャ

 DirectX 10世代GPUは、いよいよ2ラウンド目を迎える。NVIDIAが次のDirectX 10世代GPUを、AMD(旧ATI Technologies)が初めてのDirectX 10世代GPU「R600」を準備しているからだ。NVIDIAのG8x世代のミッドレンジGPUとメインストリーム&バリューGPUは、3月のCeBITですでに数社のOEMから姿を見せている。AMDもR600については当初第1四半期中の発表と説明していた。いずれも秒読み状態に入っている。

 そこで、NVIDIAのGeForce 8800(G80)アーキテクチャを整理、スケーラブルに展開するG8x系コアを展望してみたい。

 G8x系アーキテクチャについては、NVIDIAがGPU向けの汎用(General Purpose)プログラミングモデル「CUDA (クーダ:compute unified device architecture)」の説明を通じて、詳細を明らかにしつつある。その説明の中には、G80発表時にはぼかされていたり単純化されていた部分も含まれている。マイクロアーキテクチャについては、これまでのGPUにないほど詳細が明らかになりつつある。それにつれて、G8xアーキテクチャは高いスケーラビリティを持つことが明確になって来た。

●クラスタ化されたG80の演算プロセッサ群

 G80の場合、合計で128個のスカラ演算プロセッサ「Streaming Processor(SP)」を搭載している。このStreaming Processor群は実際には16個ずつのクラスタに組織化されている。CUDAではこのクラスタを「Texture Processor Cluster(TPC)」と呼んでいる。最初のGPUの説明ではShader Clusterと呼ばれていたが、Texture Processor Clusterの方がより実態を表している。それはG8x系ではShader Processorが分解されているからだ。

 G7x世代では、1つのShader Processorの中に、4wayのSIMD(Single Instruction, Multiple Data)プロセッサとスカラ演算ユニット、テクスチャユニットが含まれていた。ひとまとまりとなったShader Processorが4個で、1個のクラスタに構成されていた。それに対して、G8x世代ではプロセッサとテクスチャユニットは分離され、さらにプロセッサもSIMDからスカラへと分解されている。分離されたプロセッサ群とテクスチャユニットを、従来のShaderとは異なる単位でクラスタ化したのがG8x系アーキテクチャだ。

 GPUの場合、通常、プロセッサ部分はクラスタ単位でモジュール化する。クラスタの内部構成を変えず、クラスタの数を増減させてバリエーションを作る。GPUのコアの設計を容易にするためだ。モジュール化されたブロックを組み合わせて、ハイエンドGPU、ミッドレンジGPU、メインストリーム&バリューGPUの3種類のダイ(半導体本体)を作り分けている。G80では、合計で8個のTexture Processor Clusterがあり、セオリー通りならこのクラスタ数が変わることになる。

 G80の各Texture Processor Clusterの中では、16個のStreaming Processor群は、8個ずつ2つのバンドルに分けられている。このバンドルは「Streaming Multiprocessor(SM)」と呼ばれるユニットで、名前の通りStreaming Processorのマルチプロセッサ構成となっている。クラスタの中にさらに2つのクラスタがある入れ子構造のイメージだ。

 このほか、G8xのクラスタ(Texture Processor Cluster)には2つのStreaming Multiprocessorで共有するリソースが含まれる。テクスチャのプロセッシングを行なう「Texture Unit」、テクスチャデータをキャッシュする「Texture L1 Cache」、L2命令キャッシュとL2コンスタントキャッシュ「Instruction & Constant L2 Cache」、メモリからのデータのロードとストアを行なう「Load/Store Unit」などだ。

●制御の単位となるStreaming Multiprocessor

 G8xでは、Streaming Processorの制御はStreaming Multiprocessor単位で行なわれる。言い換えると、2つのStreaming Multiprocessorには、それぞれ個別の命令ユニット(Instruction Unit)があり、両Streaming Multiprocessorはそれぞれ異なる命令を平行して実行できる。少なくともCUDAの説明ではそうなっており、グラフィックスパイプでも基本的な動作は同様だと推測される。

G8x系アーキテクチャ概要(※別ウィンドウで開きます)
PDF版はこちら

 NVIDIAのチャートを元にした上の図では、2つのStreaming Multiprocessorがパイプライン状に見える。しかし、実際には並列的に接続されているはずだ。

 G7x世代では4個の4way SIMDプロセッサでクラスタが構成され、クラスタ毎に1個の命令ユニットがありクラスタ単位でプロセッサ群が制御されていた。4wayが4個なので、換算すると合計16個の演算ユニットがクラスタに含まれていたことになる。実際には、他にも演算を担当するユニットはあるのだが、メインの演算ユニット数は16個だった。

 それに対してG8x世代では、16個のスカラプロセッサでクラスタが構成されている。4wayのSIMD構成は取らないが、クラスタに含まれるメインの演算ユニットの数は単純計算ではG7x世代と同じだ。しかし、プロセッサの制御自体は8個単位で行なわれる。つまり、プロセッサ群を制御する粒度を、より小さくしている。

 もう少し細かく見ると、G7x系の場合は4way SIMDが4ユニットで4つのスレッドを同時に実行できる構造になっていた。SIMDユニットは2分割して異なる命令を実行することも可能だが、同じスレッドの枠内でコンパイラで命令をスケジュールして実行する形態だった。それに対してG8x系では各スカラユニットが分離されており、別なスレッドを実行できる。

●制御の粒度を小さくしたG80のアーキテクチャ

 ただし、1命令ユニットからの命令で、1つのバンドル内の演算ユニットが制御される仕組み自体はG7xでもG8xでも変わっていない。

 G7x系では、クラスタの命令ユニットから4個の4way SIMDユニットに対して同じ命令が発行される。基本的には、4way SIMDユニットが、それぞれのデータエレメントに対して同じ命令を実行する。そのため、通常は、16個のデータエレメントに対して同じ命令を実行することになる。クラスタ全体が、1つの命令で複数のデータに対して処理を行なう16wayのSIMD(Single Instruction, Multiple Data)型プロセッサとなっている(実際にはSIMDを分割して異なる命令を実行させることもできる)。

 G80の場合は、Streaming Multiprocessorの命令ユニットからの命令を8個のスカラプロセッサが実行する。Streaming Multiprocessor全体で見ると、8wayのSIMD構造になっている。プロセッサを制御する粒度はG80の方がより小さくなっている。

 また、G7xのPixel Shaderでは、カスケードで同じ命令を220個のピクセルに対して実行する構造になっていた。そのため、880ピクセルが、G7xのスレッドブロックの粒度となっていた。

 G80ではこれも小さくなっている。プログラミングモデル上ではG80はStreaming Processorでの実行を「warp」と呼ぶ単位で制御しており、warpの単位は32スレッド(16スレッドもサポートする)だ。Streaming Multiprocessorに含まれるStreaming Processorの数は8個であるため、各Streaming Processorが4サイクルに渡って同じ命令を異なるスレッドに対して実行すると思われる。warpの32スレッドがG80の場合の分岐粒度となる。

 warpの中のスレッドが全て1方向に分岐する場合は、そのwarpは1方向の分岐パスだけを実行する。しかし、スレッドによって分岐方向が分かれた場合、そのwarpは両方のパスを実行しなければならない。そのため、プログラムの実行に必要なサイクルが長くなり効率が悪化する。そのため、GPUは世代が進むにつれて分岐粒度を小さくする方向へと向かっている。

 ちなみに、G80では複数のwarpで、さらに大きなスレッドブロックを構成しており、このスレッドブロックがコヒーレンシを取る単位となっている。また、複数のwarpを切り替えて実行することでパイプラインを充填する仕組みとなっている。実行パイプをフルに稼働させるためには、典型的には8個のwarpが必要だとされている。

 8個のwarpがそれぞれ32個のスレッドを走らせるとなると、スレッドは合計で256個となる。G80のStreaming Multiprocessorの命令ユニットは、最大512スレッドまでをアクティブに走らせることができるが、それは、パイプラインを充填するためだ。G70ではパイプラインを充填するスレッドの数が分岐粒度だった。しかし、G80ではそれが分離されている。

●積和算ユニットと複雑演算ユニットに分離

 G80の演算ユニットはStreaming Processor(SP)とSuper Function Unit(SFU)の2つのパイプで構成されている。各Streaming Multiprocessorにつき、Streaming Processorが8個、Super Function Unitが2個備えられている。Super Function Unitは4個のStreaming Processorで共有される構成となっている。

 G80発表時の説明では、Streaming Processorの中に、浮動小数点積和算(FMAD:Floating Point Multiply-Add)ユニットと積算(FMUL:Floating Point Multiply)ユニットの2ユニットがあると単純化されて説明されていた。しかし、CUDAでの説明ではより具体的に演算ユニットの中身が明らかになった。

 Streaming Processor自体は、スカラの積和算(MAD)演算ユニット(ALU)で、FMUL/FADD/FMAD/整数オペレーション/フォーマットコンバージョンなどを実行できる。1命令/クロックの実行スループットだ。

 Super Function Unitは、RCP/RSQ/LG2/EX2/SIN/COSといった複雑な演算を行なうユニットだ。4個のStreaming Processorの間で、共有されるリソースとなっている。コストの高いユニットを分離して、共有リソースにしたと考えることができる。4クロック毎に1命令を発行できる。実際には、1クロック毎に1スレッドの命令を発行していると考えられる。Super Function Unitは、FMULとムーブ命令も実行できる。

 Streaming Multiprocessorのレジスタは合計で32KBと見られる。G80全体ではStreaming Multiprocessorが16個あるので、その場合は合計で512KBのレジスタとなる。この数字は正確かどうかわからないが、同じUnifide-Shaderアーキテクチャを取るXbox 360 GPU(Xenos)が、合計で24,576本のベクタレジスタ(384KB)を持つので、不自然ではない。レジスタの量が多いのはスレッディングでメモリレイテンシを隠蔽するためだ。CPUがキャッシュを大きくしてメモリレイテンシを隠蔽するように、GPUもレジスタを大きくしてメモリレイテンシを隠蔽する。

 G8xアーキテクチャでは、各スレッドの使う物理レジスタ数は固定されていない。「各スレッド毎に専用のレジスタスペースを持つが、固定されてはいない。スレッド数が増えれば、レジスタ数が減る」とNVIDIAのDavid B. Kirk(デビッド・B・カーク)氏(Chief Scientist)は説明していた。

●汎用コンピューティングのためのShared Memory

 従来のGPUは「Embarassingly Parallel」と呼ばれる、依存性のない並列処理に特化していた。そのため、演算ユニット間での相互のデータ利用は、GPUコアから遠いメモリを介するしかなかった。オンチップで、自由にリード&ライトアクセスができるメモリを持たないためだ。これが、非グラフィックス処理を行なう場合の、GPUの弱点の1つだと言われていた。

 そこで、G80ではStreaming Multiprocessor(SM)毎に、Streaming Processor間で共有するメモリ「Shared Memory」を16KB備えている。これがG80の大きな特徴となっている。

 Shared Memoryは、G80の発表当時、「Parallel Data Cache」と呼んでいたメモリだ。プログラム側から完全に見えるメモリで、各演算パイプから並列にアクセスが可能となっている。そのため、1個のStreaming Processorの演算結果を、他のStreaming Processorが低レイテンシで参照が可能であり、従来のGPUの制約を軽減している。

 G80のShared Memoryは、プログラムから完全に見え、コヒーレンシメカニズムをハードウェアで持たない点で、CPUのキャッシュとは異なる。その意味では、名称としては当初のParallel Data Cacheより、Shared Memoryの方が正確だ。どちらかと言えばCell Broadband Engine(Cell B.E.)の各SPE(Synergistic Processor Element)が備えるLocal Storeメモリに似ている。

 NVIDIAが推奨するモデルではGPUの外部メモリ上のデータを、まずShared Memoryにフィットするサブセットに分割する。そのサブセットをShared Memoryにロードし、スレッドブロックのスレッド群で計算する。処理が終わった時点で、Shared MemoryからGPU外部メモリにデータサブセットを書き戻す。全てをShared Memoryで行なうことを前提としている。このモデルがうまくワークすると、計算する間、外部メモリにアクセスする必要が激減する。

 NVIDIAは、プロセッサのローカルメモリ間でメモリ内容をメッセージパッシングするモデルはプログラミングが難しいとCUDAで説明している。これは、間接的に、Cell B.E.のモデルを否定している。もっとも、これは、NVIDIAが想定するアプリケーションが限定されているからでもある。

 NVIDIAは、G8xアーキテクチャでは、こうしたG80の特徴をそのまま引き継いで展開すると想定される。

□関連記事
【2月28日】【海外】GPU命令のx86体系への統合
http://pc.watch.impress.co.jp/docs/2007/0228/kaigai341.htm
【2006年11月21日】【海外】G80とG7xの最大の違いはマルチスレッディング
http://pc.watch.impress.co.jp/docs/2006/1121/kaigai320.htm

バックナンバー

(2007年4月16日)

[Reported by 後藤 弘茂(Hiroshige Goto)]


【PC Watchホームページ】


PC Watch編集部 pc-watch-info@impress.co.jp ご質問に対して、個別にご回答はいたしません

Copyright (c) 2007 Impress Watch Corporation, an Impress Group company. All rights reserved.