我是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微秒。
有没有人想加快这个计算?
谢谢!
答案 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个整数。如果你想要完全减少,这会有所帮助,因为在内核执行后要添加的内容要少得多。