如何通过连续的异步内核启动来避免Cuda错误6(启动超时)?

如何通过连续的异步内核启动来避免Cuda错误6(启动超时)?,cuda,timeout,Cuda,Timeout,我得到一个Cuda错误6(也称为cudaErrorLaunchTimeout和Cuda\u error\u LAUNCH\u TIMEOUT),代码如下(简化): 我希望避免这种同步,因为它会大大降低程序的速度 由于内核启动是异步的,我猜发生错误的原因是看门狗从异步启动开始测量内核的执行持续时间,而不是从实际执行开始测量 我是Cuda的新手。这是发生错误6的常见情况吗?有没有办法在不改变性能的情况下避免此错误?看门狗本身并没有测量内核的执行时间。看门狗跟踪发送到GPU的命令队列中的请求,并确定其

我得到一个Cuda错误6(也称为
cudaErrorLaunchTimeout
Cuda\u error\u LAUNCH\u TIMEOUT
),代码如下(简化):

我希望避免这种同步,因为它会大大降低程序的速度

由于内核启动是异步的,我猜发生错误的原因是看门狗从异步启动开始测量内核的执行持续时间,而不是从实际执行开始测量


我是Cuda的新手。这是发生错误6的常见情况吗?有没有办法在不改变性能的情况下避免此错误?

看门狗本身并没有测量内核的执行时间。看门狗跟踪发送到GPU的命令队列中的请求,并确定其中是否有任何请求在超时时间内未被GPU确认

正如@talonmies在评论中指出的,我的最佳猜测是(如果您确定没有内核执行超过超时时间),这种行为是由于CUDA驱动程序WDDM批处理机制造成的,该机制通过将GPU命令批处理在一起并批量发送到GPU来降低平均延迟

您无法直接控制批处理行为,因此一般来说,在不禁用或修改windows TDR机制的情况下尝试解决这一问题是不精确的

关于低成本“刷新”命令队列(您可以尝试使用)的一般建议(有些没有文档记录)是使用
cudaEventQuery(0)(如建议)代替
cudaDeviceSynchronize(),可能每50个内核启动一次左右。在某种程度上,具体情况可能取决于机器配置和使用的GPU


我不确定这对你有多有效。我不认为它可以作为避免TDR事件的“保证”,而不需要更多的实验。您的里程数可能会有所不同。

多亏了Talonmes和Robert Crovella(他们提出的解决方案对我不起作用),我才能够找到一个可接受的解决方案

为了防止CUDA驱动程序同时批处理内核启动,必须在每次内核启动之前或之后执行另一个操作。例如,一个虚拟副本会起到以下作用:

void* dummy;
cudaMalloc(&dummy, 1);

for(int i = 0; i < 650; ++i)
{
    int param = foo(i); //some CPU computation here, but no memory copy
    cudaMemcpyAsync(dummy, dummy, 1, cudaMemcpyDeviceToDevice);
    MyKernel<<<dimGrid, dimBlock>>>(&data, param);
}
void*dummy;
Cudamaloc(和假人,1);
对于(int i=0;i<650;++i)
{
int param=foo(i);//这里有一些CPU计算,但没有内存拷贝
cudaMemcpyAsync(虚拟,虚拟,1,cudaMemcpyDeviceToDevice);
MyKernel(&data,param);
}
此解决方案比包含调用
cudaDeviceSynchronize()
(请参见问题)的解决方案快8秒(50到42秒)。
此外,它更可靠,
50
是一个任意的、特定于设备的时段。

这是在Windows平台上吗?是的。我听说过注册表技巧,但我不想强迫我的客户应用它。问题可能是因为Windows驱动程序将GPU操作批处理在一起,以分期偿还您的反应。您的解决方案对我不起作用(
cudaErrorInvalidResourceHandle
出现未知错误),但由于您建议的解释,我找到了一个可接受的解决方法。
for(int i = 0; i < 650; ++i)
{
    int param = foo(i); //some CPU computation here, but no memory copy
    MyKernel<<<dimGrid, dimBlock>>>(&data, param);
    if(i % 50 == 0) cudaDeviceSynchronize();
}
void* dummy;
cudaMalloc(&dummy, 1);

for(int i = 0; i < 650; ++i)
{
    int param = foo(i); //some CPU computation here, but no memory copy
    cudaMemcpyAsync(dummy, dummy, 1, cudaMemcpyDeviceToDevice);
    MyKernel<<<dimGrid, dimBlock>>>(&data, param);
}