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

GPU性能の倍増を目指すArmの第2世代「Bifrost」アーキテクチャ

Armの今後のGPUアーキテクチャ

 Armは、先週、北京で新IPの発表イベントを開催した。今回公開されたのは、メインストリーム向けGPUコア「Mali-G52」とエントリ向けGPUコア「Mali-G31」。ArmのGPUコアは、Mali-G7系が高性能モバイル、Mali-G5系がメインストリーム、Mali-G3xがエントリー/高効率となっている。ハイエンドを据え置きで下の2系列の発表となった。しかし、Mali-G52は、GPUアーキテクチャのリフレッシュとなっており、内実はGPUのアーキテクチャ改革のお披露目だった。

3系列のArm GPUコアのうち2系列が刷新

 Armの現在のGPUアーキテクチャは「Bifrost(バイフロスト)」で、Mali-G52では第2世代の拡張版のBifrostが採用された。現在は、メインストリーム向けのGPUにしか実装されていない拡張版Bifrostだが、Armの高性能GPUコアIPも新アーキテクチャに変わることは明瞭だ。単に開発サイクルのずれの問題で、次世代のArmの高性能GPU(Mali-G7x系)もG52同様のアーキテクチャになると見られる。

高性能コアのMali-G7x系は最大32個のシェーダコアをGPUコアに搭載できる
Mali-G52では、最大4個のシェーダコアをGPUコアに搭載可能
PDF版はこちら

 Mali-G52でのアーキテクチャ革新は重要で、ArmのGPUアーキテクチャの方向性を示している。GPUのSIMT(Single Instruction, Multiple Thread)の実行レーンを、従来の4レーンから8レーンに拡張した。GPU面積あたりの演算性能を高めることで、よりシェーダリッチなグラフィックスへの対応を目指す。

 さらに、Armは機械学習(ML)のインファレンス(Inference:推論)向けに、8-bit整数(Int8)の特殊な演算命令を加えた。Mali-G52の最大構成でのInt8のインファレンス性能は、計算上は652GOPS相当となり、iPhone Xの「A11 Bionic」に内蔵されているニューラルネットワークプロセッサの性能と互角かそれ以上となる。

 つまり、コスト重視でニューラルネットワーク専用コアを搭載する余地が少ないメインストリーム向けのモバイルSoCであっても、Arm Maliによって高精度なMLによる認識処理が可能となる。消費電力あたりの性能では、専用コアと戦う必要があるが、ダイ面積(=コスト)的にはArmのソリューションが有利となる。

ArmのMali-G52のInt8ドット積の概念図
PDF版はこちら

8レーンへと演算コアの実行レーンを倍増

 Armは、Mali-G52からSIMTの演算パイプを8レーンに拡張した。そのため、単純には各Execution Enginesの演算能力は2倍になった。もっとも、従来のBifrostの4レーンというSIMT構成自体が、異例に狭かったので、今回の拡張で、より今どきのGPUらしい構成になったとも言える。とは言え、アーキテクチャには、まだいくつもの疑問が残る。

 Armは、2011年に発表した「Mali-T600」ファミリから「Midgard(ミッドガルド)」と呼ぶGPUアーキテクチャを採用していた。Midgardの演算コアはSIMD(Single Instruction, Multiple Data)ベースだった。それを2016年に導入したBifrostアーキテクチャから、SIMTへと切り替えた。

 GPUの実行モデルは大きく分けて2種類がある。1つは「Array of Structures (AOS)」や「パックド(Packed)」「SIMD(Single Instruction, Multiple Data)」と呼ばれる方式。もう1つは「Structure of Arrays (SOA)」や「スカラ(Scalar)」「SIMT(Single Instruction, Multiple Thread)」と呼ばれる方式だ。AOS/パックド/SIMD型ではデータを一定の粒度でパックされたかたちで処理する。それに対して、SOA/スカラ/SIMT型ではあたかもシリアルなスカラ処理を複数束ねたようなかたちで処理する。

 かつては、NVIDIAもAMDもみなAOS/パックド/SIMD型モデルのアーキテクチャを採用していた。しかし、PC向けGPUは、より汎用性の高いSOA/スカラ/SIMT型へと切り替えて、GPUコンピューティング時代となった。そうしたなか、モバイルGPU専業のArmはAOS/パックド/SIMDを継続して来たが、BifrostからはSOA/スカラ/SIMT型へと切り替えた。

16個の演算ユニットをAOSとSOAのそれぞれの実行モデルで動作させた場合の例
PDF版はこちら

 AOS/パックド/SIMD型モデルと、SOA/スカラ/SIMT型モデルにはそれぞれ利点と弱点がある。おおまかに言えば、データが決まった数のパックになっている場合は、AOS/パックド/SIMD型が効率がいい。しかし、データタイプが多様な場合は、SOA/スカラ/SIMT型の方が柔軟に対応しやすい。また、SOA/スカラ/SIMT型の方がコンパイラによる最適化が容易で、実行効率を上げやすい。

多様なプログラムに対応して実行効率を上げるSIMT

 Armがよく示すのはvec3(3-wayベクタ)の例だ。空間座標のx,y,zの3要素のベクタを演算する。AOS/パックド/SIMD型モデルでは、1頂点(x,y,z)ずつ処理する。この場合、4エレメンツを演算できる4-wayのSIMDユニットでは、3エレメンツの頂点処理では1ユニットがアイドルになってしまう。演算ユニットの実行効率は75%となる。

 しかし、SOA/スカラ/SIMT型モデルの場合は、各頂点のxをまとめて実行、次のサイクルでyをまとめて実行といったかたちでSIMDを分解して実行する。1サイクル目には4個のxを演算、次のサイクルでは4個のyといった具合だ。そのため、4-wayなら全ての演算ユニットをフルに使うことができる。プログラム側から見るとスカラ実行されているように見える。

4-wayのSIMDで3-wayのvec3を処理した場合。1演算レーンがアイドルになってしまう
クアッド(4-way)のSIMTで、3-wayのvec3を処理した場合。3サイクルで処理が終わり、アイドルが生じない
ピクセルのRGBAの4エレメンツをSIMDとSIMTでそれぞれ実行した場合
PDF版はこちら
頂点のxyzの3エレメンツをSIMDとSIMTでそれぞれ実行した場合
PDF版はこちら

 3エレメンツの頂点演算では有効なSOA/スカラ/SIMT型だが、それ以上に汎用コンピューティングでは有効だ。汎用的なコンピューティング処理では、4エレメンツが揃わないワークロードも非常に多い。SOA/スカラ/SIMT型では、そうした多用なワークロードでも、コンスタントに性能を発揮できる。

 演算ユニットの有効活用では効果的なSIMTだが、問題もある。SIMDの場合は、例えば1つの頂点(x,y,z)や1つのピクセル(R,G,B,A)に対して同じ命令を実行する。頂点やピクセルの各要素(x,y,z/R,G,B,A)は分離されることがないため、SIMDで同じ命令を実行しても問題は生じない。ところが、SIMTの場合は、頂点Aのxと頂点Bのx……を同時に実行する。そのため、必ずしも同じ命令を実行することができない。頂点やピクセルによって、命令フローが条件分岐するような場合は、問題が生じてしまう。

 そこで、SIMTの場合は、マスクレジスタを使ったプレディケーションを行なうのが一般的だ。プレディケーションでは、各レーンのスレッドごとに、命令を実行するかしないか(または演算の結果をレジスタに書き込むか書き込まないか)をマスクレジスタによって選択できる。プレディケーションを使えば、レーン上のスレッドに条件で分岐が発生しても、あたかも分岐したかのように見せかけることができる。スカラ実行と呼んでいるのはそのためだ。ArmのBifrostも、同様のアプローチを採っている。

条件分岐の場合、SIMTでは通常プレディケーションを行なう
PDF版はこちら

