はじめに
このテキストではSIMD(シムディー)について解説します。
GPUの動作原理
最近のCG,3Dグラフィックというのは数学的な演算を非常に多く行うものなので,CPUにも勝る計算能力を備えたGPUが一般的に出回るようになってきました。3Dグラフィックでは,整数や浮動小数点の演算を非常に数多く並行して行う必要があることから,最近のGPUにはCPU以上の並列処理機能が備わっています。
上図↑は少し古いグラフィックボードですが,これらの中にGPUが入っています。
SIMD と MIMD
一般的なGPUの並列プログラミングのモデルは,SIMD (シムディー)と呼ばれるものです。SIMD は Single Instruction, Multiple Data の略で,直訳すると,単一の命令列で複数のデータを処理するということになります。GPUは同じような計算を異なるオブジェクトに対して行うことが多いので,SIMDが適合します。
ちなみにSIMDを「シムディー」と読むのは米国流だそうです。日本の多くの方は「シムド」と読むことがあるそうです。「シムド」だと外国に行くと通じないので,注意してくださいね。(私はもともと「シムディー」と呼んでいて「シムド」と読むことを知りませんでした)
これに対し一般的なCPUの並列プログラミングのモデルは,MIMD(ミムディー)と呼ばれるものです。MIMD は Multiple Instruction, Multiple Data の略で,直訳すると複数の命令列で複数のデータを処理するということになります。CPUは異なるタスクを並行動作させて雑多な処理をすることが多いことから,SIMDは適合せずにMIMDで処理する必要があります。
SIMDとMIMDでは異なる進化を遂げてきました。SIMDは単純な処理ができるプロセッサを100以上とか1000以上といった超並列で動作させるという方向で進化してきています。最新のGPU,たとえばNVIDIAのGeForce GTX 1080 Tiでは3000を超えるコア数からなる並列度を備えています。Intel や AMD の x86 互換のCPUのコア数がせいぜい数10くらいのレベルに留まっていることを考えるとすさまじいです。
そのかわり,MIMDであるCPUでは1つのコアでの高度な処理能力を発展させてきました。特に違いが顕著なのは,CPUでは高度な分岐予測と投機的実行の機能を備えることにより,複雑な条件分岐と複雑なデータ構造からなるプログラムを高速に実行できるように進化してきました。このようなプログラムをGPUに与えても性能を発揮しません。
SIMD や GPU が向いている計算
GPUが向いているのは,単純な構造で均質で大量にあるデータを,ほぼ同じような命令列で処理する場合です。多くの画像処理があてはまります。また最近の流行りですとディープラーニングやビットコインのマイニングもあてはまります。このようにグラフィック処理だけでなく一般的な目的でGPUを活用することをGPGPU (General Purpose computing on Graphics Processing Units)と呼びます。
まったくの余談ですが,中古のグラフィックボードの価格は,仮想通貨の価格に連動することが知られていますが,それはGPUでマイニングするのが一般的だからですね。なので,ゲーム用途やVR/AR用途,画像処理用途,人工知能用途などでGPUを利用する人は,仮想通貨の価格が下がったら,中古で良質のグラフィックボードが市場に出回っていないか,チェックするといいですよ。
CPU の SIMD 命令
PCで用いられるIntelやAMDのx86互換CPUや,携帯電話などで使われる ARM などのCPUには,最近は SIMD 命令というのが搭載されています。CPU の SIMD 命令では,いくつかのレジスタを同時に演算することができます。
たとえば x86CPU の SSE 命令では128ビットの浮動小数点数レジスタ,AVX 命令では256ビットの整数/浮動小数点数レジスタ,AVX-512命令では512ビットの整数/浮動小数点数レジスタを搭載しています。
単精度浮動小数点数(C言語のfloat)でしたら1個あたり32ビットですので,AVX命令で256/32=8個,AVX-512命令で512/32=16個の浮動小数点数を同時に計算できます。
倍精度浮動小数点数(C言語のdouble)でしたら1個あたり64ビットですので,AVX命令で256/64=4個,AVX-512命令で512/64=8個の浮動小数点数を同時に計算できます。
SIMD のコード生成
SIMDのコード生成の考え方を示します。
- ループしたい回数を
n
とします。 -
m
個の演算を同時に実行できるSIMD命令を活用することを考えます。 - それとは別に1個の演算を同時に実行できる同様の命令もあるものとします。
-
n
をm
で割った時の商l
と余りr
を求めます。 - SIMD命令で
m
個分演算をします。 -
l
を1減らして非0ならば2へジャンプします。 - (以上で
l
*m
回の演算を実行できました。残りはr
個の演算です) -
r
が0ならば終了します。 - 1個分演算をします。
-
r
を1減らして5へジャンプします。
これにより,l + r
回の演算で実行することができます。すなわち C言語で書くと,(n / m) + (n % m)
回の演算で実行することができるというわけです。
SIMD を活用した研究例
筆者の研究室で研究・開発している Hastega (ヘイスガ) は,SIMDによる高速実行を行う処理系です。
原理としては,Elixir (エリクサー)という並列プログラミング言語で書いたコードを,CPUのSIMD命令やGPUで実行できるコードに変換します。
興味があったら下記のポスターを参照してください。