第4章:存储系统与数据流

在NPU设计中,存储系统往往是决定整体性能的关键瓶颈。本章深入探讨NPU存储层次设计、数据重用策略、DMA机制以及片上网络基础,帮助读者理解如何通过精心的存储系统设计来最大化NPU的计算效率。我们将以200 TOPS的设计目标为例,定量分析各级存储的带宽需求,并探讨不同数据流模式下的优化策略。

4.1 存储层次设计

4.1.1 存储器技术对比

NPU的存储层次通常包含三个主要层级,每层在容量、带宽、延迟和功耗方面都有不同的权衡:

片上SRAM特性

片上SRAM提供最高的带宽和最低的访问延迟,但容量受限且成本高昂。典型参数:

  • 访问延迟:1-2 cycles
  • 带宽密度:~10 TB/s/mm²(7nm工艺)
  • 功耗:~1 pJ/bit access
  • 容量:通常10-100 MB(占芯片面积的30-50%)

SRAM的物理实现通常采用6T或8T单元结构。6T SRAM单元包含6个晶体管,面积约为0.05 μm²(7nm工艺),而8T SRAM提供独立的读写端口,避免读干扰但面积增加约30%。在NPU设计中,通常采用混合策略:权重缓存使用高密度6T SRAM,而需要频繁读写的激活缓存使用8T SRAM。

SRAM的设计需要在多个维度进行权衡。从电路层面看,降低工作电压可以显著减少功耗,但会增加访问延迟并降低噪声容限。现代NPU通常采用多电压域设计,关键路径上的SRAM运行在标称电压(如0.8V),而非关键路径可以降至0.6V,实现30%的功耗节省。从架构层面看,SRAM的组织方式直接影响访问效率。分布式SRAM设计将存储分散到各个计算单元附近,减少了布线延迟但增加了管理复杂度。相比之下,共享SRAM池提供了更好的容量利用率,但需要更复杂的仲裁机制。

在自动驾驶场景中,SRAM的可靠性尤为重要。软错误率(SER)在先进工艺节点下显著增加,7nm工艺下的SER约为28nm的3-4倍。因此需要采用ECC(Error Correction Code)保护,典型方案是SECDED(Single Error Correction, Double Error Detection),开销约12.5%的额外存储。对于关键数据如神经网络权重,可能需要更强的保护如DEC-TED(Double Error Correction, Triple Error Detection)。此外,老化效应如NBTI(Negative Bias Temperature Instability)会导致SRAM性能随时间退化,需要在设计时预留10-15%的时序裕量。

对于200 TOPS的NPU,假设MAC利用率为80%,nvfp4精度下: $$\text{所需带宽} = 200 \times 10^{12} \times 0.8 \times 3 \times 4 \text{ bits/s} = 1.92 \text{ Pb/s} = 240 \text{ TB/s}$$ 其中因子3来自两个输入操作数和一个输出,因子4是nvfp4的位宽。

这个带宽需求远超单片SRAM所能提供,因此需要采用分布式SRAM架构。假设采用1024个SRAM bank,每个bank需要提供: $$\text{Bank带宽} = \frac{240 \text{ TB/s}}{1024} = 234 \text{ GB/s}$$ 在1 GHz时钟频率下,每个bank需要234位宽的接口,这在物理实现上是可行的。

HBM技术演进

HBM (High Bandwidth Memory) 提供了容量和带宽的良好平衡:

HBM代际对比:
         HBM2E    HBM3     HBM3E
带宽      460      819      1230    GB/s/stack
容量      16       24       36      GB/stack  
功耗效率   7        5.5      4.5     pJ/bit
I/O宽度   1024     1024     1024    bits
频率      3.6      6.4      9.6     Gbps/pin
电压      1.2      1.1      1.1     V

HBM采用2.5D封装技术,通过硅中介层(interposer)实现与主芯片的连接。每个HBM stack包含8-12层DRAM die,通过TSV(Through Silicon Via)垂直互连。对于200 TOPS的NPU设计,典型配置为4个HBM3 stack,提供总计3.2 TB/s的带宽和96 GB的容量。

HBM的关键优势在于其极短的物理距离(<10mm)和宽I/O接口,相比GDDR6降低了约3倍的pJ/bit访问能耗。然而,HBM的成本约为DDR的5-8倍,且需要先进封装技术支持。

HBM的物理实现涉及多项关键技术。TSV是实现垂直互连的核心,典型TSV直径5-10μm,深度50-100μm,间距40-50μm。每个TSV的寄生电容约20-30fF,电阻约1-2Ω,这些参数直接影响信号完整性。微凸块(micro-bump)技术用于die间连接,间距通常40-55μm,每个凸块可承载约100mA电流。硅中介层采用65nm或更成熟的工艺制造,包含再分布层(RDL)用于信号路由。信号完整性是HBM设计的关键挑战,需要考虑串扰、反射和电源噪声。差分信令和伪差分架构被广泛采用,配合DBI(Data Bus Inversion)减少同步开关噪声。

HBM的控制器设计也颇具挑战。PHY层需要处理1024位宽的并行接口,实现精确的时序校准。训练序列包括ZQ校准、读写时序训练和周期性的重新训练以补偿温度和电压变化。刷新管理采用per-bank刷新或全bank组刷新,刷新间隔通常为3.9μs(高温)或7.8μs(常温)。错误处理机制包括链路层的CRC保护和ECC,典型配置为每128位数据配8位ECC,可纠正单比特错误。温度管理至关重要,HBM3支持实时温度监控和动态频率调节,当结温超过85°C时自动降频。

DDR与GDDR权衡

DDR提供大容量但带宽有限,GDDR则在两者间取得平衡:

  • DDR5:~50 GB/s/channel,容量可达128GB/DIMM
  • GDDR6X:~80 GB/s/chip,容量2-4GB/chip
  • 功耗:DDR ~20 pJ/bit,GDDR ~15 pJ/bit

在自动驾驶场景中,需要存储大量的高精地图、历史轨迹和中间特征图。一个典型的BEV感知模型可能需要:

  • 输入缓存:6个相机 × 1920×1080×3 × 4 bytes = 150 MB
  • 特征图缓存:多尺度特征 ~500 MB
  • 历史帧缓存:10帧 × 200 MB = 2 GB
  • 模型权重:~1 GB(INT8量化后)

因此,边缘端NPU通常采用混合存储架构:

  1. 片上SRAM(50 MB):存储当前计算tile和部分权重
  2. HBM/GDDR(8-16 GB):存储完整模型和中间结果
  3. DDR(32-64 GB):存储历史数据和预取缓冲

4.1.2 存储带宽需求计算

算子带宽需求分析

以矩阵乘法 $C = A \times B$ 为例,计算不同数据流模式的带宽需求:

设矩阵维度为 $M \times K$ 和 $K \times N$,计算量为 $2MNK$ FLOPs。

无重用情况下的理论带宽需求: $$B_{\text{no-reuse}} = \frac{(MK + KN + MN) \times \text{bits}}{2MNK / \text{FLOPS}} = \frac{(M+N+K) \times \text{bits}}{2K} \times \text{FLOPS}$$ 引入重用后,实际带宽需求取决于片上缓存大小 $S$:

  • Output Stationary (OS):缓存输出矩阵块 $$B_{OS} = \frac{2 \times \text{bits} \times \text{FLOPS}}{K}$$

  • Weight Stationary (WS):缓存权重矩阵块 $$B_{WS} = \frac{2 \times \text{bits} \times \text{FLOPS}}{M}$$ 带宽需求的精确建模需要考虑多个因素。首先是数据布局的影响,行主序(row-major)和列主序(column-major)会导致不同的缓存行为。对于矩阵乘法,采用分块矩阵布局(blocked layout)可以改善空间局部性。其次是预取策略的影响,硬件预取器可能会额外加载不必要的数据,导致实际带宽需求比理论值高20-30%。第三是写回策略的影响,write-through策略会立即写回所有修改,而write-back策略只在替换时写回,后者通常更节省带宽。

