技术背景

在CUDA编程中有可能会遇到一些相对比较隐蔽的报错,但是直接编译运行cu文件是不显现的。那么可以通过添加一个用于检查的宏,来监测CUDA程序运行过程中可能出现的报错。

error.cuh

我们在CUDA头文件中实现这个宏:

#pragma once
#include <stdio.h> #define CHECK(call) do{const cudaError_t error_code = call; if (error_code != cudaSuccess){printf("CUDA Error:\n"); 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)

然后在调用CUDA相关函数或者核函数的时候,就可以使用CHECK操作来监测其中有无相关异常。

调用测试

先用一个简单的测试案例,就是显存分配的场景,如果是一个正常的显存分配:

// nvcc ./test_error.cu -Xcompiler -fPIC -o ./test_error && ./test_error
#include "error.cuh"
#include <stdio.h> int main(void){
const int N = 100000000;
const int M = sizeof(double) * N;
double *d_x;
CHECK(cudaMalloc((void **)&d_x, M));
CHECK(cudaFree(d_x));
printf("Success!\n");
}

运行结果是没有报错的:

Success!

但是如果我们调大N的值,使其超出显存大小:

// nvcc ./test_error.cu -Xcompiler -fPIC -o ./test_error && ./test_error
#include "error.cuh"
#include <stdio.h> int main(void){
const int N = 1000000000;
const int M = sizeof(double) * N;
double *d_x;
CHECK(cudaMalloc((void **)&d_x, M));
CHECK(cudaFree(d_x));
printf("Success!\n");
}

再次运行,就会报OOM错误:

./test_error.cu(7): warning #69-D: integer conversion resulted in truncation
const int M = sizeof(double) * N;
^ Remark: The warnings can be suppressed with "-diag-suppress <warning-number>" ./test_error.cu(9): warning #68-D: integer conversion resulted in a change of sign
do{const cudaError_t error_code = cudaMalloc((void **)&d_x, M); if (error_code != cudaSuccess){printf("CUDA Error:\n"); printf(" File: %s\n", "./test_error.cu"); printf(" Line: %d\n", 9); printf(" Error code: %d\n", error_code); printf(" Error text: %s\n", cudaGetErrorString(error_code)); exit(1);}} while (0);
^ ./test_error.cu(7): warning #69-D: integer conversion resulted in truncation
const int M = sizeof(double) * N;
^ Remark: The warnings can be suppressed with "-diag-suppress <warning-number>" ./test_error.cu(9): warning #68-D: integer conversion resulted in a change of sign
do{const cudaError_t error_code = cudaMalloc((void **)&d_x, M); if (error_code != cudaSuccess){printf("CUDA Error:\n"); printf(" File: %s\n", "./test_error.cu"); printf(" Line: %d\n", 9); printf(" Error code: %d\n", error_code); printf(" Error text: %s\n", cudaGetErrorString(error_code)); exit(1);}} while (0);
^ ./test_error.cu: In function 'int main()':
./test_error.cu:7:31: warning: overflow in conversion from 'long unsigned int' to 'int' changes value from '8000000000' to '-589934592' [-Woverflow]
7 | const int M = sizeof(double) * N;
| ~~~~~~~~~~~~~~~~^~~~
CUDA Error:
File: ./test_error.cu
Line: 9
Error code: 2
Error text: out of memory

当然,中间因为整形溢出,还有一些其他的warnning信息,但是这里主要要展现的是OOM报错问题。

核函数检测

上面的异常检测针对是cudaMalloc这个CUDA操作,其实对于核函数,也是一样可以检测出其异常。我们先演示一个正常的示例:

