当前位置:网站首页>精简CUDA教程——CUDA Driver API

精简CUDA教程——CUDA Driver API

2022-04-23 19:23:00 Adenialzz

精简CUDA教程——CUDA Driver API

Driver API概述

CUDA 的多级 API

CUDA 的 API 有多级(下图),详细可参考:CUDA环境详解

  • CUDA Driver API 是 CUDA 与 GPU 沟通的驱动级底层 API。早期 CUDA 与 GPU 沟通都是直接通过 Driver API。cuCtxCreate()cu 开头的基本都是 Driver API。我们熟悉的 nvidia-smi 命令就是调用的 Driver API。
  • 后来发觉 Driver API 太过底层,细节太过复杂,故演变出了 Runtime API,Runtime API 是基于 Driver API 开发的,常见的 cudaMalloc() 等 API 都是 Runtime API。

在这里插入图片描述

CUDA Driver

环境相关

CUDA Driver 是随着显卡驱动发布,要与 cudatoolkit 分开看

CUDA Driver 对应于 cuda.hlibcuda.so 两个文件。注意 cuda.h 会在安装 cudatoolkit 时包含,但是 libcuda.so 是随着显卡驱动安装的我们的系统中的(而不是也跟着 cudatooklit 安装)。因此,如果要直接复制移动 libcuda.so 文件时要注意驱动版本需要与之适配。

如何了解CUDA Driver

本精简课程对于底层的 Driver API 的理解,是为了有利于后续的 Runtime API 的学习与错误调试。Driver API 是理解 cudaRuntime 中上下文的关键。因此,本精简课程在 CUDA Driver 这部分的主要的知识点是:

  • Context 的管理机制
  • CUDA 系列接口的开发习惯(错误检查方法)
  • 内存模型

关于context和内存的分类

关于context,有两种:

  1. 手动管理的 contextcuCtxCreate ,手动管理,以堆栈的方式 push/pop
  2. 自动管理的 contextcuDevicePrimaryCtxRetain,自动管理,Runtime API 以此为基础

关于内存,有两大类:

  1. CPU 内存,称之为 Host Memory
    • Pageable Memory:可分页内存
    • Page-Locked Memory:页锁定内存
  2. GPU 内存(显存),称之为 Device Memory
    • Global Memory:全局内存
    • Shared Memory:共享内存
    • … 其他

以上内容之后会展开介绍。

cuIint 驱动初始化

  1. cuInit 的意义是,初始化驱动 API,全局执行一次即可,如果不执行,则所有 API 都将返回错误。
  2. 没有对应的 cuDestroy,不需要释放,程序销毁自动释放。

返回值检查

版本一

正确友好地检查 cuda 函数的返回值,有利于程序的组织结构,使得代码的可读性更好,错误更容易发现。

我们知道 cuInit 返回的类型是 CUresult,该返回值会告诉程序员函数成功还是失败,失败的原因是什么。

官方版本的检查的逻辑,如下:

// 使用有参宏定义检查cuda driver是否被正常初始化, 并定位程序出错的文件名、行数和错误信息
// 宏定义中带do...while循环可保证程序的正确性
#define checkDriver(op) \ do{
       \ auto code = (op); \ if(code != CUresult::CUDA_SUCCESS){
       \ const char* err_name = nullptr; \ const char* err_message = nullptr; \ cuGetErrorName(code, &err_name); \ cuGetErrorString(code, &err_message); \ printf("%s:%d %s failed. \n code = %s, message = %s\n", __FILE__, __LINE__, #op, err_name, err_message); \ return -1; \ } \ }while(0)

是一个宏定义,我们在调用其他 API 的时候,对函数的返回值进行检查,并在出错时将错误码和报错信息打印出来,方便调试。比如:

checkDriver(cuDeviceGetName(device_name, sizeof(device_name), device));

如果有未初始化等错误,报错信息会被清晰地打印出来。

这个版本一也是 Nvidia 官方使用的版本,但是存在一些问题,比如代码可读性较差,直接返回 int 型错误码等。推荐使用版本二。

版本二

// 很明显,这种代码封装方式,更加的便于使用
//宏定义 #define <宏名>(<参数表>) <宏体>
#define checkDriver(op) __check_cuda_driver((op), #op, __FILE__, __LINE__)

bool __check_cuda_driver(CUresult code, const char* op, const char* file, int line){
    

    if(code != CUresult::CUDA_SUCCESS){
        
        const char* err_name = nullptr;    
        const char* err_message = nullptr;  
        cuGetErrorName(code, &err_name);    
        cuGetErrorString(code, &err_message);   
        printf("%s:%d %s failed. \n code = %s, message = %s\n", file, line, op, err_name, err_message);   
        return false;
    }
    return true;
}

很明显的,版本二的返回值、代码可读性、封装性等都相较版本一好了很多。使用的方式是一样的:

checkDriver(cuDeviceGetName(device_name, sizeof(device_name), device));
// 或加一个判断,遇到错误即退出
if (!checkDriver(cuDeviceGetName(device_name, sizeof(device_name), device))) {
    
    return -1;
}

CUcontext

手动上下文管理

  • context 是一种上下文,关联对 GPU 的所有操作。

  • 一个 context 与一块显卡关联,一块显卡可以被多个 context 关联。

  • 每个线程都有一个栈结构存储 context,栈顶是当前使用的 context,对应有 push/pop 函数操作 context 的栈,所有 API 都以当前 context 为操作目标

试想一下,如果执行任何操作你都需要传递一个 device 决定送到哪个设备执行,得多麻烦。context 就是为了方便管理当前 API 是在哪个 device 上执行而提出的一种手段,而栈结构的使用则是为了保存之前的上下文中的 device,从而方便控制多个设备。

在这里插入图片描述

自动上下文管理

  • 由于高频操作都是一个线程固定访问一个 device 不变,不经常会有同一个线程来回多次访问不同 device 的情况,且只会使用到一个 context,很少用到多 context。
  • 即在多数情况下, CreateContextPushCurrentPopCurrent 这种多 context 管理就显得很麻烦
  • 因此就推出了 cuDevicePrimaryCtxRetain ,为设备关联主 context,这样分配、设置、释放、栈都不需要我们再去手动管理,是一种自动管理 context 的方式
  • primaryContext :给我设备 id,给你 context 并设置好,此时一个 device 对应一个 primary context。不同线程,只要设备 id 相同,primary context 就相同,且 context 是线程安全的。
  • 在之后要介绍的 CUDA Runtime API 中,就是自动使用 cuDevicePrimaryCtxRetain 的。

在这里插入图片描述

DriverAPI 内存管理

  1. host memory 是计算机本身的内存,可以用 CUDA Driver API 来申请和释放,也可以用 C/C++ 的 malloc/freenew/delete 来申请和释放。
  2. device memory 是显卡上的内存,即显存,有专用的 Driver API 来进行申请和释放。

版权声明
本文为[Adenialzz]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_44966641/article/details/124357747