在实际NPU实现中,带宽利用效率很少能达到理论峰值。造成这种差距的原因包括:访问模式的不规则性导致DRAM页面命中率下降,从典型的70%降至30-40%;读写切换造成的总线周转时间(bus turnaround time),每次切换损失10-20个时钟周期;刷新操作占用的带宽,约7-8%的时间用于DRAM刷新;仲裁和调度开销,特别是在多主设备共享内存时。因此,实际设计中通常需要预留30-40%的带宽裕量。

实际案例:Transformer中的Attention计算

考虑自动驾驶中的多相机BEV Transformer,序列长度 $L = 10000$(100×100的BEV网格),嵌入维度 $d = 256$:

  1. Q、K、V投影:$3 \times L \times d^2$ 计算量 - 带宽需求:$\frac{3Ld(L+d) \times 4 \text{ bits}}{3Ld^2 \times 2} = \frac{2(L+d)}{d} = 78.5$ bits/FLOP

  2. Attention分数计算:$Q \times K^T$,计算量 $2L^2d$ - 带宽需求:$\frac{2Ld \times 4 + L^2 \times 4}{2L^2d} = \frac{4}{d} + \frac{2}{L} ≈ 0.016$ bits/FLOP

  3. 加权求和:$\text{Softmax}(\text{scores}) \times V$,计算量 $2L^2d$ - 带宽需求:类似于步骤2

可见,Attention的不同阶段对带宽要求差异巨大,需要动态调整数据流策略。

带宽效率指标

定义带宽效率 $\eta_B$ 为实际计算吞吐量与理论峰值的比值: $$\eta_B = \frac{\text{实际FLOPS}}{\min(\text{计算峰值}, \text{带宽} \times \text{算术强度})}$$ 其中算术强度(Arithmetic Intensity)定义为: $$AI = \frac{\text{FLOPs}}{\text{Bytes accessed}}$$ Roofline模型应用

对于200 TOPS NPU,假设HBM带宽3.2 TB/s,构建Roofline模型:

  1. 计算屋顶线:200 TOPS(nvfp4)
  2. 内存屋顶线:$3.2 \text{ TB/s} \times AI$
  3. 平衡点:$AI_{balance} = \frac{200 \times 10^{12}}{3.2 \times 10^{12}} = 62.5$ FLOPS/byte

常见算子的算术强度:

  • 全连接层(1024×1024):$AI = \frac{2 \times 1024^3}{3 \times 1024^2 \times 4} ≈ 171$ FLOPS/byte
  • 1×1卷积:$AI ≈ \frac{2 \times C_{out}}{4}$ (假设输入已缓存)
  • 3×3卷积:$AI ≈ \frac{2 \times 9 \times C_{out}}{4 \times 9 + 4}$
  • Depthwise 3×3:$AI ≈ \frac{18}{40} = 0.45$ FLOPS/byte

可见,depthwise卷积严重受限于内存带宽,而大矩阵乘法则受限于计算能力。

4.1.3 Bank冲突与访问模式优化

Bank组织结构

典型的多Bank SRAM组织:

      ┌─────────────────────────┐
      │    Crossbar Switch      │
      └─────┬───┬───┬───┬───────┘
            │   │   │   │
         ┌──▼─┐ │   │ ┌──▼─┐
         │Bank│ │   │ │Bank│
         │ 0  │ │   │ │ N-1│
         └────┘ │   │ └────┘
              ┌─▼─┐ └─▼─┐
              │Bank│ ... │
              │ 1  │     │
              └────┘     │

Bank数量选择需要平衡面积开销和访问灵活性。常见配置:

  • Bank数量:16-64
  • 每Bank容量:64-256 KB
  • 端口数:1R1W或2R1W

多Bank SRAM的设计涉及复杂的微架构决策。交叉开关(crossbar)是连接请求端口和存储bank的关键组件,其复杂度为O(N²),其中N是端口数。为降低复杂度,常采用层次化交叉开关或Benes网络。仲裁逻辑需要在单周期内解决多个访问请求的冲突,常用的仲裁算法包括固定优先级、轮询(round-robin)和矩阵仲裁器。对于N个请求者和M个资源,矩阵仲裁器需要N×M个比较器,能在O(log N)的延迟内完成仲裁。

Bank的物理布局对性能有重要影响。相邻bank之间的布线延迟差异可能导致时序不平衡,需要通过精心的floorplan来优化。H-tree布局是一种常用方案,能够均衡从控制器到各bank的延迟。另一个关键考虑是电源网络设计,大量bank同时切换可能导致严重的电源噪声(IR drop)。解决方案包括交错的bank激活时序、分布式去耦电容和独立的电源域。功耗优化也很重要,未使用的bank可以进入低功耗状态,通过时钟门控和电源门控技术可节省50-70%的静态功耗。

访问模式分析

以2D卷积为例,不同的数据布局导致不同的访问模式:

  1. NCHW布局:连续访问同一通道的空间维度 - 优点:空间局部性好 - 缺点:通道间切换开销大

  2. NHWC布局:连续访问同一位置的所有通道 - 优点:适合depthwise操作 - 缺点:大通道数时缓存利用率低

  3. NCHWc布局(通道分块):将C维度分块为C/c × c - 结合两种布局优点 - c通常选择为SIMD宽度(如16或32)

实际访问模式优化案例

以YOLOv8的C2f模块为例(输入256×80×80,输出256×80×80):

采用NCHW布局时的Bank访问模式:

时刻t:   Bank[0]: C0,H0,W0-W15
         Bank[1]: C0,H0,W16-W31
         ...
         Bank[4]: C0,H1,W0-W15

问题:当卷积kernel跨行时,会访问Bank[0]和Bank[4],可能造成冲突。

优化方案:

  1. Padding对齐:将宽度从80 padding到84(Bank数的倍数)
  2. 交织存储:$\text{Bank}_{id} = (C \times 7 + H \times 13 + W) \mod N_{banks}$
  3. 双缓冲:一个buffer用于当前行,另一个预取下一行

这样可将Bank冲突率从15%降低到2%以下。

冲突消除策略

  1. 地址交织(Interleaving): $$\text{Bank}_{\text{id}} = (\text{addr} >> \text{offset}) \bmod N_{\text{banks}}$$

  2. 素数Bank数量:选择素数个Bank(如17、31)减少规律性冲突

  3. 双缓冲(Double Buffering):计算与数据传输重叠

Bank仲裁器设计

多端口Bank访问需要仲裁机制,常见策略:

  1. 固定优先级:计算单元 > DMA > 调试接口
  2. 轮询(Round-Robin):公平但可能降低关键路径性能
  3. 加权轮询:根据请求源的带宽需求分配权重
  4. 信用机制(Credit-based):每个请求源有信用额度

仲裁延迟模型: $$T_{access} = T_{arbitration} + T_{bank_access} + T_{routing}$$ 典型值(1GHz时钟):

  • $T_{arbitration}$:1 cycle(简单仲裁)或2-3 cycles(复杂仲裁)
  • $T_{bank_access}$:1-2 cycles
  • $T_{routing}$:1 cycle(近距离)或2-3 cycles(跨片)

存储一致性保证

在多个计算单元共享Bank时,需要保证数据一致性:

  1. 写后读(RAW)hazard:通过scoreboard跟踪pending写操作
  2. 写后写(WAW)hazard:保证写操作的顺序
  3. 原子操作支持:实现atomic_add等操作用于累加

硬件实现通常采用:

  • 版本号机制:每个地址关联版本号
  • 锁机制:细粒度锁保护关键区域
  • 事务内存:支持回滚的投机执行

4.2 数据重用模式

数据重用是提高NPU能效的核心策略。通过最大化片上数据的重用次数,可以显著降低对外部存储器的访问需求,从而减少功耗并提高性能。

4.2.1 重用分类:Temporal vs Spatial

时间重用(Temporal Reuse)

时间重用指同一数据在不同时间被同一计算单元多次使用: $$\text{时间重用度} = \frac{\text{数据使用次数}}{\text{数据加载次数}}$$ 以矩阵乘法为例,当计算 $C_{ij} = \sum_{k} A_{ik} \times B_{kj}$ 时:

  • $A_{ik}$ 在计算 $C_{ij}$ 的所有 $j$ 值时被重用
  • $B_{kj}$ 在计算 $C_{ij}$ 的所有 $i$ 值时被重用