// nvcc ./test_error.cu -Xcompiler -fPIC -o ./test_error && chmod +x ./test_error && ./test_error
#include "error.cuh"
#include <math.h>
#include <stdio.h> void __global__ add(const double *x, const double *y, double *z, const int N){
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N){
z[idx] = x[idx] + y[idx];
}
} int main(void){
const int N = 10;
const int M = sizeof(double) * N;
const double a = 1.23;
double *h_x = (double*) malloc(M);
for (int n = 0; n < N; ++n)
{
h_x[n] = a;
}
double *d_x, *d_z;
CHECK(cudaMalloc((void **)&d_x, M));
CHECK(cudaMalloc((void **)&d_z, M));
CHECK(cudaMemcpy(d_x, h_x, M, cudaMemcpyHostToDevice));
const int block_size = 1024;
const int grid_size = (N + block_size - 1) / block_size;
add<<<grid_size, block_size>>>(d_x, d_x, d_z, N);
CHECK(cudaGetLastError());
CHECK(cudaDeviceSynchronize());
CHECK(cudaFree(d_x));
CHECK(cudaFree(d_z));
free(h_x);
printf("Success!\n");
return 0;
}

这个CUDA程序运行的是一个数组加法。运行结果:

$ nvcc ./test_error.cu -Xcompiler -fPIC -o ./test_error && chmod +x ./test_error && ./test_error
Success!

调整一下block_size参数:

// nvcc ./test_error.cu -Xcompiler -fPIC -o ./test_error && chmod +x ./test_error && ./test_error
#include "error.cuh"
#include <math.h>
#include <stdio.h> void __global__ add(const double *x, const double *y, double *z, const int N){
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N){
z[idx] = x[idx] + y[idx];
}
} int main(void){
const int N = 10;
const int M = sizeof(double) * N;
const double a = 1.23;
double *h_x = (double*) malloc(M);
for (int n = 0; n < N; ++n)
{
h_x[n] = a;
}
double *d_x, *d_z;
CHECK(cudaMalloc((void **)&d_x, M));
CHECK(cudaMalloc((void **)&d_z, M));
CHECK(cudaMemcpy(d_x, h_x, M, cudaMemcpyHostToDevice));
const int block_size = 1025;
const int grid_size = (N + block_size - 1) / block_size;
add<<<grid_size, block_size>>>(d_x, d_x, d_z, N);
CHECK(cudaGetLastError());
CHECK(cudaDeviceSynchronize());
CHECK(cudaFree(d_x));
CHECK(cudaFree(d_z));
free(h_x);
printf("Success!\n");
return 0;
}

由于Block大小在CUDA程序中最大只能是1024,因此如果超出这个数就会出现异常,但是如果没有异常检测函数的话,程序是能够正常执行下去的,这样这个异常就会一直保留在程序中。运行结果:

$ nvcc ./test_error.cu -Xcompiler -fPIC -o ./test_error && chmod +x ./test_error && ./test_error
CUDA Error:
File: ./test_error.cu
Line: 29
Error code: 9
Error text: invalid configuration argument

因为加上了cudaGetLastError()函数,并使用了异常捕获的宏,所以这里就会提示参数配置异常。

总结概要

本文主要介绍了在CUDA编程的实践中,增加一个异常捕获的宏模块,以保障CUDA项目结果的准确性。主要代码内容参考了樊哲勇所著的《CUDA编程基础与实践》,是一本很好的CUDA编程入门书籍。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/cuda_error.html

作者ID:DechinPhy

更多原著文章:https://www.cnblogs.com/dechinphy/

请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

参考内容

  1. 《CUDA编程基础与实践》——樊哲勇

