摘要:在第一章我们建立了异构计算的宏观视野。本章我们将拿起"手术刀",深入 GPU 内部。
为什么 H100 的 L2 Cache 激增?为什么 Warp Scheduler 要设计成"双发射"?Tensor Core 如何从 Ampere 的"同步阻塞"进化为 Hopper 的"异步流水线"?
读完本章,当你再次注视 CUDA 代码时,你看到的不再是 C++ 语法,而是数据在晶体管间的流动。
1. GPU架构
NVIDIA GPU采用分层结构设计,能够高效处理复杂的图形和计算工作负载。这种结构可以形象地形象地描述为一个金字塔,每一层代表不同的组织层级。
网格位于层级结构的顶端,代表整个GPU及其资源。它的外观如下

1.1 图形处理集群GPC (Graphics Processing Cluster)**:最高物理层级
GPC 代表了 GPU 内部的高度组织性。它们对于在芯片上分配工作负载和管理资源至关重要。每个GPC相对独立地运行,并包含自己的纹理处理集群(TPC)、流式多处理器(SM)和共享资源,从而实现高效的工作负载分配和资源管理。
GPU 中的 GPC 数量取决于具体型号及其用途。专为游戏、专业渲染和复杂计算工作负载等高要求任务设计的高端 GPU 通常配备更多 GPC,以应对更高的并行处理需求。相反,为处理强度较低的任务而构建的低端 GPU 则配备较少的 GPC。

1.2 纹理处理集群TPC (Texture Processing Cluster):GPC 的下级单位。
TPC负责执行核心图形处理。
构成我们在屏幕上看到的视觉体验的工作负载。它们处理诸如以下任务:
-
顶点着色: 换3D顶点,将坐标转换为二维屏幕坐标。
-
纹理映射:将纹理(图像)应用到 3D 模型上。
-
栅格化:将多边形转换为像素以进行显示

每个 TPC 包含多个 SM,它们是 GPU 的核心组件,并行执行这些任务。它们还包含以下内容:
- 纹理单位:这些部门负责处理与以下方面相关的任务:纹理映射例如,从内存中获取纹理数据、进行过滤以及将纹理应用于像素或顶点。它们确保纹理正确映射到 3D 模型上,从而创建细节丰富、逼真的图像。
- L1缓存:一个小型、高速的内存缓存,用于存储频繁访问的纹理数据和指令。这有助于降低延迟并提高纹理处理操作的效率。* 共享内存:TPC 使用共享内存,从而实现集群内纹理单元和 SM 之间的高效数据共享。这种共享内存对于高性能纹理映射和滤波操作至关重要。
- 特殊功能单元(SFU):TPC 中的 SFU 专门针对纹理映射和渲染操作进行了优化。它们能够处理复杂的数学函数,但更侧重于纹理处理所需的任务。
- 栅格引擎:光栅引擎将矢量图形(例如 3D 模型)转换为光栅图像(像素)。它在渲染的最后阶段起着至关重要的作用,决定着纹理如何应用于屏幕上的各个像素。
- 纹理缓存:这些缓存将纹理数据存储在靠近纹理单元的位置,以最大限度地减少从主内存中获取数据所需的时间。它们通过减少内存访问延迟来帮助加快纹理映射过程。
1.3 SM (Streaming Multiprocessor):核心战场
SM是GPU内部的基本处理单元。GPU中SM(流式多单元)的数量是决定其整体性能的关键因素。
以下是其组成部分的详细分解:
- 指令缓存(I-Cache):存储SM要执行的指令,通过将常用指令靠近执行单元,实现快速访问并降低延迟。
- 多线程问题(MT Issue):负责将指令分发到 SM 内的各个执行单元。它同时管理多个线程,优化可用计算资源的利用。
- 常量缓存(C-Cache):此缓存存储执行过程中不会改变的常量数据。它允许线程快速访问这些常量值
- 流处理器/CUDA核心(SP):SP,也称为CUDA核心,是SM中负责执行大部分算术运算(例如,浮点运算和整数运算)的核心。多个SP单元可以实现指令的并行处理。
- 特殊功能单元 (SFU): SM 还具有SFU,用于处理更复杂的数学功能,例如三角函数计算、指数函数以及其他比标准算术运算计算量更大的特殊功能。 双精度单元
- (DP):这些单元处理双精度浮点运算,对于需要高数值精度的应用(如科学计算和模拟)至关重要。
- 共享内存:与线程处理计算机 (TPC)类似,子处理器 (SM) 也使用共享内存,这是一种高速片上内存,SM内的所有线程均可访问。它允许线程之间高效地共享和协调数据,从而显著加快需要频繁数据交换的计算速度。

