我有一个循环,我试图在CUDA中并行化。它是这样的:
float *buf = new float[buf_size]; // buf_size <= 100
for (int j; j<N; j++){
caluculate_with(buf);
}
delete [] buf;
循环的本质是每次迭代开始时缓冲区数组中的值无关紧要。因此循环本身可以非常简单地并行化。
但是在CUDA中,由于异步调用内核,我现在需要一个更大的缓冲区。
void __global__ loop_kernel(float *buf_gpu) {
const int idx = index_gpu(blockIdx, blockDim, threadIdx);
float *buf = buf_gpu + (idx*buf_size);
caluculate_with(buf);
}
....
float * buf_gpu;
cudaMalloc(&buf_gpu,sizeof(float)*N*buf_size);
loop_kernel<<<mesh,block>>>(buf_gpu);
cudaFree(buf_gpu);
}
由于对内核的每次调用都有自己的缓冲区段,因此缓冲区大小现在随着循环大小N而缩放,这显然是个问题。我现在必须分配(缓冲区大小*循环大小),而不是使用(缓冲区大小)内存量。在我正在处理的问题中,我的GTX590的GPU内存限制因N的某些典型值而受到影响。
编辑:详细说明我的另一次尝试。 由于buf_size不是太大,我也尝试重写内核,如下所示:
void __global__ loop_kernel() {
float *buf = new float[buf_size];
caluculate_with(buf);
delete [] buf;
}
...
assert(cudaSuccess == cudaDeviceSetLimit(cudaLimitMallocHeapSize,8*1024*1024));
loop_kernel<<<mesh,block>>>();
assert(cudaSuccess == cudaDeviceSynchronize());
cudaDeviceSynchronize()断言失败,返回状态为4.不知道这意味着什么。
答案 0 :(得分:1)
你还没有告诉我们关于calculate_with()
的任何信息,所以不清楚其中任何一项是否可以并行化,但这肯定是值得研究的。
然而,一种方法是简单地将缓冲区大小限制为GPU内存可以处理的内容,然后根据缓冲区大小在循环中调用内核:
void __global__ loop1_kernel(float *buf_gpu) {
const int idx = index_gpu(blockIdx, blockDim, threadIdx);
float *buf = buf_gpu + (idx*buf_size);
caluculate_with(buf);
}
....
float * buf_gpu;
cudaMalloc(&buf_gpu,sizeof(float)*num_buffs*buf_size);
for (int j=0; j<(N/num_buffs; j++){
loop_kernel<<<mesh,block>>>(buf_gpu);
cudaMemcpy(host_data, buf_gpu, (sizeof(float)*num_buffs*buf_size), cudaMemcpyDeviceToHost);
}
cudaFree(buf_gpu);
}
显然,cudaMemcpy
行只需要是实际生成的需要从内核操作中保存的数据。