Lecture 12: Mapping AI Applications to the Datacenter Computer(将 AI 应用映射到数据中心计算机)(日期:Oct 30)

目录 · ← l11 · l13 →

Lecture 12: Mapping AI Applications to the Datacenter Computer(将 AI 应用映射到数据中心计算机)(日期:Oct 30)

概述:前两讲讨论了”为 AI 设计专用硬件”与”如何编程专用硬件”。本讲把视角从单芯片提升到数据中心规模:AI 模型越来越大(从 1.7B 到 1T 参数),单颗加速器装不下、算不动,必须把模型与计算映射(map)到成千上万台加速器组成的集群。本讲内容分两大块:(1) 存储系统基础——从 CPU vs GPU 内存、3D 堆叠的 HBM,到 DRAM 的工作原理(row buffer、bank、burst mode、DIMM、memory controller 调度),解释”内存墙”为何是数据中心计算的根本瓶颈;(2) 数据中心级并行——DGX SuperPOD 集群拓扑、通信原语(AllReduce/ReduceScatter/AllGather/All-to-All)、AI 模型中的并行维度(DP/TP/PP/EP/SP/CP)、分布式矩阵乘的 K 维切分 + reduce-scatter 合并、计算-通信重叠,以及训练中的细粒度流水并行(micro-batch)。最后回到能耗主题:减少数据搬运与专用处理是降低能耗的两大思想。

注意:本讲与 Assignment 4(Trainium2 加速器编程)的片上存储管理/数据搬运思想一脉相承,也为 Assignment 5(GPU kernel 优化)与期末的”数据中心规模”讨论打基础。补充说明:本讲幻灯片聚焦”数据中心存储系统 + 并行策略”,未展开 LLM serving(连续批处理、KV cache 管理、prefill/decode 等)细节,这些内容以”补充阅读”形式附在本讲末尾,供延伸学习。


一、核心概念与定义

1. CPU vs GPU memory(CPU 与 GPU 的内存系统差异)

  • 定义:CPU 通过 64-bit memory bus 连接 DRAM;GPU 通过 1024-bit(甚至 6144-bit)bus 连接 HBM。GPU 用极宽的接口换取极高带宽,以支撑成千上万个核心同时发出的访存请求。
  • 现实类比:CPU 像”窄而深的通道”(延迟优先,靠缓存层级缩短距离);GPU 像”宽而浅的河面”(带宽优先,靠宽度吞吐海量数据)。
  • 公式/图示:带宽 ≈ 总线宽度 × 频率 × 每周期传输次数(DDR4 2400:64-bit × 1.2GHz × 2 = 19.2 GB/s/通道,双通道 38.4 GB/s,CAS 约 13 ns)。

2. HBM(High-Bandwidth Memory,高带宽内存)

  • 定义:通过 3D 堆叠 DRAM 芯片实现的超高带宽内存:DRAM 芯片层层堆叠,用硅通孔(TSV, through-silicon-vias)穿过芯片连接;堆叠底层是”逻辑层”(memory controller),负责管理处理器请求;硅中介层(silicon interposer)作为 DRAM 堆与处理器之间的高带宽互连。HBM 的接口宽度为 1024-bit/stack
  • 三大优势(第 6 页):More Bandwidth(更多带宽)、High Power Efficiency(高能效)、Small Form Factor(小尺寸)。
  • 现实类比:把一摞煎饼(DRAM 层)用吸管(TSV)竖着串起来,再放在一个底座(逻辑层/中介层)上——比平铺一堆煎饼(传统 DRAM 排列)省地方、连接更密、传输更快。
  • 关键数据:H100 用 6 个 HBM3 堆 × 1024-bit = 6144-bit 接口,3.2 TB/s 峰值带宽,80 GB 容量;P100(2016)4×HBM2 = 4096-bit、720 GB/s、16 GB;AMD Fury(2015)4096-bit、512 GB/s。

3. Scale up vs Scale out(纵向扩展 vs 横向扩展)

  • 定义:Scale up = 把单个节点做强(更大内存、更快互连、更多算力);Scale out = 用标准节点堆出大规模集群(通过网络互连)。数据中心 AI 计算两者都需要:单机内 scale up(NVLink 全连接),机群间 scale out(InfiniBand 胖树)。
  • 现实类比:scale up 是把一个工位升级成”全能超人”;scale out 是招 1000 个普通工人并配好对讲机网络。
  • 图示:DGX SuperPOD 1K GPU 集群:140 个 DGX A100 节点(1120 块 GPU)组成一个 GPU POD;DGX A100 节点 = 2× AMD EPYC 7742 CPU + 8× A100 GPU + NVLink 3.0 全连接交换机;用 Mellanox HDR 200 Gb/s InfiniBand 全胖树(full fat-tree)互连;计算网络与存储网络分离,支持自适应路由与 SharpV2 卸载。

