前提
CUDAとCで非常に大きな一次元配列の総和を求めたいです。
double[100000000]のようなサイズです。
総和を求めるプログラムは下記URLをほぼそのまま使っています。
https://qiita.com/gyu-don/items/ef8a128fa24f6bddd342
下記コードだと配列数1048576までは総和を求められますが、
それ以上のサイズだと求めることができません。
大きな配列の総和を求めるようにするにはどのようにしたらよいのでしょうか。
CUDA(GPU)自体あまり理解できておらず、このような用途ではGPUはつかわないのか、
総和を求めるだけならCPUが早いのかなど一般的なCUDAの利用についても教えていただけるとたすかります。
該当のソースコード
C
1#include <stdio.h> 2 3__global__ void reduce0(double *g_idata, double *g_odata, unsigned int n){ 4 5 extern __shared__ double sdata[]; 6 7 unsigned int tid = threadIdx.x; 8 unsigned int i = blockIdx.x * blockDim.x + threadIdx.x; 9 10 sdata[tid] = (i < n) ? g_idata[i] : 0; 11 __syncthreads(); 12 13 for (unsigned int s=1; s<blockDim.x; s*=2) { 14 if (tid % (2*s) == 0) { 15 sdata[tid] += sdata[tid + s]; 16 } 17 __syncthreads(); 18 } 19 20 if (tid == 0) g_odata[blockIdx.x] = sdata[0]; 21 22} 23 24int main(int argc, char *argv[]){ 25 26 int threads_per_block = 1024; 27 int number_of_blocks = 1024; 28 29 //NG 30 unsigned int n = 1048577; 31 //OK 32 //unsigned int n = 1048576; 33 double array = n * sizeof(double); 34 double result = number_of_blocks * sizeof(double); 35 double *pt_array, *pt_result, cpu_result = 0.0, gpu_result = 0.0; 36 cudaMallocManaged(&pt_array, array); 37 cudaMallocManaged(&pt_result, result); 38 39 // Initialize 40 for(unsigned int i=0; i<n; i++){ 41 pt_array[i] = 2.0; 42 } 43 44 // CPU 45 for(unsigned int i=0; i<n; i++){ 46 cpu_result = cpu_result + pt_array[i]; 47 } 48 49 printf("cpu_result: %.1f\n", cpu_result); 50 51 cudaFuncSetAttribute(&reduce0, cudaFuncAttributeMaxDynamicSharedMemorySize, 163840); 52 reduce0<<< number_of_blocks, threads_per_block, 163840 >>>(pt_array, pt_result, n); 53 cudaDeviceSynchronize(); 54 55 for(int i=0; i<number_of_blocks; i++){ 56 gpu_result = gpu_result + pt_result[i]; 57 } 58 // GPU 59 printf("gpu_result: %.1f\n", gpu_result); 60 61 cudaFree(pt_array); 62 cudaFree(pt_result); 63 64}
試したこと
cudaFuncSetAttributeで共有メモリのサイズを拡張しました。
補足情報(FW/ツールのバージョンなど)
CUDA11.4で動作検証をしています。
> 総和を求めるだけならCPUが早いのか
CPU/GPUのふたつでやってみればいいじゃん