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

时间:2018-03-26 10:01:33

标签: cuda error-checking

我使用CUDA Toolkit Samples中的checkCudaErrors辅助函数。参见" helper_cuda.h"。我很困惑为什么checkCudaErrors没有捕获此示例的启动错误。错误是启动太多线程(2048)。

从Debug(linux gdb),控制台打印(stderr为红色)"警告:检测到Cuda API错误:cudaLaunch返回(0x9)"。

当我从Bash shell执行Release或Debug构建时,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;
}

2 个答案:

答案 0 :(得分:1)

This answer by talonmies具体说明内核启动需要稍微不同的模式来处理。 The CUDA API documentation 3.2.9. on Error Checking解释了这一点。

This answer by Robert Crovella表示有两种错误类型,它们在API报告(返回)它们的方式上有所不同。

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

答案 1 :(得分:0)

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

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

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