使用 CPU 时的 OpenCL 段错误
Posted
技术标签:
【中文标题】使用 CPU 时的 OpenCL 段错误【英文标题】:OpenCL segfault when using CPU 【发布时间】:2014-01-17 20:34:09 【问题描述】:我正在使用 OpenCL 实现 FFT 算法(特别是 OpenCL in Action 中的算法。它在两个不同的 NVIDIA GPU(Tesla K20c 和 GeForce GTX 650)上运行良好,但是当我在我的 Intel CPU 上运行它时给我一个分段错误。
我在内核代码中找到了问题,但这没有意义。包含错误的唯一两行是下面块中对本地内存的最后两次写入。其他对内存的写入不会导致 CPU 出现问题,也不会导致 GPU 出现问题。
__kernel void fft_init(__global float2 *g_data, __local float2 *l_data,
uint points_per_group, uint size, int dir)
uint4 br, index;
uint points_per_item, g_addr, l_addr, i, fft_index, stage, N2;
float2 x1, x2, x3, x4, sum12, diff12, sum34, diff34;
points_per_item = points_per_group/get_local_size(0);
l_addr = get_local_id(0) * points_per_item;
g_addr = get_group_id(0) * points_per_group + l_addr;
for(i=0; i<points_per_item; i+=4)
...
l_data[l_addr] = sum12 + sum34;
l_data[l_addr+1] = diff12 + diff34;
l_data[l_addr+2] = sum12 - sum34;
l_data[l_addr+3] = diff12 - diff34;
l_addr+= 4;
我也知道问题不在于l_addr + 2,3
,因为在内核中,该数组至少被l_addr + 4
访问。
以前有没有人遇到过这样的问题,或者对如何解决它有任何想法?为了运行内核,我使用 EnqueueNDRangeKernel,在设置本地内存数组的参数时,我使用了整个可用的本地内存大小。
提前致谢!
【问题讨论】:
我的猜测是您正在访问已分配数组的末尾。您期望l_data
数组的大小是多少(以字节为单位)以及您在 clSetKernelArg 大小参数中传递的值是多少?另外,CL_DEVICE_LOCAL_MEM_SIZE 的 clGetDeviceInfo 返回什么?合身吗?最后,如果您使用的本地内存是固定大小的(而不是动态的),更好的形式是:__local float localBuffer[1024];
,而不是使用内核参数。
l_data 数组是 LOCAL_MEM_SIZE 的确切大小,由 GetDeviceInfo 返回。在本例中,它是 32768,这就是我传递给 clSetKernelArg 的数字。 clSetKernelArg 的指针参数为 NULL,我现在将使用它来查看是否有问题。本地内存是动态的,而不是固定的,因为我使用设备可用的整个本地内存 - 但我会从内核内部研究一种方法。
忽略我上面所说的关于 NULL 参数的内容,我发现它应该是这样的。我发现在最小的情况下,l_addr 永远不会大于get_local_id(0)
。由于每个组的工作项数量远小于 LOCAL_MEM_SIZE,我无法理解为什么访问 l_data[l_addr+3]
会超出数组的末尾。
【参考方案1】:
我不完全确定它为什么会起作用,但我已经设法找到了解决方案。使用此程序,工作组大小需要为 1024。两张 NVIDIA 卡已经将此作为其最大工作组大小,但 Intel CPU 的最大工作组大小为 4096(均由 clGetKernelWorkGroupInfo(...CL_KERNEL_WORK_GROUP_SIZE...)
返回。这就是为什么GPU 可以工作,而 CPU 没有。
同样,不知道为什么这可以使代码正常工作,但这是一个修复,我会接受它。
【讨论】:
以上是关于使用 CPU 时的 OpenCL 段错误的主要内容,如果未能解决你的问题,请参考以下文章