4.3 OMPCUDA の評価
4.3.2 円周率の計算 (グレゴリ級数) を用いた性能確認
4.3 OMPCUDAの評価 115
結果を見ると,OMPCUDAはOMPCUDA-loop3とOMPCUDA-loop2で大きく 性能が異なっている.これは3重ループ(OMPCUDA-loop3)の場合には並列度が外側 ループのループ回数である1024であり,CUDA Thread数が256のためCUDA Block 数が1024/256=4という低い並列度で実行されたのに対して,loop2では並列度が 1024*1024,CUDA Thread数が256のためCUDA Block数は1024*1024/256=4096 となり,高い並列度で実行されたことにより性能が向上したものと考えられる.ま たOmniCPUの実行時間を見ると,OmniCPUではCPUのコア数を超える数のス レッドを利用しても性能が向上しないのに対して,CUDAでは物理的な演算器の数 が適切な並列度に直接対応していないことが確認できる.
さらにCUDA-loop2について,問題サイズを1024に保った状態でCUDA Thread 数とCUDA Block数をいくつか変化させた際の実行時間を図49に示す.結果を見 ると,CUDA Thread数は256または512のときに実行時間が短く,CUDA Block 数は多いほど良い性能が得られている.CUDA Block単位での共有メモリである SharedMemoryを用いていないため,並列度が性能を大きく左右するパラメタとなっ ていることがわかる.
以上の結果から,OMPCUDAはGPUの持つ高い並列性を活用したプログラムの 高速化を行えたと言える.
4.3 OMPCUDAの評価 116
図 49: 行列積の実行時間 2 (問題サイズ 1024)
f l o a t answer = 0 . 0 f ;
i n t i , n = 0 x10000000 ; // 256∗1024∗1024=268435456=0 x10000000
#pragma omp p a r a l l e l f o r r e d u c t i o n (+: answer ) f o r ( i = 0 ; i < n ; i ++){
answer += ( 4 . 0 / ( 4 ∗ i + 1 ) − 4 . 0 / ( 4 ∗ i + 3 ) ) ; }
図 50: 円周率計算のソースコード
4.3 OMPCUDAの評価 117
3. OmniCPU : Omniを用いたループ並列化(図50をOmniでコンパイルしたも の,CPU上で実行,1スレッドから8スレッド)
4. CUDA-CPUreduction : SimpleCUDAに対して,リダクション演算の一部(CUDA Block間のリダクション演算) をCPU側に移動した実装
5. CUDA-GLOBALreduction : SimpleCUDAに対して,全てのリダクション演 算をatomic演算で行うようにした実装
評価2では評価1と異なりforループ内部の計算において各CUDA Threadが共通 に参照するデータはないため,SharedMemoryを用いた実装との比較は意味をなさ ない.一方,前節で述べたようにリダクション演算が性能に影響を与える可能性が ある.特にデフォルトのCUDA Block数・CUDA Thread数ではforループのイタ レーション数が多いほどCUDA Block数が多くなりリダクション演算が実行時間に 与える影響が大きくなると考えられる.そこで,SimpleCUDAのプログラムを書き 換え,CUDA Block間のリダクション演算をCPU側に移動したプログラム (CUDA-CPUreduction)と全てのリダクション演算を単純にatomicな加算命令で構成したプ ログラム (CUDA-GLOBALreduction) を作成し,性能を比較することにした.
各実装の実行時間を図51に示す.前項の行列積と同様,CUDAを用いた実装に ついては初期化の時間を含んでいない.
グレゴリ級数は理想的な並列性を持つため,Omniではスレッド数を2,4と増や すことで実行時間が1/2,1/4と短縮されており,同時実行可能なスレッド数を超え ると性能が頭打ちになっている.一方OMPCUDAでは,CPUと比べてコアクロッ クが低いにも関わらず実行時間が短くなっており,多数の演算器による並列処理の 効果が得られていることが見て取れる.OMPCUDAとSimpleCUDAを比較すると,
この実験ではOMPCUDAの生成するプログラムとSimpleCUDAの生成するプログ ラムはforループの書き換えとOMPCUDAの初期化以外はほぼ同等のプログラム であり,実行時間の差として現れるのはループの書き換えによる時間のみである.
OMPCUDAのスケジューリングは単純なスタティックスケジューリングであり複雑
な計算は行っていないため,実行時間に有意な差は見られなかった.
一方でリダクションの方法を変更したCUDA-CPUreductionでは実行時間が40%近 く短くなり,CUDA-GLOBALreductionは100倍以上長い実行時間となった.
CUDA-4.3 OMPCUDAの評価 118
図 51: 円周率の求解の実行時間1 (問題サイズ 0x10000000)
4.3 OMPCUDAの評価 119
CPUreductionの実行時間内訳を確認したところ,CPU上でのリダクション演算は 数ミリ秒で終了していることがわかった.OMPCUDAと比べてGPUからCPUへ転 送されるデータ量が増加してはいるものの,増加した容量はたかだかCUDA Block 数(1024*1024) * float変数の容量(32bit) = 1MBであり,CPU-GPU間の転送速度
が実測値1GB/secを超える今回の実験環境では実行時間に大きな影響を及ぼすと
は考えにくい.そのため,CUDA-CPUreductionはGPU上のCUDA Block間での リダクションにかかる時間を大きく削減できたため実行時間が短く,また CUDA-GLOBALreductionでは逆にGPU上のCUDA Block間でのリダクション時間が大 きくなったためにこのような結果が得られたと考えられる.
ここで,OMPCUDAとCUDA-CPUreductionについてCUDA Block数とCUDA Thread数を変更した場合の性能を図52に示す.OMPCUDA,CUDA-CPUreduction ともにCUDA Block数・CUDA Thread数が一定の範囲であれば性能に大きな差はな く,また行列積ではOMPCUDAのデフォルト設定であるできる限り多くのCUDA Block・CUDA Threadを利用する割り当てが高い性能を得ていたのに対して,今回 の性能評価ではCUDA Block数を増やした場合に性能低下が見られている.この原 因として,CUDAが効率よくタスクスイッチ可能なCUDA Block数を超えているこ とが考えられる.
図53は,OMPCUDAの実行時間を1とした場合のCUDA-CPUreductionの実行 時間比である.CUDA Block数が少ない場合は実行時間にほとんど差がないものの,
CUDA Block数が多い場合には大きな実行時間の差が生じている.CUDA Block数
が多くCUDA Thread数が少ない場合に実行時間の差が生じていないように見える
のは,計算時間が非常に長くリダクション演算の実行時間が表面化していないため である.なお,1CUDA BlockあたりのCUDA Thread数とCUDA Block数の両方 が大きな場合の点がいくつか足りていないのは,CUDA Block数*CUDA Thread数 が問題サイズを超えており評価が意味をなさないためである.
以上から,対象問題の計算量やリダクション対象のデータ量によってはリダクショ ン演算を全てGPU上で行うか一部をCPUで行うかによって性能に差が生じると考 えられる.ただし今回の問題設定では,OMPCUDA・CUDA-CPUreductionともに CUDA Thread数256,CUDA Block数16384の時に最も実行時間が短くなり,所要 時間はともに285.5msecであった.
4.3 OMPCUDAの評価 120
図 52: 円周率の求解の実行時間2 (問題サイズ 0x10000000)
4.3 OMPCUDAの評価 121
図 53: 円周率の求解の実行時間3 (問題サイズ 0x10000000)
4.3 OMPCUDAの評価 122
今回の問題設定では,OMPCUDAデフォルトのCUDA Block数・CUDA Thread 数設定よりも高い性能を得ることができるCUDA Block数・CUDA Thread数の設 定が存在した.常に最も高い性能を得られるようにするためには,デフォルトでよ り適したCUDA Block数・CUDA Thread数が選ばれるような仕組みが必要である.
しかしながら評価1と同様に,OMPCUDAを用いることでGPUの持つ高い並列演 算性能を活用できることが確認できたと言える.