全部文档/系列目录
GPU 编程基础:给 CPU 程序员的 GPU 教程
这一页写给这样的读者:会 C/C++,知道线程、cache 和向量化是什么,但没系统写过 CUDA。所以不假设你懂 warp、occupancy、bank conflict;每个概念第一次出现时都给定义、给数字量级,再给一段能编译的短代码。
与 CPU 相同的部分只做速览:IEEE 浮点、补码、局部性、Amdahl、先测量再优化。重点放在真正不同的地方:SIMT 与分支发散、显式内存层级与合并访问、显式同步与弱内存模型、主机/设备分离、异步错误、以及必须靠测量判断的性能。
代码用 CUDA C++,nvcc -O3 -arch=native 可编译,面向 sm_70 及以上。为了短,片段只保留核心逻辑;完整的 host 骨架与错误检查见第 6 节。文中的硬件数字以 H100 SXM(132 SM、3.35 TB/s、67 TFLOPS FP32)为参照,换卡后结论不变、常数要换。
怎么读
- 第一次:从第 0 节顺序读到第 7 节。每节先讲“和 CPU 哪里不一样”,再给代码,最后列“容易写错的地方”。
- 只想知道差异:0、1.2(warp 发散)、2.3(合并访问)、3.5(同步原语对照)、7.5(移植检查清单)。
- 动手之前:1.3 的启动配置 + 7.5 的检查清单,能避开大多数“能跑但很慢”。
- 查 API / 公式:附录 A 一页表格。
章节
-
为什么 GPU 把面积花在并行而不是分支预测;三个直接后果;什么时候不该用 GPU;第一个可运行的向量加程序。
-
三层线程结构;一个 warp 共享一条指令流,分支为什么会串行;启动配置取值;grid-stride 循环;占用率的快速估算。
-
寄存器 / shared / L1 / L2 / 显存的容量与延迟;Little 定律算“在途字节”;32B sector 与合并访问;bank conflict;转置实战。
-
__syncthreads的真实语义;原子操作与热点竞争;弱内存模型、fence 与发布-订阅;warp 级 shuffle / ballot;与 CPU 同步原语的对应表。 -
树形归约(shuffle 版);Hillis-Steele 扫描;halo 与 stencil;直方图的私有化;从 work/span 看 GPU 为什么“多干活”。
-
roofline 模型与 ridge point;朴素 GEMM 的瓶颈;shared 分块与寄存器分块;WMMA / Tensor Core;fp16、bf16、tf32 的取舍。
-
cudaMalloc 与 cudaMemcpy 的真实成本;pinned memory 为什么必要;多流 overlap;事件计时;统一内存与多卡。
-
正确的基准写法;三个性能极限;Nsight 看哪几个指标;浮点精度与确定性;一份移植检查清单。
-
公式、API、启动配置、症状与原因对照、术语表。
一张表看完 CPU 与 GPU 的差别
下面这张表是整份教程的提纲:每一行在后面的章节里都会展开。
| 维度 | CPU | GPU | 直接后果 |
|---|---|---|---|
| 优化目标 | 降低单线程延迟 | 提高总吞吐 | GPU 单线程更慢,靠并行补回来 |
| 并行单元 | 8–128 个重量级核,每核乱序执行 + SIMD | 60–160 个 SM,上万条 lane | 线程要十万级才喂得饱 |
| 主频 | 2.5–5.5 GHz | 1.0–2.5 GHz | 串行段落在 GPU 上慢 10–50 倍 |
| 分支 | 预测 + 推测执行 | SIMT 掩码,路径串行 | 分支密集代码可能慢一倍以上 |
| 缓存 | 硬件自动管理多级 cache | 显式 shared memory + 弱一致 cache | 数据复用要自己搬 |
| 内存 | 统一地址空间,可换页、可超卖 | 独立显存,手动拷贝,不可超卖 | 传输可能吃掉全部收益 |
| 同步 | 锁、条件变量、futex | barrier、原子、fence | 没有 mutex,跨 block 同步很难 |
| 启动开销 | 函数调用,纳秒级 | kernel launch,约 5 µs | 小任务不要拆成多个 kernel |
| 错误模型 | 同步异常 / 信号 | 异步错误码,可能“粘住” | 每个 API 都要查返回值 |
| 抢占 | 时间片抢占 | block 一旦开始通常跑完 | 长 kernel 会拖住整卡 |
| 编程模型 | 共享内存 + 锁 | SIMT + 显式数据搬运 | 移植不是换个 API 那么简单 |
符号与术语
| 符号 / 术语 | 含义 | 本教程的取值 |
|---|---|---|
| warp | GPU 的调度单位,固定 32 个 lane | 32 |
| SM | 流多处理器,GPU 的基本计算单元 | H100 有 132 个 |
| \(N\) | 元素个数 | — |
| \(T\) | 分块边长(tile size) | 示例用 32 |
| \(P\) | 峰值算力 | \(67\times10^{12}\) FLOP/s(FP32) |
| \(BW\) | 内存带宽 | \(3.35\times10^{12}\) B/s |
| \(I\) | 算术强度,每字节做多少次浮点运算 | FLOP/byte |
| occupancy | 常驻 warp 数 / 硬件上限 | 0–100% |
公式用本地 KaTeX 渲染;样式与 KaTeX 都在 ../assets 下,断网也能看。如果要把 gpu 目录单独拷走,记得一并带上 assets,否则公式和排版会失效。