时间重用的效率取决于数据的生命周期管理。在理想情况下,数据应该在其整个使用周期内都保持在片上存储中。然而,有限的片上存储容量要求精心的调度策略。常用的管理策略包括LRU(Least Recently Used)替换、基于重用距离的替换和编译器指导的显式管理。重用距离定义为两次访问同一数据之间访问其他唯一数据的数量,这个指标直接关联到所需的缓存大小。对于规则的访问模式如矩阵乘法,重用距离可以静态分析得出,而对于不规则模式如稀疏矩阵运算,则需要运行时profiling。

时间重用的一个关键优化是循环变换。循环交换(loop interchange)可以改变数据访问顺序,使得重用距离最小化。循环分块(loop tiling)将大循环分解为嵌套的小循环,确保工作集适配缓存大小。循环融合(loop fusion)将多个循环合并,增加数据重用机会。这些变换的合法性需要满足数据依赖约束,可以通过多面体模型(polyhedral model)形式化分析。

空间重用(Spatial Reuse)

空间重用指同一数据同时被多个计算单元使用:

     广播数据
        │
    ┌───▼───┐
    │       │
  ┌─▼─┐   ┌─▼─┐
  │PE0│   │PE1│  ... │PEn│
  └───┘   └───┘      └───┘

空间重用的效率取决于:

  • PE阵列的组织方式
  • 数据广播网络的设计
  • 计算的并行维度选择

重用优化的数学模型

给定片上存储容量 $S$,优化目标是最小化数据传输量 $D$: $$\min D = \sum_{i} \frac{s_i \times u_i}{r_i}$$ 其中:

  • $s_i$:数据 $i$ 的大小
  • $u_i$:数据 $i$ 的使用次数
  • $r_i$:数据 $i$ 的重用次数

约束条件:$\sum_{i \in \text{on-chip}} s_i \leq S$

具体示例:MobileNet中的Depthwise Separable卷积

考虑MobileNetV3中的一个典型块,输入112×112×24,输出112×112×96:

  1. Depthwise 3×3: - 计算量:$112^2 \times 24 \times 9 \times 2 = 5.4M$ FLOPs - 数据量:

    • 输入:$112^2 \times 24 \times 4 = 1.2$ MB
    • 权重:$3^2 \times 24 \times 4 = 0.9$ KB
    • 输出:$112^2 \times 24 \times 4 = 1.2$ MB
    • 算术强度:$\frac{5.4M}{2.4M} = 2.25$ FLOPs/byte
  2. Pointwise 1×1: - 计算量:$112^2 \times 24 \times 96 \times 2 = 57.8M$ FLOPs - 数据量:

    • 输入:$112^2 \times 24 \times 4 = 1.2$ MB(可重用上一步输出)
    • 权重:$24 \times 96 \times 4 = 9.2$ KB
    • 输出:$112^2 \times 96 \times 4 = 4.8$ MB
    • 算术强度:$\frac{57.8M}{6.0M} = 9.6$ FLOPs/byte

优化策略:

  1. 融合执行:将depthwise和pointwise融合,避免中间结果写回
  2. 空间tiling:将112×112分成7×7个16×16的tile
  3. 通道分块:将96个输出通道分成3批,每批32通道

通过这些优化,可将总数据传输量从8.4 MB降低到2.1 MB,提高4倍性能。

4.2.2 Loop Tiling与Blocking策略

基本Tiling原理

Loop tiling将大的迭代空间分解为小块,使每块的工作集适配片上缓存:

原始循环:

for i = 0 to M-1:
    for j = 0 to N-1:
        for k = 0 to K-1:
            C[i][j] += A[i][k] * B[k][j]

Tiled版本:

for i_outer = 0 to M-1 step T_i:
    for j_outer = 0 to N-1 step T_j:
        for k_outer = 0 to K-1 step T_k:
            // 内层循环处理tile
            for i = i_outer to min(i_outer+T_i, M)-1:
                for j = j_outer to min(j_outer+T_j, N)-1:
                    for k = k_outer to min(k_outer+T_k, K)-1:
                        C[i][j] += A[i][k] * B[k][j]

Tile大小选择

最优tile大小需要满足:

  1. 容量约束:$T_i \times T_k + T_k \times T_j + T_i \times T_j \leq S$
  2. 带宽平衡:使计算时间与数据传输时间相匹配

对于计算密度为 $\rho$ FLOPS/cycle 的NPU: $$T_{\text{opt}} = \sqrt{\frac{S \times \rho \times f_{\text{clk}}}{3 \times BW}}$$ 其中 $f_{\text{clk}}$ 是时钟频率,$BW$ 是内存带宽。

多级Tiling

针对多级存储层次,采用递归tiling:

L3 Cache Tile: 256×256×256
    │
    └─► L2 Cache Tile: 64×64×64
            │
            └─► L1 Cache Tile: 16×16×16
                    │
                    └─► Register Tile: 4×4×4

每级的tile大小比例通常遵循: $$\frac{T_{L_{i+1}}}{T_{L_i}} \approx \sqrt[3]{\frac{S_{L_{i+1}}}{S_{L_i}}}$$ Tiling搜索空间优化

对于一个6层嵌套循环的卷积操作(N, C, H, W, K, R, S),tiling参数空间为: $$|\mathcal{S}| = \prod_{i=1}^{7} d_i$$ 其中$d_i$是维度$i$的可能分块大小数。对于典型的224×224×256卷积层,搜索空间可达$10^{15}$。

常用优化方法:

  1. 解析模型:基于屋顶线模型预测性能 $$T_{exec} = \max(T_{compute}, T_{memory})$$

  2. 机器学习方法:使用XGBoost/LSTM预测最优tiling - 训练数据:随机采样的10000个配置 - 特征:tile大小、重用率、带宽需求 - 目标:实测执行时间

  3. 遗传算法:平衡探索与利用 - 初始种群:基于启发式规则 - 适应度函数:$f = \alpha \times \text{FLOPS} - \beta \times \text{Energy}$ - 变异策略:随机扰动tile大小

实践中,通常结合三种方法:解析模型快速筛选,ML模型精细调优,遗传算法处理边缘情况。

4.2.3 Dataflow分类:WS/OS/RS

Weight Stationary (WS)

权重驻留数据流中,权重保持在PE本地,输入激活和部分和在PE间流动:

特征:

- 每个PE存储部分权重
- 输入激活广播或单播
- 部分和累加并传递

优势:

- 权重重用最大化
- 适合batch size大的场景
- 减少权重读取能耗

劣势:

- 输入/输出数据传输开销大
- irregular网络支持差

数学表达: $$\text{数据传输量}_{WS} = \text{Batch} \times (H \times W \times C_{in} + H \times W \times C_{out})$$ Output Stationary (OS)

输出驻留数据流中,部分和保持在PE本地直到完成累加:

特征:

- 每个PE负责特定输出元素
- 权重和激活流经PE
- 部分和本地累加

优势:

- 部分和不需要传输
- 减少累加器带宽需求
- 适合深度网络

劣势:

- 权重和激活重用受限
- PE利用率可能不均

数学表达: $$\text{数据传输量}_{OS} = K \times H \times W \times (C_{in} + C_{out})$$ Row Stationary (RS)

行驻留数据流试图在PE内最大化所有数据类型的重用:

特征:

- 1D卷积原语映射到PE行
- 权重、激活、部分和都有重用
- 灵活支持不同层类型

优势:

- 能量效率最优
- 支持多种数据流模式
- 硬件利用率高

劣势:

- 控制复杂度高
- 编译器映射挑战大

能量模型比较: $$E_{total} = E_{RF} \times N_{RF} + E_{NoC} \times N_{NoC} + E_{DRAM} \times N_{DRAM}$$ 其中典型能量成本(45nm):

  • $E_{RF}$ ≈ 1 pJ
  • $E_{NoC}$ ≈ 2-6 pJ
  • $E_{DRAM}$ ≈ 200 pJ

实际案例:Eyeriss v2的RS数据流实现

Eyeriss v2采用分层式RS数据流,针对不同层类型自适应调整:

  1. CONV层映射: - 每个PE处理1D卷积(1×1×K) - 水平PE共享输入激活 - 垂直PE共享部分和 - 对角PE共享权重

  2. FC层映射: - 切换到OS模式 - 每个PE负责1个输出神经元 - 权重广播至所有PE

  3. Depthwise层映射: - 每个PE处理一个通道 - 无需PE间通信 - 最大化并行度