现代GPU中的SM(小型存储器)通常包含额外的核心和专用单元,其中可能包括:
- L1 缓存:一种小型、快速的内存缓存,用于存储靠近 SM 内核的频繁访问的数据和指令,以减少访问时间。
- 寄存器:每个 SM内的高速存储位置专门用于存储活动线程的临时数据,以便在计算期间快速访问。
- 张量核心:专门用于深度学习和人工智能任务,执行神经网络训练和推理所必需的矩阵运算。 光线
- 追踪核心(RT 核心):专门用于处理光线追踪计算,提供逼真的光照、阴影和反射的实时渲染。
GPU 中的每个 SM 都集成了这些组件,以高效地执行各种并行处理任务,从而平衡通用计算与图形、AI 和其他高要求工作负载的专用处理。
1.4 内存墙的救赎:L2 Cache 的暴涨
观察近三代旗舰 GPU 的参数,你会发现一个惊人的趋势:
- A100 (Ampere): 40 MB L2
- H100 (Hopper): 50 MB L2
- RTX 4090 (Ada): 72 MB L2
- Blackwell : 更大的 L2(具体取决于 SKU)
为什么?
因为 HBM 的带宽增长(~3TB/s)跟不上 Tensor Core 算力的增长(~2000 TFLOPS)。
L2 Cache 是所有 SM 共享的**"中央数据交换枢纽"和"原子操作中枢"**。巨大的 L2 缓存可以捕获更多的数据重用(Data Reuse),减少对 HBM 的访问,从而缓解"内存墙"问题。
2. 微观解剖
很多初学者把 SM 看作一个巨大的 CPU 核心,这是错误的。SM 实际上被物理切割成了 4 个分区 (Partitions / SMSP)。
这是理解 Occupancy(占用率)和 Latency Hiding(延迟掩盖)的物理基础。

2.1 SMSP:SM 的子宇宙
每个 SM 包含 4 个 SMSP。每个 SMSP 是一个相对独立的执行单元,拥有独立的:
- Warp Scheduler (L0 Instruction Cache):负责指令发射。
- Dispatch Unit:负责分发指令到 ALU。
- LD/ST(装载/存储单元):内存访问,负责将数据从内存加载到寄存器,并将结果存储回内存。该单元负责与GPU的内存层次结构(共享内存、L1缓存、全局内存)进行交互
- Register File (寄存器堆) :16,384 个 32-bit 寄存器 。
- 这是 GPU 上最快但也最稀缺的资源。如果你在一个 Kernel 里用了太多寄存器,SMSP 就只能容纳更少的 Warp,导致无法掩盖内存延迟。
2.2 Warp Scheduler 与"双发射"
Warp Scheduler 每一时钟周期会选择一个"就绪(Ready)"的 Warp 发射指令。什么是"就绪"?即该 Warp 的所有操作数都已准备好,且执行流水线空闲。
在 Ampere 和 Hopper 架构中,Scheduler 支持 Dual Issue (双发射):
- 它可以同时发射一条 FP32 指令和一条 INT32 指令。
- 优化启示 :我们在 Kernel 中计算数组索引(如
idx = blockIdx.x * blockDim.x + threadIdx.x)通常是 INT32 运算。得益于双发射,这些索引计算往往能被浮点数计算(FP32)完美掩盖,几乎是"免费"的。
2.3 核心计算单元 (CUDA Cores)
每个 SMSP 内部包含:
- FP32 Cores:浮点单元 (FPU),对浮点数据类型(例如,单精度 FP32 和半精度 FP16)执行浮点算术运算(加法、减法、乘法、除法)。
- INT32 Cores:整数单元,对整数数据类型执行整数算术运算(加法、减法、乘法、除法)。
- SFU (Special Function Units) :处理
sin,cos,exp,rsqrt等超越函数。- 注意 :SFU 数量很少(通常是 FP32 单元的 1/4)。大量使用
expf(如 Softmax)可能会导致计算流水线阻塞。
- 注意 :SFU 数量很少(通常是 FP32 单元的 1/4)。大量使用
3. tensor core
NVIDIA 的 Tensor Core 是专为加速深度学习运算而设计的专用处理单元。它们针对矩阵乘法和卷积运算进行了优化,而矩阵乘法和卷积运算是深度神经网络的基本组成部分。Tensor Core 可以使用单精度和半精度浮点数的组合来执行这些运算,从而在不牺牲精度的前提下显著提高吞吐量
张量核心的组成部分如下:
- 矩阵乘加 (MMA) 单元:这些是张量核心中的核心计算单元。每个 MMA 单元可以在单个时钟周期内执行 4x4 矩阵乘加运算。多个 MMA 单元并行工作,以加速大型矩阵运算。
- Warp调度器:这些单元负责调度和管理张量核心上线程束(线程组)的执行。它们确保MMA单元保持繁忙状态,并优化数据流以实现高效计算。
- 寄存器和共享内存: Tensor 核心可以访问高速寄存器和共享内存,用于存储中间结果和线程束内线程之间共享的数据。
- 混合精度支持: Tensor核心支持混合精度计算,这意味着它们可以使用不同的数值格式(例如FP16、FP32、INT8、INT4)执行计算。这种灵活性平衡了计算速度和精度,因为深度学习模型通常不需要所有操作都具有极高的精度。

