超过特定系统大小时的OpenCL随机内核行为
我有这样的问题。基本上,我在主机上分配了一个2D网格:超过特定系统大小时的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
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,则不会引发错误。但是,当从缓冲区读回值时,网格根本没有改变。这意味着它返回的网格值与发送到内核函数之前的值完全相同
非常感谢这看起来像是一个同步问题<代码>网格[索引]+=值具有相同的
索引
值,可由多个工作项同时执行。此操作不是原子操作,所有这些工作项都将加载grid[index]
,添加它们的值并将其存储回去,可能会在过程中丢失一些增量
为了解决这个问题,如果这些工作项在单个工作组中,您可以使用barrier
来同步它们,否则就让更多的内核排队
另一种可能性是确保只有一个工作项能够修改网格的给定元素(通常是最佳解决方案)
如果多个工作项需要在网格的公共子集上工作,则使用本地内存和本地内存屏障可能会很有用。这看起来像是一个同步问题<代码>网格[索引]+=值具有相同的
索引
值,可由多个工作项同时执行。此操作不是原子操作,所有这些工作项都将加载grid[index]
,添加它们的值并将其存储回去,可能会在过程中丢失一些增量
为了解决这个问题,如果这些工作项在单个工作组中,您可以使用barrier
来同步它们,否则就让更多的内核排队
另一种可能性是确保只有一个工作项能够修改网格的给定元素(通常是最佳解决方案)
如果多个工作项需要在网格的公共子集上工作,则使用本地内存和本地内存屏障可能很有用。除非您仅将一个工作组排队,否则无法安全地使用屏障来完成此操作。OpenCL中的屏障为一个工作组中的所有工作项提供同步,但它不同步工作组间的访问。这就是我的意思:“如果它们在一个工作组中”。你不能安全地使用屏障来实现这一点,除非你只让一个工作组排队。OpenCL中的一个屏障为一个工作组中的所有工作项提供同步,但它不同步工作组间的访问。
clEnqueueReadBuffer(queue, cl_grid, CL_TRUE, 0, sizeof(double) * 9 * nx * ny, checkGrid, 0, NULL, NULL);