超过特定系统大小时的OpenCL随机内核行为

超过特定系统大小时的OpenCL随机内核行为,opencl,Opencl,我有这样的问题。基本上,我在主机上分配了一个2D网格: double* grid = (double*)malloc(sizeof(double)*(ny*nx) * 9); 按照正常的openCL程序将其置于openCL设备上: cl_mem cl_grid = clCreateBuffer(context, CL_MEM_COPY_HOST_PTR, sizeof(double) * (ny*nx) * 9, grid, &error); 以及排队和启动: clEnqueueND

我有这样的问题。基本上,我在主机上分配了一个2D网格:

double* grid = (double*)malloc(sizeof(double)*(ny*nx) * 9);
按照正常的openCL程序将其置于openCL设备上:

cl_mem cl_grid = clCreateBuffer(context, CL_MEM_COPY_HOST_PTR, sizeof(double) * (ny*nx) * 9, grid, &error);
以及排队和启动:

clEnqueueNDRangeKernel(queue, foo, 1, NULL, &global_ws, &local_ws, 0, NULL, NULL);
在核函数中,对网格的第一列执行简单算法:

__kernel void foo(__constant ocl_param* params, __global double* grid)
{
    const int ii = get_global_id(0);
    int jj;
    jj=0;

    if (ii < params->ny) {
        grid[getIndexUsingMacro(ii,jj)] += params->someNumber;
    }
}
问题是当网格大小(即nx*ny*9)超过16384*9*8字节=1152KB(*8,因为使用了双精度)时

  • 如果在CPU上使用openCL,则在启动内核时会抛出一个错误CL_OUT_OF_RESOURCES,无论我为全局_ws和本地_ws设置了什么(我将它们设置为1,并且仍然会抛出该错误)。CPU是Intel i5 2415m,具有8GB RAM和3MB缓存

  • 如果在GPU(NVIDIA TESLA M2050)上使用openCL,则不会引发错误。但是,当从缓冲区读回值时,网格根本没有改变。这意味着它返回的网格值与发送到内核函数之前的值完全相同

例如,当我设置nx=30、ny=546、nx*ny=16380时,一切正常。网格返回,结果按预期更改。但是当ny=547,nx*ny=16410时,问题会出现在CPU和GPU上,如上所述。如果我交换nx和ny,问题是一样的,因此,如果nx=547,ny=30,它仍然会发生。你们能告诉我这里有什么问题吗


非常感谢

这看起来像是一个同步问题<代码>网格[索引]+=值具有相同的
索引
值,可由多个工作项同时执行。此操作不是原子操作,所有这些工作项都将加载
grid[index]
,添加它们的值并将其存储回去,可能会在过程中丢失一些增量

为了解决这个问题,如果这些工作项在单个工作组中,您可以使用
barrier
来同步它们,否则就让更多的内核排队

另一种可能性是确保只有一个工作项能够修改网格的给定元素(通常是最佳解决方案)


如果多个工作项需要在网格的公共子集上工作,则使用本地内存和本地内存屏障可能会很有用。

这看起来像是一个同步问题<代码>网格[索引]+=值具有相同的
索引
值,可由多个工作项同时执行。此操作不是原子操作,所有这些工作项都将加载
grid[index]
,添加它们的值并将其存储回去,可能会在过程中丢失一些增量

为了解决这个问题,如果这些工作项在单个工作组中,您可以使用
barrier
来同步它们,否则就让更多的内核排队

另一种可能性是确保只有一个工作项能够修改网格的给定元素(通常是最佳解决方案)


如果多个工作项需要在网格的公共子集上工作,则使用本地内存和本地内存屏障可能很有用。

除非您仅将一个工作组排队,否则无法安全地使用屏障来完成此操作。OpenCL中的屏障为一个工作组中的所有工作项提供同步,但它不同步工作组间的访问。这就是我的意思:“如果它们在一个工作组中”。你不能安全地使用屏障来实现这一点,除非你只让一个工作组排队。OpenCL中的一个屏障为一个工作组中的所有工作项提供同步,但它不同步工作组间的访问。
clEnqueueReadBuffer(queue, cl_grid, CL_TRUE, 0, sizeof(double) * 9 * nx * ny, checkGrid, 0, NULL, NULL);