OpenCL优化
我是OpenCL的新手。 我写了一个OpenCL内核来计算灰度。我如何优化代码,这是可能的?为什么计算时间浮动这么多?有时我会加快别人的速度。我做错了什么OpenCL优化,opencl,Opencl,我是OpenCL的新手。 我写了一个OpenCL内核来计算灰度。我如何优化代码,这是可能的?为什么计算时间浮动这么多?有时我会加快别人的速度。我做错了什么 kernel code: kernel void grayscale(__global unsigned char *input) { size_t i = get_global_id(0); float grayscaleValue = (input[i*3] * 0.299F) + (input[i*3+1] *
kernel code:
kernel void grayscale(__global unsigned char *input)
{
size_t i = get_global_id(0);
float grayscaleValue = (input[i*3] * 0.299F) + (input[i*3+1] * 0.587F) + (input[i*3+2] * 0.114F);
input[i*3] = grayscaleValue;
input[i*3+1] = grayscaleValue;
input[i*3+2] = grayscaleValue;
}
cpu code:
void GrayScaleCPU(struct PPMFile *ppmStruct)
{
for (int i = 0; i < ppmStruct->imageSize; i+=3)
{
float greyscaleValue = (ppmStruct->data[i] * 0.299F) + (ppmStruct->data[i+1] * 0.587F) + (ppmStruct->data[i+2] * 0.114F);
ppmStruct->out[i] = greyscaleValue;
ppmStruct->out[i+1] = greyscaleValue;
ppmStruct->out[i+2] = greyscaleValue;
}
}
int main(void)
{
struct timespec tS1, tS2;
tS1.tv_sec = 0;
tS1.tv_nsec = 0;
tS2.tv_sec = 0;
tS2.tv_nsec = 0;
...
clock_settime(CLOCK_REALTIME, &tS1);
GrayScaleCPU(ppmf);
clock_gettime(CLOCK_REALTIME, &tS1);
printf ("Timming took %.12lu seconds to run.\n", tS1.tv_nsec);
...
clock_settime(CLOCK_REALTIME, &tS2);
GrayScaleOpenCL(ppmf2);
clock_gettime(CLOCK_REALTIME, &tS2);
printf ("Timming took %.12lu seconds to run.\n", tS2.tv_nsec);
float time2 = tS2.tv_nsec;
float time1 = tS1.tv_nsec;
float speedup = time2/time1;
printf ("Speed UP OpenCL/CPU %.20f.\n", speedup);
return 0;
}
内核代码:
内核无效灰度(uu全局无符号字符*输入)
{
size\u t i=获取全局\u id(0);
浮点灰度值=(输入[i*3]*0.299F)+(输入[i*3+1]*0.587F)+(输入[i*3+2]*0.114F);
输入[i*3]=灰度值;
输入[i*3+1]=灰度值;
输入[i*3+2]=灰度值;
}
cpu代码:
void GrayScaleCPU(结构PPMFile*ppmStruct)
{
对于(int i=0;iimageSize;i+=3)
{
浮动灰度标度值=(ppmStruct->data[i]*0.299F)+(ppmStruct->data[i+1]*0.587F)+(ppmStruct->data[i+2]*0.114F);
ppmStruct->out[i]=灰度标度值;
ppmStruct->out[i+1]=灰度标度值;
ppmStruct->out[i+2]=灰度标度值;
}
}
内部主(空)
{
结构timespec tS1、tS2;
tS1.tv_sec=0;
tS1.tv_nsec=0;
tS2.tv_sec=0;
tS2.tv_nsec=0;
...
时钟设置时间(时钟实时和tS1);
灰度ecpu(ppmf);
时钟获取时间(时钟实时,&tS1);
printf(“Timming运行时间为%.12lu秒。\n”,tS1.tv\u nsec);
...
时钟设置时间(时钟实时和tS2);
灰度图(ppmf2);
时钟获取时间(时钟实时,&tS2);
printf(“Timming运行时间为%.12lu秒。\n”,tS2.tv\u nsec);
浮动时间2=tS2.tv\u nsec;
浮动时间1=tS1.tv\u nsec;
浮动加速=时间2/时间1;
printf(“加速OpenCL/CPU%.20f.\n”,加速);
返回0;
}
尝试将全局内存缓冲到线程内存中:
unsigned char l_input0 = input[i*3];
unsigned char l_input1 = input[i*3 + 1];
unsigned char l_input2 = input[i*3 + 2];
//compute grayscale using l_input0,1,2
input[i*3] = grayscale;
input[i*3 + 1] = grayscale;
input[i*3 + 2] = grayscale;
此外,如果在调用内核时数据的间隔不正确,则可能会在每个无符号字符上执行,而不是像for循环中那样在第三个无符号字符上执行
然后,您可以进一步使用本地内存和工作组,并分块进行计算,尽管这更具挑战性,因为本地工作大小非常特定于设备,需要是全局工作大小的倍数。我发现16、32和64的本地工作大小适用于大多数设备
最后,对OpenCL进行基准测试,确保测量的是内核性能,而不是内核排队时间。最简单的方法是启动一个计时器,让内核排队,在队列上调用clainish,然后停止计时器。大多数OpenCL设备都内置了定时和评测功能,这些功能由队列处理。您测量的是什么,如何测量?我测量的是这两个功能中的时间。在opencl的情况下,我会测量所有与准备内核午餐有关的事情。使用struct timespec。是吗@您正在测量创建命令队列、上下文和构建程序?如果你这样做是错误的,你也应该衡量执行情况大约十次,放弃第一次,因为它通常较慢,然后取平均值。是的,我衡量一切,不应该这样做吗?我应该只测量内核“clEnqueueNDRangeKernel”的执行情况?关于设备之间的内存传输,我也应该放弃吗?内存事务可以包括在内,但在现代GPU上,它们与计算并行进行(第二次迭代计算可以在第一次迭代数据读回的同时进行)。但是是的,你应该只测量内核执行时间和数据传输检查这个,还有一些其他问题也应该帮助你为什么我不应该测量排队时间?它属于过程,不是吗@当然,您可以测量它,但它是A)无关紧要的,B)仅仅因为内核排队并不意味着它就完成了,所以在收集计时数据时要小心。这就是警告。