OpenCL内核执行时间过长导致崩溃

OpenCL内核执行时间过长导致崩溃,opencl,watchdog,raymarching,Opencl,Watchdog,Raymarching,我目前正在建造一个ray marcher,用来观察像mandelbox之类的东西。它工作得很好。然而,在我当前的程序中,它使用每个工作者作为从眼睛投射的光线。这意味着每个工人有大量的执行。因此,当查看一个极其复杂的对象或试图以足够大的精度渲染时,会导致我的显示驱动程序崩溃,因为内核在单个辅助程序上执行的时间太长。我试图避免更改注册表值以延长超时时间,因为我希望此应用程序在多台计算机上工作 有什么办法可以补救吗?目前,每个工作项的执行完全独立于附近的工作项。我已经考虑过向GPU订阅一个缓冲区,它将

我目前正在建造一个ray marcher,用来观察像mandelbox之类的东西。它工作得很好。然而,在我当前的程序中,它使用每个工作者作为从眼睛投射的光线。这意味着每个工人有大量的执行。因此,当查看一个极其复杂的对象或试图以足够大的精度渲染时,会导致我的显示驱动程序崩溃,因为内核在单个辅助程序上执行的时间太长。我试图避免更改注册表值以延长超时时间,因为我希望此应用程序在多台计算机上工作

有什么办法可以补救吗?目前,每个工作项的执行完全独立于附近的工作项。我已经考虑过向GPU订阅一个缓冲区,它将在该光线上存储当前进度,并且只执行少量迭代。然后,我会一遍又一遍地调用程序,结果可能会进一步细化。问题是,我不确定如何处理分支光线(例如反射和折射),除非我有一个最大数量的每个预期


有人对我应该如何解决这个问题有什么建议吗?我是OpenCL的新手,已经有相当一段时间了。我觉得我好像做错了什么或滥用了OpenCL,主要是因为我的单个工作项背后有很多逻辑,但我不知道如何分割任务,因为这只是一系列步骤、检查和调整。

你正在经历的崩溃是由nVIDIA的硬件看门狗计时器造成的。此外,操作系统还可以检测到GPU没有响应并重新启动它(至少Windows7会这样做)

您可以通过多种方式避免:

  • 改进/优化内核代码以节省时间
  • 购买更快的硬件(美元)
  • 禁用看门狗定时器(但这不是一项容易的任务,而且并非所有设备都具有此功能)
  • 通过启动多个小内核来减少每次排队等待到设备上的工作量(注意:通过启动每个小内核,这样做会带来一些开销)
简单明了的解决方案是最后一个。但是如果可以的话,也试试第一个


例如,这样的调用(1000x1000=1M工作项,全局大小):

可以分成许多小的调用((100x100)x(10x10)=1M)。由于全局大小现在小于100倍,因此不应触发看门狗:

for(int i=0; i<10; i++)
    for(int j=0; j<10; j++)
        clEnqueueNDRangeKernel(queue, kernel, 2, NDRange(i*100,j*100)/*Offset*/, NDRange(100,100)/*Global*/, ... );

用于(int i=0;我能把它反过来吗?每次只运行图像的一小部分?即:不是1000x1000,而是启动100x100 100次的块。@DarkZeros噢,是整个任务的操作持续时间决定了我的显示驱动程序是否不再喜欢我的内核而不是任何一个工作项?我可以尝试一下,然后重新启动很遗憾,我现在不在家。所以,这需要一些重构。但我已经将它划分为多个内核调用,并且它不会崩溃。如果您想从您的评论中创建一个答案,@DarkZeros,我很乐意接受它。现在来弄清楚NVidia为什么要制作ClenqueueEndRangeKernel调用块,但这是另一天的另一个问题。谢谢你的建议,我被错误地告知了内核是如何计时的。效果很好。我没有为1920x1080图像的每一条光线运行一个工作线程,而是在大约50000个工作线程的批处理中调用内核。从最初的大约200万个工作线程中,我调用内核20次,而不是一次。我也在考虑使用我之前概述的方法,该方法允许对同一个工作者的多个较小的调用以少量方式附加其以前的工作。但目前它确实阻碍了崩溃,并且调用额外的19个内核会产生相当不明显的开销。谢谢,我还没有意识到计时器工作由于内核使用所有的GPU资源,其他应用程序/操作系统不能再将它们的内容呈现到屏幕上。在许多丢失的帧之后,他们认为GPU已经死机并重新启动它。然而,通过拆分作业,它允许其他任务在内核调用之间执行。我想知道是否在OpenCL 1.2(带设备FISE)中。子设备也会受到此行为的影响,或者其他应用程序可能会与内核执行并行运行。(因为子设备只是实际设备的一部分)
for(int i=0; i<10; i++)
    for(int j=0; j<10; j++)
        clEnqueueNDRangeKernel(queue, kernel, 2, NDRange(i*100,j*100)/*Offset*/, NDRange(100,100)/*Global*/, ... );