演算性能に対するメモリ帯域の比率が大幅に改善 NVIDIAの次世代GPUアーキテクチャ「Pascal」は、過去のNVIDIA GPU世代と比較すると、その特徴が際立つ。NVIDIAは、Fermi→Kepler→Maxwellと、GPUアーキテクチャを発展させて来た。FermiとKeplerでは大きく設計思想が変わった。MaxwellはKeplerの発展形で、一見、Pascalもその延長にある。しかし、Pascalで強化されているポイントを見ると、Maxwellとは明確に設計の思想が変化していることが分かる。 スーパーコンピュータにとって重要な、演算とメモリ帯域の関係を、4世代のTesla系GPU製品で比較すると下のようになる。演算性能は、GPUであるためFP32(32-bit単精度浮動小数点演算)で示している。Fermi世代からKepler世代に移ると、NVIDIA GPUの演算性能に対するメモリ帯域の比率であるByte/FLOPSはガクッと半分に落ちる。演算性能の伸びに、メモリ転送レートの高速化が追いつかなかったためだ。 Maxwell世代でもGDDR5のメモリ転送レートは据え置きで、そのためメモリ帯域はKepler世代と同等の288GB/secに留まった。それに対して、FP32の演算性能は上がったことで、Byte/FLOPS比率はさらに下がった。過去2世代のNVIDIA GPUは、演算性能こそ上がったものの、メモリ帯域の足枷がどんどんキツくなっていったことが分かる。メモリバウンドのアプリケーションが難しくなっていった。 Pascalではそれが大幅に緩和される。MaxwellからPascalで、演算性能の1.6倍の上昇に対して、メモリ帯域は2.5倍に上昇。演算に対するメモリ帯域の比率はKepler世代より高くなった。まだFermi世代の比率にまでは戻っていないが、低下の一途を辿っていたByte/FLOPS比率が急転して上昇し始めた。 より重要な点は、Pascal世代でGPU内部のレジスタファイルやキャッシュも大幅に増量された点。レジスタファイルは、Maxwell世代のGM200がGPU全体で6.1MBだったのに対して、Pascal世代のGP100では14.3MBと、2.3倍に増えている。共有メモリはMaxwell GM200の2.3MBに対して、Pascal GP100は3.6MB。これも約1.56倍となっている。それに対して、32-bit単精度の浮動小数点演算ユニットは、Maxwell GM200の3,072個から、Pascal GP100の3,584個へと1.17倍しか増えていない。相対的に演算ユニットに対するレジスタやメモリの量は大幅に増えた。 GPUアーキテクチャ世代毎のユニット数を比較すると、Maxwell/KeplerからPascalで、演算ユニットに対するレジスタ量が飛躍的に増えていることが分かる。Pascalのレジスタは、Maxwellの2.3倍、Keplerの3.7倍だ。

インフライトで走るスレッド数を倍増させる レジスタの増量は、GPUが走らせることができるスレッド数の増加に繋がる。GPUでは物理レジスタファイルの量に比例して、GPUが立ち上げることができるスレッド数が増大するためだ。 NVIDIAのGPUは、「Warp」と呼ばれるスレッドバッチを単位として実行する。Warpは、コンピュータアーキテクチャ的に言えば論理ベクタで、NVIDIAの場合は32エレメンツをまとめて同じ命令を実行する。その意味では、32-wayのSIMD(Single Instruction, Multiple Data)だ。 ただし、Warpの32の各レーンは、見かけ上はそれぞれ独立したスレッドのように実行されるが、マスクレジスタを使ったプレディケーションによって、32-wayの各レーン毎に命令を実行するかしないかを制御する。そのため、GPUでは、SIMT(Single Instruction, Multiple Thread)実行と呼んでいる。 簡単に言えば、シングル命令ストリームのように実行できるスレッドが32個集まるとWarpになる。さらに上位のプログラミングモデル上の概念として、最大32個のWarpで構成するスレッドブロックがある。 GPUでは、CPUと異なりスレッドあたりのレジスタ本数は固定されていない。動的な割り当てが可能で、初期のGPUでは、スレッド当たりのレジスタ本数が非常に少なかった。現在のNVIDIA GPUでは、スレッドあたりのレジスタは最大255本まで割り当てることができる。標準的には32レジスタ/スレッドだ。そのため、同じ32レジスタ/スレッドなら、レジスタ数が多いアーキテクチャが、より多くのスレッドを立ち上げることが可能となる。 例えば、Pascal GP100の場合は、GPU全体で3,670,016本のレジスタを備え、GPU全体で3,584のWarpをインフライトで制御できる。各Warpは32スレッドのバッチであるため、インフライトで制御できるスレッド数はGPU全体で114,688となる。367万のレジスタに対して、11.4万のスレッドだ。各スレッド毎に32本のレジスタの計算となる。 Pascal GP100は、立ち上げることができるWarp数はMaxwell GM200と比較すると2.3倍、Keplerと比較すると3.7倍以上だ。NVIDIA GPUの演算ユニット数は、Kepler以来、増加のペースが衰えたが、インフライトWarp数は大幅に伸びていることが分かる。 簡単に言えば、PascalにおけるNVIDIAのアーキテクチャ的な目的は、インフライトで実行できるスレッド、つまりWarp数を増やすことにある。そのためにレジスタファイルの量を増やす必要があった。もちろん、レジスタ増量では、スレッドあたりのレジスタ数割り当てを増やすことが容易になることも利点だが、それよりもインフライトWarp数の増大の方が主眼だろう。共有メモリも各スレッド毎に一定量が欲しいため、インフライトWarp数が増えると共有メモリ量も増える。

