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

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.mzph.cn/bicheng/50694.shtml

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

相关文章

C++ - char*、const char*、char[]、string

const char* const char* 用来定义字符串常量。 char[ ] char型的字符数组是一种定长的数组&#xff0c;存储指定长度的字符序列&#xff0c;数组中的每个元素都是一个char类型的变量&#xff0c;如&#xff1a; char arr[] {h, a, l, l, o, \0}; char c arr[0]; // 访问…

【二叉树 C++DFS】2458. 移除子树后的二叉树高度

本文涉及知识点 二叉树 CDFS LeetCode 2458. 移除子树后的二叉树高度 给你一棵 二叉树 的根节点 root &#xff0c;树中有 n 个节点。每个节点都可以被分配一个从 1 到 n 且互不相同的值。另给你一个长度为 m 的数组 queries 。 你必须在树上执行 m 个 独立 的查询&#xff…

模式Hash和history

vuerouter有两种路由模式Hash和history。区别&#xff1a;Hash为默认模式&#xff0c;url中包含一个#符号的哈希部分。优势&#xff1a;兼容性好&#xff0c;不需要后端服务器的特殊配置。缺点&#xff1a;不够美观&#xff0c;搜索引擎优化较差。History模式使用的浏览器的His…

C# 写入SQLServer数据库报错SqlException: 不能将值 NULL 插入列 ‘ID‘

private int id; [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]//id自增 public int ID { get > id; set > id value; } 将ID属性下的标识规范由否改成是

STM32-寄存器时钟配置指南

目录 启动 SystemInit SetSysClock 总结 启动 从startup_stm32f0xx.s内的开头的Description可以看到 ;* Description : STM32F051 devices vector table for EWARM toolchain. ;* This module performs: ;* - Set the in…

微信小程序支付流程

前端需要做的事情&#xff1a; 生成平台订单&#xff1a;前端调用接口&#xff0c;向后端传递购买的商品信息、收货人信息&#xff0c;&#xff08;后端生成平台订单&#xff0c;返回订单编号&#xff09;获取预付单信息&#xff1a;将订单编号发送给后端后&#xff0c;&#x…

Hadoop单机版环境搭建

一 . 案例信息 Hadoop 的安装部署的模式一共有三种&#xff1a; 本地模式&#xff0c;默认的模式&#xff0c;无需运行任何守护进程&#xff08; daemon &#xff09;&#xff0c;所有程序都在单个 JVM 上执行。由 于在本机模式下测试和调试 MapReduce 程序较为方便&#x…

leetocde662. 二叉树最大宽度,面试必刷题,思路清晰,分点解析,附代码详解带你完全弄懂

leetocde662. 二叉树最大宽度 做此题之前可以先做一下二叉树的层序遍历。具体题目如下&#xff1a; leetcode102二叉树的层序遍历 我也写过题解&#xff0c;可以先看看学习一下&#xff0c;如果会做层序遍历了&#xff0c;那么这题相对来说会简单很多。 具体题目 给你一棵…

[OJ]水位线问题,1.采用回溯法(深度优先遍历求解)2.采用广度优先遍历求解

1.深度优先遍历 使用回溯法,深度优先遍历利用栈先进后出的特点,在加水控制水量失败时, 回到最近一次可对水进行加水与否的位置1.对于给定水量k,是否在[l,r]之间&#xff0c; 是:是否加水(加水y,用掉x,是否在[l,r]之间)(不加水y,用掉x,是否在[l,r]之间)先尝试加水&#xff0c;如…

NVIDIA全面转向开源GPU内核模块

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

FastAPI(七十八)实战开发《在线课程学习系统》接口开发-- 评论

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 梳理下思路 1.判断是否登录 2.课程是否存在 3.如果是回复&#xff0c;查看回复是否存在 4.是否有权限 5.发起评论 首先新增pydantic模型 class Cour…

音视频入门基础:WAV专题(2)——WAV格式简介

注&#xff1a;本文有部分内容引用了维基百科&#xff1a;https://zh.wikipedia.org/wiki/WAV 一、引言 Waveform Audio File Format&#xff08;缩写WAVE或WAV&#xff09;是微软与IBM公司所开发在个人电脑存储音频流的编码格式&#xff0c;在Windows平台的应用软件受到广泛的…

AI/机器学习(计算机视觉/NLP)方向面试复习3

1. Pooling 有哪些方式&#xff1f;pytorch的实现&#xff1f; Pooling可以分成&#xff1a;最大池化&#xff0c;平均池化&#xff0c;全局平均池化&#xff0c;随机池化&#xff0c;空间金字塔池化。 1. 最大池化&#xff08;Max Pooling&#xff09; 最大池化是最常用的池…

union的特性和大小端

一、union在c和c语言中的特性 1.共享内存空间&#xff1a;union的所有成员共享同一块内存空间。意味着在同一时刻&#xff0c;union 只能存储其成员 中的一个值。当你修改了union中的一个成员&#xff0c;那么其它成员的值也会被改变&#xff0c;因为它们实际上都是指向同一块…

JS逆向高级爬虫

JS逆向高级爬虫 JS逆向的目的是通过运行本地JS的文件或者代码,以实现脱离他的网站和浏览器,并且还能拿到和浏览器加密一样的效果。 10.1、编码算法 【1】摘要算法&#xff1a;一切从MD5开始 MD5是一个非常常见的摘要(hash)逻辑. 其特点就是小巧. 速度快. 极难被破解. 所以,…

skywalking docker部署

skywalking-oap # 拉取skywalking-oap镜像 docker pull apache/skywalking-oap-server:9.7.0# 启动容器 docker run --name oap \ -d \ -p 11800:11800 \ -p 12800:12800 \ apache/skywalking-oap-server:9.7.0skywalking-ui # 摘取skywalking-ui镜像 docker pull apache/sky…

大屏使用技巧——如何实现数据分发

当多个组件需共用同一数据源时&#xff0c;为了减少重复请求&#xff0c;需要进行数据分发。那如何实现接一次数据就能让多个组件映射同一数据源中的不同数据字段呢&#xff1f; 实现思路 目标组件的静态数据中添加标记字段&#xff0c;数据过滤器内通过 data 参数获取到对应…

加密micropython写的程序为.mpy的方法

2024年7月26日 用虚拟机安装一个Linux&#xff0c;本例为CentOS7的Linux系统。 1.保证Linux能够连接网络。 2.进入root用户&#xff0c;使用下面的命令行安装gcc编译器&#xff1a; yum install gcc 3.安装完成后&#xff0c;查看gcc是否安装成功&#xff0c;用下面的命令…

家政项目小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;家政人员管理&#xff0c;家政服务管理&#xff0c;咨询信息管理&#xff0c;咨询服务管理&#xff0c;家政预约管理&#xff0c;留言板管理&#xff0c;系统管理 微信端账号功能…

前端开发知识-vue

大括号里边放键值对&#xff0c;即是一个对象。 一、vue可以简化前端javascript的操作。 主要特点是可以实现视图、数据的双向绑定。 使用vue主要分为三个步骤&#xff1a; 1.javascript中引入vue.js 可以src中可以是vue的网址&#xff0c;也可以是本地下载。 2.在javasc…