小さなクアッド単位で制御するArmのBifrostアーキテクチャ

 このように、ArmはBifrostアーキテクチャから、SOA/スカラ/SIMT型モデルへと切り替えた。上の方の図で示しているような、頂点やピクセルを“縦に”分解してスカラ実行すること自体は、NVIDIAやAMD、Imagination Technologiesなども行なっており、とくに珍しくはない。しかし、ArmはBifrostには、ほかにない特徴がある。

 多くのベンダーは、演算ユニットを16~32-wayのワイドな構成にしている。ハードウェア的には16~32-wayのワイドなベクタユニットで、16~64-wayの論理ベクタを実行するスタイルが主流だ。NVIDIAのWarp(32 thread)やAMDのWavefront(64 threads)が、これにあたる。ほとんどのケースでは、論理ベクタごとにプログラムカウンタを1個として、制御のオーバーヘッドを小さくしている。つまり、NVIDIAなら32スレッドで1プログラムカウンタ(Voltaから変わった)、AMDなら64スレッドで1プログラムカウンタだった。

 それに対して、ARMのBifrostは、ハードウェア的にも論理的にも4-wayの狭い構成のベクタとしなっていた。Bifrostでは、4個の頂点や4個のピクセルなどの要素をバンドルした「Quad(クアッド)」を生成。Quadを実行単位として、4-wayのSIMTに割り当てていた。つまり、4スレッドでプログラムカウンタを共有する粒度となっていた。ほかのGPUベンダーと比べると論理上のベクタサイズが小さく、その分、コントロールオーバヘッドが大きい。

 Armによると、これは解像度が小さなデバイスでも効率を上げるためだという。もともと、ArmのようなモバイルGPUは、頂点やピクセルの単位でプログラムカウンタを持っており、頂点やピクセル単位での条件分岐などのコントロールフローが可能となっていた。対して、NVIDIAやAMDのSIMTでは説明したようにプレディケーションによってコントロールフローを制御している。

 しかし、複雑な分岐となると、ワイドなSIMTでのプレディケーションでは効率が落ちる場合がある。解像度が低く、かつ画面が狭いスクリーンでは、ピクセルや頂点の条件分岐が多くなる。そのため、分岐粒度が小さな方が効率がよくなる。Armの4スレッドでのコントロールフローは、従来方式とPC向けGPUの中間を取った粒度のように見える。

左は旧来のモバイルGPU、右はPC GPUのコントロールフロー。解像度が下がると粒度が小さな方が効率がよくなる
PDF版はこちら

8レーンへと拡張しつつクアッド単位の制御は継続

 こうした設計思想から、ArmのBifrostでは4-wayベクタを粒度とするQuad制御を行なってきた。そのため、実行ユニット自体も4-wayとなっていた。ところが、Mali-G52の拡張版Bifrostでは、実行ユニットのベクタ幅が8-wayとなった。物理的なベクタ幅が2倍になり、1サイクルの演算性能が倍増した。

8-wayの実行レーンを備えたMali-G52のExecution Engines

 ポイントはここで、8-wayの演算ユニットに合わせて、処理するスレッドのバンドルも8-wayになったのかどうかだ。8-wayになったのなら、スレッドのバンドルのディスパッチもそれに合わせて8スレッドで構成されなければならない。

 しかし、Armが公開しているMali-G52のブロック図には、依然として「Quad Creator(クアッドクリエータ)」があり、スレッドのマネージャも「Quad Manager(クアッドマネージャ)」となっている。ArmでMali-G52を担当するAnand Patel氏(Director of Product Management, Client Business Line, Arm)も、引き続きQuadが処理の粒度だと説明する。

Mali-G52のコア設計
Mali-G52のシェーダコアのブロック図
PDF版はこちら
Mali-G71のシェーダコア
ArmでMali-G52を担当するAnand Patel氏(Director of Product Management, Client Business Line, Arm)
ArmのGPUのALUの変遷。一番上が旧来のMidgardの128-bit SIMD、中央が現在のBifrostの4x32-bitのSIMT、下が新しいMali-T604の8x32-bitのSIMT
PDF版はこちら
Mali-G71の実行レーンのアーキテクチャ

 Bifrostのシェーダコアでは、フロントエンドにQuad Creatorがあり、頂点やピクセル、コンピュートそれぞれについてスレッドを4つずつバインドしてQuadを生成する。頂点やコンピュート系のフロントエンドと、ピクセルのフロントエンドは分離しているが、これは、ピクセル系のパイプは頂点からラスタライザでピクセルを生成し、アーリーZで不要なピクセルを除去するといった操作が加わっているからだ。

 Quad Creatorで生成したQuadは、Quad Managerでプールされ、Execution Enginesにディスパッチされる。つまり、スレッドは全てQuad単位で扱われる。これは、NVIDIAがWarp単位で、AMDがWavefront単位で行なっている制御と同じだ。

 そうなると、Mali-G52の8-wayの実行レーンに割り当てる場合に、Quadをどう扱うかが問題となる。8-wayのレーンを分割して2つの4-wayとしてそれぞれにQuadを割り当てるとしたら、その2つのQuadはプログラムカウンタを共有するのか。つまり、同じ命令を8-wayすべてで実行するのか。実際問題として、同じ命令を実行するのでないと、8-wayに拡張する利点が減ってしまう。

 これについては、Armのアーキテクチャはまだ明かされていない。2つのQuadを連結させる場合は、実質的に8スレッドのバンドルとして扱われることになる。Quad Managerは、実質的に2 Quadのバンドルを管理することになる。

