2.39MB文件运行时间 CPU:43.511ms GPU:65.219ms
32.9MB文件运行时间 CPU:289.541ms GPU:605.400ms
我尝试使用本地内存,虽然我100%确定我用错了,遇到了两个问题。内核在任何设置本地工作大小的情况下都会在1000-3000ms之间完成,或者我会遇到状态码-5,即CL_OUT_OF_RESOURCES。
这是一个SO成员帮助我解决的内核。
__kernel void lowpass(__global float *Array, __global float *coefficients, __global float *Output) {
int globalId = get_global_id(0);
float sum=0.0f;
for (int i=0; i< 65; i++)
{
float tmp=0;
if (globalId+i > 63)
{
tmp=Array[i+globalId-64]*coefficients[64-i];
}
sum += tmp;
}
Output[globalId]=sum;
}
这是我尝试使用本地内存。第一部分是主机代码片段,接下来的部分是内核代码。
//Set the size of localMem
status |= clSetKernelArg(
kernel,
2,
1024, //I had num_items*(float) but it gave me a -5. Num items is the amount of elements in my array (around 1.2 million elements)
null);
printf("Kernel Arg output status: %i \n", status);
//set a localWorkSize
localWorkSize[0] = 64;
//execute the kernel with localWorkSize included
status = clEnqueueNDRangeKernel(
cmdQueue,
kernel,
1,
NULL,
globalWorkSize,
localWorkSize,
0,
NULL,
&someEvent);
//Here is what I did to the kernel***************************************
__kernel void lowpass(__global float *Array, __global float *coefficients, __global float *Output, __local float *localMem) {
int globalId = get_global_id(0);
int localId = get_local_id(0);
localMem[localId] = globalId[globalId];
float sum=0.0f;
for (int i=0; i< 65; i++)
{
float tmp=0;
if (globalId+i > 63)
{
tmp=localMem[i+localId-64]*coefficients[64-i];
}
sum += tmp;
}
Output[globalId]=sum;
}
我尝试设置本地变量时使用的参考链接: 如何在OpenCL中使用本地内存? 用于查找kernelWorkGroupSize的链接(这就是为什么我在kernelArg中设置了1024): 1GB VRAM中有200万个浮点数的CL_OUT_OF_RESOURCES? 我看到其他人也有类似的问题,其中GPU比CPU更慢,但对于他们中的许多人来说,他们正在使用clEnqueueKernel而不是clEnqueueNDRangeKernel。
如果您需要有关此内核的更多信息,请参阅我的以前的问题: FIFO实现在OpenCL内核中的最佳方法 还发现了一些针对GPU的优化技巧。 https://developer.amd.com/wordpress/media/2012/10/Optimizations-ImageConvolution1.pdf 编辑后的代码;错误仍然存在
__kernel void lowpass2(__global float *Array, __global float *coefficients, __global float *Output) {
int globalId = get_global_id(0);
float sum=0.0f;
float tmp=0.0f;
for (int i=64-globalId; i< 65; i++)
{
tmp = 0.0f;
tmp=Array[i]*coefficients[i];
sum += tmp;
}
Output[globalId]=sum;
}
for
循环中使用if()
语句。一个聪明的编译器也许能够将if
提升出循环,但 GPU 驱动程序可能没有足够的时间和智能来有效地执行此操作。 - EOFif (globalId+i > 63)
显然等同于if (globalId+i >= 64)
,而这显然等同于if (i >= 64 - globalId)
,这可以通过改变for循环的初始化语句轻松消除:for (int i=64-globalId; i<65; i++)
。 - EOF