【发布时间】: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]会超出数组的末尾。
标签: opencl