CUDA编程笔记
date
Feb 12, 2025
slug
cuda-program
status
Published
tags
CUDA
summary
type
Post
1. 什么是GPU
GPU性能指标:
- 核心数
- GPU显存容量
- GPU计算峰值
- 显存带宽

2. 核函数
- 核函数在GPU上进行并行执行
- 注意:
- (1) 限定词
__global__
修饰 - (2) 返回值必须是void
★ 1、核函数只能访问GPU内存
★ 2、核函数不能使用变长参数
★ 3、核函数不能使用静态变量
★ 4、核函数不能使用函数指针
★ 5、核函数具有异步性
★ CUDA程序编写流程:
核函数不支持C++的
iostream
3. CUDA的线程模型
3.1 线程模型结构
- 线程模型重要概念:
- grid 网格
- block 线程块
- 线程分块是逻辑上的划分,物理上线程不分块
- 配置线程:
<<<grid_size, block_size>>>
- 最大允许线程块大小:1024
- 最大允许网格大小:2^31-1(针对一维网格)

3.2 一维线程模型
线程唯一标识:
Idx = threadIdx.x + blockIdx.x * blockDim.x
★ 网格大小限制:
gridDim.x
最大值----2^31-1
gridDim.y
最大值----2^16-1
gridDim.z
最大值------2^16-1★ 线程块大小限制:
blockDim.x
最大值 ------ 1024
blockDim.y
最大值 ------ 1024
blockDim.z
最大值 ------ 64


4. GPU架构

指定虚拟架构计算能力
-arch=compute_XY
指定真实架构计算能力
-code=sm_XY
- 二进制
cubin
代码,大版本之间不兼容!
- 指定真实架构计算能力的时候必须指定虚拟架构计算能力!
- 指定的真实架构能力必须大于或等于虚拟架构能力!
5. CUDA矩阵加法运算程序
5.1 CUDA程序基本框架
5.2 设置GPU设备
5.3 内存管理
CUDA通过内存分配、数据传递、内存初始化、内存释放进行内存管理
标准C语言内存管理函数 | CUDA内存管理函数 |
malloc | cudaMalloc |
memcpy | cudaMemcpy |
memset | cudaMemset |
free | cudaFree |
5.4 内存分配
主机分配内存:
设备分配内存:
5.5 数据拷贝
主机数据拷贝:
设备数据拷贝:
5.6 内存初始化
主机内存初始化:
设备内存初始化:
5.7 内存释放
释放主机内存:
释放设备内存:
5.8 实例
5.9 自定义设备函数
- 设备函数(device function)
- 定义只能执行在GPU设备上的函数为设备函数
- 设备函数只能被核函数或其他设备函数调用
- 设备函数用
__device__
修饰
- 核函数(kernel function)
- 用
__global__
修饰的函数称为核函数,一般由主机调用,在设备中执行 __global__
修饰符既不能和__host__
同时使用,也不可与__device__
同时使用
- 主机函数(host function)
- 主机端的普通C++函数可用
__host__
修饰 - 对于主机端的函数,
__host__
修饰符可省略 - 可以用
__host__
和__device__
同时修饰一个函数减少冗余代码。编译器会针对主机和设备分别编译该函数。
6. CUDA错误检查
6.1 运行时API错误代码
- CUDA运行时API大多支持返回错误代码,返回值类型:
cudaError_t
- 运行时API成功执行,返回值为
cudaSuccess
- 运行时API返回的执行状态值是枚举变量

6.2 错误检查函数
1、获取错误代码对应的名称:
cudaGetErrorName
2、获取错误代码描述信息:
cudaGetErrorString
参数
filename
一般使用__FILE__
;参数lineNumber
一般使用__LINE__
6.3 检查核函数
错误检查函数无法捕捉核函数错误
7. CUDA Stream
7.1 什么是CUDA Stream
CUDA Stream 是CUDA中一个关键概念,能够实现GPU上的异步并行操作(并发)
CUDA Stream 是一系列按照指定顺序执行的命令(内核启动、内存拷贝)。每个流中的操作按照提交的顺序依次执行,但不同流之间的操作可以并发执行。这意味着可以将多个操作分配到不同流中,以实现真正的并行计算
7.2 为什么使用CUDA Stream
- 提高并行性
- 隐藏计算与数据传输延迟
- 更好的资源管理
默认流(空流):如果在CUDA操作中未指定流,则默认使用默认流。默认流中的操作按顺序执行,会阻塞其他流中的操作
非默认流(非空流):由用户显式创建的流,允许并行执行不同流中的操作
7.3 CUDA Stream的基本使用方法
7.3.1 创建和销毁Stream
7.3.2 在指定Stream上执行操作
默认情况下,CUDA操作在默认流cudaStreamDefault上执行。要在特定流上执行操作,需要在函数调用中指定流参数。
异步内存拷贝
启动内核
7.3.3 同步操作
- 流内同步:同一流中的操作按顺序执行,无需额外同步
- 流间同步:使用
cudaStreamSynchronize()
等待特定流中的操作完成
- 全局同步:
cudaDeviceSynchronize()
等待所有流中的操作完成