内存层级
本页上的每个大小、偏移和枚举值都从
libtpu-0.0.40-cp314wheel 中的libtpu.so(BuildID md589edbbe81c5b328a958fe628a9f2207d)逐字节精确解码而来。其他版本会有所不同。
摘要
TPU TensorCore 看到的是一个扁平、由软件管理的 scratchpad 层级,而不是透明 cache。在 off-chip HBM 和计算单元之间有五个片上层级:HBM(设备全局 backing store)、VMEM(向量工作集,类似 L1/shared-memory scratchpad)、SMEM(标量/定序器 scratchpad)、SFLAG(DMA 引擎和 barrier primitives 轮询的专用同步标志层级)以及 CMEM(仅 Pufferfish 拥有的第二个大型 scratchpad)。没有硬件一致性,也没有自动逐出:kernel 显式地在层级之间 DMA tile,而编译器的 allocator(第 X 部分)把每个 buffer 精确放入一个空间。本页是这些层级的定位地图 — 它们是什么、每代上各有多大,以及运行时如何表示它们 — 并把 allocator 内部细节交给第 X 部分,把 ISA 级寻址交给第 VI 部分。
每个层级的运行时大小和 word 几何都是单个逐设备 xla::jellyfish::Target 对象中的一个字段。Target::Init 在启动时从嵌入的 <codename>_chip_parts.binarypb proto 填充这些字段(参见 逐代号常量),编译器其余部分通过简单 accessor 读取它们 — Target::HbmSizeBytes() 字面上就是 return *(int64_t*)(this + 0x450)。同一个 Target 还携带 bank 数量(一组独立的 C++ MemBanks 字面量,不是 proto 字段)以及用于把 byte offset 转换为硬件 word address 的逐层级 word size。因此,这个层级不是覆盖在硅片常量之上的抽象 — 它就是那些常量,按层级索引。
二进制文件中以两种不同枚举两次命名这组层级,重新实现者必须将它们分开。编译器侧的 xla::jellyfish::MemorySpace enum(由 MemorySpaceToString 读取 0x21ce6b08 处的指针表解码,17 个 region 值,索引 0..16)命名 buffer 可以所在的每个空间,包括 BarnaCore 和 SparseCore 子空间以及 host/pinned_hbm。0x21ce6b08 字符串数组在物理上比 17 更长 — 索引 17/18/19 解析为 absolute/heap_relative/stack_relative — 但这些是 LloAddress 指针相对性标签,不是 region-enum 成员,因此规范 enum 是 17 个值(参见 MemorySpace Enum)。LLVM 级 address-space ID(Address-Space IDs)是 LLO/LLVM IR 在 addrspace(N) 中携带的数字。二者相关但不相同,而 cost-model DMA dispatcher 对同一批物理层级还使用第三套更窄的编号(Hbm=1、Vmem=3、Cmem=4、Smem=5)。本页把物理层级锚定到这三者。
定位用的约定是:
- 五个物理层级、其角色,以及哪些世代拥有它们。
- 逐世代 size / word / bank 表 — 与权威来源 逐代号常量 保持一致。
Target字段图 — 哪个 struct offset 和 accessor 支撑哪个层级,从而可重建运行时视图。- 枚举关系 — 每个层级的
MemorySpaceint、DMA-dispatcher int 和 address-space ID。
| 运行时载体 | xla::jellyfish::Target 对象(每设备一个);层级位于 Target+0x450..+0x510 |
| 启动填充 | Target::Init(0x1d60fc20),来自 TpuChipParts::FromProto(0x20b1b400) |
| 层级 accessor | HbmSizeBytes 0x1d615320、VmemSizeBytes 0x1d615e00、SmemSizeBytes 0x1d615e40、CmemSizeBytes 0x1d615e20、SflagSizeBytes 0x1d615e60 |
| 空间枚举 | MemorySpaceToString(0x1d6ffae0)→ 表 0x21ce6b08(17 个 region 值,索引 0..16;表在 17+ 处因 relativity tags 而超长) |
| DMA 带宽 dispatcher | Target::LocalDmaBandwidth(MemorySpace,MemorySpace) 0x1d6168e0 |
| 层级 | HBM · VMEM · SMEM · SFLAG · CMEM(仅 v4) |
| 世代 | jellyfish v2 / dragonfish v3 / pufferfish v4 / viperfish v5p·v5e / ghostlite v6e / 6acc60406 v7x |
五个层级
每个层级都是一个物理上独立的片上(或对 HBM 而言是封装上)内存,拥有自己的宽度、容量和访问成本。图示勾勒了 TensorCore 看到的数据路径;每个箭头都是由 LocalDmaBandwidth 定价的显式 DMA,绝不是隐式 cache fill。下表是定位摘要;逐世代大小在下一节给出,跨层级带宽矩阵位于 Memory Bandwidth & Latency Model。
off-package / per-die
+-------------------------------------------+
| HBM | Target+0x450 (int64)
| 8..190 GiB · word 32..1024 B · MS=1 | HbmSizeBytes 0x1d615320
+----+--------------------+-----------------+
| DMA | DMA (v4: staged via VMEM)
v v
per-TensorCore scratchpads +---------------------+
+-----------------------+ | CMEM (v4 only) | Target+0x460 (int64)
| VMEM |<----->| 128 MiB · word 512 | CmemSizeBytes 0x1d615e20
| 16..128 MiB | DMA | MS=4 | (==0 ⇒ absent)
| word 512 B · MS=3 | +---------------------+
+-----------+-----------+
| DMA
v
+-----------------------+ +-----------------------+
| SMEM | | SFLAG | Target+0x468 (int32)
| 16 KiB..1 MiB | | 1..16 KiB | SflagSizeBytes 0x1d615e60
| word 4 B · MS=5 | | word 4 B · MS=6 | (sync-flag words;
| Target+0x470 (int32) | | polled by DMA/barrier) BarnaCore SFLAG @+0x478)
+-----------------------+ +-----------------------+
scalar operands completion / sync
```text
| 层级 | 角色 | 作用域 | Word | 首个世代 |
|---|---|---|---|---|
| **HBM** | 设备全局 backing store;所有程序输入/输出、spill、embeddings | 整个芯片 / per-die | 32 B – 1024 B(逐世代) | v2(全部) |
| **VMEM** | 向量工作集 — MXU/VPU 操作数经过的 tiled scratchpad | 每个 TensorCore | 512 B(所有世代) | v2(全部) |
| **SMEM** | 标量 / 定序器 scratchpad — 地址、循环边界、标量操作数 | 每个 TensorCore | 4 B(所有世代) | v2(全部) |
| **SFLAG** | 同步标志层级 — DMA/barrier completion words,被轮询以进行跨引擎同步 | 每个 TensorCore | 4 B(所有世代) | v2(全部) |
| **CMEM** | 第二个大型 scratchpad(`SharedMemory[CMEM]`)— 位于 VMEM 上方的 staging buffer | 整个芯片 | 512 B | 仅 v4 |
> **注意 —** 这些层级是软件管理的 scratchpad,不是 cache。把 VMEM/SMEM 建模为由 HBM backing 的 coherent cache 的重新实现是错误的:层级之间唯一的数据路径是显式 DMA,由 `LocalDmaBandwidth` 定价。编译器选择每个 buffer 的 home tier;运行时没有东西会迁移 buffer。
### HBM — 设备全局存储
HBM 是唯一大到足以容纳整个程序 tensor 的层级。它的大小、word 和 clock 是 proto 字段(`SharedMemory[HBM]`),物化到 `Target+0x450`(`int64`,`HbmSizeBytes`),per-stack clock 位于 `Target+0x910`,full-chip bandwidth 位于 `Target+0x4f0`(`HbmFullChipBytesPerSecond`)。**HBM word 跨世代变窄** — v2/v3 上 1024 B,v4 上 512 B,随后从 v5p 起为 32 B — 这与 DMA 路径用作 granule 的值相同(`DmaRequirements.granule_bytes`);参见 [HBM DMA Alignment](../memory/hbm-dma-alignment.md)。切分 HBM 的 allocator 是 [HBM Allocator](../memory/hbm-allocator.md);sub-allocate host-visible regions 的嵌入式 tcmalloc 是 [Embedded tcmalloc](../memory/embedded-tcmalloc.md)。
### VMEM — 向量工作集
VMEM 是每个 TensorCore 的 scratchpad,MXU 和 vector units 从中读取操作数;它类似 TPU 的 GPU shared memory,但由编译器显式分配,而不是按 kernel 声明。`VmemSizeBytes`(`0x1d615e00`)把 `Target+0x458` 读作 **`int32`**(一个 `movslq` 对它做符号扩展),且 VMEM word 在每个世代固定为 **512 B**(`Target+0x50c`,`VmemWordSizeBytes`)。VMEM 容量跨世代从 16 → 64 → 128 MiB 增长。placement/coloring 引擎是 [VMEM Allocator](../memory/vmem-allocator.md),它消费的逐 buffer tile shape 是 [TPU Buffer Layout](../memory/tpu-buffer-layout.md)。
### SMEM — 标量 scratchpad
SMEM 保存标量:循环归纳变量、计算出的地址、定序器常量。相对 VMEM 它很小(v2/v3 为 16 KiB,从 v4 起为 1 MiB),并以 **4-byte words** 寻址(`Target+0x508`,`SmemWordSizeBytes`)。`SmemSizeBytes` 位于 `Target+0x470`(`int32`)。SMEM 的 register-window 视图及其 allocator 分别是 [SMEM Register Window](../memory/smem-register-window.md) 和 [SMEM Scalar Memory](../memory/smem-scalar-memory.md)。
### SFLAG — 同步标志层级
SFLAG 是由 4-byte sync-flag words 组成的专用小内存,DMA 引擎在完成时递增它们,barrier/wait primitives 则轮询它们。它是一等成员 — 拥有自己的 `Target` size 字段(`Target+0x468`,`int32`,`SflagSizeBytes 0x1d615e60`)、自己的 word size(`Target+0x504`)和 log2(`Target+0x4c8`),以及自己的 bank ladder — 正是为了让同步协议能够寻址它而不与数据层级冲突。SFLAG 在 v2/v3 上是 1 KiB,在 v4–v6e 上是 2 KiB,并在 **v7x 上跃升到 16 KiB**。消费它的 wait/clear 协议是 [SFLAG Protocol](../memory/sflag-protocol.md),barrier 绑定是 [Barrier-to-SFLAG Binding](../barrier/barrier-to-sflag-binding.md)。
> **怪癖 —** `Target` 中有**两个**物理 SFLAG 层级,而不是一个。主芯片 SFLAG(size `+0x468`,word `+0x504`)与单独的 **BarnaCore SFLAG**(size `Target+0x478`,accessor `BarnaCoreSflagSizeBytes 0x1d615f80`)共存;后者只在 `HasBarnaCore` vtable predicate(`vtable+0x258`)为 true 时存在 — 也就是 v2/v3/v4。BarnaCore 还拥有自己的 SMEM(`BarnaCoreSmemSizeBytes`、base `BarnaCoreSmemBaseBytes`)。面向 v2–v4 embedding 路径的重新实现必须分配两个 SFLAG region;面向 v5p+ 时只有一个。
### CMEM — Pufferfish 的第二个 scratchpad
CMEM 是一个 128 MiB 的芯片级 `SharedMemory[CMEM]`,**仅存在于 Pufferfish(v4)**。`CmemSizeBytes`(`0x1d615e20`)读取 `Target+0x460`(`int64`);在其他每个世代上该字段都是 `0`,并且二进制文件中的规范 CMEM 存在性测试正是 `target().CmemSizeBytes() > 0`。CMEM pool allocator 及其 VMEM-staged transfer 模型是 [CMEM Pool](../memory/cmem-pool.md)。
> **陷阱 —** “CMEM 仅 v4” 以*三种*独立方式编码,并且重新实现中的三者必须一致:(1) `CmemSizeBytes` 除 v4 外都是 `0`;(2) 只有 `PufferfishTarget::MemBanks` 有 CMEM(space-4)条目,其他每代都会在其上 `LOG(FATAL)`;(3) 只有 v4 `chip_parts` blob 携带 `SharedMemory[CMEM]`。也不存在 `LocalDmaBandwidthHbmToCmem` virtual — cost-model dispatcher 把 `(Hbm,Cmem)` 路由到 `VmemToVmem` slot,因为 HBM→CMEM 被建模为 HBM→VMEM→CMEM staging。
---
## 逐世代大小
这是 size/word/bank 行的定位副本;权威且完整标注来源的主表(包含 bandwidth、clocks、MXU geometry、register files、SparseCore tiers)是 [逐代号常量](per-codename-hw-constants.md)。这里的值是数据层级的 proto 解码大小(`bytes_per_word × word_count`)以及 bank count 的 C++ `MemBanks` 字面量。除非标注,否则均为 CONFIRMED。
| 层级 / 字段 | v2 JF | v3 DF | v4 PF (std / lite) | v5p / v5e VF | v6e GL | v7x |
|---|---|---|---|---|---|---|
| **HBM size** | 16 GiB | 32 GiB | 32 / 8 GiB | 96 / 16 GiB | 31.5 GiB | 95 / 190 GiB |
| HBM word | 1024 B | 1024 B | 512 B | 32 / 512 B | 32 B | 32 B |
| **VMEM / TensorCore** | 16 MiB | 16 MiB | 16 MiB | 64 / 128 MiB | 128 MiB | 64 MiB |
| VMEM word | 512 B | 512 B | 512 B | 512 B | 512 B | 512 B |
| **SMEM / TensorCore** | 16 KiB | 16 KiB | 1 MiB | 1 MiB | 1 MiB | 1 MiB |
| SMEM word | 4 B | 4 B | 4 B | 4 B | 4 B | 4 B |
| **SFLAG / TensorCore** | 1 KiB | 1 KiB | 2 KiB | 2 KiB | 2 KiB | 16 KiB |
| SFLAG word | 4 B | 4 B | 4 B | 4 B | 4 B | 4 B |
| **CMEM (chip)** | absent | absent | 128 MiB | absent | absent | absent |
| VMEM banks | 8 | 8 | 16 | 32 | 32 | 32 |
| SMEM banks | 2 | 2 | 8 | 8 | 8 | 8 |
| CMEM banks | FATAL | FATAL | 32 | FATAL | FATAL | FATAL |
三个不连续点值得记住,因为它们会打破“所有东西都线性缩放”的重新实现:
- **SMEM 在 v4 跃升 64×**(16 KiB → 1 MiB),随后保持不变 — 标量 scratchpad 在 Pufferfish 之后不再是瓶颈。
- **SFLAG 在 v7x 跃升 8×**(2 KiB → 16 KiB),反映 v7 collective fabric 大得多的 sync-flag fan-out。
- **VMEM 非单调** — 它在单 TensorCore lite/v6e die 上达到 128 MiB 峰值(这些 die 每 core 配备更多 VMEM),并在 v7x 上*回落*到 64 MiB。每 TensorCore 的 VMEM 不是世代的代理指标。
> **注意 —** bank counts *不是* proto 字段。它们是逐代号 `*Target::MemBanks` override 中的 C++ 字面量:`JellyfishTarget`(`0x1d48fc80`)对 spaces 3/–/5 返回 8/–/2;`PufferfishTarget`(`0x1d493900`)对 spaces 3/4/5 索引 `.rodata` 表 `0xB5305C8 = {16, 32, 8}`;Dragonfish 没有 override,继承 Jellyfish。对某个世代缺失的 space 调用 `MemBanks` 是硬 `LOG(FATAL)`,不是零 — 这就是 CMEM-on-v2 被做成不可表示而不仅仅是空的方式。
---
## `Target` 字段图
整个层级的运行时视图是一个连续的 `Target` struct 字段块,由 `Target::Init` 从 chip-parts proto 填充。每个层级 accessor 都是单指令 getter,并已对照反编译 body 验证:`HbmSizeBytes` 是 `return *((int64_t*)this + 138)`(= `+0x450`),`VmemSizeBytes` 是 `return *((int*)this + 278)`(= `+0x458`),`SflagSizeBytes` 是 `return *((uint*)this + 282)`(= `+0x468`)。下图是重新实现必须复现的字段布局,使相同 accessor 解析到相同 offset。
| Target off | Accessor (VA) | Type | 层级数据 |
|---|---|---|---|
| `+0x438` / `+0x448` | user-alloc shared-mem limit clamp | int64 | HBM / scoped (CMEM) user-alloc cap |
| `+0x450` | `HbmSizeBytes` (`0x1d615320`) | int64 | HBM size |
| `+0x458` | `VmemSizeBytes` (`0x1d615e00`, `movslq`) | int32 | VMEM size |
| `+0x460` | `CmemSizeBytes` (`0x1d615e20`) | int64 | CMEM size(0 ⇒ absent) |
| `+0x468` | `SflagSizeBytes` (`0x1d615e60`) | int32 | SFLAG size |
| `+0x470` | `SmemSizeBytes` (`0x1d615e40`) | int32 | SMEM size |
| `+0x478` | `BarnaCoreSflagSizeBytes` (`0x1d615f80`) | int32 | BarnaCore SFLAG(v2–v4,由 `HasBarnaCore` 门控) |
| `+0x4c8` / `+0x4cc` / `+0x4d0` | Sflag/Smem/Vmem `WordSizeLog2` | int32 | 逐层级 word log2(byte→word shift) |
| `+0x4f0` | `HbmFullChipBytesPerSecond` (`0x1d6172a0`) | int64 | HBM bandwidth |
| `+0x4f8` | `CmemFullChipBytesPerSecond` (`0x1d6172c0`) | int64 | CMEM bandwidth(非 v4 为 0) |
| `+0x504` / `+0x508` / `+0x50c` / `+0x510` | Sflag/Smem/Vmem/Cmem `WordSizeBytes` | int32 | 逐层级 word size |
| `+0x90c` / `+0x910` | TC freq / HBM freq MHz | int32 | clocks(启动填充,pre-init 哨兵 `0xFFFFFFFF`) |
word-size 对(`WordSizeBytes` + `WordSizeLog2`)存在的原因是 ISA 产生的每个层级地址都是 *word* address,而不是 byte address:buffer 的 byte size 通过 `>> WordSizeLog2` 转为硬件 word count,allocator 断言每个 buffer 都是该层级 word 的倍数。门控寻址的 bounds-check assertions 在二进制文件中可逐字看到:`byte_address < target().HbmSizeBytes()`、`< target().VmemSizeBytes()`、`< target().SmemSizeBytes()`、`< target().SflagSizeBytes()` — 每个数据层级一个 — 这是最干净的证据,说明每个层级的 `Target` size 字段是寻址上限,而不仅仅是容量提示。
---
## 层级、`MemorySpace` 和 Address Spaces
重新实现者会为同一批物理层级遇到三套不同编号。把它们分清是内存模型中最容易出错的部分,因此这里把层级(五个 TensorCore 数据层级,加上共享该 enum 的 BarnaCore / SparseCore 子空间)与 `MemorySpace` int 和更窄的 DMA-dispatcher int 一起列出;完整 17 值 enum 和 LLVM address-space band 位于各自页面。
### 三套编号
编译器侧 `xla::jellyfish::MemorySpace` enum 是 `0x21ce6b08` 处的字符串表,由 enum 值直接索引(`MemorySpaceToString(e)` 字面上就是 `off_21CE6B08[e]`)。cost-model DMA dispatcher `Target::LocalDmaBandwidth` 使用同一批整数中的一个更窄集合 — 它的反编译 body 将参数与 `1`(Hbm)、`3`(Vmem)、`4`(Cmem)、`5`(Smem)做 XOR 以选择 vtable offset,从而确认这些数据层级的四个 enum 值。LLVM 级 address-space IDs 是 `addrspace(N)` 中携带的另一套编号,详见 [Address-Space IDs](address-space-ids.md)。
| 物理层级 | `MemorySpace` 名称 | enum int | DMA-dispatcher int |
|---|---|---|---|
| HBM | `hbm`(也作 `kDefault`) | 1 | 1 |
| HIB(host-interface) | `hib` | 2 | — |
| VMEM | `vmem` | 3 | 3 |
| CMEM | `cmem` | 4 | 4 |
| SMEM | `smem` | 5 | 5 |
| SFLAG | `sflag` | 6 | — |
| IMEM(instr.) | `imem` | 7 | — |
| BarnaCore SMEM | `barna_core_smem` | 9 | — |
| BarnaCore SFLAG | `barna_core_sflag` | 10 | — |
| SC sequencer SFLAG | `sparse_core_sequencer_sflag` | 12 | — |
| host | `host` | 13 | — |
| SC sequencer SMEM | `sparse_core_sequencer_smem` | 14 | — |
| pinned HBM | `pinned_hbm` | 16 | — |
> **注意 —** 规范 enum 分配是 `hib = 2`、`sflag = 6`、`imem = 7`,全部 CONFIRMED — `hib` 附近没有额外 slot。四个独立的逐字节精确探针固定了它:`MemorySpaceToString` flat lookup(字符串表 `0x21ce6b08`)、`MemorySpaceToDriverResource`(`0x1d6223e0`)逐 case switch、`MakeCmemConstant`/`MakeSparseCoreSequencerSmemConstant` ctors,以及 `MemBanks` overrides(参见 [MemorySpace Enum](../isa/memory-space-enum.md) 和 [Memory-Space Master Table](../appendix/memory-space-table.md))。数据层级值(Hbm 1、Vmem 3、Cmem 4、Smem 5)由 `LocalDmaBandwidth` XOR 常量独立确认。
### SFLAG 的子空间
SFLAG 是唯一在 MLIR 级别拆成 scoped sub-spaces 的层级,因为同步发生在三种粒度:全局跨引擎 `sflag`(唯一可跨 CORE 到达的 — TC↔SC、SC↔SC、TC↔TC 和 remote)、per-tile `sflag_tile`(TEC sub-engine scope)以及 per-SCS `sflag_scs`。这些是不同的 `mlir::sparse_core::MemorySpace` 值,由 verifier 断言;它们在 [SFLAG Protocol](../memory/sflag-protocol.md) 中详细说明,此处不重复。对层级地图来说,重点是单个物理 SFLAG 层级支撑全部三个 scope — sub-spaces 是寻址 scope,而不是单独的 memory。
### SparseCore 层级
从 v5p 起,SparseCore 带来了自己的内存族 — SPMEM、TILESPMEM 以及 per-SCS SMEM/SFLAG — 它与这里描述的 TensorCore 层级并列,而不是其中一部分。这些大小列在 [逐代号常量](per-codename-hw-constants.md)(SC 行)中,BarnaCore↔SparseCore pivot 是 [BarnaCore overview](../barnacore/overview.md)。除了说明 `SPMEM→HBM` 是一个*单独的* DMA-bandwidth virtual、无法通过 TensorCore `LocalDmaBandwidth` dispatcher 到达之外,它们超出本 TensorCore-tier 定位页的范围。
---
## 相关组件
| 名称 | 关系 |
|---|---|
| `Target::Init` | 从 `chip_parts` 填充 `Target+0x450..+0x510`;每个层级 size 的启动来源 |
| `TpuChipParts::FromProto` (`0x20b1b400`) | 解码 `chip_parts` proto,其字段变成层级大小 |
| `*Target::MemBanks` | 逐层级 bank count 的 C++ 来源(此处唯一的非 proto 整数) |
| `Target::LocalDmaBandwidth` (`0x1d6168e0`) | (src,dst) 层级 → bandwidth dispatcher;层级 enum ints 的消费者 |
| `MemorySpaceToString` (`0x1d6ffae0`) | 命名每个层级和子空间的 enum→name 表 |
## 交叉引用
- [逐代号常量](per-codename-hw-constants.md) — 这些大小所来自的权威、完整标注来源主表(bandwidth、clocks、MXU geometry、SparseCore tiers)
- [Address-Space IDs](address-space-ids.md) — 这些层级的 LLVM `addrspace(N)` 编号,包括 SparseCore fat-pointer bands
- [MemorySpace Enum](../isa/memory-space-enum.md) — 完整 17 值 `MemorySpace` region enum(`0`..`16`)、其字符串表以及 proto↔enum remap
- [MemorySpace 表](../appendix/memory-space-table.md) — 同一个 enum 的参考附录
- [内存子系统概览](../memory/overview.md) — 第 X 部分入口:这些层级如何被分配和管理
- [HBM Allocator](../memory/hbm-allocator.md) — 设备全局存储 allocator
- [VMEM Allocator](../memory/vmem-allocator.md) — vector-scratchpad placement/coloring 引擎
- [SMEM Scalar Memory](../memory/smem-scalar-memory.md) — 标量层级 allocator 和 register window
- [SFLAG Protocol](../memory/sflag-protocol.md) — 驱动 SFLAG 的 sync-flag wait/clear protocol
- [CMEM Pool](../memory/cmem-pool.md) — 仅 Pufferfish 拥有的第二 scratchpad pool
- [Memory Bandwidth & Latency Model](../cost/memory-bandwidth-latency-model.md) — 跨层级 `LocalDmaBandwidth` 矩阵和 DMA latencies