OpenCL:区分计算失败和TDR中断

时间:2016-11-09 09:32:07

标签: java windows opencl

当使用也运行主显示器的GPU在Windows上运行长OpenCL计算时,操作系统可能会使用 Timeout Detection and Recovery中断计算。

根据我的经验(Java,使用NativeLibs4Java的JavaCL,使用NVidia GPU),这表现为" Out Of Resources" ivoking clEnqueueReadBuffer时出现(cl_out_of_resources)错误。

问题是,由于其他原因(例如,由于访问无效内存),我在OpenCL程序时收到完全相同的消息。

是否存在一种(半)可靠的方法来区分“资源外”和“#34;由TDR和" Out of Resources"其他问题引起的?

或者,我是否可以至少可靠地(在Java /通过OpenCL API中)确定用于计算的GPU也在运行显示器?

我知道this question但是,那里的答案是关于clFinish没有返回的情况,这对我来说不是问题(我的代码到目前为止从未在OpenCL API中保持冻结)。

1 个答案:

答案 0 :(得分:2)

  

是否有(半)可靠的方法来区分“Out of   “由TDR引起的资源和由其他人引起的”资源外“   问题

<强> 1)

如果可以访问

KeyPath   :
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GraphicsDrivers
KeyValue  : TdrDelay ValueType : REG_DWORD ValueData : Number of
seconds to delay. 2 seconds is the default value.
从WMI

将其乘以

KeyPath   : HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GraphicsDrivers
KeyValue  : TdrLimitCount
ValueType : REG_DWORD
ValueData : Number of TDRs before crashing. The default value is 5.

再次使用WMI。当你乘以这些时,你得到10秒。而且,你应该得到

KeyPath   :
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GraphicsDrivers
KeyValue  : TdrLimitTime ValueType : REG_DWORD ValueData : Number of
seconds before crashing. 60 seconds is the default value.

应该从WMI读取60秒。

对于此示例计算机,在最终崩溃限制60秒之前需要5 x 2秒+ 1个额外延迟。然后您可以从应用程序检查最后一个秒表计数器是否超过这些限制。如果是,可能是TDR。除此之外还有一个线程退出驱动程序时间限制

KeyPath   :
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GraphicsDrivers
KeyValue  : TdrDdiDelay ValueType : REG_DWORD ValueData : Number of
seconds to leave the driver. 5 seconds is the default value.

默认为5秒。访问无效的内存段应该更快退出。也许你可以将这些TDR时间限制从WMI增加到几分钟,这样它就可以让程序计算而不会因为抢占饥饿而崩溃。但是更改注册表可能很危险,例如您将TDR时间限制设置为1秒或其中的一部分,然后Windows可能永远不会在没有持续TDR崩溃的情况下启动,因此只需读取这些变量就必须更安全。

2)

您将总工作分成更小的部分。如果数据不可分离,请复制一次,然后开始将长期运行的内核作为非常短程的内核排队n次,并在任意两次之间等待。

然后,您必须确保TDR被消除。如果这个版本运行但是长时间运行的内核没有运行,那就是TDR错误。如果相反,那就是内存崩溃。看起来像这样:

short running x 1024 times
long running
long running <---- fail? TDR! because memory would crash short ver. too!
long running

另一次尝试:

short running x 1024 times <---- fail? memory! because only 1ms per kernel
long running
long running 
long running
  

或者,我可以至少可靠地(在Java /通过OpenCL API)   确定用于计算的GPU也在运行   显示?

1)

使用两种设备的互操作性属性:

// taken from Intel's site:
std::vector<cl_device_id> devs (devNum);
//reading the info
clGetGLContextInfoKHR(props, CL_DEVICES_FOR_GL_CONTEXT_KHR, bytes, devs, NULL))

这给出了可互操作的设备列表。如果你不想使用它,你应该得到它的id来排除它。

2)

让另一个线程运行一些opengl或directx静态对象绘图代码,以保持其中一个gpus忙。然后使用另一个线程同时测试所有gpus以获得一些简单的opencl内核代码。测试:

  • opengl开始绘制具有高三角形数@ 60 fps的东西。
  • 启动opencl计算设备,获得每秒平均内核执行次数
  • 设备1:30 keps
  • 设备2:40 keps
  • 过了一会儿,停止opengl并关闭它的窗口(如果还没有)
  • 设备1:75 keps -----&gt;百分比增幅最高! - &gt;显示!!!
  • 设备2:41 keps ----&gt;没有那么高的增长,但它可以

执行此操作时,不应在设备之间复制任何数据,因此CPU / RAM不会成为瓶颈。

3)

如果数据是可分的,那么你可以使用分而治之算法让任何gpu只有在可用时才能获得自己的工作,并让显示部分更具灵活性(因为这是性能感知的解决方案,可能是类似的短版本,但调度是在多个gpus上完成的)

4)

我没有检查,因为我卖掉了我的第二个gpu,但你应该试试

CL_DEVICE_TYPE_DEFAULT

在你的multi-gpu系统中测试它是否得到显示gpu。关闭电脑,将显示器电缆插入其他卡,再试一次。关闭,更换卡座,再试一次。关闭,删除其中一张卡,只留下1个gpu和1个cpu,再试一次。如果所有这些只给出显示gpu那么它应该标记显示gpu为默认值。