4. Communication primitives(通信原语)

  • 定义:多节点协同的基本消息传递操作(rank = 一个加速器节点):
    • AllReduce:所有节点得到所有数据的归约结果,AllReduce = ReduceScatter + AllGather
    • ReduceScatter:先归约,再把结果按 rank 分片(每个节点各拿一部分);
    • AllGather:每个节点把自己的分片广播汇总,最终所有节点都拥有完整数据;
    • All-to-All:每个节点把自己的数据分片发送给所有其他节点(如 rank 0 的 A0,A1,A2,A3 分别发给 rank 0..3)。
  • 现实类比:全班合写一份报告——AllReduce 是”每人把自己的部分发给大家并汇总成完整版”;ReduceScatter 是”先汇总统计,每人领回自己负责的那一段”;All-to-All 是”每人把自己写的章节分别发给所有同学”(像交换名片)。
  • 公式/图示
    AllReduce = ReduceScatter + AllGather
    分布 GEMM 例子:inputA[MxK] × inputB[KxN] = out[MxN],沿 K 维切分到 S 个 RDU
    每个 socket 算 [MxK/S] × [K/SxN] = [MxN] 的部分结果 → S 份部分结果 → S-way reduce-scatter 合并
    

5. Parallelism in AI models(AI 模型中的并行维度)

  • 定义:现代 AI 模型(Transformer)的张量有三个维度:Batch_dim(批维度)、Sequence_dim(序列维度)、Hidden_dim(隐藏维度),加上模型自身的”层”维度。并行策略按切分哪个维度划分(第 36 页):
    • Data Parallel (DP):按 batch 切分数据,各副本持有完整模型;
    • Tensor Parallel (TP):按 hidden_dim 切分权重/激活(如把权重矩阵劈成多块,各卡算一部分);
    • Pipeline Parallel (PP):按层切分,不同层在不同设备上,数据流水式流过;
    • Expert Parallel (EP):Mixture-of-Experts 中不同 expert 放在不同设备;
    • Sequence Parallel (SP) / Context Parallel (CP):按序列/上下文长度切分。
  • 通信模式对应(第 37 页):TP → ReduceScatter + AllGather 或 AllReduce;PP → Send-Receive;EP → All-to-All;DP → ReduceScatter + AllGather 或 AllReduce。
  • 现实类比:一个大型报告团队——按章节分工(PP:各写各的章节)、按主题分工(TP:每人负责一个主题列)、按读者分组复制(DP:每人服务一批读者)。
  • 公式/图示
    Activation Tensor 的维度: [Batch, Sequence, Hidden] × Layers
    Weight Tensor 的维度:    [Hidden, Hidden] × Layers(+ vocab)
    并行维度:DP(批) / SP·CP(序列) / TP(隐藏) / PP(层) / EP(专家)
    

6. Distributed matrix multiply(分布式矩阵乘)

  • 定义:把单个超大 GEMM(如 M=24576, K=131072, N=8192)分发到多个加速器:沿 K 维切分,每个 socket 计算 [MxK/S] × [K/SxN] = [MxN] 的部分结果,得到 S 份 [MxN] 部分结果后做 S-way reduce-scatter 合并成最终 [MxN]。
  • 现实类比:多个小组各自算一部分”公共因子的乘积”(K 维是共享的求和维),最后把大家的中间结果汇总归约。
  • 关键点:选择切分维度决定了通信量——切 K 维只需一次 reduce-scatter;切 M/N 维则需要 AllGather 完整输入。

7. Compute-communication overlap(计算-通信重叠)

  • 定义:让通信(如 AllReduce)与计算(如 GEMM)并行进行。RDU 上把 AllReduce 与 Down GEMM 等流水化(”Pipelined AllReduce with Compute, no HBM traffic!”),使通信不消耗 HBM 容量与带宽;GPU 上若不做重叠,随着 socket 数增加通信时间占比上升,通信成为瓶颈(”GPUs need large interconnect bandwidth to get high utilization”)。
  • 量化数据(第 41 页,BS=16, M=24576, K=131074, N=8192,总 844.44 TFLOPs):8/16/32 个 RDU 时,compute roofline 时间为 66.3/33.1/16.5 ms,reduce-scatter 时间为 8.6/9.7/15 ms;不重叠的理论峰值利用率仅 88.5%/77%/52%,而重叠后实测利用率 72%/75%/79%——32 socket 仍保持 70%+ 利用率。
  • 现实类比:厨师炒菜(计算)的同时,传菜员(通信)把上一桌的菜端出去——传菜不占用灶台,出菜率(利用率)不随桌数增加而崩。

