GPGPUの観点から見る VideoCore VI と VideoVore IV の違い

Idein大川です.主に最適化回りを担当しています.

Raspberry Pi 4 が(技適も通過し)発売され入手可能になりましたね.これまでRaspberry Pi シリーズのGPUはVideoCore IV (以下VC4)でしたが,Pi4からは VideoCore VI (以下VC6)が採用されています.

VC4と異なり,VC6には性能を引き出す上で最大とも言える問題があります.それは「リファレンスマニュアルが公開されていない」ということです.VC4ではリファレンスマニュアルが公開されていたために py-videocore 等を作ることができ,誰でもGPGPUを嗜むことができました.しかし,VC6ではなかなかそうもいきません.幸いグラフィックライブラリMesa 3DのVideoCore対応から読み取れるものはありますが,使う必要が無いためか実装されてない(というかあるかないかもわからない)ような部分もあり,不明な部分も未だ多いです.

Ideinでも残念ながら?特別なドキュメントもらっているとかそんなことは全くありません.(VC4のように)ドキュメントを公開してもらえるのか問い合わせを行いましたが,必要な情報はMesaのVC6ドライバを参考に調査してくれ,成果は公開してもかまわないと案内頂くにとどまっています.そのため「こういう機能がきっとある筈だからたぶんこのあたりのbitに何らかのエンコーディングで入ってるだろう,本当にあるかないかもわからんそれを実装して試してみよう」とか「何らかの命令や特殊目的レジスタの存在はわかるけど具体的に何をするものなのか不明なので推測しつつ作用を調査する」といったようなエスパー行為も駆使して未解明な部分を埋めつつ,VC6 GPGPUのためのPython EDSL(embedded domain specific language)なアセンブリ py-videocore6 を開発しており,既にDNNに使うパーツの実装に足る程度には仕上がっています.また,これを利用したVC6の性能評価等も進めてみています.

たぶんこれが一番速いと思います.(フラグ)


本記事では,VC4とVC6両方に触れてみて,VC4からVC6への差分がどうなっているのかについてざっと紹介します.Pi4の性能を完全に引き出す助けにしてみて下さい.ただし,上記の通り推測が多分に含まれています.VC4同様リファレンスが公開されることを祈りましょう.

理論性能

演算器QPUが16way SIMDの32bit演算器である点はVC4と一緒です.VC4のときは3つあったスライスがVC6では2つに減っています.そのかわり(Pi3で)300MHzだったGPU動作周波数が,500MHzに向上しています.この変更により,(Pi3やPi0で)28.8Gflopsだった理論性能は32Gflopsに微増しました.ただ,Pi4ではCPUがトータルで48Gflops持っています.Pi0や旧Pi2までは圧倒していたGPU性能も新Pi2やPi3では逆転し,Pi3+,Pi4となるにつれ理論性能の差はだんだんと広がっています.実はPi3 VC4の段階で既にCPUより速く動かすのは大変なのですが,Pi4 VC6からはさらに顕著になっています.まぁ,Pi4は(Pi3とかもですが)CPUを全力全開すると一瞬でお熱になるのですが.

レジスタ/命令セット

VC4では結構いろいろな種類があった命令ですが,VC6では大まかに算術命令と分岐命令のみになりました.セマフォ命令(というかセマフォ自体)が恐らくなくなっています.また,即値ロード命令相当のものを見つけられてないだけかもしれませんが無くなっており,これはやや不便なこともありました.

VC4ではregister fileのA/B面がありましたが,VC6では総数変わらずもこの区別が無くなっています.また,1命令分のディレイも無くなっており,総じて扱い易くなる良い変更となっています.

特殊目的レジスタのうち,命令のsrcレジスタとして利用する形のものが恐らく一律で無くなりました.一部,同等機能としてdstレジスタに格納する形の命令に変化して残っているようです.同じ命令でもsrcレジスタによってストールするかどうか変わるというような挙動を嫌ったのかもしれませんが,実際の意図はわかりません.

packing/unpackingに関しては8bit整数が無くなり,絶対値unpackなどにやや顔ぶれが変わりました.また,packing/unpacking可能な命令が限定されています.というかそれらが可能な命令に対するopコードの一部として表現されているという状態です.関連して,算術命令としてfp16の乗算が追加されました.やや流行りを感じなくもないです.ただ,加算が無いようなので,使う場合はfp32命令とpacking/unpackingを利用することになるのでしょう.

条件フラグの挙動もかなり変更されています.VC4ではznc三種類のフラグがそれぞれ同時セットされ,個別に参照することができましたが,VC6ではzncのどれか1つをセットして保持する形になり同時には参照できません.そのかわり,A面B面で長さ2の条件フラグバッファを持っており,新しくセットしたらA面に,それまでA面にあったものがB面に移動するようになっているようです.また,A面のフラグに対しand/norで更新する機能が付きました.算術命令からはA面B面両方参照でき,分岐命令からはA面のみが参照されるみたいです.