大きなワークロードに対応するためのスレッドリソースの増強 もちろん、ワークロードによっては、これだけ膨大な数のスレッドを必要としないものも多い。NVIDIAでGPU開発を指揮するJonah Alben氏(Senior Vice President, GPU Engineering, NVIDIA)は次のように説明する。 「原則的には、設計上のリソースの量を増やせば、それだけ多くのコードを走らせることができる。それほど多くのコードを走らせる必要がないタスクもあるだろう。しかし、タスクによっては、増やしたリソースを活かすことができる。設計思想として、我々は200～300Wの電力の枠の中で、ほとんど誰もが基本的に必要とすることが確実なリソースのエリア効率を追求するだけでなく、追加のリソースも加える。付加したリソースでより多くのコードを走らせることで、他のユーザーのニーズにも応える」。 ラフに言えば、NVIDIAはHPC(High Performance Computing)のような、問題のサイズが大きなワークロードでもベネフィットを得られるようにPascalのアーキテクチャを拡張しているようだ。ノードあたり11万以上のスレッドを、インフライトで立ち上げる必要があるようなワークロードだ。軽いタスクでは不要な機能であっても、それを必要とする有力な市場が存在するリソースは強化する方針だ。 また、その背景には、時代とともにGPUコンピューティングが必要なワークロードの規模が大きくなり、ワンノードにより多くのリソースが必要になるだろうというNVIDIAの読みがある。このあたりは、より小さなタスク群にも対応が容易なように、APU(Accelerated Processing Unit)化を推し進めようとしたAMDと発想が異なる点だ。乱暴に言うと、AMDはGPUが実行するタスクの粒度が小さくても快適に利用できるようにと指向し、NVIDIAはGPUが実行するタスクの粒度が大きい時に最大の効率を発揮できるように指向して来た。ただし、AMDは方向性が変わりつつある。

メモリアクセスレイテンシを隠蔽できるインフライトスレッドの倍増 GPUのレジスタ量の変化は、メモリアクセスレイテンシの隠蔽とも関係がある。CPUとGPUでは、メモリアクセスレイテンシの隠蔽の方法が異なる。CPUは実行時の遅延がクリティカルであるため、キャッシュを使ってメモリアクセスのレイテンシを隠蔽する。それに対して、膨大な数のスレッドを並列実行できるGPUでは、スレッドの並列性でメモリアクセスレンテンシを隠蔽する。あるスレッドがメモリアクセス待ちでストールしている間も、別なスレッドを走らせることで、アクセスレイテンシを隠蔽してしまう。 現在のGPUはキャッシュも搭載しているが、それでもマルチスレッディングによるメモリレイテンシ隠蔽の傾向は強い。そして、スレッディングでレイテンシを隠蔽するためには、レジスタ数が必要となる。 視点を変えると、Pascal世代でNVIDIA GPUはメモリ帯域が大幅に増えたため、インフライトのスレッド数を増やすことが可能になったとも言える。Maxwell/Kepler世代では、メモリ帯域の制約がキツいため、インフライトのWarp数を増やしても、アクセス競合でストールしてしまう。Pascalではメモリ帯域制約が緩んだために、Warp数を増やしてメモリアクセスレイテンシをカバーする意味が出てきたとも見える。 ちなみに、NVIDIA GPUのインフライトWarp数とレジスタ&メモリ量を、それぞれ32-bit単精度浮動小数点演算性能と比較すると下の図のようになる。GFLOPSと比較すると、レジスタ数とWarpの増大はそれなりに釣り合っているように見える。実効GFLOPSを向上させるには、それだけスレッド数を増やす必要があるという発想も見える。