3.1 工作原理
Tensor Core 的核心原理可以浓缩成一句话:
"把一次 4×4 矩阵乘加做成一条硬件指令,用 64 个 FP16 乘法-加法在同一周期内同时完成,并把累加器保持在 FP32。"
-
宏观公式
D = A × B + C
其中 A、B 是 4×4 FP16,C、D 可以是 FP16 或 FP32(混合精度)。A(4×4,FP16) B(4×4,FP16) \ / \ / ▼ ▼ ┌──────────────────┐ │ Tensor Core │ ← C(4×4,FP32) │ 64 × FMA │ │ 单周期完成 │ └──────────────────┘ │ ▼ D(4×4,FP32)
-
物理映射
Volta 用 1 个 warp(32 线程)拆成 4 个 quadpair,每 8 线程协作完成 8×8×4 子块,实际只占 2 个 Tensor Core。warp(32 threads)
┌--- quadpair-0 ---┐ ┌--- quadpair-1 ---┐
T0-3,T16-19 │ T4-7,T20-23 │ ...
│ 线程寄存器 │ │ 线程寄存器 │
│ 保存 2×4 A片 │ │ 保存 2×4 A片 │
│ 保存 4×4 B片 │ │ 保存 4×4 B片 │
│ 保存 2×4 C片 │ │ 保存 2×4 C片 │
└─────────────────┘ └─────────────────┘
▲ ▲
│ │
└---- 同时喂给同一个 Tensor Core
-
微架构流水线
每个 Tensor Core 内部放 16 个"四元点积单元"(FEDP),每个 FEDP 4 周期流水线:
周期 0:4 个 FP16 乘法
周期 1-3:3 级 FP32 累加
16 单元 × 4 路并行 = 64 FMA/周期,刚好覆盖 4×4×4=64 次乘加。16 FEDP┌───┬───┬───┬───┐
│m0 │m1 │m2 │m3 │ ← FP16 乘法
├───┼───┼───┼───┤
│a0 │a1 │a2 │a3 │ ← FP32 累加
├───┼───┼───┼───┤
│a0 │a1 │a2 │a3 │
├───┼───┼───┼───┤
│a0 │a1 │a2 │a3 │
└───┴───┴───┴───┘
4 周期流水,每周期推出 16 个结果
-
数据搬运"
因为 Tensor Core 只认寄存器操作数,所以 CUDA 程序要先用 warp-level 指令(PTXmma或 C++wmma::mma_sync)把共享内存里的瓦片 preload 到每个线程的寄存器,计算完再 store 回共享内存,最后写回全局内存。Global Memory (HBM)
│
▼
Shared Memory (SMEM)
│
▼
Thread Register File ← preload
│
▼
Tensor Core 4×4×4 FMA
│
▼
Thread Register File ← store back
│
▼
Shared Memory
│
▼
Global Memory
"软件把大矩阵切成 4×4 瓦片 → 瓦片进寄存器 → 一条 warp 指令触发 64 个 FMA 同时算 → 结果写回寄存器 → 继续算下一块"。
整个过程中,乘法用 FP16,累加用 FP32,既省带宽又保精度,这就是混合精度加速的核心。
3.2 Tensor Core 演进史
Tensor Core 是 AI 算力的核动力引擎。从软件工程师的视角看,它的演进方向只有两个词:变大 ,变异步 。