能效对比(AlexNet CONV2层):

  • WS:1.4 TOPS/W
  • OS:1.6 TOPS/W
  • RS:2.5 TOPS/W

RS通过灵活的数据流切换,在不同层类型上都能达到较高效率。但代价是控制逻辑复杂度增加约40%,面积开销增加15%。

4.3 DMA设计与数据预取

DMA(Direct Memory Access)是NPU中实现计算与数据传输重叠的关键组件。通过精心设计的DMA系统和预取策略,可以有效隐藏内存访问延迟,提高整体系统性能。

4.3.1 DMA架构设计

基本DMA架构

现代NPU的DMA控制器通常包含以下组件:

┌─────────────────────────────────────┐
│         DMA Controller              │
├──────────┬──────────┬──────────────┤
│ Command  │ Address  │   Data       │
│  Queue   │Generator │   Buffers    │
├──────────┴──────────┴──────────────┤
│         Arbitration Logic           │
└──────────┬──────────────────────────┘
           │
     ┌─────▼─────┐
     │   Memory  │
     │ Interface │
     └───────────┘

关键设计参数:

  • 通道数量:典型8-32个独立DMA通道
  • 突发长度:64-256字节(匹配内存系统)
  • 队列深度:16-64个待处理请求
  • 支持模式:线性、2D/3D块传输、scatter-gather

多通道DMA设计考量

在自动驾驶NPU中,不同通道通常专门用于特定数据类型:

  1. 相机数据通道(6个): - 实时从MIPI/GMSL接口接收 - 时延要求:< 10ms - 带宽:6 × 4MP × 30fps × 12bit = 3.5 GB/s

  2. 特征图通道(4个): - 在多个网络层间传输中间特征 - 支持2D/3D tensor转置 - 带宽:~20 GB/s

  3. 权重加载通道(2个): - 预加载下一层权重 - 支持2:4稀疏解压 - 带宽:~5 GB/s

  4. 输出通道(2个): - 将结果写回主存 - 支持NMS后处理 - 带宽:~2 GB/s

通道优先级设置: $$P_i = \alpha_i \times \text{latency_sensitivity} + \beta_i \times \text{bandwidth_demand}$$ 其中相机数据通道的$\alpha$最高,确保实时性。

带宽分配策略

多通道DMA的带宽分配可建模为优化问题: $$\max \sum_{i=1}^{N} w_i \times \min(r_i, b_i)$$ 约束条件:$\sum_{i=1}^{N} b_i \leq B_{total}$

其中:

  • $w_i$:通道 $i$ 的优先级权重
  • $r_i$:通道 $i$ 的请求带宽
  • $b_i$:分配给通道 $i$ 的带宽
  • $B_{total}$:总可用带宽

地址生成模式

支持复杂访问模式的地址生成器:

  1. 线性模式: $$\text{addr} = \text{base} + \text{offset} \times \text{stride}$$

  2. 2D块模式: $$\text{addr} = \text{base} + x \times \text{stride}_x + y \times \text{stride}_y$$

  3. 循环缓冲模式: $$\text{addr} = \text{base} + (\text{offset} \bmod \text{size})$$

  4. 3D tensor模式(用于BEV特征): $$\text{addr} = \text{base} + z \times S_z + y \times S_y + x \times S_x$$ 其中$S_z = H \times W \times C$, $S_y = W \times C$, $S_x = C$

  5. 稀疏索引模式(用于2:4稀疏): $$\text{addr} = \text{base} + \text{index}[i] \times \text{elem_size}$$ 地址生成器的硬件实现

     ┌─────────────────┐
       Base Register  
     └───────┬─────────┘
              
     ┌────────┴─────────┐
        Counter Bank   
       [X][Y][Z][N]    
     └───────┬──────────┘
              
     ┌────────┴─────────┐
       Stride Multiply 
     └────────┬─────────┘
              
     ┌────────┴─────────┐
        Accumulator    
     └────────┬─────────┘
              
         Final Address

关键优化:

  • 使用移位代替乘法(当stride为2的幂)
  • 多级计数器级联,减少进位链延迟
  • 预计算常用stride组合

4.3.2 描述符与链表管理

描述符格式

典型的DMA描述符包含:

struct DMADescriptor {
    uint64_t src_addr;      // 源地址
    uint64_t dst_addr;      // 目标地址
    uint32_t length;        // 传输长度
    uint16_t src_stride;    // 源跨步
    uint16_t dst_stride;    // 目标跨步
    uint8_t  burst_len;     // 突发长度
    uint8_t  flags;         // 控制标志
    uint64_t next_desc;     // 下一描述符指针
};

链表管理机制

支持多种链表组织方式:

  1. 单链表:简单但灵活性有限
  2. 循环链表:适合重复的传输模式
  3. 树形结构:支持条件分支和复杂控制流

描述符预取优化:

  • Shadow寄存器:预加载下一个描述符
  • 描述符缓存:减少重复读取开销
  • 批量更新:减少描述符写回次数

描述符压缩技术

为减少描述符存储开销,可采用压缩编码:

  1. 差分编码:存储与前一描述符的差值 $$\text{desc}_i = \text{desc}_{i-1} + \Delta_i$$

  2. 模板编码:预定义常用模板 - 模板0:连续线性传输 - 模板1:2D块传输(图像) - 模板2:3D tensor传输

  3. 位域压缩:减少未使用位

原始:64bit地址 + 32bit长度 + 16bit stride = 112 bits
压缩:32bit基址 + 16bit偏移 + 16bit长度 + 8bit stride = 72 bits

通过这些技术,可将描述符存储开销减少40-60%。

4.3.3 预取策略与隐藏延迟

静态预取策略

编译时确定的预取模式:

计算时间线:|--Compute Layer N--|--Compute Layer N+1--|
数据传输:      |--Prefetch N+1--|    |--Prefetch N+2--|

预取距离计算: $$D_{prefetch} = \lceil \frac{L_{mem}}{T_{compute}} \rceil$$ 其中:

  • $L_{mem}$:内存访问延迟
  • $T_{compute}$:计算一个tile的时间

动态预取策略

运行时自适应的预取机制:

  1. 基于历史的预测: $$\text{addr}_{next} = \text{addr}_{current} + \alpha \times \Delta_{history}$$

  2. 基于stride的检测: - 检测连续访问的stride模式 - 自动触发相应的预取请求

双缓冲与流水线

双缓冲机制的时序分析:

Buffer A: |--Load--|--Compute--|--Store--|
Buffer B:          |--Load--|--Compute--|--Store--|
时间:     0       T        2T        3T        4T

理想情况下的效率: $$\eta_{pipeline} = \frac{T_{compute}}{\max(T_{compute}, T_{load}, T_{store})}$$ 实现200 TOPS的系统,假设:

  • 计算密度:1000 GFLOPS/s
  • 所需数据量:100 GB/s
  • DMA延迟:100 cycles

则需要的预取深度: $$N_{prefetch} = \lceil \frac{100 \text{ cycles} \times 1 \text{ GHz}}{1000 \text{ GFLOPS} / 100 \text{ GB/s}} \rceil = 10$$ 预取性能建模

考虑预取准确率和覆盖率: $$\text{Speedup} = \frac{1}{(1-h) + \frac{h}{1+\alpha \times p}}$$ 其中:

  • $h$:预取命中率
  • $p$:预取覆盖率(隐藏的延迟比例)
  • $\alpha$:预取开销系数

实际测量数据(ResNet-50):

  • 静态预取:$h=0.95$, $p=0.8$, 加速1.7倍
  • 动态预取:$h=0.85$, $p=0.9$, 加速1.6倍
  • 混合策略:$h=0.92$, $p=0.85$, 加速1.75倍

4.4 片上网络(NoC)基础

片上网络是NPU内部各计算单元、存储单元和I/O接口之间的通信基础设施。良好的NoC设计对于实现高效的数据流和低延迟通信至关重要。在200 TOPS级别的NPU设计中,NoC需要提供数百TB/s的聚合带宽,同时保持纳秒级的延迟。

