技術

AoSからSoAに代えたら2倍ぐらい速くなった

CUDAで書いた例のレイキャストのプログラムがさらに高速化した。

カーネルの引数にレイの情報を線形メモリで渡してたが、その中身は構造体の配列(Array of Structs, AoS)だった。
GPU的にはAoSより配列の構造体(Struct of Arrays, SoA)の方が効率的に扱えるらしい(コアレッシングがらみ?)ので、データの中身をAoSからSoAにしてみたら、なんと処理時間が2倍くらい速くなった。

Geforce 9400M(Mac)の場合、最初1.7秒だった処理時間が、atomicAddの効率化で0.9秒に、さらに今回のSoA化で0.5秒に縮まった。
GTX 460(Ubuntu)の場合、最初0.06秒だったのが、atomicAddの効率化で0.055秒に、コンパイルのsm_11化で0.04秒に、さらに今回のSoA化で0.027秒に縮まった。

SoA化は、構造体をfloat4のサイズ(16バイト)で分けることによって行った。
さらに小さい、floatのサイズ(4バイト)でも試してみたけど、ここまでは速くならなかった。

データは、レイの情報、レイの衝突情報、BVHのノードの情報、三角形の情報、の4種類あるが、今回SoA化したのはレイの情報のみ。

じゃあ、他の情報もSoA化したらさらに高速化するんじゃないかと思って試してみたけど、それはダメだった。

まず、1つのレイの衝突情報のサイズはすでにfloat4と同じ16バイトとなっているのでSoA化出来なかった。
次に、ノードの情報はテクスチャリファレンスを通してランダムアクセスされるため、SoA化しても実際のアクセスがアドレス連続にならないからか、むしろ微妙に遅くなった。
三角形の情報はSoA化を試してないけど、ノードの情報と同じような条件なのであまり効果はないだろう。

SoA化ってのも基本的なテクニックだけど、ここまで高速化するとは思わなかった。
しかしSoAはgetやsetでクラスや構造体との相互変換が必要になるので、少々めんどくさい。
C++ならアロケータを使えばそこんとこ透過的に出来たりするのかな。

コメントを残す

メールアドレスが公開されることはありません。



※画像をクリックして別の画像を表示

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください