Cuda编程模型中常见的错误检测方法

news2024/9/21 22:06:36

Cuda编程模型中常见的错误检测方法

  • 1 CUDA错误检测简介
  • 2 直接嵌入检测函数
    • 2.1 检测函数介绍
    • 2.2 使用示例
  • 3 封装在`.cuh`头文件中嵌入
    • 3.1 创建 `error.cuh` 头文件
    • 3.2 在 CUDA 程序中包含 `error.cuh` 并调用 CHECK 宏
    • 3.3 使用示例


1 CUDA错误检测简介

CUDA编程模型中的错误检测是确保在GPU上运行的程序能够正确执行的关键步骤。CUDA(Compute Unified Device Architecture)提供了多种错误检测机制,以帮助开发者识别和处理在CUDA程序执行过程中可能出现的错误。这些错误检测机制包括:

  • API错误检测:CUDA提供了一系列API函数,每个函数调用后都会返回一个错误码,开发者可以通过检查这个错误码来确定函数调用是否成功。例如,cudaError_t err = cudaMalloc(&d_ptr, size); 后可以使用 if (err != cudaSuccess) { /* 错误处理代码 */ } 来检测内存分配是否成功。

  • 内核错误检测:在CUDA中,内核函数在GPU上并行执行,内核的执行状态可以通过 cudaGetLastError()cudaPeekAtLastError() 函数来检查。这些函数返回最后一个内核执行的错误状态,帮助开发者捕捉内核执行过程中发生的错误。

  • 同步和异步错误检测:CUDA操作分为同步和异步操作。同步操作的错误可以立即检测到,而异步操作的错误(如内核执行)可能会延迟。使用 cudaDeviceSynchronize() 可以强制同步,确保所有先前的CUDA调用完成,从而检测任何潜在的错误。

  • 调试和分析工具:CUDA提供了多种调试和分析工具,如cuda-gdb、NVIDIA Nsight等,这些工具可以帮助开发者深入分析CUDA程序的执行情况,检测和修复错误。

通过结合这些错误检测机制,开发者可以有效地检测和处理CUDA编程中的各种错误,从而提高程序的稳定性和可靠性。


2 直接嵌入检测函数

2.1 检测函数介绍

在CUDA编程中,错误检测是确保代码正确性和性能优化的重要部分。以下是几个常用的CUDA错误检测函数的介绍:

__host__​__device__​const char* 	cudaGetErrorName ( cudaError_t error )
Returns the string representation of an error code enum name.  

__host__​__device__​const char* 	cudaGetErrorString ( cudaError_t error )
Returns the description string for an error code.  

__host__​__device__​cudaError_t 	cudaGetLastError ( void )
Returns the last error from a runtime call.  

__host__​__device__​cudaError_t 	cudaPeekAtLastError ( void )
Returns the last error from a runtime call.  

1. cudaGetErrorName(cudaError_t error)

  • 函数原型:

    __host__ __device__ const char* cudaGetErrorName(cudaError_t error);
    
  • 功能:
    这个函数返回给定错误码的名称字符串。它对调试和日志记录非常有用,使开发人员能够通过错误名称快速识别问题。

  • 参数:
    error: 需要获取名称的CUDA错误码。

  • 返回值:
    对应错误码的名称字符串。

  • 示例:

    cudaError_t err = cudaMalloc(...);
    if (err != cudaSuccess) {
        printf("CUDA Error: %s\n", cudaGetErrorName(err));
    }
    

2. cudaGetErrorString(cudaError_t error)

  • 函数原型:

    __host__ __device__ const char* cudaGetErrorString(cudaError_t error);
    
  • 功能:
    这个函数返回给定错误码的描述字符串。与cudaGetErrorName类似,这个函数提供了更详细的错误信息,有助于理解错误的原因。

  • 参数:
    error: 需要获取描述的CUDA错误码。

  • 返回值:
    对应错误码的描述字符串。

  • 示例:

    cudaError_t err = cudaMalloc(...);
    if (err != cudaSuccess) {
        printf("CUDA Error: %s\n", cudaGetErrorString(err));
    }
    