分岐命令は,相対即値,絶対即値,レジスタ内絶対値,リンクレジスタ値のいずれかに飛ぶ形になりました.VC4であったレジスタ内相対値が無くなりましたが,大きな影響は無いでしょう.VC4のときは明示的にリンクレジスタとしてregister fileのどれかを指定し,分岐時にそれに格納される形でしたが,VC6では通常のレジスタとしては参照できない暗黙のレジスタになっているようです.前述のように特殊目的レジスタでsrcとして利用できるものは消えているので,これも追加された「現在のリンクレジスタ値を引き出す命令」を使って取り出す形になっています.1段飛んで戻るだけであればregister fileを消費しなくなったということでもあります.

データの転送

VC4ではデータをTMUやuniformsでロードし,VPMを経由してDMAで書き戻していました.VC6ではTMUがロード・ストア両方に対応し,MMUも挟まっているようです.VC4では,TMUやuniformの前にはL2がありますが,DMAはそれを経由しないため,同一領域に対する読み書き読みを行うとL2キャッシュの状態によってデータの整合性が崩れることがありました(当然Ideinの変換器はこれも考慮して変換しています)が,VC6ではこの現象も発生しなくなっています.ただ,TMUでストアした直後にuniformでロードすると,どこかのキャッシュのせいなのかわかりませんがデータの整合性が崩れることがあるため,この点だけは引き続き注意しましょう.

VC4でDMA転送に使う転送元のVPM及びDMA操作には,全QPUで排他制御が必要でした.そのためVC4は書き出し(必須な処理にも関わらず!)を行うと並列性が損なわれるという性質を持ちます.VC6ではこの制約もみかけ上ありません.

TMUはスロット毎に2つだったのが1つに統合され,そのかわり同時に投入しておけるリクエスト数の限界は各4から恐らく8になっています.良い面も悪い面もある変更という感じでした.ちなみに限界数を越えてリクエストした場合の挙動はVC4よりもお行儀が悪い子です.

TMUロード時の格納先レジスタは,VC4ではr4に固定でしたが,ロードシグナルに格納先を指定できるようになりました.レジスタプレッシャーの緩和に繋がる良い変更でしょう.

uniformsは,VC4では読み出しがsrcレジスタとして使う特殊目的レジスタになっていましたが,VC6ではTMU同様シグナルで読み出しを指定するようになっています.こちらも格納先をシグナルに持たせてロードしたりすることができます.また,指定せずr5にロードすることもできます.指定する場合としない場合で同時に指定できるシグナルが変わるので使い分けになります.

uniformsの読み出し先変更は,特殊目的レジスタにアドレスを書く形であったVC4と異なり,分岐命令で行うようになりました.分岐命令が,命令列の分岐先に加えて,uniformアドレスの分岐先を指定できる形になっています.

スレッド関連

VC4ではQPUあたり2スレッド投入できましたが,切り替え時にレジスタ値を自分で退避させておく必要があり,(我々の目的に対してはですが)普通の神経で扱って性能が出せるようなものではありませんでした.VC6でも複数(ID的には4つまでありますが同時に投入される数は未確認)投入できますが,やはりレジスタを退避させる必要があるようで,引き続き性能に寄与する類のものとはあまり思えません.

命令の項でも書きましたが,セマフォは無くなったようです.そのかわりというわけでもないとは思いますが,簡易なバリア同期が入りました.もしかすると簡易じゃない特殊な使い方もあるかもしれませんが詳細不明です.

VPMは命令はあるようなのですが本当についてるのかまだよくわかってません.ただ,VC4同様排他制御が必要なのであれば,セマフォも無く,書き出しもTMU経由で行うようになってしまったVC6では使い道もあまり無さそうです.

ドライバ側の話になりますが,VC4のMailbox property interfaceでは,スレッド毎にuniformアドレスを個別に渡せていましたが,VC6では1つだけになっています.そのため,スレッド毎に別の仕事をさせるには若干の工夫が必要になっています.他にもCompute Shaderのドライバまわりはまだdispatchしたジョブの扱いに関してパフォーマンス的に少し問題を抱えていることがわかっています.

まとめ

Pi4では公式にOpenGL ES 3.1対応している(というかVC6への進化もそれをし易くする方向の変化が目立つ)ので普通にシェーダ言語が使えるようになると思います.しかし,それで期待通りのパフォーマンスを発揮させるのは難しいハードウェアになってるのではないかという印象です.