跳转至

Scratchpad and NoC

导言

解释 Scratchpad 时,我们很快会遇到一个新问题:数据由 DMA 显式搬入片上 SRAM,但它从 HBM 到计算核心附近的 Scratchpad,究竟经过了什么?答案里反复出现的 NoC,又是什么概念?

这篇文章沿着一次数据搬运,把几个容易混在一起的对象摆回各自的位置:Scratchpad 负责本地存取,NoC 负责片上运输,DMA 负责执行显式搬运。

从工作台到道路

可以先把一颗复杂芯片想成一座城市。不同的计算核心、Scratchpad 和内存控制器是分散在城市里的建筑,NoC Router 是路口,连接 Router 的链路是道路,数据包则是行驶在路上的车辆。

沿着这个类比继续看:

  • HBM 或 DRAM 是远处的仓库,容量大,但计算核心不能把每次细小访问都当成本地操作。
  • Scratchpad 是计算核心旁边的工作台,空间有限,却适合摆放马上要反复使用的数据。
  • DMA 像搬运调度者,按照程序、编译器或运行时给出的地址和大小执行搬运。
  • NoC 是芯片内部的道路系统,把请求和数据送到对应模块。

这个类比先给出了一条主线:Scratchpad 与 NoC 解决的不是同一个问题。前者回答“数据在计算时放在哪里”,后者回答“数据怎样在芯片内部到达那里”。

Scratchpad 解决本地访存

Scratchpad Memory,简称 SPM,通常是一块靠近计算单元的片上 SRAM。它的核心特征不是单纯的“快”,而是由软件显式管理

三个显式步骤

一次典型使用过程可以拆成三步:

  1. 搬入。程序先确定接下来需要的 Tile,再让 DMA 把这一块数据从 HBM 搬入 Scratchpad。
  2. 本地访问。数据到达后,计算核心通过普通的 load/store 访问 Scratchpad,并在寄存器和计算单元中完成计算。
  3. 写回。结果先写入 Scratchpad,再由 DMA 搬回 HBM。

用伪代码表示,大致是:

copy_async(HBM[A_global], SPM[A_local], tile_size)
wait_or_barrier()

value = load(SPM[A_local + offset])
SPM[C_local] = compute(value)

copy_async(SPM[C_local], HBM[C_global], tile_size)

搬运完成前,计算核心通常不能安全读取对应区域,因此程序需要等待 DMA 完成,或者通过事件、屏障和双缓冲安排好先后关系。

没有自动补充

Scratchpad 中没有所需数据时,硬件通常不会像 Cache miss 那样自动从 HBM 加载。程序必须提前完成搬运,否则可能读到旧数据、未初始化数据,或者触发非法访问。

它为什么不是 Cache

Cache 和 Scratchpad 都可能使用片上 SRAM,也都试图缩短访存路径,因此很容易被看成同一种东西。真正的分界在于谁管理数据的进入、停留和离开

维度 Cache Scratchpad
数据搬运 硬件自动完成 软件、编译器或 DMA 显式完成
数据是否存在 通过 Tag 判断是否命中 程序必须自己保证
替换与生命周期 主要由硬件决定 主要由程序安排
延迟表现 受命中和缺失影响 通常更加确定
使用代价 编程负担较低 需要规划分块、同步和数据布局

所以,Scratchpad 的可预测性来自明确控制,代价也同样来自明确控制。

但“由 DMA 显式搬运”只说明了谁来执行,还没有解释数据怎样跨过芯片内部的距离。接下来就轮到 NoC 了。

NoC 解决片上运输

NoC(Network-on-Chip,片上网络)是芯片内部连接计算单元、缓存、Scratchpad、DMA 和内存控制器的通信网络。它不是内存,而是片上通信基础设施。

一个 NoC 通常包含几个基本对象:

  • Router:根据目标地址选择下一条链路。
  • Link:连接相邻 Router,实际传输数据。
  • Network Interface:把 DMA 或计算核心的请求转换成 NoC 数据包。
  • Buffer:暂存正在等待转发的数据。
  • Routing Algorithm:决定数据经过哪条路径。
  • Flow Control:接收端繁忙时施加背压,避免数据丢失。