3. cudaGetLastError(void)

  • 函数原型:

    __host__ __device__ cudaError_t cudaGetLastError(void);
    
  • 功能:
    这个函数返回并清除最近一次执行的CUDA API调用产生的错误。如果没有错误发生,则返回cudaSuccess。这个函数通常在核函数调用之后使用,以检查核函数是否成功执行。

  • 参数:
    无。

  • 返回值:
    最近一次CUDA错误码。

  • 示例:

    kernel<<<blocks, threads>>>(...);
    cudaError_t err = cudaGetLastError();
    if (err != cudaSuccess) {
        printf("Kernel launch failed: %s\n", cudaGetErrorString(err));
    }
    

4. cudaPeekAtLastError(void)

  • 函数原型:

    __host__ __device__ cudaError_t cudaPeekAtLastError(void);
    
  • 功能:
    这个函数返回最近一次执行的CUDA API调用产生的错误,但不清除错误状态。这对于需要多次检查相同错误状态的情况非常有用。

  • 参数:
    无。

  • 返回值:
    最近一次CUDA错误码。

  • 示例:

    kernel<<<blocks, threads>>>(...);
    cudaError_t err = cudaPeekAtLastError();
    if (err != cudaSuccess) {
        printf("Kernel launch status: %s\n", cudaGetErrorString(err));
    }
    

2.2 使用示例

在示例中,我们使用最近一次执行的CUDA API调用产生的错误,并将更详细的错误信息给输出,检测代码如下:

cudaError_t err = cudaGetLastError();		// Get error code
if(err != cudaSuccess)
{
	printf("CUDA Error:%s\n"cudaGetErrorstring(err));
	exit(-1);
}

将上述检测代码嵌入到我们执行的CUDA核函数下方,如下图所示:
在这里插入图片描述

重新编译CUDA文件,如果代码中存在错误,将会如下图所示输出。
在这里插入图片描述


3 封装在.cuh头文件中嵌入

3.1 创建 error.cuh 头文件

我们将检测代码做一个宏定义,并将其封装在 error.cuh 文件中,用于检查CUDA函数调用的返回值是否表示成功。如果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)

如果发生错误,执行以下代码块:

  • printf("CUDA Error:\n")
    • 打印错误信息头。
  • printf(" File: %s\n", __FILE__)
    • 打印发生错误的源文件名,__FILE__是预定义的宏,表示当前文件名。
  • printf(" Line: %d\n", __LINE__)
    • 打印发生错误的行号,__LINE__是预定义的宏,表示当前行号。
  • printf(" Error code: %d\n", error_code)
    • 打印错误代码。
  • printf(" Error text: %s\n", cudaGetErrorString(error_code))
    • 打印错误文本描述,cudaGetErrorString函数将错误代码转换为可读的字符串。
  • exit(1)
    • 退出程序,并返回状态码1,表示发生错误。

3.2 在 CUDA 程序中包含 error.cuh 并调用 CHECK 宏

在你的CUDA源文件中,包括 error.cuh 头文件,然后使用 CHECK 宏来包装CUDA API调用。以下是一个完整的使用示例程序:

// main.cu
#include <cuda_runtime.h>
#include <stdio.h>
#include "error.cuh"

// 简单的CUDA核函数
__global__ void kernel()
{
    // 核函数内部代码
}

int main()
{
    // 设备属性
    cudaDeviceProp deviceProp;
    int dev = 0;

    // 获取设备属性
    CHECK(cudaGetDeviceProperties(&deviceProp, dev));

    // 设置设备
    CHECK(cudaSetDevice(dev));

    // 分配设备内存
    int* d_array;
    size_t size = 100 * sizeof(int);
    CHECK(cudaMalloc((void**)&d_array, size));

    // 启动核函数
    kernel<<<1, 1>>>();

    // 检查核函数执行情况
    CHECK(cudaGetLastError());

    // 释放设备内存
    CHECK(cudaFree(d_array));

    // 重置设备
    CHECK(cudaDeviceReset());

    printf("CUDA程序成功完成。\n");
    return 0;
}

3.3 使用示例

首先在你的CUDA源文件中,引入 error.cuh 头文件。
在这里插入图片描述

