1

我正在使用 pyOpenCL 进行一些复杂的计算。它在 CPU 上运行良好,但在 NVIDIA GeForce 9400M (256 MB) 上运行时出现错误。我正在使用 Mac OS X Lion (10.7.5)

奇怪的是,这个错误并不总是出现。当我的计算使用更大的数字(导致更大的迭代)但仅在 GPU 上运行时似乎会发生这种情况。

我不写我不应该写的内存位置。通过将代码作为单个工作项运行,我排除了并发修改可能出现的问题。


我尽可能简化了我的 OpenCL 代码,并从剩下的内容中创建了一些非常简单的代码,这些代码具有非常奇怪的行为,导致pyopencl.LogicError. 它由 2 个嵌套循环组成,其中对result数组进行了几个赋值。这种分配甚至不需要依赖于循环的状态。shape = (1,)这是在 GPU上的单个线程(或工作项)上运行的。

__kernel void weirdError(__global unsigned int* result){
    unsigned int outer = (1<<30)-1;
    for(int i=20; i--; ){
        unsigned int inner = 0;
        while(inner != outer){
            result[0] = 1248;
            result[1] = 1337;
            inner++;
        }
        outer++;
    }
}

奇怪的是,删除结果数组的任一个分配都会删除错误。此外,减小外部的初始值((1<<20)-1例如降低到)也可以消除错误。在这些情况下,代码会正常返回,并在相应的缓冲区中提供正确的结果。在 CPU 上,它永远不会引发错误。


OpenCL 代码使用 PyOpenCL 从 Python 运行。

设置中没有什么花哨的:

platform = cl.get_platforms()[0]
device = platform.get_devices(cl.device_type.GPU)[0]
context = cl.Context([device])
program = cl.Program(context, getProgramCode()).build()
queue = cl.CommandQueue(context)

在此 Python 代码中,我将 设置result_buf0,然后在 OpenCL 中运行计算,该计算将在大迭代中设置其值。之后我尝试从设备内存中收集这个值,但这就是出错的地方:

result = numpy.zeros(2, numpy.uint32)
result_buf = cl.Buffer(context, mem_flags.READ_WRITE | mem_flags.COPY_HOST_PTR, hostbuf=result)

shape = (1,)
program.weirdError(queue, shape, None, result_buf)

cl.enqueue_copy(queue, result, result_buf)

最后一行给了我:

pyopencl.LogicError: clEnqueueReadBuffer failed: invalid command queue

  • 这种重复分配如何导致错误?

  • 更重要的是:如何避免?


我知道这个问题可能与平台有关,因此可能难以重现。但这是我唯一可以访问的机器,所以代码应该可以在这台机器上运行。

免责声明:我以前从未使用过 OpenCL(或 CUDA)。我在 GPU 不支持 OpenCL 的机器上编写代码。我总是在 CPU 上测试它。现在我切换到 GPU,我发现错误不会持续发生令人沮丧,我不知道为什么。

4

2 回答 2

1

我的建议是避免内核内部出现如此长的循环。Work Item 进行了超过 10 亿次迭代,这是一个很长的目标。驱动程序可能会杀死您的内核,因为它需要太多时间来执行。将迭代次数减少到最大量,不会导致错误并查看执行时间。如果它需要几秒钟的时间 - 那太多了。

正如您所说,减少迭代次数可以解决问题,这就是我认为的证据。减少分配操作的数量也使内核运行得更快,因为 IO 操作通常是最慢的。

由于显而易见的原因,CPU 不会面临这样的困难。

于 2014-07-29T14:25:21.847 回答
0

这个超时问题可以在 Windows 和 Linux 中修复,但在 Mac 中显然不行。


视窗

This answer to a similar question(解释Windows中的症状)告诉了发生了什么以及如何解决它:

这是 Windows 下的一个已知“功能”(不确定 Linux)——如果视频驱动程序停止响应,操作系统将重置它。除此之外,由于 OpenCL(和 CUDA)是由驱动程序实现的,因此耗时过长的内核看起来就像一个冻结的驱动程序。有一个看门狗计时器可以跟踪这一点(我相信是 5 秒)。

您的选择是:

  1. 您需要确保您的内核不会太耗时(最好)。
  2. 您可以关闭看门狗定时器:超时检测和 GPU 恢复
  3. 您可以在未连接到显示器的 GPU 上运行内核。

我建议你选择1。

这个答案解释了如何在 Windows 7 中实际执行 (2)。但是这些注册表项的 MSDN 页面提到它们不应被目标测试或调试之外的任何应用程序操作。所以它可能不是最好的选择,但它是一个选择。


Linux

(来自 Cuda 发行说明,但也适用于 OpenCL)

未连接显示器的 GPU 不受 5 秒运行时间限制。因此,建议在未连接到 X 显示器的 GPU 上运行 CUDA。

虽然 X 不需要运行才能使用 CUDA,但 X 在启动后必须至少初始化一次才能正确加载 NVIDIA 内核模块。即使在 X 关闭后,NVIDIA 内核模块仍保持加载状态,从而允许 CUDA 继续运行。


苹果电脑

苹果显然不允许摆弄这个看门狗,因此唯一的选择似乎是使用第二个 GPU(没有附加屏幕)

于 2014-08-04T10:12:11.237 回答