-1

我有一个循环,我试图在 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。不知道这意味着什么。

4

1 回答 1

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行只需要是实际生成的需要从内核操作中保存的任何数据。

于 2013-09-02T16:31:20.843 回答