【问题标题】:CUDA printf() crashes when large number of threads and blocks are launched启动大量线程和块时,CUDA printf() 崩溃
【发布时间】:2014-10-11 12:03:59
【问题描述】:

我使用的是 CUDA 6.5 + VS2013 + GTX Titan black。我观察到当线程总数大于 65536 时,以下打印代码会崩溃。我搜索了一下,但没有看到任何有用的东西。有没有其他人观察到相同的行为?或者任何人都可以提供一些解释吗?非常感谢!

__global__ void testKernel(int val)
{
    int X = blockDim.x * blockIdx.x + threadIdx.x;
    int Y = blockDim.y * blockIdx.y + threadIdx.y;
    printf("[%d, %d]:\t" "\tValue is:%d\n", X, Y, val);
}

void main(){

    dim3 block(16,16);
    dim3 grid(16,16);
    testKernel << <grid, block >> >(10);
    cudaDeviceSynchronize();
    cudaGetLastError();

    cudaDeviceReset();
}

我在使用 block(32,16) 和 grid(16,16) 时收到以下错误消息:

Gpu API 调用(启动超时并被终止)...

【问题讨论】:

  • 我无法重现失败。但是,您可能想知道内核中的printf 功能有很大的限制that you may want to read about。由于各种原因,它确实不是为大规模输出而设计的。特别是这个活动的缓冲区是有限的,当溢出时,之前的缓冲区数据将丢失(即不打印出来)。此外,您可能不会说“将崩溃”,而是具体说明崩溃,例如将崩溃文本粘贴到您的问题中。
  • 当我运行您的代码时,即使您希望输出 65536 行,由于缓冲区限制,我只得到 4096 行输出。您遇到的崩溃可能是 Windows TDR 超时,因为每个线程的printf 导致内核花费了很长时间。
  • 谢谢罗伯特!您尝试过的线程数是多少?你可以试试块(32,32)网格(32,32)吗?
  • 是的,内核需要很长时间并且肯定会达到默认的 Windows TDR 超时。我不确定你在谷歌上搜索了什么,但如果你在谷歌上搜索“启动超时并被终止”,你会得到很多有启发性的结果,比如this one

标签: cuda printf


【解决方案1】:

您的内核执行时间过长:

the launch timed out and was terminated

这是a limitation of the windows operating system, when running on WDDM devices

有多种可能的解决方法。有些是:

  1. 减少内核执行时间
  2. 如果可能,将 GPU 切换到 TCC 模式(GeForce GPU 不可能)。
  3. 通过修改 Windows 注册表延长 TDR 超时延迟(或将其删除)

此外,内核中的 printf 功能具有 significant limits。由于各种原因,它确实不是为大规模输出而设计的。特别是这个活动的缓冲区是有限的,当溢出时,之前的缓冲区数据将丢失(即不打印出来)。

【讨论】:

【解决方案2】:

感谢罗伯特的回答,我意识到问题可能是由于缓冲区的大小。我用下面的代码发现默认情况下打印缓冲区的大小是1048576字节(1M)

size_t sz;
cudaDeviceGetLimit(&sz, cudaLimitPrintfFifoSize);
std::cout << sz << std::endl;

当我使用以下代码将缓冲区大小增加到 100 Mb 时,错误消失了,我得到了所有预期的输出,总共 131072 行! (我使用块(32,16);..网格(16,16);...)

sz = 1048576 * 100;
cudaDeviceSetLimit(cudaLimitPrintfFifoSize, sz);

不知何故,打印缓冲区的溢出导致响应时间比平时更长,并触发了 TDR。当我相应地增加缓冲区大小时,代码会在超时之前完成。更重要的是,足够的缓冲区大小确保不会丢失数据。

但是,我认为缓冲区大小和执行时间的上限取决于设备。它在 Titan Black 上运行良好并不一定意味着它也适用于其他 NVidia 卡。同样,我同意 Robert 的观点,即使用 printf 从 CUDA 内核导出大量数据在实践中是不可靠的。我只是用它来转储一些信息来调试内核。

【讨论】:

  • 我认为这不会使 TDR 问题在更大的内核大小上消失,例如您询问的块 (32,32)、网格 (32,32)。所以它确实在一定程度上改善了一些事情,但它只是将失败的边界推开了一小部分。我不建议以这种方式使用内核内printf
  • 当我将打印缓冲区大小增加到 1024M 时,block(32,32) 和 grid(32,32) 也适用于我。但我同意以这种方式使用 printf 用于任何实际目的都不是一个好主意。就我而言,我只是使用 printf 进行调试。
  • 非常感谢!这解决了我的问题。一分钟以为我要疯了。
猜你喜欢
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-29
  • 1970-01-01
  • 2012-05-03
  • 1970-01-01
  • 2017-04-10
相关资源
最近更新 更多