CUDA技術を利用したGPUコンピューティングの実際(後編) ―― FFTを利用した光波の伝播(フレネル回折)をGPUで高速計算
C言語にはない書式ですが,<<< ~ >>>の部分がブロック数とスレッド数を指定する部分です.そのあとに,通常のC言語と同じように,カーネル関数の引き数が続きます.dim3はCUDAにあらかじめ組み込まれた構造体で, int型でx,y,zのメンバを持ちます.カーネルは実装方法によって演算性能が大幅に変わるので,本稿ではKernel1~Kernel3の3タイプのカーネル関数を用意し,その実装方法によってどの程度性能に差が出るのかを次節で紹介します.ここでは,Kernel1関数を実行しています.このKernel1は,GPU上のメモリd_aとd_bの行列データを乗算し,その計算結果をd_cに格納します.また,ブロック数とスレッド数は,WIDTH=512,BLOCK=16なので,行列を1024個のブロック数(32×32)に分割し,各ブロックのスレッド数が256個(16×16)として行列の乗算が実行されます.
(6)の部分は,GPUによって計算された結果(d_c)を,cudaMemcpyを使用してホスト側の領域(h_c)へコピーします.
(7)の部分は,GPU上に確保したメモリを開放する必要があるため,CUDAのAPIであるcudaFreeを使って開放します.
このソース・コードを実行すると,画面にコンソールが現れ,計算時間とともに計算結果が表示され,GPU上で正しく計算が行われていることを確認できます.
2.カーネルの実装
CUDA特有のスレッドやブロック,また,スレッドの同期やシェアード・メモリ(共有メモリ)の効果など,CUDAで何らかの計算を加速する場合に理解しなければならない事項を紹介します.
まず初めに,ホスト側のCPUのみで行列の乗算を行うソース・コードをリスト2に示します.このソース・コードとGPUのソース・コードを比較することで,CPUとGPUの計算方法の違いを示していきます.この関数は,WIDTH×WIDTHサイズの行列Aと行列Bを乗算し,結果をCの領域に格納します.このプログラムをホストで計算させたところ,実行時間(WIDTH=512の場合)は514ms(ミリ秒)となりました.ホスト・コンピュータは,CPUがIntel Core 2 Duo E6600(2.40GHz動作),メイン・メモリの容量が2Gバイト,OSがWindows XP Professional SP2のものを使用しました.
void Host(float *A, float *B, float *C)
{
//ホスト側での行列の乗算
int i,j,k;
int row,col;
float tmp;
for(i=0; i<WIDTH; i++){
for(j=0; j<WIDTH; j++){
tmp=0.0;
for(k=0; k<WIDTH; k++){
row=k+i*WIDTH;
col=j+k*WIDTH;
tmp+=A[row]*B[col];
}
C[j+i*WIDTH]=tmp;
}
}
}
リスト2 ホストのCPUによる行列の乗算