GPUの造りは良く分からない

このように、GPUはCPUとは違って多数のスレッドを並列に実行するプロセサであり、その造りはCPUと似ている部分もあるが、異なっている部分も多い。しかし、GPUのハードウェアがどのような造りになっているのかに関する公開された情報は少ない。

情報が公開されない大きな理由は、ハードウェアの進歩が急速で、世代ごとにマイクロアーキテクチャが変わってしまうが、それによってプログラムの作り直しが必要になるのは困るので、ユーザから見た使い方はできるだけ変わらないようにしたいということがある。

このため、NVIDIAはGPUハードウェアを直接制御するマシン命令を公開していない。その代わりにPTX(PARALLEL THREAD EXECUTION ISA)という抽象化した命令セットを公開している。

そして、NVIDIAのGPUでは、高級言語で書かれたGPUプログラムは図3-30のような過程でマシン命令に変換されて実行される。

図3-30 NVIDIA GPUの高級言語からマシン命令への変換の流れ

CPUと異なるのはPTXという抽象化命令が間に入る点で、この部分でGPUハードウェアのマイクロアーキテクチャの変更を隠すようにしている。CPUの場合は、ドライバのようなものは無く、昔はプログラムをメモリにロードする時にリアルタイムに変換を行うCPUパワーもなかったのでコンパイラでマシン命令を直接生成しており、それが続いている。しかし、CPUパワーの向上で、現在ではJavaのバイトコードのエミュレーション実行を行なったり、x86のバイナリを別のアーキテクチャのCPUで、バイナリ変換しながら実行したりできるようになってきている。

抽象化命令であるPTXは、ある意味、Javaのバイトコードのような役割を担っており、GPUでは、ドライバにコンパイル的な機能を持たせ、抽象化命令やより高級な記述のプログラムをリアルタイムに変換しながら実行していると考えられる。

そのため、仕様書に書かれているGPUの機能は、ハードウェアで実現されているもの、ドライバレベルで実現されているもの、GPUチップに内蔵されたマイクロコードで実装されている機能もあり、ハードウェアで実装されている機能だけを取り出すことが難しい。特に、NVIDIAのGPUでは、直接ハードで実行される命令ではなくPTXしか公開されていないので、GPUのハードウェア構造を隠すベールが1枚厚くなっており、より内部構造が分かりにくくなっている。また、PTX命令は同じでも、ハードウェアの構造は違っているという場合も多くあると思われる。

AMDのGPUはマシン命令(と呼んでいるものを)を公開しているが、例えば、GCN(Graphic Core Next)のGeneration 2アーキテクチャとGeneration 3アーキテクチャの間ではかなりの数の命令の削除と追加があり、CPUでは考えられない規模の命令アーキテクチャの変更が行われている。つまり、CPUのようなアセンブラレベルの上位互換性の維持は目標とされていないようである。

このような理由から、GPUのハードウェア構成に関して、確度の高い最新の情報を得ることが難しい。また、筆者の理解不足からの間違いもあると思うが、ご容赦を願いたい(と予防線を張っておく)。

しかし、細部まで分からなくても、おおよそのGPUのハードウェアアーキテクチャを理解することで、超並列の実行がどのようなメカニズムで実現されているかを理解し、GPUの強みを理解して性能の高いプログラムを書くことや、GPUの弱みを避けて性能の低下を抑えるプログラムを書くことができるようになる。また、プログラムの並列度を増し、性能を向上させる汎用的なチューニングは、次の世代のGPUに対しても有効である。

一方、GPUのハードウェの進化は速いので、特定のハードウェア構造に依存したチューニングはハードウェアの世代交代で有効性が落ちてしまうという危険があり、再チューニングが必要となるというリスクがあることは留意して置くべきであろう。

CUDAやOpenCLなどの高級言語を使えば、マイクロアーキの違いはある程度コンパイラが吸収してくれるので、世代ごとの違いを意識する必要は無くなる。また、コンパイラはターゲットとなるGPUアーキテクチャを指定すれば、そのマイクロアーキに向けた最適化も行なってくれるので、リコンパイルすれば、新しいマイクロアーキのハードウェアを有効利用できるというメリットもある。

しかし、CUDAやOpenCLで書いたプログラムに比べてアセンブラやPTXで書く方がハードウェアをフルに使えて、性能が高いという面があるので、NVIDIAの一部のライブラリなどはPTXや非公開のマシン命令で記述されている部分がある。