CUDA优化:嵌套循环

时间:2013-10-12 21:53:11

标签: loops optimization cuda nested

我正在尝试在此代码中导入CUDA:

double square=0;
for(int j=0;j<width; j++) {
  double Up=0,Down=0;
  for(int i=0;i<height; i++) {
    if(array1[i]>0 && array2[i]>0){
      square = source[i*width+j];
      square = square*square;
      Up   += square*array2[i]/array1[i];
      Down += square;
    }
  }
  if(Down>0){
    out[j] *= (1.+(Up/Down-1.));
  }
}

在第一次尝试中,我减少了第一个for循环。 (效果很好)

int j = blockDim.x * blockIdx.x + threadIdx.x;

double Up=0, Down=0, square=0;
if (j<width) {
  for(int i=0;i<height;i++) {
    if(array1[i]>0 && array2[i]>0){
      square = source[i*width+j];
      square = square*square;
      Up   += square*array2[i]/array1[i];
      Down += square;
    }
  }
  if(Down>0){
    out[j] *= (1.+(Up/Down-1.));
  }
}

我还会减少第二个for循环,我尝试使用2D网格不起作用。 这是内核:

int j = blockDim.x * blockIdx.x + threadIdx.x;
int i = blockDim.y * blockIdx.y + threadIdx.y;
int offset = j + i * blockDim.x * gridDim.x;

double Up[width],Down[width], square[height];
if (j>=width && i>=height) return;

if(array1[i]>0 && array2[i]>0){
  square[i] = source[offset]*source[offset];
  Up[j]   += square[i]*array2[i]/array1[i];
  Down[j] += square[i];
}
if(Down[j]>0){
  out[j] *= (1.+(Up[j]/Down[j]-1.));
}

这是内核调用:

dim3 blocks(32,32);
dim3 grid(width/32,height/32);
kernel <<< grid, blocks >>> (...);
cudaDeviceSynchronize();

......错误是什么?有更有效的解决方案吗? (我可以使用动态并行性吗?)

非常感谢!

1 个答案:

答案 0 :(得分:1)

在你的上一个内核中,看起来你希望UpDownsquare的数组在线程之间保持不变,但这些数组是线程本地的,所以它们包含的数据线程之间不共享。不幸的是,即使它们在线程之间共享,您的方法也不会起作用。

在你的内循环中,循环的当前轮次使用在前一轮中计算的数据。并行化这样的循环并不是完全无足轻重的,有时它根本无法完成。在您的情况下,一个简单的解决方案是使用原子运算符来增加UpDown计数器,但它不会有效,因为原子运算符会导致操作的隐式序列化。

您应该考虑使用已经优化的现有并行基元(例如前缀和)解决此问题。例如,CUBThrust中的那些。