数据包还可能被切成更小的 Flit(流控单元),在 Router 之间流水传输。

简单芯片可以让多个模块共享一条总线,但随着连接对象增加,大家会争用同一条通路。NoC 通过多条链路和多个 Router,让多组数据有机会并行传输,并处理路由、拥塞和带宽分配问题。

一次搬入发生什么

下面这张图只回答一个问题:一块数据怎样从 HBM 到达计算核心附近的 Scratchpad?

Scratchpad、NoC 与 DMA 的数据搬入路径

根据会话内容整理的自绘示意图:展示一次搬入的主数据路径;写回过程沿相反方向返回。

沿着图中的箭头,一次搬入通常经历:

  1. DMA 发出读请求。
  2. NoC 把请求送到内存控制器。
  3. 内存控制器从 HBM 读取数据。
  4. 数据经过 NoC 返回 DMA。
  5. DMA 把数据写入 Scratchpad。
  6. 计算核心再通过本地 load/store 访问它。

这里最值得记住的不是路径上有多少个方框,而是两个动作主体:DMA 决定搬什么、搬到哪里;NoC 负责把请求和数据运送过去。

快从哪里来

Scratchpad 本身靠近计算核心,但“有一块很快的 SRAM”并不会自动带来高性能。真正的收益还依赖数据怎样被分块、复用和搬运。

分块与复用

完整数据放不进 Scratchpad 时,可以把它划分成多个 Tile。每次只搬入一个 Tile,在本地重复使用,再写回结果并处理下一块。

关键不是只把数据搬近,而是让一份数据搬进来后被使用多次。如果每份数据只访问一次,DMA 的搬运成本可能抵消 Scratchpad 的收益。

双缓冲

Scratchpad 可以划分为两个 Buffer:计算单元处理 Buffer 0 时,DMA 同时向 Buffer 1 搬入下一块数据。理想情况下,每个 Tile 的时间近似为:

\[ T_{\text{tile}} \approx \max(T_{\text{DMA}}, T_{\text{compute}}) \]

如果搬运和计算没有重叠,则更接近:

\[ T_{\text{tile}} \approx T_{\text{DMA}} + T_{\text{compute}} \]

双缓冲的价值,就是尽量把后一个加法变成前一个最大值。

两种拥塞

本地和片上网络都可能成为瓶颈:

  • Scratchpad Bank 冲突。多个访问落到不同 Bank 时可以并行;同时落到同一 Bank 时则可能串行化。
  • NoC 拥塞。多个核心同时访问同一内存控制器,或者多条路径经过同一个 Router,都可能引入排队和背压。

因此,一次搬运耗时可以粗略理解为:

\[ T_{\text{move}} \approx T_{\text{HBM}} + T_{\text{NoC}} + T_{\text{queue}} + T_{\text{SPM write}} \]

Scratchpad 解决了本地访问距离,NoC 却仍决定数据能否顺畅到达。两者必须放在同一条数据路径上理解。

把角色摆正

回到最初的问题,可以用四句话区分这些概念:

对象 它主要解决什么 谁在管理
Cache 自动搬运数据并判断是否命中 硬件
Scratchpad 保存当前计算显式选择的本地工作集 软件、编译器或运行时
DMA 按给定地址和大小执行数据搬运 软件发起,专用硬件执行
NoC 在芯片内部运输请求和数据 Router、链路与流控机制

于是,“Scratchpad 为什么快”和“数据怎样到达 Scratchpad”就不再是同一个问题:前者来自片上本地 SRAM,后者依赖 DMA 的显式安排和 NoC 的片上运输。

这也是理解 Scratchpad 访存机制时最有用的一条边界。具体实现可以不同,但只要先分清存储、搬运和运输三个角色,后续看到更复杂的数据路径时,就不会再把工作台、搬运者和道路混为一谈。

评论