Skip to content

CUDA 编程与内存模型 ​

状态:入门理解 · 更新于 2026-09-14

CUDA 优化的核心不是“把代码搬到 GPU”,而是让足够多的线程并行执行,同时减少等待数据和同步的时间。本页先建立执行层级、内存层级和最基本的性能判断框架。

执行模型 ​

一次 Kernel 启动会创建一个 Grid,Grid 由多个 Thread Block 组成,每个 Block 再包含多个 Thread。硬件执行时,Block 被调度到 SM,线程通常以 32 个一组的 Warp 发射指令。

软件层级作用关键约束
Grid一次 Kernel 的全部工作普通 Kernel 内没有低成本的全 Grid 屏障
Block可协作的一组线程同一 Block 才能直接共享 Shared Memory
WarpSM 的基本执行批次分支路径不同会产生 Warp Divergence
Thread处理一个或多个数据元素寄存器使用过多会限制并发驻留量

Block 不是越大越好。选择线程数时要同时看 Warp 数量、寄存器、Shared Memory 和 Occupancy,最终以实际测量结果为准。

内存层级 ​

存储位置可见范围典型特点常见用途
Register单线程片上、延迟低、容量有限索引、累加器、线程私有临时值
Shared Memory单 Block片上、可编程缓存,需要显式同步Tile、Block 内数据复用
Global Memory整个 Device容量大、延迟高输入、输出和长期驻留数据
Constant Memory整个 Device,只读有缓存;Warp 读取同一地址时效率高小型只读参数
Local Memory逻辑上属于单线程实际位于片外显存寄存器溢出、大型线程局部数组

“Local”不代表片上。如果编译器发生 register spill,数据会落到 Local Memory,代价接近 Global Memory。

最小 Kernel ​

下面的向量加法展示最常见的索引方式:

cpp
__global__ void vector_add(const float* a, const float* b, float* c, int n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < n) {
        c[i] = a[i] + b[i];
    }
}

int threads = 256;
int blocks = (n + threads - 1) / threads;
vector_add<<<blocks, threads>>>(a, b, c, n);

这里相邻线程访问相邻的 float,有利于 Global Memory 合并访问。启动后仍需检查 CUDA 错误;计时时还要使用 CUDA Event 或显式同步,不能只测主机端的异步提交时间。

三个主要性能问题 ​

1. Global Memory 访问是否合并 ​

一个 Warp 的地址如果连续且合理对齐,硬件可以用较少的内存事务完成访问。大步长、散乱或未对齐访问通常会浪费带宽。优先调整数据布局和线程到数据的映射,再考虑更复杂的技巧。

2. 数据是否值得搬进 Shared Memory ​

Shared Memory 适合被同一 Block 多次复用的数据。只用一次的数据先搬进去通常得不偿失。使用时还要避免 Bank Conflict,并用 __syncthreads() 保证 Block 内生产者和消费者的顺序。

3. 并发度是否被资源限制 ​

寄存器或 Shared Memory 占用过高,会减少一个 SM 上可同时驻留的 Block 和 Warp。Occupancy 太低可能无法隐藏延迟,但 Occupancy 最高也不等于性能最好;需要结合吞吐、访存和指令瓶颈判断。

基础优化顺序 ​

  1. 先做 CPU 或框架基线,固定输入 shape、dtype 和误差标准。
  2. 检查相邻线程的 Global Memory 访问是否连续。
  3. 找到可复用数据,再设计 Shared Memory Tile。
  4. 观察寄存器、Shared Memory 和 Occupancy 的约束。
  5. 用 Nsight Systems 判断时间花在哪,再用 Nsight Compute 分析目标 Kernel。
  6. 每次只改一个变量,同时做正确性和性能回归。

常见误区 ​

  • Kernel 启动是异步的,主机计时可能只测到提交开销。
  • __syncthreads() 只同步一个 Block,且不能放在部分线程无法到达的分支中。
  • Shared Memory 更快,但搬运、同步和 Bank Conflict 都有成本。
  • 小输入可能主要受 Launch Overhead 影响,优化计算主体不一定有效。
  • 不同 Compute Capability 的资源限制和最佳参数可能不同。

信息来源 ​

延伸阅读 ​

更新日志 ​

  • 2026-09-14:建立执行模型、内存层级与基础优化流程。

学习、验证、修订,持续构建 AI Infra 知识地图。