CUDA异常捕获的更多相关文章

  1. .NET 基础 一步步 一幕幕[数组、集合、异常捕获]

    数组.集合.异常捕获 数组: 一次性存储多个相同类型的变量. 一维数组: 语法: 数组类型[] 数组名=new 数组类型[数组长度]; 声明数组的语法: A.数据类型 [] 数组名称= new 数据类 ...

  2. MVC 好记星不如烂笔头之 ---> 全局异常捕获以及ACTION捕获

    public class BaseController : Controller { /// <summary> /// Called after the action method is ...

  3. atitit.js浏览器环境下的全局异常捕获

    atitit.js浏览器环境下的全局异常捕获 window.onerror = function(errorMessage, scriptURI, lineNumber) { var s= JSON. ...

  4. C#中的那些全局异常捕获

    1.WPF全局捕获异常     public partial class App : Application     {         public App()         {    // 在异 ...

  5. Spring-MVC开发之全局异常捕获全面解读

    异常,异常 我们一定要捕获一切该死的异常,宁可错杀一千也不能放过一个! 产品上线后的异常更要命,一定要屏蔽错误内容,以免暴露敏感信息! 在用Spring MVC开发WEB应用时捕获全局异常的方法基本有 ...

  6. JavaScript异常捕获

    理论准备 ★   异常捕获 △ 异常:当JavaScript引擎执行JavaScript代码时,发生了错误,导致程序停止运行: △ 异常抛出:当异常产生,并且这个异常生成一个错误信息: △ 异常捕获: ...

  7. SQLServer异常捕获

    在SQLserver数据库中,如果有很多存储过程的时候,我们会使用动态SQL进行存储过程调用存储过程,这时候,很可能在某个环节就出错了,但是出错了我们很难去跟踪到出错的存储过程,此时我们就可以使用异常 ...

  8. Asp.Net MVC3(三)-MvcApp实现全局异常捕获

    定义异常捕获类: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMu ...

  9. iphone 异常捕获处理

    iphone 异常捕获处理 1 void UncaughtExceptionHandler(NSException *exception) { 2 NSArray *arr = [exception ...

  10. iOS异常捕获

    文章目录 一. 系统Crash 二. 处理signal 下面是一些信号说明 关键点注意 三. 实战 四. Crash Callstack分析 – 进⼀一步分析 五. demo地址 六. 参考文献 前言 ...

随机推荐

  1. openEuler欧拉安装Gitlab

    1. 安装GitLab wget https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh sud ...

  2. Flutter枚举

    Flutter枚举 Enum Extension 在Dart2.7版本,Dart新增了扩展函数,使枚举相关的代码定义.调用更加简洁 通过扩展枚举定义方法 定义一个元素枚举 enum Element { ...

  3. Flutter ListView报错RenderBox was not laid out: RenderViewport#680c1 NEEDS-LAYOUT NEEDS-PAINT

    RenderBox was not laid out: RenderViewport#680c1 NEEDS-LAYOUT NEEDS-PAINT 使用ListView.builder()布局时,如果 ...

  4. TeamViewer 的替代品 ZeroTier + NoMachine

    之前不怎么用 TeamViewer,最近用的多了,特别好用,有点上瘾,在哪儿都能连家里的 RTX,太棒了. 然后它就开始作了. 有没有好的替代方案呢?有人推荐向日葵,向日葵显然是以盈利为目的的我不想再 ...

  5. .NET 阻止系统睡眠/息屏

    本文介绍Windows系统设备下如何阻止系统睡眠/息屏,以及想看当前阻止睡眠/息屏的应用信息 powercfg /requests查看活动列表 在播放音乐时,我们会发现设置了系统电源管理-自动睡眠,计 ...

  6. SM国密算法

    package com.abc.apollo.common.util; import javax.crypto.IllegalBlockSizeException; import java.secur ...

  7. How to Use cURL HTTP/2 on macOS

    cURL is one of most powerful tools for testing HTTP traffic. We typically use cURL to interact with ...

  8. APP网站小程序微信登录同步:需要微信公众号、小程序、开放平台打通用户体系(不同主体也行)

    要想APP网站小程序微信登录同步打通用户体系.我们需要将(不同主体也行)多个公众号和小程序都绑定到同一个微信开放平台上,获取到UnionID记录到数据库就可以了. 微信UnionID 机制说明 如果开 ...

  9. Qt编写地图综合应用32-区域地图

    一.前言 echart本身是没有提供省市区域轮廓图的,需要引入外部的js文件才能绘制,为了拿到全国各省市的对应轮廓图js文件,特意去网上搜索了很多的相关文章并理解,下载到了对应的省市区域的json数据 ...

  10. MFC-error C2589: “(”:“::”右边的非法标记

    MFC-error C2589: "(":"::"右边的非法标记 错误信息 出错语句 问题原因 解决办法 错误信息 ① 错误 C2589 "(&quo ...