NPP 和 CUDA 错误检查

NPP and CUDA error checking

本文关键字:检查 错误 CUDA NPP      更新时间:2023-10-16

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

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

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

首先,NPP 是否在错误时设置 CUDA 错误标志?我很确定答案是"不明确",所以这段代码会错过仅限 NPP 的错误,但我想检查一下。

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

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

还是我应该检查两者以防万一?有一个NPP_CUDA_KERNEL_EXECUTION_ERROR向我表明,也许检查cudaGetLastError()会很有用,但它是吗?

首先,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();

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