![]() |
ノート/CUDA/マルチGPUhttp://pepper.is.sci.toho-u.ac.jp/pepper/index.php?%A5%CE%A1%BC%A5%C8%2FCUDA%2F%A5%DE%A5%EB%A5%C1GPU |
![]() |
CUDA
訪問者数 2519 最終更新 2010-08-24 (火) 13:14:46
マルチGPUとなるために、pthreadを使って2つのスレッドを立てる。この例題では
CUTThread thread = start_thread( routine, &(data[0]) ); routine( &(data[1]) );
というところ。1行目で0側のスレッドを生成し、2行目は今走っている自分自身が1側のスレッドとしてプログラムroutineを呼び出す。
start_thread自体はcommon/book.hに置かれていて、基本的にWindowsとLinuxの場合によっての区分けをしていて、Linuxの場合はpthread_createを使って
CUTThread start_thread(CUT_THREADROUTINE func, void * data){ pthread_t thread; pthread_create(&thread, NULL, func, data); return thread; }
としている。
つまり、ホスト側で2つのスレッドが走り始めたことになる。どちらも同じ「routine」を実行するスレッドである。それぞれが
cudaMalloc( (void**)&dev_a, size*sizeof(float) ) デバイス側に領域aを確保 cudaMalloc( (void**)&dev_b, size*sizeof(float) ) 同 b cudaMemcpy( dev_a, a, size*sizeof(float), cudaMemcpyHostToDevice ) aをデバイスへコピー cudaMemcpy( dev_b, b, size*sizeof(float), cudaMemcpyHostToDevice ) 同 b dot<<<blocksPerGrid,threadsPerBlock>>>( size, dev_a, dev_b, dev_partial_c );
カーネル dot を起動。
cudaMemcpy( partial_c, dev_partial_c, blocksPerGrid*sizeof(float), cudaMemcpyDeviceToHost )
としている。
呼び出されるカーネル dot はベクトルの内積(dot product)を計算するもので、本の85ページにリストされているものと同じである。
__global__ void dot( int size, float *a, float *b, float *c ) { __shared__ float cache[threadsPerBlock]; int tid = threadIdx.x + blockIdx.x * blockDim.x; スレッド番号 int cacheIndex = threadIdx.x; キャッシュインデックス=スレッド番号 float temp = 0; while (tid < size) { temp += a[tid] * b[tid]; 内積の加算 tid += blockDim.x * gridDim.x; スレッド番号をblockDim*gridDim分進める } // set the cache values cache[cacheIndex] = temp; 内積の結果をcache[スレッド番号]に格納 // synchronize threads in this block __syncthreads(); // for reductions, threadsPerBlock must be a power of 2 // because of the following code int i = blockDim.x/2; while (i != 0) { if (cacheIndex < i) cache[cacheIndex] += cache[cacheIndex + i]; cacheを集める。どういう風に? __syncthreads(); i /= 2; } if (cacheIndex == 0) c[blockIdx.x] = cache[0]; }
理解したこと: