CUDA
GPU/CUDA简介#
GPU(Graphics Processing Units):图形处理单元
GPU——CPU的协处理器(eg:天河一号)
CUDA(Compute Unified Device Architecture):统一计算 设备架构——建立在GPU基础之上的通用计算开发平台 (Only NVIDIA !)
CPU vs GPU#
CPU——优化延迟的设计思路
- 大容量cache、复杂的控制逻辑、强大的计算单元
- 低计算密度、低延迟容忍度
GPU(众核)——优化吞吐率的设计思路 - 小cache、简单的控制、能耗高效的计算单元、高并发
- 高计算密度、高吞吐率、高延迟容忍度
CUDA
- 使用C语言编写GPU 程序,语言层面只 有很小的扩展
- 易于编程
- 属于SIMD模式
- 标准的SPMD模式 (单程序多数据流,所有线程执行相同的Kernel代码)
- 不再需要图形API
CUDA程序设计模型#
- host: 指代CPU端的代码
- device:指代GPU端的代码
- kernel:从host调用,在device端运行的函数
Serial Code (host)
Parallel Kernel (device)
KernelA<<<nBlk,nTid >>>(args);
Serial Code (host)
Parallel Kernel (device)
KernelB<<<nBlk,nTid >>>(args);
- Serial Code (host):这是主机端的代码,它通常负责管理整个计算任务,包括数据的准备、内存分配等操作。这个部分的代码是在 CPU 上运行的。
- Parallel Kernel (device):这是在设备端运行的并行内核代码。通常,CUDA 内核(Kernel)是并行执行的,并且是由多个线程在 GPU 上执行的。每个内核函数都有一个特定的线程布局,由
<<<nBlk, nTid>>>
这样的语法指定,其中:nBlk
表示 线程块(block)的数量,nTid
表示每个线程块中的 线程数(threads per block)。
- KernelA<<<nBlk, nTid>>>(args);:这是调用设备端内核
KernelA
的代码。KernelA
是你在 GPU 上运行的函数。<<<nBlk, nTid>>>
语法指定了内核的执行配置,控制有多少线程块(blocks)和每个线程块中有多少个线程(threads)。args
是传递给内核的参数。 - Serial Code (host):在执行内核后,主机端代码通常会等待内核完成计算,可能还会进行一些后处理操作。
- Parallel Kernel (device):这是在设备端执行的另一个内核,类似于
KernelA
。它在 GPU 上并行地执行。KernelB<<<nBlk, nTid>>>(args);
是调用内核KernelB
,与KernelA
类似。
#include <iostream>
#include <cuda_runtime.h>
using namespace std;
__global__ void demo(void) {
}
int main() {
demo<<<1,1>>>();
cout << "Hello, world!"<< endl;
return 0;
}
一个kernel对应一个Grid
Grid是三层线程结构
- 线程格Grid
- 一组线程块Block
- 一些线程Thread
- 连续32个线程组成一个warp,在SM(流多处理器)上运行
- Warp是GPU执行程序时的调度单位,同一个Warp里的线程执行相同的指令
- 一些线程Thread
- Block里支持线程间同步、共享内存
- Block内一个块至多512个线程、或 1024个线程
- Block间不能协作
- 一组线程块Block
- 同一个Grid上的线程共享相同的全局内存空间
1 个 Grid 包含 9 个 Blocks ,每个 Block 包含了 16 个 Threads
gridDim:gridDim.x, gridDim.y , gridDim.z 分别表示 grid 各个维度的大小,这里都是 3
blockDim:blockDim.x,blockDim.y , blockDim.z分别表示 block 中各个维度的大小,这里都为 4
blockIdx:blockIdx.x , blockIdx.y , blockIdx.z 分别表示当前 block 所处的Grid的坐标位置
threadIdx threadIdx.x , threadIdx.y , threadIdx.z分别表示当前线程所处的Block的坐标位置
总线程数 :N = gridDim.x * gridDim.y * gridDim.z *blockDim.x * blockDim.y * blockDim.z
当前线程在该 Block 位置 threadId = threadIdx.x +threadIdx.y*blockDim.x + threadIdx.z * blockDim.x * blockDim.y
从0开始编号
Thread工作模式
所有线程执行相同的 kernel 代码 (SPMD)
每个线程使用自己的编号计算不同数据 内存地址 以及执行不同分支
Block 内线程协同计算 共享内存 、 原子操作 、同步机制
Block 间不能协作
连续32个线程组成一个warp,在SM上运行
❑ SM:Stream Multiprocessor,流多处理器
❑ Warp是GPU执行程序时的调度单位,同一个Warp里的线程执行相同的指令
❑ SM动态调度warp
CUDA内存层次简介#
三层内存:
-
Global Memory
- Shared Memory
- Register
- Shared Memory
-
Device代码可以
- 读/写每线程独占的寄存器
- 读/写每kernel共享的全局内存
-
Host代码可以
- 在CPU主存和Device全局内存间传输数据
读写独占的寄存器(~1周期)
读写block内共享的共享内存 (~5周期)
读写全体线程共享的全局内存 (~500周期)
只读全体线程共享的 Host 常量内存(~5周期, 有cache的情况)
CUDA函数声明#
执行位置 | 调用位置 | ||
---|---|---|---|
__device__ float DeviceFunc() |
device | device | |
__global__ void KernelFunc() |
device | host | |
__host__ float HostFunc() |
host | host | |
CUDA程序优化#
两周优化思路:
掩盖访存
共享内存
作者:AuroraKelsey
出处:https://www.cnblogs.com/AuroraKelsey/p/18669407
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了