CUDA全スレッド同一メモリデータ取得

概要

GPU上で簡単な仮想マシン的なものを動かしたいとき,実行する命令列をGPU側に置く必要がります. この場合全スレッドが同一命令を同期的にフェッチする必要があり,命令列の保持の仕方によってフェッチ速度が異なってきます. この記事ではデータの保持のさせ方の違いによるフェッチ速度(命令へのアクセス速度)の違いを調べました.

保持のさせ方とアクセスの種類

想定命令数は5000語程度です. 命令の型はuint64_tとしています.

1. Constantメモリ

Constantメモリにすべて乗せて全スレッドが同一アドレスへアクセスしフェッチします. Constantメモリは64KBなので5000語のuint64_tであれば乗せることができます. Constantキャッシュを用いることになります.

2. Globalメモリ

Globalメモリにすべて乗せて全スレッドが同一アドレスへアクセスしフェッチします. Globalメモリはサイズが大きいので5000語以上に拡張したくなったときにも簡単に拡張できます. もちろんL1,L2キャッシュを用いることになります.

3. Globalメモリ + ROキャッシュ

Globalメモリにすべて乗せて全スレッドが同一アドレスへアクセスしフェッチします. このときRO(Read-Only)キャッシュを通してアクセスします. __ldgを使うだけなので実装は簡単.

4. 分散Globalメモリ + ROキャッシュ

Globalメモリにすべて乗せてますが,ブロック間では異なるアドレスへアクセスしフェッチします. ROキャッシュを通してアクセスします. キャッシュをうまく使えなくなる可能性があります.

4. Constantメモリ + Sharedメモリ

1度ブロック内の各スレッドがConstantメモリから別の命令列を読み込み,Sharedメモリに書き込みます. このSharedメモリから命令列を読み込みます. これによりConstantメモリへのアクセス回数を削減させることができます(1/Blockサイズになります).

5. Globalメモリ + Sharedメモリ

1度ブロック内の各スレッドがGlobalメモリから別の命令列を読み込み,Sharedメモリに書き込みます. このSharedメモリから命令列を読み込みます. これによりGlobalメモリへのアクセス回数を削減させることができます(1/Blockサイズになります).

実験

それぞれの方式の読み込み速度を比較しました. Block内で各スレッドが別のアドレスへアクセスする際は結合メモリアクスセスを行うようプログラムを書きました.

実験環境

実験結果

横軸にGridサイズ,縦軸に全スレッドが読み込んだ場合の読み込み速度を取っています. Blockサイズは256固定です. 縦軸の値ですが,読み込みだけではなく他の計算も含んだ実行時間から計算しているため,相対的なものだと思ってください.

やはりGlobalメモリから読み込むのは遅いな,という感じですね. Sharedメモリに移してからアクセスするととても早くなりました. バンクコンフリクトがあるはずなので,工夫次第ではもっと早くなりそうです.

分散Globalメモリ方式はやはりキャッシュをうまく使えていないのか速度が落ちますね. ROキャッシュを通すか否かは今回はあまり関係なさそうです.

方式1のConstantメモリのみを用いた場合,Grid数120で最高速となりましたが,この120という数字が何かは分かっていません(128かも?). カーネル関数のOccupancyが最大になるGrid数にSMの数をかけると120になるかもですが.

終わりに

Globalメモリ+Sharedメモリ方式を使っていこうかなと言う感じです. 5000語以上への拡張も簡単にできそうですし.
カテゴリー:CUDA
記事作成日:2019-03-03