有人可以解释这个OpenCL程序有什么问题吗?

Chu*_*cky 0 c multithreading kernel gpu opencl

我已经包含了主机程序的主要部分,我怀疑这里不正确:

http://pastebin.com/qVkv9E11

我的指针还不是很好,并且认为我可能错误地分配了一些变量.

这是内核程序,它应该让我知道我的程序正在尝试做什么:

    const char *KernelSource =           "\n"
"__kernel void sumElements(           \n"
"   __global float* input,            \n"
"   __global float output,            \n"
"   __global int N)                   \n"
"{                                    \n"
"   int i = get_global_id(0);         \n"
"   if(i < N)                         \n"
"       output += input[i];           \n"
"}                                    \n"
"\n";
Run Code Online (Sandbox Code Playgroud)

也许这会导致错误,因为我从未尝试过SIMT写入一个变量,如上所述.有可能做这样的事吗?我需要得到数组中所有元素的总和.

小智 5

如果您试图实际读回输出值,那么您还需要将其声明为指针.现在,输出的值被复制为内核参数,但是在内核结束后会忽略对它所做的任何更改.

所以,__global float output改为__global float* output.然后在你的内核中更改:

if(i < N)
    output += input[i];
Run Code Online (Sandbox Code Playgroud)

if(i < N)
    *output += input[i];
Run Code Online (Sandbox Code Playgroud)

您可能需要更改为此分配缓冲区的方式,但是我已经很长时间在OpenCL中完成此操作并且我现在找到的文档中没有显示任何明显的错误缓冲区.

这里有一个警告:添加不是原子操作.通过这种设置,总会发生的是你将有两个或更多线程读取*output的值,然后尝试在不同阶段将*output + 1写入其中.因此,*输出将具有小于它应该的值.

要解决此问题,您将需要使用OpenCL 原子操作.

  • 只是为了添加到Telgin的答案,对这样的单个元素求和是非常低效的(尽管在技术上可以使用原子操作实现).您可能需要考虑减少问题:例如,如果您的输入有N个元素,则创建I个工作项,每个项负责求和N/I个元素,然后(i)输出一个部分和的数组,然后将其累积回来主机(ii)使用OpenCL内存屏障,并且在输出单个值之前,有一个工作项累积设备上的部分和. (3认同)