在需要检查的位置插入CHECK。
在这里插入图片描述

编译并运行,如果CUDA源文件有错误,就会如下所示:
在这里插入图片描述

通过这种方式,你可以在不同的CUDA源文件中复用 CHECK 宏,而无需在每个文件中重复定义。


本篇采用的错误代码来源于:block_size设置过大错误分析(查看CUDA设备线程块大小)

部分参考信息来源:https://mp.weixin.qq.com/s/em309Ho6AaV5f1ogWpajJw

本人是一名学生,也是正在学习Jetson的过程中,如有错误请批评指正!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1950812.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】选择结构案例-三只小猪称体重

案例问题 假设有三只小猪A、B、C&#xff0c;在输入三者体重后希望能输出他们各自的体重并测出谁最重 思路 先让A与B相比较&#xff0c;如果A重&#xff0c;则让A和C相比较&#xff0c;如果A重则输出A最重&#xff0c;否则输出C最重 在最开始的条件&#xff08;AB相比较&am…

JQuery简单实现ul li点击菜单项被选中的菜单项保持高亮状态(导航ul li点击切换样式)

效果&#xff1a; JS&#xff1a; $(function () {//遍历list&#xff08;一般为ul li&#xff09;$("#menu a").each(function () {//给当前项添加点击事件&#xff08;点击后切换样式&#xff09;$(this).bind(click,function () {// 移除其他所有项的active类$(&…

Sokit(TCP/UDP调试工具)

下载&#xff1a;http://www.winwin7.com/soft/56522.html#xiazai Sokit中文版是一款免费开源的TCP / UDP 测试&#xff08;调试&#xff09;工具&#xff0c;它主要可以用于接收和发送TCP/UDP数据包&#xff0c;让你更深的了解网络状况&#xff0c;能够有效地接收、发送、转…

Linux中的进程1

进程的概念 程序&#xff1a;二进制文件 进程&#xff1a;启动的程序 所有的数据都在内存中 需要占据更多的系统资源 cpu&#xff0c;物理内存&#xff08;RAM&#xff09; 并行和并发 并发&#xff1a;在操作系统中&#xff0c;是指一个时间段中有几个程序都处于已启动…

干货讲解 | 在线教育行业如何搭建帮助中心

引言 随着互联网技术的飞速发展&#xff0c;在线教育已成为教育领域不可或缺的一部分&#xff0c;它打破了传统教育的时空限制&#xff0c;让知识传播更加高效、便捷。然而&#xff0c;在享受在线教育带来的便利时&#xff0c;用户也面临着操作复杂、功能理解不透彻、遇到问题…

Java语言程序设计——篇七(2)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 封装性与多态 封装性与访问修饰符类的访问权限类成员的访问权限 &#x1f320;防止类扩展和方法覆盖实战演练 抽象类实战演练 对象转换实战演练…

github的Codespaces是什么

目录 github的Codespaces是什么 一、定义与功能 二、特点与优势 三、工作原理 四、使用场景与限制 github的Codespaces是什么 GitHub的Codespaces是一个基于云的即时开发环境,它利用容器技术为开发者提供一个完全配置好的开发环境,以便他们能够直接在浏览器或通过Visua…

《中国数据库前世今生》观影——认识1980年起步阶段

引出 中国数据库的前世今生观影——认识1980年的起步阶段 20 世纪 60 年代国外就有了商业数据库&#xff0c;20 世纪 80 年代我国才有了第一批数据库专业人才。不要小看这 20 年的差距&#xff0c;它可能需要几代数据库人用一生去追。2024 年了&#xff0c;中国跨过数据库这座大…

【Android】Fragment的数据传递

碎片和活动之间的通信 Activity向Fragment 通过方法传递 构造方法 将碎片动态地加载到活动当中&#xff0c;先得到一个碎片&#xff0c;再将其放到活动当中。就想到碎片的替代方法&#xff0c;将我们所要传输的数据直接放到新创建的碎片里面&#xff0c;替换到原来的碎片。…

【C++】C++应用案例-大整数相加