8. Pipeline parallelism & micro-batch(流水并行与微批)

  • 定义:朴素流水并行(模型按层切分到多设备)存在计算资源利用不足(under-utilization)与整体吞吐低(low overall throughput)的问题——因为每层设备只在自己的数据到达时才干活,存在大量空闲(pipeline bubble)。细粒度流水并行(fine-grained pipeline parallelism):把 mini-batch(每次迭代处理的样本数)拆成多个 micro-batch,让 forward 与 backward 计算在 micro-batch 之间流水化——设备 1 算完 micro-batch 1 的 forward 立刻传给设备 2,同时开始 micro-batch 2 的 forward,层层推进。
  • 现实类比:流水线上第一个工位不必等整个订单做完才开工——把大订单拆成小件(micro-batch),前一件还没做完,后一件已经开工,各工位始终忙碌。
  • 公式/图示
    朴素: F1 → F2 → F3 → B3 → B2 → B1(大部分时间只有一两个设备在干活)
    微批: micro-batch1: F1→F2→F3→B3→B2→B1
           micro-batch2:   F1→F2→F3→B3→B2→B1   (错位流水,设备始终忙碌)
    

9. DRAM basics(DRAM 工作原理)

  • 定义:DRAM 阵列由”1 晶体管 + 1 电容”存储单元组成(电容存电荷,读取是破坏性的);每行约 2 Kbit 数据读入 row buffer;数据通过少量 data pins(8 bit) 传输给 memory controller。读一个字节的步骤:Precharge(预充电,就绪位线,~10 ns)→ Row activation(行激活,把行读入 row buffer,~10 ns)→ Column selection(列选择)→ Transfer(数据上总线,~10 ns);若访问的是已激活行(row hit),可跳过前两步,延迟大大降低——DRAM 访问延迟不是固定的
  • 现实类比:图书管理员找书——预充电=把书架归位,行激活=把整个书柜搬到台面(row buffer),列选择=抽出要找的那本;如果连续找同一书柜的书(row hit),就不用反复搬书柜,快得多。
  • 关键机制burst mode(一个命令批量传输多个连续列,摊销延迟)、多 bank(各 bank 共享引脚但可流水:一个 bank 在传输数据时另一个 bank 在做 precharge/activate,实现高引脚利用率)、DIMM(8 个 DRAM 芯片组成 64-bit 接口的模块,最小传输粒度 64 bit)。

10. Memory controller(内存控制器 = 访存请求调度器)

  • 定义:内存控制器接收 LLC 的 load/store 请求,负责:(1) 把物理地址映射到 DRAM 的 bank/row/column 几何结构;(2) 在相互冲突的目标(最大化吞吐、最小化延迟、最小化能耗)之间调度几十到几百个未完成的请求。常见调度策略:FR-FCFS(first-ready, first-come-first-serve)——优先服务当前已打开行的请求(最大化 row locality),其余按 FIFO;还会把多个小请求合并成大连续请求(利用 burst mode)。
  • 现实类比:机场塔台调度——优先让”跑道已清空”的航班(开放行)先起飞,其余按先来后到排队;把去同一目的地的小包裹合并成一次运输(合并请求)。
  • 公式/图示
    CPU → LLC(L3) → Memory Controller(按 bank 分队列)→ 64-bit bus → DRAM
    调度目标:吞吐↑、延迟↓、能耗↓(互相冲突,需权衡)
    FR-FCFS:先服务开放行(row hit),再按 FIFO 服务其他行
    

11. Data movement energy cost(数据搬运的能耗成本)

  • 定义:移动数据比计算贵得多(第 46-47 页):
    • 整数运算 ≈ 1 pJ;浮点运算 ≈ 20 pJ;
    • 读 64 bit 片内小 SRAM(1mm 远)≈ 26 pJ;读 64 bit LPDDR ≈ 1200 pJ
    • (另一组数据:fp32 数学运算 ~0.9 pJ;片内 SRAM 访问 ~5 pJ;LPDDR 读 32 bit ~640 pJ)
    • 推论:以 10 GB/s 从内存读数据 ≈ 1.6 瓦,而整个移动 GPU 的功率预算约 1 瓦;iPhone 16 电池约 14 瓦时。
  • 结论利用局部性极其重要(Exploiting locality matters!!!);在面向能效优化代码时,重新计算(recompute)比存储再重载(store + reload)更划算
  • 现实类比:为了喝一杯水(一次运算)专程开车去水库(DRAM)取水,油费(能耗)是水本身价值的几百倍;不如把水存在手边(SRAM)或干脆用自来水(重算/近存计算)。