4.4.1 NoC拓扑结构

常见拓扑对比

总线(Bus):          环形(Ring):        网格(Mesh):
┌─┬─┬─┬─┬─┐        ┌──┐──┌──┐        ┌──┬──┬──┐
│ │ │ │ │ │        │  └──┘  │        │  │  │  │
└─┴─┴─┴─┴─┘        │        │        ├──┼──┼──┤
                    │  ┌──┐  │        │  │  │  │
                    └──┘  └──┘        ├──┼──┼──┤
                                      │  │  │  │
                                      └──┴──┴──┘

Torus(环面):        Fat Tree(胖树):     Crossbar(交叉开关):
┌──┬──┬──┐         ╱─┴─╲               ┌─┬─┬─┬─┐
│╲ │╱ │╲ │         ╱     ╲              ├─┼─┼─┼─┤
├──┼──┼──┤        ┌─┐   ┌─┐            ├─┼─┼─┼─┤
│╱ │╲ │╱ │        │ │   │ │            ├─┼─┼─┼─┤
├──┼──┼──┤        └┬┘   └┬┘            └─┴─┴─┴─┘
│╲ │╱ │╲ │         │     │
└──┴──┴──┘        PE    PE

性能特征比较: | 拓扑 | 直径 | 分割带宽 | 成本 | 扩展性 | 功耗复杂度 |

拓扑 直径 分割带宽 成本 扩展性 功耗复杂度
总线 1 O(1) O(N)
环形 N/2 O(2) O(N)
2D网格 2√N O(√N) O(N)
Torus √N O(2√N) O(N)
胖树 logN O(N) 优秀 O(NlogN)
Crossbar 1 O(N) 极高 O(N²)

拓扑选择的定量分析

对于200 TOPS的NPU设计,需要支持:

  • 计算单元:256-1024个MAC阵列
  • 存储带宽:240 TB/s(内部)
  • 节点间通信:~50 TB/s

拓扑选择的约束条件: $$\text{Cost} = \alpha \times N_{routers} + \beta \times N_{links} + \gamma \times \text{Wire_length}$$ 其中:

  • $N_{routers} = N$(节点数)
  • $N_{links} = k \times N / 2$(k为节点度数)
  • Wire_length取决于拓扑和物理布局

以16×16 2D Mesh为例的详细分析:

  • 节点数:256
  • 链路数:480(内部) + 64(边界)
  • 最大跳数:30
  • 平均跳数:10.67
  • 分割带宽:16 × 单链路带宽

若每条链路32位宽,运行在2GHz,则: $$BW_{link} = 32 \text{ bits} \times 2 \text{ GHz} = 8 \text{ GB/s}$$ $$BW_{bisection} = 16 \times 8 = 128 \text{ GB/s}$$ 层次化NoC设计

现代NPU通常采用层次化NoC,结合多种拓扑:

全局NoC (2D Mesh)
    │
├───┼───────────┐
│   │           │
▼   ▼           ▼
局部集群       局部集群
(Crossbar)     (Ring)
│   │          │   │
PE  PE        PE  PE

层次化设计的优势:

  1. 局部通信低延迟(1-2 cycles)
  2. 全局通信高带宽
  3. 功耗优化(局部通信功耗低)
  4. 面积效率(减少长距离布线)

拓扑的物理实现考虑

在7nm工艺下的布线资源:

  • Metal层数:15-17层
  • 低层金属(M1-M4):局部互连,间距45-56nm
  • 中层金属(M5-M8):中等距离,间距80-100nm
  • 高层金属(M9-M15):全局布线,间距200-360nm

2D Mesh的物理布局优化:

  1. 折叠布局:减少最长线延迟
  2. 对角线增强:添加对角链路减少跳数
  3. Express通道:跨多跳的快速通道

4.4.2 路由算法与流控

维序路由(Dimension-Order Routing)

最常用的死锁避免路由算法,先沿X维路由,再沿Y维:

def xy_routing(src_x, src_y, dst_x, dst_y):
    # 先X后Y,避免死锁
    path = []
    # X维路由
    while src_x != dst_x:
        if src_x < dst_x:
            path.append("EAST")
            src_x += 1
        else:
            path.append("WEST") 
            src_x -= 1
    # Y维路由
    while src_y != dst_y:
        if src_y < dst_y:
            path.append("NORTH")
            src_y += 1
        else:
            path.append("SOUTH")
            src_y -= 1
    return path

XY路由的死锁避免证明:

  • 通道依赖图(CDG)无环
  • 东西向通道优先级高于南北向
  • 不会形成循环等待

自适应路由

根据网络拥塞动态选择路径: $$P_{route} = \arg\min_{p \in \text{paths}} \sum_{l \in p} C_l$$ 其中$C_l$是链路$l$的拥塞度量,可定义为: $$C_l = \alpha \times Q_l + \beta \times U_l + \gamma \times D_l$$

  • $Q_l$:链路$l$的队列占用率
  • $U_l$:链路利用率(过去N周期平均)
  • $D_l$:链路传输延迟
  • $\alpha, \beta, \gamma$:权重系数

部分自适应路由算法

  1. West-First路由:先向西,然后自适应选择
  2. North-Last路由:最后向北,之前自适应
  3. Odd-Even路由:奇偶列采用不同限制

Odd-Even路由规则:

  • 偶数列:禁止E→N和E→S转向
  • 奇数列:禁止N→W和S→W转向

这保证了无死锁同时提供路径多样性。

容错路由

处理故障节点和链路的路由策略:

故障节点绕行示例:
┌──┬──┬──┐
│  │  │  │
├──┼XX┼──┤  XX: 故障节点
│  │↗↘│  │  绕行路径:→↗→
├──┴──┴──┤            →↘→

容错路由的实现:

  1. 故障表维护:每个路由器维护邻居状态
  2. 动态重路由:检测到故障后更新路由表
  3. 多路径冗余:预先计算备用路径

虚通道(Virtual Channel)

通过多个虚拟通道共享物理链路,提高利用率并避免死锁:

物理链路
┌─────────────────────┐
│  VC0: [████    ]    │  请求消息
│  VC1: [  ████  ]    │  响应消息
│  VC2: [      ████]  │  多播消息
│  VC3: [██      ]    │  逃逸通道
└─────────────────────┘

虚通道分配策略:

  • 静态分配:不同消息类型使用固定VC
  • 动态分配:基于信用的VC分配
  • 逃逸通道:保留一个VC用于死锁恢复

虚通道的硬件实现

输入端口结构:
         ┌──────────────┐
输入 ──> │ VC Demux     │
         ├──────────────┤
         │ VC0 Buffer   │
         ├──────────────┤
         │ VC1 Buffer   │
         ├──────────────┤
         │ VC2 Buffer   │
         ├──────────────┤
         │ VC3 Buffer   │
         ├──────────────┤
         │ VC Allocator │
         ├──────────────┤
         │ Switch Alloc │
         └──────────────┘
                │
              交叉开关

VC分配的两阶段过程:

  1. VC分配阶段:为包头flit分配输出VC
  2. 开关分配阶段:为数据flit分配交叉开关时隙

分配器的仲裁算法:

  • iSLIP:迭代轮询匹配
  • PIM:并行迭代匹配
  • 波前仲裁:对角线扫描

4.4.3 流控机制

信用流控(Credit-based Flow Control)

接收方向发送方发放信用,控制数据发送:

发送方                     接收方
┌──────┐                 ┌──────┐
│Buffer│ ──data(3 flits)─> │Buffer│
│Count │ <──credit(3)──── │Free  │
│=N-3  │                 │=3    │
└──────┘                 └──────┘

信用计算的详细推导: $$\text{Credits}_{min} = \lceil \frac{\text{RTT} \times BW}{\text{flit_size}} \rceil + \text{buffer_depth}$$ 其中RTT (Round-Trip Time)包括:

  • 前向延迟:$T_{fwd} = T_{router} + T_{link} + T_{deserialize}$
  • 信用返回延迟:$T_{credit} = T_{process} + T_{link_back}$
  • 总RTT = $T_{fwd} + T_{credit}$

对于2GHz时钟,128位flit的系统:

  • RTT = 8 cycles(典型值)
  • 链路带宽 = 256 Gbps
  • 最小信用数 = $\lceil \frac{8 \times 256}{128} \rceil = 16$

