Opencl大小的本地内存对速度有影响吗?

时间:2014-05-08 07:07:50

标签: opencl histogram

我是OpenCL的新手,我正在尝试计算灰度图像的直方图。我在GPU nvidia GT 330M上执行此计算。

代码是

__kernel void histogram(__global struct gray * input, __global int * global_hist, __local volatile int * histogram){
    int local_offset = get_local_id(0) * 256;
    int histogram_global_offset = get_global_id(0) * 256;
    int offset = get_global_id(0) * 1920;
    int value;
    for(unsigned int i = 0; i < 256; i++){
        histogram[local_offset + i] = 0;
    }
    barrier(CLK_LOCAL_MEM_FENCE);

    for(unsigned int i = 0; i < 1920; i++){
        value = input[offset + i].i;
        histogram[local_offset + value]++;
    }

    barrier(CLK_LOCAL_MEM_FENCE);
    for(unsigned int i = 0; i < 256; i++){
        global_hist[histogram_global_offset + i] = histogram[local_offset + i];
    }
}

对图像1920 * 1080执行该计算。

我正在使用

启动内核
queue.enqueueNDRangeKernel(kernel_histogram, cl::NullRange, cl::NDRange(1080), cl::NDRange(1));

当直方图的局部大小设置为256 * sizeof(cl_int)时,该计算的速度为(通过nvidia nsight性能分析)11 675微秒。

因为本地工作组大小设置为1。我尝试将本地工作组大小增加到8.但是当我将直方图的局部大小增加到256 * 8 * sizeof(cl_int)并使用本地wg大小1计算时,我得到85 177微秒。

因此,当我用每个工作组的8个内核启动它时,我不会从11毫秒开始加速,而是从85毫秒开始。因此,每个worgroup 8个内核的最终速度为13 714微秒。

但是当我创建计算错误时,将local_offset设置为零并且局部直方图的大小为256 * sizeof(cl_int)并且每个工作组使用8个内核我得到更好的时间 - 3 854微秒。

有没有人想加快这个计算?

谢谢!

1 个答案:

答案 0 :(得分:0)

这个答案假设您希望最终将直方图减少到256个int值。您可以使用与设备上的计算单元一样多的工作组来调用内核,并且组大小应该(一如既往)是设备上CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE的倍数。

__kernel void histogram(__global struct gray * input, __global int * global_hist){
  int group_id = get_group_id(0);
  int num_groups = get_num_groups(0);
  int local_id = get_local_id(0);
  int local_size = get_local_size(0);

  volatile __local int histogram[256];

  int i;
  for(i=local_id; i<256; i+=local_size){
    histogram[i] = 0;
  }

  int rowNum, colNum, value, global_hist_offset

  for(rowNum = group_id; rowNum < 1080; rowNum+=num_groups){
    for(colNum = local_id; colNum < 1920; colNum += local_size){
      value = input[rowNum*1920 + colNum].i;
      atomic_inc(histogram[input]);
    }
  }

  barrier(CLK_LOCAL_MEM_FENCE);
  global_hist_offset = group_id * 256;
  for(i=local_id; i<256; i+=local_size){
    global_hist[global_hist_offset + i] = histogram[i];
  }

}

每个工作组一次在图像的一行上协同工作。然后该组移动到另一行,使用num_groups值计算。无论你有多少个团体,这都会很好用。例如,如果您有7个计算单位,则组3(第四组)将从图像中的第3行开始,然后每隔7行开始。第3组将计算总共153行,其最后一行将是第1074行。某些工作组可能计算另外1行 - 在此示例中为0和1组。

在查看图像的列时,在工作组内完成相同的隔行扫描。在colNum循环中,第N个工作项从N列开始,并由local_size列向前跳过。此循环的其余部分不应经常播放,因为CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE可能是1920的因子。请尝试从(1..X)* CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE到设备的最大工作组大小的所有工作组大小。

关于这个内核的最后一点:结果与原始内核不同。您的global_hist数组是1080 * 256整数。我需要的是num_groups * 256个整数。如果你想要完全减少,这会有所帮助,因为在内核执行后要添加的内容要少得多。