12. Locality & near-memory processing(局部性与近存处理)

  • 定义:解决内存瓶颈的多层次方案(第 72 页总结):应用程序员——调度计算以最大化局部性(最小化数据搬运);新硬件——智能 DRAM 请求调度、把数据搬到离处理器更近处(深层缓存层级、3D 堆叠)、加宽内存系统、研究在内存”内部/附近”执行有限计算(近存计算)、硬件加速压缩。通用原则:把数据存储放在处理器附近;把计算搬到数据存储处;数据压缩(用额外计算换取更少数据传输)。
  • 现实类比:与其每次都从市中心仓库(DRAM)取货,不如在工厂旁边建分仓(缓存/HBM)、甚至让小型加工设备直接开进仓库(近存计算)。

二、代码示例与详细解说(本讲重点)

示例 1:分布式矩阵乘(沿 K 维切分 + ReduceScatter 合并)

# 伪代码:S 个加速器(RDU/GPU)协同计算 C = A[M,K] @ B[K,N]
# 参数:BS=16, M=24576, K=131072, N=8192, S=4(示例为 4 个 socket)
# 策略:沿 K 维切分 → 各算部分结果 → S-way reduce-scatter 合并

import numpy as np
from mpi4py import MPI

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
S    = comm.Get_size()          # 4 个 socket