3.2.1 Ampere (Gen 3):同步的基石
- 指令 :
mma.sync - 行为 :这是一个 Warp 级同步指令。32 个线程必须在同一个 Program Counter 集合,把数据加载到寄存器中,喂给 Tensor Core,算完后再写回寄存器。
- 局限 :数据必须经过 Register File 中转(Global → \to → Shared → \to → Register → \to → TC),消耗了宝贵的寄存器带宽。
3.2.2 Hopper (Gen 4):异步革命
- 指令 :
wgmma.mma_async(Warpgroup MMA) - 变革一:Warpgroup。由 4 个连续的 Warp 组成一个"Warpgroup (128线程)",协同驱动更大的 Tensor Core 单元。
- 变革二:Bypass Register 。Tensor Core 可以直接读取 Shared Memory,不再需要寄存器中转。这极大地降低了寄存器压力。
- 变革三:Asynchronous。指令发射后,Warp 不会阻塞,可以立即去处理下一块数据的加载(TMA)。
3.2.3 Blackwell (Gen 5):微缩放时代
- 新精度 :原生支持 FP4 和 FP6。
- Block-wise Scaling:为了在 FP4 下保持精度,Blackwell 引入了微缩放格式,即每组数据共享一个高精度的 Scale Factor。这是下一代量化推理(如 vLLM)的主战场。
4. 内存架构与管理
高效的内存管理对于实现 NVIDIA GPU 的高性能至关重要。在本节中,我们将深入探讨 NVIDIA GPU 复杂的内存架构,该架构使 NVIDIA GPU 能够在处理海量数据的同时,最大限度地降低延迟并提高吞吐量。我们将探讨共享内存、L1 缓存、L2 缓存、GDDR 内存,以及内存控制器和接口在协调数据传输中的作用。
4.1 共享内存
共享内存是一块小巧、低延迟的内存区域,线程块内的所有线程都可以访问它。它作为线程间的通信和同步机制,使线程能够高效地交换数据并协调执行。共享内存位于芯片内部,驻留在流式多处理器(SM)中,因此其访问速度远快于GPU的全局内存。

通过使用共享内存,线程可以避免从全局内存进行冗余数据传输,从而降低延迟并提高性能。例如,在图像处理中处理相邻像素的线程可以共享共享内存中的数据,从而无需多次从全局内存中获取相同的数据。
4.2 L1缓存
L1缓存是位于每个SM(流式存储器)内部的小型高速缓存。它存储频繁访问的数据和指令,从而减少从共享内存或全局内存等速度较慢的内存层级获取数据的需要。L1缓存通常分为独立的指令缓存和数据缓存,从而允许同时访问指令和数据。
L1缓存有助于降低内存访问延迟并提升整体性能。通过缓存常用数据和指令,GPU可以避免代价高昂的内存访问,确保CUDA核心能够持续获得稳定的数据和指令流,从而保持高效运行。
4.2 L2缓存
L2缓存是GPC内所有SM共享的更大、更慢的缓存。它作为L1缓存和全局内存之间的中间层,存储那些访问频率不高(不足以保留在L1缓存中)但又比全局内存中的数据访问频率更高的数据。
二级缓存有助于减少对全局内存的访问次数,而全局内存访问往往是性能瓶颈。通过缓存多个子模块 (SM) 之间共享的数据,二级缓存可以减少对全局内存带宽的争用,从而提高整体吞吐量。
4.3 L1 Cache 与 Shared Memory 的爱恨情仇
- 物理本质 :在 SM 内部,L1 Cache 和 Shared Memory 实际上共用同一块片上 SRAM。
- 可配置性 :你可以通过
cudaFuncSetAttribute调整它们的比例。- 计算密集型?调大 L1 增加缓存命中率。
- 访存密集型(需要手动 Tiling)?调大 Shared Memory。
- Hopper 的改变:H100 为 L1 和 Shared Memory 提供了更独立的带宽保证,以支持 TMA 的高速写入。
4.4 Register File:Bank Conflict 的隐秘角落
很多人知道 Shared Memory 有 Bank Conflict,却不知道寄存器也有。
- Operand Collector:为了让 ALU 能全速运转,SM 内部有一个名为"操作数收集器"的组件。它负责从寄存器堆的 Bank 中读取数据。
- 优化启示 :如果你的代码中有大量连续指令访问同一个寄存器索引(例如累加器
sum += ...),编译器会尝试指令重排(Instruction Scheduling)来错开访问,避免寄存器 Bank 冲突。
5. 新物种:TMA 与 Clusters (Hopper+)
这是区分"现代 CUDA 开发者"与"传统 CUDA 开发者"的分水岭。
5.1 TMA (Tensor Memory Accelerator)
在 Hopper 之前,搬运数据是线程的苦力活(Load/Store 指令)。
- 定义 :SM 旁边的一个独立 DMA 引擎。
- 工作流 :
- CPU/Kernel 创建一个"搬运描述符 (Descriptor)"。
- 发出指令"TMA,把这块 Global Memory 搬到 Shared Memory"。
- SM 里的 CUDA Cores 立刻解放,去算别的东西。
- 结果 :地址计算开销归零,带宽利用率拉满。