实际应用中&#xff0c;有时会遇到非常大的整数&#xff0c;可能会超过long、甚至long long的范围。这时就需要用不限长度的字符串保存数据&#xff0c;然后进行计算。 最简单的需求就是“大整数相加”&#xff0c;即给定两个字符串形式的非负大整数 num1 和num2 &#xff0c;计…

深入理解SQL中的INNER JOIN操作

本文介绍了INNER JOIN的定义、使用场景、计算方法及与其他JOIN的比较。INNER JOIN是关系数据库中常用的操作&#xff0c;用于返回两个表中匹配的行&#xff0c;只有在连接条件满足时才返回数据。本文详细解释了INNER JOIN的语法及其在一对多、多对多关系中的应用&#xff0c;通…

【YOLOv5/v7改进系列】引入中心化特征金字塔的EVC模块

一、导言 现有的特征金字塔方法过于关注层间特征交互而忽视了层内特征的调控。尽管有些方法尝试通过注意力机制或视觉变换器来学习紧凑的层内特征表示&#xff0c;但这些方法往往忽略了对密集预测任务非常重要的被忽视的角落区域。 为了解决这个问题&#xff0c;作者提出了CF…

day05 Router、vuex、axios

配置 router和vuex需要在创建vue项目的时候&#xff0c;开始的时候选择Manually select features&#xff0c;于是就可以在下一个创建配置讯问中选择router和vuex。 axios则需要执行命令行&#xff1a; npm install axios -S 之后再在需要发送请求的view导入即可。 router…

Pytorch基础:Tensor的squeeze和unsqueeze方法

相关阅读 Pytorch基础https://blog.csdn.net/weixin_45791458/category_12457644.html?spm1001.2014.3001.5482 在Pytorch中&#xff0c;squeeze和unsqueeze是Tensor的一个重要方法&#xff0c;同时它们也是torch模块中的一个函数&#xff0c;它们的语法如下所示。 Tensor.…

堆的基本实现

一、堆的概念 在提出堆的概念之前&#xff0c;首先要了解二叉树的基本概念 一颗二叉树是节点的有限集合&#xff0c;该集合&#xff1a; 1、或者为空&#xff1b; 2、或者由一个根节点加上两颗分别称为左子树和右子树的两颗子树构成&#xff1b; 堆就是一颗完全二叉树&…

Python学习笔记45:游戏篇之外星人入侵(六)

前言 飞船模块的功能基本已经完成。今天继续完成子弹模块的功能。 子弹模块 子弹和飞船模块&#xff0c;在游戏逻辑中有一种生成与被生成的表面关系&#xff0c;因为子弹在游戏中是由飞船发射的。但是在我们实际抽象的过程中&#xff0c;飞船与子弹并不是is的关系&#xff0…

【机器学习】机器学习之多变量线性回归-Multiple_Variable_Soln

引言 扩展数据结构和之前开发的例程&#xff0c;以支持多个特征。有几个例程被更新&#xff0c;使得实验看起来有些冗长&#xff0c;但实际上只是对之前的例程进行了小的调整&#xff0c;因此快速回顾是可行的 文章目录 引言一、多变量线性回归1.1 目标1.2 工具 二、问题陈述2.…

2024年【山东省安全员C证】考试题及山东省安全员C证复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年山东省安全员C证考试题为正在备考山东省安全员C证操作证的学员准备的理论考试专题&#xff0c;每个月更新的山东省安全员C证复审考试祝您顺利通过山东省安全员C证考试。 1、【多选题】.以下属于建设单位的质量行…

【SpringBoot教程:从入门到精通】掌握Springboot开发技巧和窍门(四)-Vue项目配置环境、导航栏

主要写前端页面&#xff0c;采用vue框架写页面的导航栏&#xff01;&#xff01;&#xff01; 文章目录 前言 Vue项目配置环境 安装依赖 创建菜单 总结 前言 主要写前端页面&#xff0c;采用vue框架写页面的导航栏&#xff01;&#xff01;&#xff01; Vue项目配置环境 安装…

[练习]如何使用递归算法?

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;算法(Java)&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1. 递归概述 2.汉诺塔问题 题目描述​编辑 题解 代码实现 3…