2系統の演算パイプからなる実行レーン

 ArmのGPUの演算コアは、実際には2種類の演算パイプからなっている。「FMA(Fused Multiply–Add)」ユニットと「ADD/SF(Special Function)」ユニットの2つだ。FMA側では、積和算、乗算と割り算が実行可能だ。ADD/SFでは、加算と除算、超越関数などの実行が可能だ。両ユニットで、並列実行可能な命令組み合わせもあるが、同じスレッドの連続した命令でリソースが競合しないものに限られる。積和算とSFの2系統のパイプは、従来のGPUでは一般的な構成だった。

G52のシェーダのExecution Enginesの中のALUアーキテクチャ
PDF版はこちら
Mali-G71で示されたALUアーキテクチャ

 演算ユニットの実行レーンは、従来のBifrostは4レーン、Mali-G52が8レーンと倍増している。それに合わせて汎用レジスタファイルを増強されたはずだが、まだ公開されていない。Bifrostアーキテクチャのレジスタ数は、従来は64x32-bitレジスタと発表されていた。これは、1レーンあたりのレジスタ数と推測される。レジスタファイルの総量も、Mali-G52では倍増されたと推測される。

 GPUの場合、レジスタファイルの量とインフライトで走らせることができるスレッド数と、プログラムが使うことができるレジスタ数が密接に連結している。これは、スレッドあたりのレジスタ数が固定されていないためだ。一定のレジスタ量の元では、スレッド数を増やすと、スレッドあたりに使うことができるレジスタ数が減ってしまう。逆にレジスタ割り当てを増やすと、走らせることができるスレッド数が減ってしまう。スレッド数が減ると、メモリアクセスやテクスチャフィルタリングのレイテンシを隠蔽することができなくなる。

 Armは今回のMali-G52でも、(演算レーンあたりのインフライトの)スレッド数は保っているはずだと説明している。そのため、レジスタファイルは倍増されていると推測される。また、Bifrostアーキテクチャでは、演算結果をパスするためのミニレジスタ「Temp Registers」を備えているが、そこも倍増されているはずだ。

ArmのBifrostのクローズエグゼキューション

 ちなみに、BifrostのTemp Registers(テンプレジスタ)は、バックツーバックのアクセスのための、汎用レジスタのバイパスのために使われる。前の演算の結果が、次の演算のソースになるようなケースだ。Temp Registersを使うことで、大きなレジスタファイルへとアクセスする電力をセーブする。

従来は演算の結果が、次の演算で使われる場合も汎用レジスタにいったん書き込んでいた
Bifrostでは、汎用レジスタをバイパスしてALUに付属の小さなテンプレジスタで受け渡しができる

 上のスライドにある「Clause execution(クローズエグゼキューション)」というのは、Bifrostで導入されたスケジューリングメソッドだ。プログラムの命令ストリームを、Clause(節)に分割してスケジューリングする。命令実行レイテンシが一定以下に揃っていて、バックツーバックで連続して実行できる命令をブロックとして区切る。そのブロック内の命令は、GPUがスケジューリングすることなく、そのまま連続して実行できる仕組みだ。そのさいに、前の命令の結果をレジスタに書き込んで読み出す必要がないようにレジスタをバイパスする。

BifrostのClause execution

 そこに、テクスチャアクセスのようなレイテンシが非常に長い命令が来た場合に、ブロックを管理してテクスチャフィルタリングを待つQuadの実行を停止。間に別なQuadの実行を挟むことで、マルチスレッディングによってレイテンシを隠蔽する。

ロングレイテンシの命令が来た場合
別なQuadの実行へとスイッチする

 クローズ単位で管理することで、レイテンシの長い命令の待ちを隠蔽し、クローズの中でのレジスタアクセスを減らして電力をセーブする。また、レイテンシが揃ったクローズの中で最適化することで、命令のペアリングを行ない、2種類の実行パイプで、並列に実行できるようにすることも可能だ。レイテンシを揃えた命令はスケジューリングを自動化し、ロングレイテンシの命令だけスコアボーディングで管理する方式はNVIDIAなどほかのGPUベンダーも採用している。

Clause executionとtemp Registerによる最適化の例