使用 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 段错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 CUDA 流时的段错误

将 += 与字符串一起使用时的 Stange 段错误

使用 std::string.c_str() 作为另一个方法的参数时的段错误

Struct 上下文中未使用 printf 时的段错误

调用 glDrawElements 时的段错误

并行测试与地理相交时的段错误