写在前面
本篇文章程序链接:https://github.com/Shao-junliang/TensorRT-Course-Notes/tree/master/cuda-driver-api
1. 显卡,显卡驱动,nvcc, cuda driver,cudatoolkit,cudnn到底是什么?
关于显卡驱动与cuda驱动的版本匹配。
- Table 1. CUDA 11.6 Update 1 Component Versions
- 结论:尽量将显卡驱动升级到新的,因为显卡驱动向下兼容cuda驱动。
简单了解显卡相关概念:
- 显卡:GPU
- 显卡驱动:驱动软件,类比声卡驱动,摄像头驱动;
- GPU架构:gpu架构指的是硬件的设计方式,例如是否有L1 or L2缓存;
- CUDA: 其中一种理解是它是一种编程语言(像c++,python等,只不过它是专门用来操控GPU的);
- cudnn: 这个其实就是一个专门为深度学习计算设计的软件库,里面提供了很多专门的计算函数;
- CUDAToolkit:这是我们真正需要首先安装的工具包,所谓的装cuda首先指的是它;它里面包含了许多库,例如:cudart, cublas等;
- 其他涉及到的知识有nvcc与nvidia-smi, 多个 cuda 版本之间进行切换, cuda的安装等;详细请参考: https://zhuanlan.zhihu.com/p/91334380
cuda-driver-api 与 cuda-runtime-api
- CUDA Driver与CUDA Runtime相比更偏底层,就意味着Driver API有着更灵活的控制,也伴随着更复杂的编程。
- 因此CUDA driver需要做显式的初始化
cuInit(0)
,否则其他API都会返回CUDA_ERROR_NOT_INITIALIZED
- 经过初始化后驱动和显卡的信息可以轻松获取:
2. 使用宏定义来检查是否有做cuda初始化
- CUDA driver需要做显式的初始化
cuInit(0)
,否则其他API都会返回CUDA_ERROR_NOT_INITIALIZED
; - 采用宏定义可以在每次调用API前都检查初始化;
- 采用封装带参宏定义使代码更清晰、好调试,养成一种良好的编码习惯也是很重要!
3. context的概念和使用方法
设备与特定进程相关连的所有状态。比如,写的一段kernel code对GPU的使用会造成不同状态(内存映射、分配、加载的code),Context则保存着所有的管理数据来控制和使用设备。
- gpu 的 context 相当于 cpu 的 program,一块gpu上可以有多个contexts,但是它们之间是相互隔离的。建议一块设备就一个context。参考:https://dragan.rocks/articles/18/Interactive-GPU-Programming-3-CUDA-Context
上下文管理可以干的事儿:
- 持有分配的内存列表;
- 持有加载进该设备的kernel code
- cpu与gpu之间的unified memory
如何管理上下文:
- 在cuda driver同样需要显式管理上下文
- 开始时
cuCtxCreate()
创建上下文,结束时cuCtxDestroy
销毁上下文。像文件管理一样须手动开关。用cuDevicePrimaryCtxRetain()
创建上下文更好! cuCtxGetCurrent()
获取当前上下文;- 可以使用堆栈管理多个上下文
cuCtxPushCurrent()
压入,cuCtxPopCurrent()
推出; - 对ctxA使用
cuCtxPushCurrent()
和cuCtxCreate()
都相当于将ctxA放到栈顶(让它成为current context)
- 开始时
- cuda runtime可以自动创建,是基于
cuDevicePrimaryCtxRetain()
创建的。
- 在cuda driver同样需要显式管理上下文
4. 内存分配
统一内存(Unified addressing) ;
分配线性内存
cuMemAlloc()
:线性内存:线性内存被组织在单个连续的地址空间中,可以直接以及线性地访问这些内存位置。
内存分配空间以字节为大小,并返回所分配的内存地址
分配主机锁页内存
cuMemAllocHost()
:- 参考:https://leimao.github.io/blog/Page-Locked-Host-Memory-Data-Transfer/
- 参考:https://www.youtube.com/watch?v=p9yZNLeOj4s
- 锁页内存:
- 定义:页面不允许被调入调出的叫锁页内存,反之叫可分页内存;
- 优点:快;
- a. 设备可以直接访问内存,与可分页内存相比,它的读写带宽要高得多;
- b. 驱动程序会跟踪使用
cuMemAllocHost()
分配的虚拟内存范围,并自动加速对cuMemcpy()
等函数的调用; - 使用注意:分配过多锁业内存会减少系统可用于分页的内存量,可能会降低系统性能。因此,在主机和设备之间为数据交换分配临时区域时,最好少用此功能。
- 这里是从主机分配内存,因此不是输入device prt的地址,而是一个主机的二级地址。
内存的初始化
cuMemsetD32(CUdeviceptr dstDevice, unsigned int ui, size_t N)
, 将N个32位值的内存范围设置为指定的值ui。内存的释放
cuMemFreeHost()
: 有借有还 再借不难~
声明: 本文部分内容来源于网络,如有侵权请联系删除。