CUDA编程笔记(3)


前言

CUDA程序运行时的错误检测

1.CUDA程序运行时的错误检测

检测运行错误的头文件

像一些日志文件,一般检测错误都会编写一个头文件来包含要检测错误api运行的代码。在基础的cuda程序api的运行检错中,前面已经了解了基本所有的cuda的api的返回值都有一个是否成功使用的cudaError_t结构的标志信息,成功调用返回cudaSuccess。所以,可以根据返回值,在头文件上定义一个宏函数来检查cuda程序运行是否出错。

#pragma once
#include<stdio.h>

#define CHECK(call) \
do                  \
{
      
      \
    const cudaError_t error_code = call; \
    if(error_code != cudaSuccess) \   
    {
    
    \
        printf("cuda error"); \
        printf("  File:   %s\n",__FILE__); \
        printf("  Line:   %d\n",__LINE__); \
        printf("  Error code: %d\n",error_code); \
        printf("  Error text: %s\n",cudaGetErrorString(error_code)); \
        exit(1); \
    }\
} while(0)

(1)#pragma once是一个预处理指令,作用和条件编译命令#ifndef作用一样,但更加简洁。
(2)宏函数CHECK的参数是cuda运行时api函数。
(3)预编译器有预定义的宏:

    __FILE__ // 获取当前文件名
    __func__ // 获取当前函数名
    __LINE__ // 获取当前行号
    __DATE__ // 获取当前日期
    __TIME__ // 获取当前时间
    __WORDSIZE // 获取当前编译器的位数,适合用来显示警告、错误信息。

(4)宏函数中不使用do while语句也可以,但在某些情况下不安全。使用宏函数,在编译引入到源程序代码时会自动加上分号,所以while(0)后面不需要加分号了

检查运行时的CUDA的api函数

在源程序中包含编写的头文件,cuda程序头文件名,一般命名为xxx.cuh。直接将调用cuda运行时的api函数作为参数传入头文件的CHECK宏函数中即可,如:

    // 分配设备内存
    double *d_x,*d_y,*d_z;
    // printf("%p",d_x);
    CHECK(cudaMalloc((void **)&d_x,M));
    CHECK(cudaMalloc((void **)&d_y,M));
    CHECK(cudaMalloc((void **)&d_z,M));
    // 将某些数据从主机复制到设备上
    CHECK(cudaMemcpy(d_x,h_x,M,cudaMemcpyHostToDevice));
    CHECK(cudaMemcpy(d_y,h_y,M,cudaMemcpyHostToDevice));

    // 数组求和
    const int block_size = 128;
    const int gride_size = N/block_size;
    add<<<gride_size,block_size>>>(d_x,d_y,d_z);
    CHECK(cudaMemcpy(h_z,d_z,M,cudaMemcpyHostToDevice));

若程序报错,会显示如下信息:
在这里插入图片描述

检查运行时的CUDA的核函数

上述的方法因为核函数没有返回值,所以不能直接像上面那样使用。在cuda的api里,有方法可以捕捉到核函数可能发生的错误。
cudaGetLastError():
在这里插入图片描述
注意:此函数还可能返回以前异步启动的错误代码。
所以,在后面检查时还要检查是否同步主机与设备,如:

    // 数组求和
    const int block_size = 1240;  // 最大限制是1024
    const int gride_size = N/block_size;
    add<<<gride_size,block_size>>>(d_x,d_y,d_z);
    // 检查核函数的调用
    CHECK(cudaGetLastError());
    CHECK(cudaDeviceSynchronize());  // 可用可不用,后面的隐式的起到了同步主机与设备的作用
    // 将某些数据从设备复制到主机上,这个数据传输函数隐式的起到了同步主机与设备的作用,所以后面用不用cudaDeviceSynchronize都可以
    CHECK(cudaMemcpy(h_z,d_z,M,cudaMemcpyDeviceToHost));
    check(h_z,N);

使用显示的同步主机与设备的cudaDeviceSynchronize(),报错位置比较精确。
检查到错误的报错信息:
在这里插入图片描述

CUDA-MEMCHECK工具

cuda提供了CUDA-MEMCHECK的一个工具集,由cuda-memcheck命令来检查内存的错误。
通过-h可以发现,检查内存的主要是:
在这里插入图片描述

总结

cuda程序错误的检查基本方法
参考:
如博客内容有侵权行为,可及时联系删除!
CUDA 编程:基础与实践
https://docs.nvidia.com/cuda/
https://docs.nvidia.com/cuda/cuda-runtime-api
https://github.com/brucefan1983/CUDA-Programming

猜你喜欢

转载自blog.csdn.net/weixin_41311686/article/details/128720882