5.2 Thread Block Clusters
- 痛点:传统 CUDA 中,SM 是孤岛。SM 0 无法快速访问 SM 1 的 Shared Memory。
- Clusters:允许 GPC 内的多个 SM (例如 2, 4, 8 个) 组成集群。
- Distributed Shared Memory (DSMEM):SM 之间可以通过高速互联网络直接访问邻居的 Shared Memory。这对于需要 Halo Exchange 的算子(如卷积、长序列 Attention)是革命性的。

6. 实战:硬件拓扑侦探
如果不了解你手里的显卡,怎么做优化?本章代码将展示如何挖掘 cudaDeviceProp 中隐藏的关键硬件参数。
代码地址:https://github.com/Yapeng-Gao/AI-System-Performance-Lab,欢迎大家多多建议,多多star
文件路径:examples/01_cuda_basics/02_hardware_query.cu
核心功能:
SM 资源探测:打印每个 SM 的最大寄存器数、最大 Shared Memory。
L2 Cache 大小:验证架构差异(A100 vs 4090)。
计算能力:判断是否支持 Hopper 特性(arch >= 90)。
Memory Clock:计算理论峰值带宽。
cpp
// 伪代码预览 (完整代码见项目)
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, 0);
printf("SM Count: %d\n", prop.multiProcessorCount);
printf("Max Registers/Block: %d\n", prop.regsPerBlock);
printf("Max SharedMem/Block: %zu bytes\n", prop.sharedMemPerBlockOptin);
printf("L2 Cache Size: %d MB\n", prop.l2CacheSize / 1024 / 1024);
printf("TMA Support: %s\n", (prop.major >= 9) ? "Yes" : "No");
6. 总结与下章预告
本章我们拆解了 GPU 的物理架构。在写代码前,请记住这三条**"物理铁律"**:
- SM 是资源分配的单位:寄存器用多了,驻留的 Block 就变少。
- Warp 是执行的单位:所有线程必须步调一致,否则就是 Divergence。
- Hopper 之后,数据搬运是 TMA 的事:不要再让宝贵的 CUDA Core 去做搬运工。
👉 下一章:[Module A] 03. CUDA 编程模型:Grid/Block/Warp 的真实执行顺序
既然知道了 SM 长什么样,下一章我们就来看 Grid 和 Block 是如何被"塞"进这些 SM 里去执行的,以及那个著名的"Warp Divergence"到底是怎么发生的。
📚 参考文献与延伸阅读
为了确保对底层微架构理解的准确性,本章内容深度参考了以下 NVIDIA 官方白皮书与技术文档。强烈建议读者下载这些 PDF 作为"案头书"常备。
- NVIDIA Hopper 深入研究架构
- NVIDIA A100 Tensor Core GPU Architecture Whitepaper
- 对比阅读:理解从 Ampere 到 Hopper 的 L2 Cache 增长逻辑以及 Tensor Core 的代际差异。
- NVIDIA Blackwell Architecture Technical Brief
- 前沿技术:关于 Blackwell 第二代 Transformer Engine 与 FP4/FP6 精度支持的官方技术简报。
- CUDA C++ Programming Guide (v12.3) - Chap. 5.4 Hardware Implementation
- 必读章节:官方文档中关于 SIMT 架构、Warp 调度与双发射(Dual Issue)机制的详细说明。
- Dissecting the NVIDIA Hopper GPU Architecture via Microbenchmarking
- 进阶阅读:学术界对 H100 的逆向微基准测试,揭示了官方文档未提及的缓存延迟与指令吞吐细节。
- a-beginners-guide-to-nvidia-gpus