CUDA编程笔记

date
Feb 12, 2025
slug
cuda-program
status
Published
tags
CUDA
summary
type
Post

1. 什么是GPU

💡
GPU性能指标:
  • 核心数
  • GPU显存容量
  • GPU计算峰值
  • 显存带宽
notion image

2. 核函数

  1. 核函数在GPU上进行并行执行
  1. 注意:
      • (1) 限定词__global__修饰
      • (2) 返回值必须是void
 
★ 1、核函数只能访问GPU内存 ★ 2、核函数不能使用变长参数 ★ 3、核函数不能使用静态变量 ★ 4、核函数不能使用函数指针 ★ 5、核函数具有异步性
★ CUDA程序编写流程:
核函数不支持C++的iostream

3. CUDA的线程模型

3.1 线程模型结构

💡
  1. 线程模型重要概念:
      • grid 网格
      • block 线程块
  1. 线程分块是逻辑上的划分,物理上线程不分块
  1. 配置线程:<<<grid_size, block_size>>>
  1. 最大允许线程块大小:1024
  1. 最大允许网格大小:2^31-1(针对一维网格)
notion image

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
notion image
notion image
notion image

4. GPU架构

notion image
指定虚拟架构计算能力
-arch=compute_XY
指定真实架构计算能力
-code=sm_XY
  1. 二进制cubin代码,大版本之间不兼容!
  1. 指定真实架构计算能力的时候必须指定虚拟架构计算能力!
  1. 指定的真实架构能力必须大于或等于虚拟架构能力!

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 自定义设备函数

  1. 设备函数(device function)
      • 定义只能执行在GPU设备上的函数为设备函数
      • 设备函数只能被核函数或其他设备函数调用
      • 设备函数用__device__修饰
  1. 核函数(kernel function)
      • __global__修饰的函数称为核函数,一般由主机调用,在设备中执行
      • __global__修饰符既不能和__host__同时使用,也不可与__device__同时使用
  1. 主机函数(host function)
      • 主机端的普通C++函数可用__host__修饰
      • 对于主机端的函数,__host__修饰符可省略
      • 可以用__host____device__同时修饰一个函数减少冗余代码。编译器会针对主机和设备分别编译该函数。

6. CUDA错误检查

6.1 运行时API错误代码

  1. CUDA运行时API大多支持返回错误代码,返回值类型:cudaError_t
  1. 运行时API成功执行,返回值为cudaSuccess
  1. 运行时API返回的执行状态值是枚举变量
notion image

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

  1. 提高并行性
  1. 隐藏计算与数据传输延迟
  1. 更好的资源管理
默认流(空流):如果在CUDA操作中未指定流,则默认使用默认流。默认流中的操作按顺序执行,会阻塞其他流中的操作
非默认流(非空流):由用户显式创建的流,允许并行执行不同流中的操作

7.3 CUDA Stream的基本使用方法

7.3.1 创建和销毁Stream
7.3.2 在指定Stream上执行操作
默认情况下,CUDA操作在默认流cudaStreamDefault上执行。要在特定流上执行操作,需要在函数调用中指定流参数。
异步内存拷贝
启动内核
7.3.3 同步操作
  • 流内同步:同一流中的操作按顺序执行,无需额外同步
  • 流间同步:使用cudaStreamSynchronize() 等待特定流中的操作完成
  • 全局同步:cudaDeviceSynchronize() 等待所有流中的操作完成
 

© Morgan Woods 2024 - 2025