如何捕获或处理CUDA内核启动错误

如何捕获或处理CUDA内核启动错误,cuda,error-checking,Cuda,Error Checking,我使用CUDA工具包示例中的checkCudaErrors助手函数。见“helper_cuda.h”。我不明白为什么这个示例中的启动错误没有被checkcudaerror捕获。错误是启动的线程太多(2048) 从调试(linux gdb)中,控制台打印(红色的stderr)“警告:检测到Cuda API错误:cudaLaunch返回(0x9)” 然而,当我从bashshell执行发布版本或调试版本时,checkCudaErrors不会打印任何错误 为什么会这样 我的期望是,在D2H memcpy

我使用CUDA工具包示例中的checkCudaErrors助手函数。见“helper_cuda.h”。我不明白为什么这个示例中的启动错误没有被checkcudaerror捕获。错误是启动的线程太多(2048)

从调试(linux gdb)中,控制台打印(红色的stderr)“警告:检测到Cuda API错误:cudaLaunch返回(0x9)”

然而,当我从bashshell执行发布版本或调试版本时,checkCudaErrors不会打印任何错误

为什么会这样

我的期望是,在D2H memcpy调用中,在启动后立即捕获并打印错误。这是不对的吗

最小可复制示例:

#include <cuda.h>
#include "helper_cuda.h"

__global__ void BusyIncrementKernel( const size_t increments, float * result){
    float tmp = 0;
    for ( size_t i = 0; i < increments; ++i ){ tmp += 1; }
    const int j = threadIdx.x + blockIdx.x*blockDim.x;
    if ( j == 0 ){ *result = tmp; }
}

int main( int argc, char * argv[] ){
    unsigned int blockDim = 2048;
    dim3 block{ blockDim, 1, 1};
    dim3 grid{ 1, 1, 1};
    float * dResult;
    checkCudaErrors( cudaMalloc( &dResult, sizeof(float) ));
    BusyIncrementKernel<<< grid, block >>>( 10000000, dResult );
    float result;
    checkCudaErrors( cudaMemcpy( &result, dResult, sizeof(float), cudaMemcpyDeviceToHost ));
    checkCudaErrors( cudaFree( dResult ));
    checkCudaErrors( cudaDeviceSynchronize() );
    fprintf( stderr,"result: %f\n", result );
    return 0;
}
#包括
#包括“helper_cuda.h”
__全局无效BusyIncrementKernel(常量大小增量,浮点*结果){
浮动tmp=0;
对于(size_t i=0;i(10000000,dResult);
浮动结果;
检查CUDAERRORS(cudaMemcpy(&result、dResult、sizeof(float)、cudaMemcpyDeviceToHost));
检查cudaerrors(cudaFree(dResult));
检查CUDAErrors(cudaDeviceSynchronize());
fprintf(标准,“结果:%f\n”,结果);
返回0;
}
特别指出内核启动需要稍微不同的模式来处理。这就是原因

指示有两种错误类型,API报告(返回)它们的方式不同*


我的结果是;捕获内核启动错误的唯一方法是在启动调用后使用cudaPeekAtLastError()或cudaGetLastError()。这些是唯一返回启动错误代码的API函数。其他后续API调用没有返回启动错误代码,也没有清除它;可以稍后通过cudaPeekAtLastError或cudaGetLastError获取。

CUDA内核启动不会返回启动的错误代码。要捕获错误,您需要在启动之后和任何其他API调用之前执行一些显式错误检查:

checkCudaErrors( cudaPeekAtLastError() );
checkCudaErrors( cudaDeviceSynchronize() );

第一次调用应该至少捕获任何启动错误,到第二次调用时,内核执行期间的错误也将被捕获(另请参阅)。由于您尚未执行此操作,因此在最早的下一次API调用之前,您不会看到错误。

它到底在哪里失败?我几乎可以肯定,内核错误的checkCudaError()不会出现错误,只有客户端API调用。@MichaelIV程序总是在main()中的fprintf(结果:…)之后返回。我希望它从checkCudaErrors中返回(…exit(exit_FAILURE)),但它没有返回。我还预计内核错误最终会由以后的CUDA API调用返回,例如正在进行的cudaMemcpy、cudaFree,或者肯定是cudaDeviceSynchronize。那么你是说CheckCudErrors根本不会返回任何错误?@MichaelIV。对这毫无意义。过去它对我很有效。清理重建和生成调用看起来都很正常。也许你正在版本生成模式下运行?常规断言有效吗?这种特殊情况与异步无关,也与等待时间过长无关。你答案的第一段不正确。这个问题基本上与Talonmes提供的链接相同。@RobertCrovella我也这么认为,但不明白为什么。你能详细说明一下吗?或者只是为了正确而编辑。@RobertCrovella Talonmes post有意义。但是我不能同意文档中的说法,“……如果发生异步错误,它将由后续的一些无关的运行时函数调用报告。”这意味着任何API调用,而这不是我得到的。这里的错误不是异步错误。在执行内核代码期间发生异步错误,例如越界访问等。这里的错误是无效的启动配置。这是在启动时捕获的,不会在一段时间后异步发生,因为内核实际上正在执行设备代码。基本上有两种。非常感谢:)强调有两种类型的错误正是我难以理解的。希望我已经编辑了正确的答案。我在内核启动之后以及随后的三次API调用(memcpy、free、devicesync)之后立即尝试了cudaPeekAtLastError()调用。在这两种情况下,它都返回了错误代码,而其他API调用没有返回错误代码。这意味着不需要立即调用cudaPeekAtLastError(),即后续API调用不会覆盖上一个错误。我当然希望确认或拒绝这一点。事实上,这种类型的错误会立即显现出来。与许多类型的内核错误不同,此错误是同步的。只要底层API调用(
cudaLaunch
)完成,就可以对其进行检查。不,这个错误不是“丢失的”。没有“覆盖”。@RobertCrovella:1。关于“立即”——我的意思是在用于内核启动的指令中说;编辑。2.我想OP说他的程序在最后一次
fprintf()
之后退出-这意味着在程序退出之前没有捕获到API错误。@TysonHilmer:你没有就你的问题写一条注释,说明你的程序在最后一次
fprintf()
之后才执行吗?如果是这样的话,这不意味着没有发出错误代码吗?@einpoklum Yes.$发布/测试启动器ROR;回声$?结果:0.0000000它返回0,并且没有发出错误代码。这是针对问题中当前给出的源,即缺少cudaPeekAtLastError。