On/Off流控

更简单但效率较低的流控机制:

时序图:
发送方: |--Send--|--Wait--|--Send--|
接收方: |--Recv--|--OFF----|--ON----|

On/Off流控的阈值设置:

  • OFF阈值:$T_{off} = B_{total} - \text{RTT} \times \text{Rate}$
  • ON阈值:$T_{on} = T_{off} / 2$(避免频繁切换)

背压机制(Backpressure)

当下游拥塞时,向上游传播停止信号: $$\text{Throughput} = \min_{i \in \text{path}}(\text{capacity}_i \times (1 - \text{congestion}_i))$$ 背压传播模型: $$P_{stop}(t+1, n) = \begin{cases} 1 & \text{if } Q_n(t) > T_{high} \\ P_{stop}(t, n+1) & \text{if } Q_n(t) > T_{mid} \\ 0 & \text{otherwise} \end{cases}$$ 其中$Q_n(t)$是节点$n$在时刻$t$的队列占用。

弹性缓冲流控(Elastic Buffer)

利用流水线寄存器作为分布式缓冲:

┌──┐  ┌──┐  ┌──┐  ┌──┐
│R1│──│R2│──│R3│──│R4│  弹性流水线
└──┘  └──┘  └──┘  └──┘
 ↓     ↓     ↓     ↓
Valid & Ready握手

优势:

  • 降低缓冲需求
  • 减少面积开销
  • 提高时钟频率

4.4.4 NoC性能建模

延迟模型

端到端延迟的精确建模: $$L_{total} = L_{header} + \sum_{i=1}^{H}(L_{router,i} + L_{link,i}) + L_{contention}$$ 各组件延迟分解:

  1. 路由器延迟(4级流水线): - 路由计算(RC):1 cycle - VC分配(VA):1 cycle
    - 开关分配(SA):1 cycle - 交叉开关传输(ST):1 cycle

  2. 链路延迟: $$L_{link} = \lceil \frac{d}{v_{signal}} \times f_{clk} \rceil$$ 其中$v_{signal} \approx 0.5c$(硅中信号速度)

  3. 竞争延迟(排队理论): $$L_{contention} = \frac{1}{\mu - \lambda}$$ 其中$\mu$是服务率,$\lambda$是到达率。

带宽模型

有效带宽的详细分析: $$BW_{effective} = BW_{physical} \times \eta_{total}$$ 其中: $$\eta_{total} = \eta_{protocol} \times \eta_{routing} \times \eta_{congestion} \times \eta_{serialization}$$ 各效率因子:

  • $\eta_{protocol} = \frac{\text{payload_size}}{\text{packet_size}}$(典型0.8-0.9)
  • $\eta_{routing} = 1 - P_{misroute}$(典型0.85-0.95)
  • $\eta_{congestion} = (1 - \rho)^2$($\rho$是网络负载)
  • $\eta_{serialization} = \frac{W_{flit}}{W_{phit}}$(flit到phit的转换效率)

热点和拥塞建模

热点形成的概率模型: $$P_{hotspot} = 1 - (1 - p)^N$$ 其中$p$是单个节点成为热点的概率,$N$是节点数。

拥塞扩散模型(基于流体动力学): $$\frac{\partial \rho}{\partial t} + \nabla \cdot (\rho \mathbf{v}) = S$$ 其中:

  • $\rho$:流量密度
  • $\mathbf{v}$:流速向量
  • $S$:源项(注入/移除流量)

实际案例:Google TPU v4的ICI

TPU v4使用3D Torus拓扑的Inter-Chip Interconnect (ICI):

架构参数:

  • 4096个芯片(64×64 2D Torus)
  • 每芯片6个100 Gbps光链路
  • 总分割带宽:4.8 Tbps
  • 平均跳数:32(理论)、38(实际,含拥塞)
  • 单跳延迟:50ns
  • 端到端延迟:< 2μs(轻载)、< 5μs(重载)

关键优化技术:

  1. 自适应路由避免热点 - 基于全局拥塞表的路由决策 - 每100μs更新一次拥塞信息 - 减少热点概率80%

  2. 多轨道(Multi-rail)设计 - 6条独立物理通道 - 不同流量类型分配到不同轨道 - 有效带宽提升4.5倍

  3. 硬件集合通信原语 - AllReduce:340 GB/s(4096节点) - AllGather:450 GB/s - Reduce-Scatter:380 GB/s - 相比软件实现加速10-20倍

  4. 拥塞感知的流调度 - ECN (Explicit Congestion Notification)标记 - 自适应注入率控制 - 优先级反转避免饥饿

性能测试结果(BERT-Large训练):

  • 通信效率:92%(通信时间/计算时间)
  • 扩展效率:85%(4096芯片相对单芯片)
  • 能效:15 TFLOPS/W(含通信)

本章小结

本章深入探讨了NPU存储系统与数据流设计的核心概念。我们从存储层次设计出发,分析了片上SRAM、HBM和DDR的技术特征与权衡,通过定量计算确定了200 TOPS NPU所需的240 TB/s内部带宽。在数据重用模式部分,我们对比了时间重用与空间重用,详细分析了WS/OS/RS三种数据流的能效特征。DMA设计章节介绍了多通道DMA架构、描述符管理和预取策略,展示了如何通过双缓冲实现计算与传输的重叠。最后,我们深入研究了片上网络的拓扑结构、路由算法和流控机制,并以TPU v4的ICI为例说明了大规模互连的实际实现。

关键要点:

  1. 存储带宽是NPU性能的主要瓶颈,需要通过多级存储层次和数据重用来缓解
  2. 数据流模式的选择直接影响能效,RS数据流通过灵活切换达到最优
  3. DMA预取深度需要根据内存延迟和计算吞吐量精确计算
  4. NoC设计需要在延迟、带宽和成本间权衡,2D Mesh是主流选择
  5. 虚通道和信用流控是避免死锁和提高利用率的关键机制

关键公式回顾:

  • Roofline平衡点:$AI_{balance} = \frac{\text{Peak_FLOPS}}{\text{Memory_BW}}$
  • 时间重用度:$R_t = \frac{\text{使用次数}}{\text{加载次数}}$
  • 最优tile大小:$T_{opt} = \sqrt{\frac{S \times \rho \times f_{clk}}{3 \times BW}}$
  • NoC端到端延迟:$L_{total} = L_{header} + L_{router} \times H + L_{link} \times H + L_{contention}$
  • 信用流控:$Credits_{min} = \lceil \frac{RTT \times BW}{flit_size} \rceil + buffer_depth$

练习题

基础题

练习4.1 计算存储带宽需求 一个NPU需要执行矩阵乘法 $C_{512×512} = A_{512×768} \times B_{768×512}$,采用nvfp4量化。若计算吞吐量为100 TOPS,MAC利用率80%,计算: a) 无数据重用时的理论带宽需求 b) 采用Output Stationary数据流的带宽需求 c) 若片上SRAM仅32MB,设计合理的tiling策略

提示

考虑计算量与数据传输量的比值,注意nvfp4为4位数据类型。对于tiling,需要满足三个矩阵块都能装入SRAM。

答案

a) 无数据重用时:

  • 计算量:$2 \times 512 \times 768 \times 512 = 402.7M$ FLOPs
  • 数据量:$(512×768 + 768×512 + 512×512) \times 4 \text{ bits} = 4.19M$ bytes
  • 算术强度:$\frac{402.7M}{4.19M} = 96$ FLOPs/byte
  • 带宽需求:$\frac{100 \text{ TOPS} \times 0.8}{96} = 833$ GB/s

b) Output Stationary:

  • 每个输出元素计算时,A的一行和B的一列各读取一次
  • 重用因子:K = 768
  • 带宽需求:$\frac{833 \text{ GB/s}}{768/3} = 3.25$ GB/s

c) Tiling策略:

  • 设tile大小为 $T_M × T_K × T_N$
  • 约束:$(T_M × T_K + T_K × T_N + T_M × T_N) × 4 \text{ bits} \leq 32 \text{ MB}$
  • 选择:$T_M = T_N = 128, T_K = 192$
  • 验证:$(128×192 + 192×128 + 128×128) × 0.5 = 32.25$ KB < 32 MB ✓