# 1) 数据分片:A 每行完整 [M, K],但只给本 rank K/S 列;B 每列完整 [K, N],
#    但只给本 rank K/S 行(K 维切分)
A_local = load_tile("A", rows=range(M),    cols=range(rank*K//S, (rank+1)*K//S))  # [M, K/S]
B_local = load_tile("B", rows=range(rank*K//S, (rank+1)*K//S), cols=range(N))      # [K/S, N]

# 2) 本地 GEMM:每个 socket 计算一个 [M, N] 的部分结果
partial = A_local @ B_local        # [M, K/S] × [K/S, N] = [M, N](K 维上只累加了 1/S)

# 3) S-way reduce-scatter:把 4 份 [M, N] 部分结果按列归约合并
#    ReduceScatter:先归约(逐元素相加),再把结果分片
out_local = np.zeros((M, N // S))
for k in range(S):
    # 每个 rank 把自己的 partial 中属于目标 rank 的列分片发出去
    col_chunk = partial[:, k*(N//S):(k+1)*(N//S)]
    comm.reduce_scatter_block(col_chunk, out_local, op=MPI.SUM)

# 最终:out_local 是 C 的 1/S 列分片,所有 rank 各持一份 → 完成分布式 GEMM

【代码做了什么?】 代码实现”分布式矩阵乘”:把 GEMM 的 K 维(归约维)切分到 S 个加速器。每个 socket 只持有 A 的 [M, K/S] 列分片与 B 的 [K/S, N] 行分片,本地算出一个 [M, N] 的”部分结果”——注意这个部分结果在 K 维上只累加了 1/S 项,所以需要把 S 份部分结果逐元素相加才是最终 C。第 3 步用 reduce_scatter_block(即幻灯片第 33 页的 ReduceScatter 原语):先做归约(SUM),再把结果按列分片分发给各 rank——每个 rank 最终持有 C 的 1/S 列。这正是幻灯片第 38 页”Scale-up mapping(Example shown for 4 RDUs)”的软件表达:GEMM(inA[MxK/4], inB_0[K/4xN]) → out0[MxN] ×4 → Reduce-scatter → out[MxN]

【并行机制解说】 对应本讲概念 4(communication primitives:ReduceScatter/AllReduce)、5(tensor parallelism:切 hidden/K 维)、6(distributed matrix multiply)。并行机制:S 个 socket 数据并行地计算不同的 K 分片(每份工作量为 1/S),然后通过 reduce-scatter 通信合并。选 K 维切分的好处:每个 socket 的本地 GEMM 仍是完整的 [M,N] 形状(不损失计算形状),通信只发生在最后一步(一次 S-way reduce-scatter);这等价于 AllReduce = ReduceScatter + AllGather 的前半段。注意本示例未做重叠——这正是示例 3 要解决的”通信成为瓶颈”问题。真实系统(第 39-41 页)会把 reduce-scatter 与 GEMM 流水化重叠,才能在多 socket 下保持 70%+ 利用率。

示例 2:细粒度流水并行(micro-batch 流水训练)

# 伪代码:4 个设备(layer 分片)上的细粒度流水并行训练
# 思想:mini-batch(如 512 样本)拆成多个 micro-batch(如 4 × 128 样本),
#       forward 与 backward 在 micro-batch 间流水推进,消除 pipeline bubble

NUM_DEVICES   = 4          # 模型按层切成 4 段:设备 d 持有第 d 段层
MINI_BATCH    = 512
MICRO_BATCHES = 4
micro_size    = MINI_BATCH // MICRO_BATCHES   # 128 样本/micro-batch

# 每个设备 d 的执行逻辑(1F1B 风格的错位流水,简化为示意):
for device in range(NUM_DEVICES):
    # forward 阶段:micro-batch i 的前向按层顺序穿过各设备
    for i in range(MICRO_BATCHES):
        x = recv_from(device-1, micro_batch=i)     # 接收上一层设备的激活(send-receive)
        h = my_layers.forward(x)                   # 本设备段的 forward
        send_to(device+1, h, micro_batch=i)
    # backward 阶段:梯度反向穿过各设备(错位:设备 0 先做 backward)
    for i in reversed(range(MICRO_BATCHES)):
        g = recv_from(device+1, micro_batch=i)
        grad = my_layers.backward(g)               # 本设备段的 backward
        send_to(device-1, grad, micro_batch=i)

# 关键:设备 0 算完 micro-batch 0 的 forward 后,立即开始 micro-batch 1 的 forward,
# 而不是等整批 forward 全部结束——各设备始终有活干(pipeline 填充)

【代码做了什么?】 代码示意”细粒度流水并行”:模型按层切到 4 个设备(pipeline parallelism),每次迭代的 mini-batch(512 样本)拆成 4 个 micro-batch(128 样本)。每个设备对每个 micro-batch 依次做 forward(从上游收激活、算自己那一段、传给下游),再反向做 backward。与朴素流水的区别在于错位推进:设备 0 完成 micro-batch 0 的 forward 后立刻处理 micro-batch 1,设备 1 收到 micro-batch 0 后开始干活的同时设备 0 已进入 micro-batch 1——流水被”填满”。设备间用 Send-Receive 通信(对应第 37 页表格:PP → Send-Receive)。

【并行机制解说】 对应本讲概念 8(pipeline parallelism & micro-batch)、5(PP 维度)。并行机制:层间流水并行(spatial:不同层在不同设备)+ 时间流水(temporal:多个 micro-batch 在流水线中重叠)。朴素的”一次只跑一个 batch”会让流水线大部分时间处于”只有一两个设备在算”的空闲状态(第 42 页:Under-utilization of compute resources, Low overall throughput);拆 micro-batch 后,每个设备在稳态下几乎始终忙碌。第 44 页的表格展示了实际大模型的并行配置(如 145B 模型:TP=8, PP=8, Model parallel=64, DP=24, 1536 GPUs, batch=2304, 44% peak flops;1T 模型:TP=8, PP=64, DP=6, 3072 GPUs, batch 3072, 49% peak flops)——pipelining schedule、microbatch size、degree of pipeline/tensor/data parallelism 共同决定通信量、pipeline bubble 大小与内存占用。

示例 3:计算-通信重叠(Pipelined AllReduce with Compute)

# 伪代码:把 AllReduce 与 GEMM 重叠,让通信不阻塞计算、不占 HBM 带宽
# 场景:Llama 3.1 8B 的 Down GEMM 之后需要跨设备 AllReduce 累加梯度/激活
# 硬件:RDU(数据流),通信与计算在物理上并行执行

# 朴素(无重叠):通信期间计算单元空闲,HBM 被通信流量占用
def no_overlap(down_out):
    partial = down_gemm(down_out, Wdown)     # 计算阶段
    allreduce(partial)                       # 通信阶段(等!计算空闲)
    return add(partial, residual)            # 后续计算

# 重叠(流水化):把 AllReduce 拆成块,边算边通信
def with_overlap(down_out, num_chunks=4):
    result = []
    # 每个 chunk:先发自己的部分(reduce 的开始),继续算下一个 chunk
    for i in range(num_chunks):
        chunk = down_gemm_chunk(down_out, Wdown, i)   # 算第 i 块(与通信并行)
        partial = reduce_start(chunk)                 # 发起该块的归约(异步)
        result.append(partial)
    allreduce_finish(result)                          # 收尾:所有块的归约完成
    return add(result, residual)
# RDU 上:AllReduce 走专用的芯片间通路(不经过 HBM),与 Down GEMM/权重加载完全重叠

# 关键数据(第 40-41 页):
#   不重叠时:8/16/32 sockets 的理论峰值利用率 88.5%/77%/52%(通信占比上升)
#   重叠后: 实测利用率 72%/75%/79% —— 32 socket 仍保持 70%+

【代码做了什么?】 代码对比”朴素 AllReduce”与”重叠 AllReduce”:朴素版在 GEMM 与 AllReduce 之间严格串行(通信时计算空闲);重叠版把结果/梯度切成块,算一块、异步发起一块的归约、同时继续算下一块——通信与计算在时间上重叠。在 RDU 数据流架构上,AllReduce 走芯片间专用通路(第 59 页:”Fully overlap allreduce with weight load and compute; Allreduce does not consume HBM capacity or bandwidth”),因此通信既不占用 HBM 带宽也不占用计算单元。第 39 页展示了 Llama 3.1 8B 中 “Down GEMM → Add → AllReduce” 在 RDU 0 与 RDU 1 之间的流水化示意(Pipelined AllReduce with Compute, no HBM traffic!)。

【并行机制解说】 对应本讲概念 7(compute-communication overlap)、4(AllReduce)。这是数据中心规模最关键的性能思想:多 socket 扩展时,通信时间随 socket 数增加而增长(8.6→9.7→15 ms),若不重叠,通信在 32 socket 时占掉近一半时间(利用率从 88.5% 掉到 52%);重叠后即使 32 socket 也能维持 70%+ 利用率。要做到重叠需要硬件支撑:独立的通信通路(不占用 HBM)、异步通信原语、数据流式的 token 控制(无需 lock)。GPU 上”需要巨大的互连带宽才能获得高利用率”(第 40 页),因为 GPU 的通信与计算难以像 RDU 那样完全解耦。

示例 4:DRAM 行缓冲访问(row hit vs row miss 的延迟差异)

# 时序示意:读两个字节,展示 DRAM 行缓冲机制对延迟的影响
# 硬件:DRAM 阵列(2 Kbit/row)、row buffer、8-bit data pins、memory controller
# 假设 DDR3-1600 时序,各步骤 ~10 ns(约几个 memory clock)

# 第一次读字节 X(行 R,列 0):row miss(最坏情况)
t=0    Precharge(PRE)        准备位线,~10 ns        # 位线未就绪
t=10   Row activate(RAS)     行 R 数据读入 row buffer,~10 ns
t=20   Column selection(CAS) 选列 0,~10 ns
t=30   Transfer                数据上 8-bit bus → memory controller

# 第二次读同行的字节 X+1(row hit!最佳情况)
t=40   Column selection(CAS) 行已在 row buffer,跳过 PRE 和 RAS
t=50   Transfer                直接传输,~10 ns
# 结论:row hit 延迟 ≈ row miss 延迟的 1/3(跳过 precharge + activate)

# 进一步优化:
# 1) Burst mode:一条 CAS 命令批量传输连续多列,摊销 PRE/RAS 开销
# 2) 多 bank 流水:bank 0 在传输数据时,bank 1 同时做 precharge/activate
# 3) 控制器调度(FR-FCFS):优先服务开放行(最大化 row locality)
# 4) 物理地址按字节粒度交错(interleaved)分布在多个芯片上:
#    64B 缓存行 = 8 个芯片并行各传 8 bit → 首次 64 bit 并行到达,而非串行

【代码做了什么?】 这是”DRAM 工作原理”的时序示意(第 48-62 页):读一个字节要经过 Precharge → Row activate → Column select → Transfer 四步(各约 10 ns);如果下一次访问落在同一行(row hit),可以跳过前两步。幻灯片用”读一个 64-byte cache line 的错误方式 vs 正确方式”对比说明:若 64B 缓存行全部由同一颗芯片串行服务,要 8 次列选+传输;若物理地址按字节粒度交错分布在 8 颗芯片上(DIMM 内),8 颗芯片并行各传 8 bit,首次 64 bit 同时到达——这解释了为什么”物理地址到 DRAM bank/row/column 的映射”是内存控制器的重要职责。

【并行机制解说】 对应本讲概念 9(DRAM basics)、10(memory controller)。这个示例展示了存储系统中的三层并行/流水机制:(1) burst mode——一次命令批量传多个连续列,摊销固定开销(类似”批量传输”摊销启动成本);(2) 多 bank 流水——不同 bank 共享 data pins,但 precharge/activate/传输可以在不同 bank 间流水进行(bank 0 传输时 bank 1 激活),实现高引脚利用率(第 56 页图:RAS/CAS/PRE 交错在不同 bank 上);(3) 多芯片并行(DIMM/channel)——8 芯片并行提供 64-bit 接口,或双通道(dual channel)两个 controller 独立发命令进一步加宽。这些机制共同决定”数据搬运成本”(第 11 概念),也是理解为什么”减少 off-chip 数据访问”能同时省能耗(1200 pJ vs 26 pJ)与提性能(row hit vs row miss)的基础。


三、关键要点

  1. 内存是数据中心计算的根本瓶颈:从 64-bit(CPU)到 6144-bit(H100 HBM3)的总线加宽、3D 堆叠(TSV/中介层)、多 bank 流水、burst mode、智能调度(FR-FCFS)——所有技术都在对抗同一件事:让数据更快、更省地到达计算单元。数据搬运能耗(LPDDR 1200 pJ vs 片内 SRAM 26 pJ)比运算本身贵两个数量级,”Exploiting locality matters!!!”。
  2. AI 模型有多个可切分的维度,每个维度对应一种并行策略:DP(batch)、SP/CP(sequence)、TP(hidden)、PP(layers)、EP(experts);每种策略对应特定通信原语(TP→RS+AG/AR、PP→Send-Receive、EP→All-to-All、DP→RS+AG/AR)。真实训练把多种并行组合使用(如 1T 模型:TP8 × PP64 × DP6 = 3072 GPUs)。
  3. 分布式 GEMM 的本质是”切分 + 归约”:沿 K 维切分 → 各算 [M,N] 部分结果 → reduce-scatter 合并;通信与计算必须重叠,否则 socket 数一多通信占比飙升(32 socket 不重叠利用率仅 52%),重叠后可持续 70%+。
  4. 细粒度流水并行用 micro-batch 消除 pipeline bubble:mini-batch 拆成 micro-batch,forward/backward 错位流水,各设备稳态忙碌;pipelining schedule、microbatch size、并行度配置共同决定通信量、bubble 与内存占用。
  5. 降低能耗的两大思想:用对处理器(专用化)+ 少搬数据(局部性/近存/压缩):能效优化时,重新计算比存储再重载更划算(recompute beats store-and-reload)。
  6. 从单芯片到数据中心的”映射”是全栈问题:应用层(局部性调度)、架构层(智能调度、3D 堆叠、加宽内存、近存计算)、系统层(集群拓扑、通信原语、并行策略)协同解决内存墙。

四、常见陷阱与注意事项

  1. 把”峰值带宽”当”实际带宽”:H100 的 3.2 TB/s 是峰值;DRAM 访问延迟不固定(row hit vs row miss 差 2-3 倍),且引脚利用率受 latency 限制(第 54 页:Data pins in use only a small fraction of time)。只有行局部性好、请求被合并、bank 流水充分时才能接近峰值。
  2. 忽视物理地址映射与交错(interleaving):64B 缓存行若全由同一芯片串行服务,延迟放大 8 倍;正确的字节粒度交错让 8 芯片并行。程序员看不到映射细节,但访问模式(顺序 vs 随机、跨行 vs 同行)直接决定 row hit 率——顺序访问、块状访问(tiling)是最安全的。
  3. 多节点扩展时不考虑通信比例:socket 数翻倍,计算时间减半但通信时间可能上升(8.6→15 ms);不做 compute-communication overlap,利用率随规模崩塌(88.5%→52%)。规模越大,越要重叠
  4. 分布式 GEMM 选错切分维:切 K 维只需一次 reduce-scatter;切 M/N 维需要 AllGather 完整输入,通信量更大。切分维度的选择要与后续算子(如 attention、norm)的通信需求一起考虑。
  5. 流水并行直接套朴素 pipeline:朴素按层切分、一次跑一个 batch 会有大量空闲(bubble),吞吐很低;必须拆 micro-batch 并设计流水 schedule(1F1B 等),否则”并行”反而更慢。
  6. 只优化计算不优化数据搬运:在能效与性能上,数据搬运都是大头(1200 pJ vs 20 pJ 浮点运算;10 GB/s 读取 = 1.6 W ≈ 整个移动 GPU 的功率预算)。优先减少 off-chip 流量(融合、tiling、重算、压缩),而不是盲目堆算力。

五、思考题(带答案)

Q1:为什么 H100 用 6144-bit 接口(6×HBM3×1024-bit)而不是继续加宽 64-bit 的 DDR 总线?请从”带宽 vs 引脚/功耗”与”3D 堆叠”两个角度解释,并说明为什么这对数据中心 AI 计算重要。

答案:加宽平面总线受限于引脚数量、走线面积与功耗(每根引脚都要驱动长距离信号);HBM 用 3D 堆叠把 DRAM 层叠起来、用 TSV(硅通孔) 提供超高密度的垂直连接、通过硅中介层与处理器近距离互连——距离短 → 更宽的接口(1024-bit/stack)可行且更省电(第 5 页:Increase bandwidth, reduce power by chip stacking)。数据中心 AI 模型(如 1T 参数)的权重加载与激活交换需要 TB/s 级带宽,64-bit 总线根本喂不饱上千个 SM/PCU 的访存需求;HBM 的”更多带宽、高能效、小尺寸”三大优势让它成为 GPU/加速器的标配(H100 80 GB @ 3.2 TB/s)。这也是”内存墙”问题在硬件侧的主要解法之一。

Q2:给定一个 145B 参数的 Transformer(序列长 2048、词表 51200),第 44 页表格建议 TP=8、PP=8、DP=24、1536 块 GPU。请解释:为什么 TP 要切 hidden 维、PP 要切层、DP 要复制模型,三者各自解决什么问题?它们各自的主要代价是什么?

答案:(1) TP(切 hidden)解决”单卡装不下单层权重/激活”:把每层权重按 hidden 维劈开,多卡协作算一层;代价是每层后都需要 AllReduce/RS+AG 通信(通信量随 hidden 增大而增大)。(2) PP(切层)解决”整模型放不下”:不同层放不同设备,数据流水流过;代价是引入 pipeline bubble 与设备间 Send-Receive 通信(可通过 micro-batch 流水缓解)。(3) DP(复制模型)解决”吞吐不够”:多份完整模型副本并行处理不同 batch,是扩展吞吐的主要手段;代价是每步梯度 AllReduce(通信量随模型大小线性增长)。三者组合让 145B 模型在 1536 卡上达到约 44% 峰值 flops——多维度并行是”放得下 + 算得快 + 通得了”的权衡结果。

Q3:第 41 页数据显示:32 socket 时 reduce-scatter 理论时间 15 ms、compute roofline 16.5 ms,若不重叠理论利用率仅 52%,重叠后实测 79%。请解释为什么”不重叠时利用率会低于 50%(不是 16.5/(16.5+15)≈52%)”,以及重叠为什么能超过这个比例。

答案:不重叠的利用率上限 ≈ compute/(compute+comm) = 16.5/(16.5+15) ≈ 52%,这是”通信完全串行”的理论上界;52% 正是这个式子(第 41 页”Theoretical Peak utilization without overlap”)。实际可能更低,因为还有 kernel 启动、同步、负载不均等额外开销。重叠后通信与计算并行,理论上利用率可接近 100%(只要通信通路与计算通路不争抢资源),实测 79% 已接近”通信完全隐藏”的极限(剩余 21% 来自同步开销、流水线填充/排空、负载不均等)。这也解释了第 40 页的结论:GPU 上通信时间随 socket 数增加而增加、不重叠时通信成为瓶颈,因此 GPU 需要巨大的互连带宽(把通信时间压短),而 RDU 靠重叠(把通信藏到计算背后)在同样的互连上获得高利用率——两种不同的”躲开通信瓶颈”策略。


六、补充阅读:LLM Serving 相关概念(非本讲幻灯片内容)

说明:本讲 Fall 2025 幻灯片聚焦数据中心存储系统与并行策略,未展开 LLM 推理服务(serving)的实现细节。以下为与该主题直接相关、常被问到的概念简介(基于业界通用知识,供延伸学习,不作为本讲考试范围依据)。

  • LLM serving(推理服务):把训练好的大模型部署为可响应在线请求的服务。与训练(追求吞吐、可批处理)不同,serving 还要满足延迟(latency)约束——每个用户的请求都要尽快得到回复。
  • Prefill(预填充)阶段:处理用户 prompt 的阶段:一次性把整个 prompt 的所有 token 并行计算(GEMM 密集、算力受限、compute-bound),产出首个输出 token 并写入 KV cache。
  • Decode(解码)阶段:逐 token 自回归生成阶段:每步只算一个新 token,但需要读取该序列全部的 KV cache——访存密集、带宽受限(memory-bound),计算强度远低于 prefill。
  • KV cache(键值缓存):Transformer 自回归解码时,把已生成 token 的 Key/Value 张量缓存起来,避免每步重复计算历史 token 的注意力;其大小随序列长度与 batch 规模线性增长,常成为 serving 的内存瓶颈(HBM 容量受限时可用 KV cache compression——本讲 HBM4 幻灯片中提到的”KV cache compression”正是指这类技术)。
  • Batching / continuous batching(批处理 / 连续批处理):把多个请求合并成一批同时处理以提高 GPU 利用率(特别是把 compute-bound 的 prefill 与 memory-bound 的 decode 混批,或不断把新到的请求插入正在执行的批次,避免等待整批完成);连续批处理显著提升 serving 吞吐,代价是需要动态管理每个序列的 KV cache 与调度策略。

这些概念与第 12 讲的主题紧密相连:prefill/decode 的访存特征差异决定了”为什么带宽与局部性如此重要”,KV cache 的管理体现了”数据搬运成本主导”的设计原则,而 continuous batching 则是”在数据中心规模最大化加速器利用率”的 serving 侧答案。