3

我再次继承了看起来可疑的代码;基本上是这样的:

(void) nppiFilter...(...);
cudaError_t err = cudaGetLastError();
if (err != cudaSuccess)
{
    std::cerr << cudaGetErrorString(err);
}

我们忽略 NPP 错误,而是检查 CUDA 错误。

首先,NPP 是否将 CUDA 错误标志设置为错误?我很确定答案是“不明确”,所以这段代码会遗漏 NPP-only 错误,但我想检查一下。

其次,是否有必要检查这两个错误或者这是否足够:

NppStatus nppErr = nppiFilter...(...);
if (nppErr != NPP_NO_ERROR)
{
    std::cerr << "NPP error " << nppErr;
}

或者我应该检查两者以防万一?有一个NPP_CUDA_KERNEL_EXECUTION_ERROR向我暗示,检查cudaGetLastError()可能会有用,但它是吗?

4

1 回答 1

3

首先,NPP 是否将 CUDA 错误标志设置为错误?

不,不是的。CUDA 错误状态可能是由 NPP 在幕后设置的,但 NPP 并没有专门设置 CUDA 错误状态。

或者我应该检查两者以防万一?

只需检查 NPP 状态就足够了。但是,如果您想进行额外的调试分析,检查 CUDA 错误状态可能会很有用。事实上,cuda-memcheck当我在寻找额外的线索时,我经常会跑。这将具有的唯一正常价值是提供“额外的线索”。

一个安全的假设是,许多 CUDA 库可能具有异步启动工作的函数。也就是说:即使在函数将控制权返回给 CPU 线程之后,底层 GPU 活动仍可能发生。在这种情况下,预期设计良好的库将在“稍后”执行后续库调用或 CUDA API 调用(可能从设备检索计算数据到主机)时捕获由于异步活动引起的错误。

在这种情况下,无论如何您都不能依赖函数返回值。因此,在整个程序中仔细检查错误是最安全的选择,这包括库 API 级别(例如 NPP)以及 CUDA API 级别。但出于生产目的,我会在每个机会都进行测试,不一定建议您插入额外的检查,例如:

error = cudaGetLastError();

(除非它紧跟在 CUDA API 调用之后,这是你的策略**)

我也不建议随意插入:

error = cudaDeviceSynchronize();

但是,如果您正在设计一个库,您可能希望在函数的入口处对上述类型进行某种显式错误检查。

这在某种程度上显然是一个见仁见智的问题。您可能希望将错误检查发挥到极致。只要您不插入同步调用来检查错误,它就不会对您的程序产生太大影响。

我上面的评论主要与我将如何编写生产代码有关。出于学习目的,或者在编写代码时遇到问题时,对错误检查非常严格通常是个好主意,并且确实插入额外的错误检查以捕获异步错误以将错误定位到特定函数.

**您可能希望插入:

error = cudaGetLastError();

在每次内核调用之后,在您的代码中。这将捕获在启动时可检测到的任何内核错误,例如不正确的网格尺寸。这种类型的调用应该是相对轻量级的。

于 2018-05-22T01:09:45.373 回答