练习4.2 Bank冲突分析 一个NPU有16个SRAM bank,采用交织存储,地址映射为 $Bank_{id} = addr \bmod 16$。现需要同时访问地址0x1000、0x1010、0x1020、0x1030,问: a) 是否存在bank冲突? b) 若改为 $Bank_{id} = (addr >> 4) \bmod 16$,结果如何? c) 设计一个映射函数避免此类冲突

提示

计算每个地址对应的bank编号,检查是否有重复。注意地址的二进制表示。

答案

a) 原始映射:

  • 0x1000 mod 16 = 0
  • 0x1010 mod 16 = 0
  • 0x1020 mod 16 = 0
  • 0x1030 mod 16 = 0 存在严重冲突,4个地址都映射到Bank 0

b) 改进映射:

  • (0x1000 >> 4) mod 16 = 0x100 mod 16 = 0
  • (0x1010 >> 4) mod 16 = 0x101 mod 16 = 1
  • (0x1020 >> 4) mod 16 = 0x102 mod 16 = 2
  • (0x1030 >> 4) mod 16 = 0x103 mod 16 = 3 无冲突,分别映射到Bank 0,1,2,3

c) 更好的映射函数(XOR哈希): $Bank_{id} = ((addr >> 4) \oplus (addr >> 8)) \bmod 16$ 这样可以打散规律性访问模式

练习4.3 DMA预取深度计算 一个NPU系统的参数如下:

  • 计算一个256×256矩阵乘法tile需要500 cycles
  • HBM访问延迟:200 cycles
  • DMA传输256×256×4bits数据需要100 cycles 计算最小预取深度以完全隐藏内存延迟。
提示

考虑流水线执行,预取需要覆盖整个内存访问时间。

答案

总内存访问时间:200 + 100 = 300 cycles 计算时间:500 cycles

由于计算时间大于内存访问时间,理论上1级预取即可:

  • 时刻0-300:预取tile 1,计算tile 0
  • 时刻300-500:继续计算tile 0
  • 时刻500-800:预取tile 2,计算tile 1

但考虑到可能的延迟变化,实际需要2级预取缓冲: $$N_{prefetch} = \lceil \frac{300}{500} \rceil + 1 = 2$$

这样可以容忍最多500 cycles的延迟抖动。

挑战题

练习4.4 多级存储优化 设计一个三级存储系统用于Transformer的Attention计算(序列长度8192,头维度64):

  • L1: 256KB per PE,延迟1 cycle
  • L2: 8MB shared,延迟10 cycles
  • HBM: 16GB,延迟100 cycles 要求设计数据分块和调度策略,最小化总延迟。
提示

Attention包含QK^T和Score×V两个大矩阵乘法,考虑Flash Attention的分块策略。

答案

采用Flash Attention分块策略:

  1. 外层循环:将8192序列分成32个块,每块256
  2. 中层循环:Q和K的块大小为256×64
  3. 内层循环:累加部分attention scores

存储分配:

  • L1:当前Q块(256×64×4B = 64KB) + 部分K块(64KB) + 中间结果(128KB)
  • L2:预取下一个K/V块对 + Softmax归一化因子
  • HBM:完整Q、K、V矩阵

调度策略:

for q_block in range(32):  # 外层
    load Q[q_block] to L2
    for kv_block in range(32):  # 中层  
        prefetch K[kv_block+1], V[kv_block+1] to L2
        load K[kv_block], V[kv_block] to L1
        compute S = Q[q_block] @ K[kv_block].T  # 在L1
        compute P = softmax(S)  # 在L1
        compute O += P @ V[kv_block]  # 累加到L1
    write O back to HBM

总延迟估算:

  • L1访问:32×32×256×64×2 = 33M次,33M cycles
  • L2访问:32×32×2 = 2K次,20K cycles
  • HBM访问:32×3 = 96次,9.6K cycles
  • 计算:32×32×(256×256×64×2) = 8.6G FLOPs

在100 GFLOPS的PE上,计算主导,总时间约86ms。

练习4.5 NoC路由优化 在8×8 2D Mesh上,从(0,0)发送数据到(7,7),同时存在以下流量:

  • (0,7)→(7,0): 大流量
  • (3,3)→(4,4): 中等流量 设计自适应路由策略避免拥塞。
提示

分析XY路由的冲突点,考虑YX或部分自适应路由。

答案

XY路由分析:

  • (0,0)→(7,7): 路径(0,0)→(7,0)→(7,7)
  • (0,7)→(7,0): 路径(0,7)→(7,7)→(7,0)
  • 冲突:两条路径在(7,0)-(7,7)段重叠

自适应策略:

  1. 监测(7,*)行的拥塞
  2. 当拥塞度>阈值时,(0,0)→(7,7)改用YX路由: (0,0)→(0,7)→(7,7)

  3. 中间节点(3,3)-(4,4)的流量较小,维持XY路由

负载均衡算法:

def adaptive_route(src, dst, congestion_map):
    xy_path = compute_xy_path(src, dst)
    yx_path = compute_yx_path(src, dst)

    xy_cost = sum(congestion_map[link] for link in xy_path)
    yx_cost = sum(congestion_map[link] for link in yx_path)

    if yx_cost < 0.8 * xy_cost:  # 20%改善阈值
        return yx_path
    else:
        return xy_path

预期改善:

  • 最大链路利用率从90%降至60%
  • 平均延迟减少35%
  • 吞吐量提升40%

练习4.6 数据流能效分析 比较三种数据流(WS/OS/RS)在以下场景的能效:

  • 1×1卷积,输入224×224×128,输出224×224×256
  • 3×3 Depthwise卷积,224×224×256
  • 全连接层,输入2048,输出1000 假设:RF访问1pJ,NoC传输5pJ,DRAM访问200pJ。
提示

计算每种数据流的数据传输量和重用模式,估算总能耗。

答案

1×1卷积分析:

WS (Weight Stationary):

  • 权重驻留:128×256 = 32K次RF访问
  • 输入流动:224×224×128 = 6.4M次NoC
  • 输出累加:224×224×256 = 12.8M次NoC
  • 能耗:32K×1 + 19.2M×5 = 96 mJ

OS (Output Stationary):

  • 输出驻留:224×224×256 = 12.8M次RF访问
  • 权重广播:128×256×(224×224/PE数) 次NoC
  • 假设256个PE:128×256×196 = 6.4M次NoC
  • 输入广播:类似6.4M次NoC
  • 能耗:12.8M×1 + 12.8M×5 = 76.8 mJ

RS (Row Stationary):

  • 1D卷积映射,每个PE处理部分输入输出
  • 本地RF:~8M次访问
  • NoC传输:~8M次
  • 能耗:8M×1 + 8M×5 = 48 mJ

3×3 Depthwise分析:

WS:不适用(无权重共享)

OS:

  • 每个输出像素需要9个输入
  • RF:224×224×256 = 12.8M
  • NoC:224×224×256×9 = 115M
  • 能耗:12.8M×1 + 115M×5 = 587 mJ

RS:

  • 每个PE处理一个通道
  • RF:224×224×256 = 12.8M
  • NoC:最小(仅边界像素)~2M
  • 能耗:12.8M×1 + 2M×5 = 22.8 mJ

全连接层分析:

WS:

  • 权重驻留:2048×1000 = 2M次RF
  • 输入广播到所有PE
  • 能耗:2M×1 + 输入广播开销

OS:

  • 输出驻留:1000次RF
  • 权重和输入流动
  • 能耗:取决于batch size

RS:

  • 介于WS和OS之间
  • 能耗:~1.5× min(WS, OS)

结论:

  • 1×1卷积:RS > OS > WS
  • Depthwise:RS >> OS (WS不适用)
  • 全连接:取决于batch size,通常WS较优

练习4.7 存储一致性设计 设计一个支持多个计算集群共享SRAM的一致性协议,要求:

  • 支持原子读-改-写操作
  • 最小化同步开销
  • 避免死锁
提示

考虑目录式或监听式协议,注意原子操作的实现。

答案

采用简化的MESI协议变体:

状态定义:

  • M (Modified): 独占且已修改
  • E (Exclusive): 独占未修改
  • S (Shared): 共享只读
  • I (Invalid): 无效

协议设计:

  1. 读操作: - Invalid → Shared (广播读请求) - Shared/Exclusive/Modified → 直接读

  2. 写操作: - Invalid/Shared → Exclusive (广播失效) - Exclusive → Modified (本地写) - Modified → 直接写

  3. 原子操作(Atomic RMW):

acquire_lock(addr):
  while True:
    state = get_state(addr)
    if state != Modified:
      if try_upgrade_to_modified(addr):
        break
    backoff()

atomic_add(addr, value):
  acquire_lock(addr)
  old = read(addr)
  write(addr, old + value)
  release_lock(addr)

死锁避免:

  1. 锁排序:按地址顺序获取
  2. 超时机制:等待超过阈值则回退
  3. 专用原子操作单元:避免与普通访问竞争

硬件实现:

  • 目录表:2K entries,4-way组相联
  • 状态位:2 bits per cache line
  • 同步网络:专用低延迟网络
  • 原子单元:每个cluster一个,支持16个pending操作

性能指标:

  • 读延迟:1-3 cycles (取决于状态)
  • 写延迟:3-10 cycles (需要失效)
  • 原子操作:10-20 cycles
  • 面积开销:< 5%总SRAM面积

练习4.8 端到端系统设计 为自动驾驶BEV感知设计完整的存储和NoC系统:

  • 输入:6路相机,每路4MP@30fps
  • 网络:BEVFormer-Base
  • 实时性要求:< 100ms延迟 给出详细的架构设计和带宽分配。
提示

分析BEVFormer的计算和存储需求,设计pipeline确保实时性。

答案

系统需求分析:

输入带宽:

  • 6 × 4MP × 30fps × 12bit = 10.8 Gbps

BEVFormer计算:

  • Backbone (ResNet-50): 4 GFLOPS × 6 = 24 GFLOPS
  • Neck (FPN): 2 GFLOPS × 6 = 12 GFLOPS
  • Transformer: 15 GFLOPS
  • Head: 3 GFLOPS
  • 总计:54 GFLOPS,需要540 TOPS@100ms

存储需求:

  • 输入缓冲:6 × 4MP × 2 = 48 MB (双缓冲)
  • 特征图:~200 MB
  • BEV Query:100×100×256×4 = 10 MB
  • 模型权重:150 MB (INT8)
  • 历史特征:10帧 × 50 MB = 500 MB

架构设计:

┌─────────────────────────────────┐
│     相机接口 (6× MIPI CSI-2)     │
└──────────┬──────────────────────┘
           │ 10.8 Gbps
    ┌──────▼──────────┐
    │  输入缓冲SRAM   │ 48 MB
    │   (双缓冲)      │
    └──────┬──────────┘
           │
    ┌──────▼──────────────────────┐
    │   2D Mesh NoC (16×16)       │
    │   链路: 256 Gbps             │
    │   总带宽: 4 Tbps             │
    └──┬───────────────────────┬──┘
       │                       │
┌──────▼──────┐       ┌────────▼────────┐
│ 计算集群×4  │       │  共享L2 SRAM    │
│ 150 TOPS    │       │    128 MB       │
│ L1: 8MB     │       └─────────────────┘
└─────────────┘                │
                               │
                        ┌──────▼──────┐
                        │  HBM3 16GB  │
                        │  819 GB/s   │
                        └─────────────┘

流水线设计:

Stage 1: 图像预处理 (10ms)

- 6路并行处理
- 畸变校正归一化

Stage 2: Backbone特征提取 (30ms)  

- 6路CNN并行
- 特征金字塔生成

Stage 3: BEV转换 (20ms)

- 3D2D投影
- 多尺度特征融合

Stage 4: Temporal融合 (15ms)

- 历史BEV特征对齐
- 运动补偿

Stage 5: Transformer (20ms)

- Self-attention
- Cross-attention with images

Stage 6: 检测头 (5ms)

- 3D框回归
- 类别预测

带宽分配:

  1. 相机→输入缓冲:10.8 Gbps (持续)
  2. 输入缓冲→计算集群:50 GB/s (突发)
  3. 计算集群↔L2:200 GB/s
  4. L2↔HBM:100 GB/s (平均)
  5. NoC内部:500 GB/s (峰值)

优化策略:

  1. 相机帧重叠:N+1帧预处理与N帧推理并行
  2. 特征缓存:重用backbone特征3帧
  3. 量化:INT8 backbone,FP16 transformer
  4. 稀疏化:attention mask剪枝50%
  5. 多分辨率:远处低分辨率,近处高分辨率

性能预期:

  • 延迟:85ms (含预处理)
  • 吞吐量:11.7 fps
  • 功耗:45W
  • 能效:12 TOPS/W

常见陷阱与错误 (Gotchas)

存储设计陷阱

  1. 带宽计算错误 - 错误:只考虑计算带宽,忽略控制和同步开销 - 正确:预留20-30%带宽用于控制、同步和非理想因素

  2. Bank冲突低估 - 错误:假设均匀分布的访问模式 - 正确:分析实际访问模式,考虑stride访问造成的冲突

  3. 忽视数据对齐 - 错误:任意的数据布局和tile大小 - 正确:确保数据对齐到缓存行边界,tile大小是SIMD宽度的倍数

数据流设计陷阱

  1. 单一数据流策略 - 错误:所有层使用相同的数据流 - 正确:根据层类型自适应切换数据流模式

  2. 重用机会错失 - 错误:独立优化每个维度的重用 - 正确:联合优化时间和空间重用,考虑数据生命周期

DMA设计陷阱

  1. 预取距离不当 - 错误:固定的预取距离 - 正确:根据计算时间和内存延迟动态调整

  2. 描述符链表死锁 - 错误:循环依赖的描述符链 - 正确:确保描述符DAG无环,使用超时机制

NoC设计陷阱

  1. 路由死锁 - 错误:自适应路由without escape channel - 正确:保证至少一个虚通道使用确定性无死锁路由

  2. 热点忽视 - 错误:假设均匀流量分布 - 正确:识别和处理同步点、规约操作造成的热点

  3. 信用泄露

    • 错误:信用计数器溢出或不匹配
    • 正确:使用饱和计数器,定期同步信用

最佳实践检查清单

存储系统设计审查

  • [ ] 容量规划
  • [ ] 各级存储容量是否满足最大工作集需求?
  • [ ] 是否为双缓冲预留了空间?
  • [ ] 碎片化损失是否在可接受范围(<20%)?

  • [ ] 带宽匹配

  • [ ] 计算带宽与存储带宽是否平衡?
  • [ ] 是否识别了带宽瓶颈?
  • [ ] 峰值带宽需求是否有缓冲机制?

  • [ ] 访问模式优化

  • [ ] 是否分析了主要kernel的访问模式?
  • [ ] Bank冲突率是否<5%?
  • [ ] 是否实现了合适的交织策略?

数据流优化审查

  • [ ] 重用最大化
  • [ ] 是否量化了各级数据重用率?
  • [ ] Tiling参数是否经过优化?
  • [ ] 是否考虑了融合执行机会?

  • [ ] 调度优化

  • [ ] 计算与数据传输是否充分重叠?
  • [ ] 是否消除了不必要的数据移动?
  • [ ] 关键路径是否已识别和优化?

DMA配置审查

  • [ ] 通道分配
  • [ ] DMA通道数是否充足?
  • [ ] 优先级设置是否合理?
  • [ ] 是否支持所需的传输模式?

  • [ ] 延迟隐藏

  • [ ] 预取深度是否充分?
  • [ ] 双缓冲是否正确实现?
  • [ ] 是否处理了内存延迟变化?

NoC验证审查

  • [ ] 功能正确性
  • [ ] 路由算法是否无死锁?
  • [ ] 是否处理了所有边界情况?
  • [ ] 容错机制是否完备?

  • [ ] 性能验证

  • [ ] 是否达到了目标带宽?
  • [ ] 延迟是否满足要求?
  • [ ] 负载均衡是否有效?

  • [ ] 扩展性

  • [ ] 是否支持目标规模?
  • [ ] 扩展时性能下降是否可接受?
  • [ ] 是否预留了升级接口?