CMEM 常量内存池
本页中的所有地址均适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so(构建libtpu_lts_20260413_b_RC00,build-id md589edbbe81c5b328a958fe628a9f2207d)。该镜像未被 strip;反混淆后的 C++ 符号名按原文引用。每个 codename 的 CMEM 字节大小位于嵌入的*chip_parts.binarypb资源中,而不在 C++ 中;下文的每个数值大小均按注明来源给出。其他版本会有所不同。
摘要
CMEM("constant memory",MemorySpace::kCmem = 4)是一个片上 SRAM 操作数池,作为一等内存层级只存在于一个量产 codename:Pufferfish (PXC, TPU v4)。它就是 memory-space taxonomy 所称的 “a Pufferfish-only read-mostly operand pool”,也是 Pufferfish TensorCore 能在每个 bundle cycle 获取两个向量操作数的原因:专用的 TensorCoreCmemLoad 槽会在与常规 VMEM VectorLoad 相同的 51-byte bundle 中发出 CMEM 读取,从而使 MXU 操作数获取带宽翻倍。
本页只负责三件事:(1) CMEM 池布局,包括 allocator Config、byte/word/bank 寻址模型,以及每程序 image 和 stack 的位置;(2) 逐代 sizing,即哪些 codename 拥有 CMEM,以及 size、word、bank count 如何暴露;(3) 常量打包,即编译器选择把什么放入 CMEM 以及这些字节如何到达那里。片上 SMEM 模型见 smem-scalar-memory.md;层级 taxonomy 和共享 BestFitAllocator 见 overview.md;位精确的 cmem_load bundle slot 位于 ISA 侧(slot-cmem-load-pf.md, bundle-pf-51b.md)。本页链接这些内容但不重复。
重新实现者需要内化以下契约:
- CMEM 不是单独的 allocator class。 没有
CmemAllocator。CMEM 使用与其他层级相同的双栈模型(overview.md §1):编译时的ProgramMemoryAllocator::AllocateBytes(MemorySpace::kCmem, …)和运行时的tpu::BestFitAllocator实例,仅由一个 32-byteConfig{base_offset, end, alignment, granule}区分。 - CMEM sizing 是
Target上的两个标量字段。Target::CmemSizeBytes()(Target+0x460,uint64)是总字节数;Target::CmemWordSizeBytes()(Target+0x510,uint32)是 word,也就是 allocator 的 alignment 和 granule。二者在启动时由chip_parts.binarypb填充;任何 codename 的Targetsubclass 都不会覆盖它们。 - 只有
MemBanks(kCmem)返回值时,CMEM 才是真实存在的。 只有PufferfishTarget::MemBanks(kCmem)返回一个数(32);其他每个 codename 上的MemBanks(kCmem)都是LogMessageFatal。全部逐代 CMEM 差异都归结为数据:MemBanks(kCmem)的返回、PufferfishTarget::LocalDmaBandwidth*Cmemoverrides 的存在、pxc::isa::*Cmem*opcode family 的存在,以及chip_parts.binarypb提供的 size triple。 - 常量由 MSA 打包,并由 program-prologue DMA 填充。 放置决策由 MSA pass 作出,并受
xla_tpu_cmem_*flag family 门控;字节通过编译后程序 prologue 中发出的kDmaHbmToCmem/kDmaVmemToCmem到达,不是在 NEFF 加载时到达。
| 内存空间 | xla::jellyfish::MemorySpace::kCmem = 4(name table @ 0x21ce6b08) |
| 总大小 accessor | Target::CmemSizeBytes() @ 0x1d615e20 → *(uint64*)(this+0x460) |
| Word/granule accessor | Target::CmemWordSizeBytes() @ 0x1d617320 → *(uint32*)(this+0x510) |
| Banks(仅 Pufferfish) | PufferfishTarget::MemBanks(kCmem) @ 0x1d493900 = 32({16,32,8}[MS-3] @ rodata 0xb5305c8) |
| 编译时 placer | ProgramMemoryAllocator::AllocateBytes(MemorySpace::kCmem, …) @ 0x1c629e40 |
| 运行时 allocator | tpu::BestFitAllocator(Config{base=0, end=CmemSizeBytes, align=granule=CmemWordSizeBytes});由 CreateFromProto @ 0x1c631f20 重新水合 |
| 地址缩放 | LloRegionBuilder::CmemAddrScaled @ 0x1d539980(byte→word 由 CmemWordSizeBytes 完成;kCmem guard) |
| 常量形式 | LloAddress::MakeCmemConstant(long) @ 0x1d60ba20 → LloAddress(MemorySpace=4, off) |
| 放置门控 | parent->module()->target().CmemSizeBytes() > 0(在 CreateVectorCmemResult @ 0x1d4d99a0 中断言) |
| MSA 总开关 | FLAGS_xla_tpu_cmem_memory_space_assignment @ 0x223c1750 |
| 逐代可用性 | 仅 Pufferfish(PXC, TPU v4);DF/JF/VF/GLC/GFC 上 MemBanks(kCmem) 为 LogFatal |
| 置信度 | CONFIRMED(byte-anchored, decompile-verified),除非某行或 callout 另有说明 |
1. CMEM 池布局
目的
CMEM 是一个扁平的 per-TensorCore SRAM 区域。在 allocator 层级,它是从 offset 0 开始按字节扁平的;在 LLO bundle 层级,它是按 word 编址的;在 issue 时,它由indirect-state 驱动。重新实现者必须复现全部三种视图,因为 byte→word 转换发生在 address builder 中,而不是 issue 时,bank 坐标也从 word index 推导。
allocator Config
CMEM 是由通用 32-byte MemoryAllocator::Config(overview.md §3)构造的一个 tpu::BestFitAllocator。对 CMEM 层级而言,四个字段是:
tpu::MemoryAllocator::Config {
base_offset_in_bytes_ = 0, // CMEM starts at sub-tile address 0
allocatable_range_end_ = Target::CmemSizeBytes(), // *(uint64*)(Target+0x460)
alignment_in_bytes_ = Target::CmemWordSizeBytes(), // *(uint32*)(Target+0x510)
granule_in_bytes_ = Target::CmemWordSizeBytes(), // alignment == granule
};
```text
ctor(`0x1e817500`)断言 `alignment % granule == 0` 且 `alignment` 是 2 的幂;对 CMEM 而言二者是同一个值,因此两个不变量都平凡成立。容量是 `end − base = CmemSizeBytes()`。CMEM 没有 `base_offset` 预留,也没有 `ReserveBottomOfMemory` 调用;与 HBM 不同,它没有 DMA-floor / compile-time-alignment 分裂。
> **NOTE —** CMEM 没有类似 scoped-VMEM 的 **scoped-limit machinery**。不存在 `Target::OverlayReservedCmemBytes`、`DefaultPlatformScopedCmemBytes`、`RequiredPostModuleScopedCmemBytes`。`LloRegionBuilder::AllocateScopedCmem` (`0x1d5181a0`) 只是进入共享 `AllocateScopedMemory(shape, MemorySpace::kCmem, name)` (`0x1d517c20`) 的薄 trampoline。Scoped-CMEM 分配只受 `CmemSizeBytes() − (used chunks × chunk_bytes)` 限制。
### 寻址模型
| 层级 | 单位 | 机制 |
|---|---|---|
| Allocator | **byte** offset, base 0 | `BestFitAllocator` 给出相对 `base_offset = 0` 的字节偏移 |
| Bundle / LLO | **word** index | `CmemAddrScaled` (`0x1d539980`) 将 byte address 除以 `CmemWordSizeBytes`(传给 `AddrScaled` `0x1d538880` 的 `Granule` arg);bundle `Offset` 字段携带 *word* index |
| Bank (PF) | `(word_index) mod 32` | word index 的低位选择 `MemBanks(kCmem)=32` 个 bank 之一 |
| Issue | **indirect-state slot** | `CmemIndirectState` 预构建 16-byte slots;bundle `base_address` 字段携带 slot index |
`CmemAddrScaled` 是字节 allocator 和 word-indexed bundle 之间的连接点。其反编译函数体在缩放前断言 address operand 是 `kCmem`:
```c
// LloRegionBuilder::CmemAddrScaled @0x1d539980 (verbatim-derived)
LloCheckForFailure<MemorySpace, MemorySpace, kCmem>(...); // v13[0] = 4 == kCmem
// on failure: UpdateStatus("base->memory_space() == MemorySpace::kCmem",
// "platforms/xla/service/jellyfish/llo_region_builder.cc", 4965)
return AddrScaled(this, byte_addr, base, off, /*Granule=*/0 → CmemWordSizeBytes, ...);常量形式 LloAddress::MakeCmemConstant(long off) (0x1d60ba20) 会直接构建 LloAddress(MemorySpace=4, off)(constructor 0x1d60b980, esi=0x4)。不存在 CMEM register file:CMEM load 的目的地是 VS / VEX register file 中的 Vreg;CMEM 纯粹是操作数源池加一个小型可变 stack。
每程序 image 和 stack
CMEM 内容是每程序 image,不是启动时常量池。其中包含两个区域:
- image 头部的 indirect-state table,由
Target::CmemStackBaseTableWordOffset()(0x1d6185c0) 锚定。每个条目都是程序启动时由CmemIndirectStateFactory构建的 16-byte indirect-state record(full Pufferfish 上为pfc::b0::Cmq16BIndirectStateFactory,Pufferfish-Lite 上为plc::Cmq16BIndirectStateFactory;Cmq16B名称是推断 16-byte word 的来源)。 - 位于
Target::CmemStackStartWordOffset()(0x1d618660) 的小型每程序 stack,持有运行时可变标量(由kVectorCmemLoadAndPop消费的 loop counters,即 load-and-post-increment streaming-read opcode)。rodata 锚点是"cmem stack start"和"cmem stack base table"。
GOTCHA — CMEM 是每程序 scratch,会在每次程序切换时被覆盖,不是 pinned 的全芯片常量存储。CMEM allocator 由
CreateFromProto(0x1c631f20) 按程序实例化;image 在程序 prologue 中从 HBM 填充;下一个程序的 prologue 会覆盖它。不存在编译后程序之外的专用 “CMEM load engine”;每个 CMEM 字节都由 LLO 发出的 DMA descriptor 或 VPU store opcode 写入。这就是为什么 CMEM 持有的是一个程序的 weights/LUTs working set,而不是整个模型。
2. 逐代 CMEM Sizing
目的
CMEM 是否存在是按 codename 决定的,并由数据加三个小的 Target overrides 决定,而不是 allocator 中的任何 TpuVersion 分支。驱动 CMEM 的重新实现者必须精确复现这个门控:仅当 CmemSizeBytes() > 0 且 MemBanks(kCmem) 不 LogFatal 时,才尝试 CMEM 放置;在已发布的 0.0.40 runtime 中,这只包括 Pufferfish。
sizing accessors(反编译确认)
两个 accessor 都是在 base Target 上的直接字段读取,没有 per-codename override:
// Target::CmemSizeBytes() @0x1d615e20
return *((uint64_t*)this + 140); // 140 * 8 = 0x460 — total CMEM bytes / core
// Target::CmemWordSizeBytes() @0x1d617320
return *((uint32_t*)this + 324); // 324 * 4 = 0x510 — word = alignment = granule
```text
不存在 `Target::CmemWordSizeLog2` 字段(SMEM 在 `+0x4CC` 有一个,因为 LLO bundle packing 会为 SMEM 发出 byte→word shift;CMEM 的 byte→word 转换在 `CmemAddrScaled` / indirect-state classes 内完成,它们会硬连线 granule)。
`PufferfishTarget::MemBanks(MemorySpace)` 是门控一切的唯一 override(反编译 @ `0x1d493900`):
```c
// PufferfishTarget::MemBanks(MemorySpace ms) @0x1d493900
unsigned v4 = ms - 3; // kVmem=3 → 0, kCmem=4 → 1, kSmem=5 → 2
if (v4 >= 3) // ms >= 6 (sflag, …)
LogMessageFatal("target_pufferfish.h", 228,
"Unsupported memory space specified for MemBanks()");
return qword_B5305C8[v4]; // {16, 32, 8} → kCmem ⇒ 32base Target::MemBanks 和每个非 Pufferfish override 都会让 kCmem 落入 LogMessageFatal 分支;MemBanks(kCmem) 在 JF/VF/GL/GF 上根本没有有效返回值。
逐 codename CMEM 矩阵
Sizes 来自启动时的 chip_parts.binarypb;每个 codename 的 alignment = granule = CmemWordSizeBytes()。Pufferfish bandwidth/latency immediates 由 PufferfishTarget::LocalDmaBandwidth* / InitialDmaLatencyInNs 函数体解码,并在这里对照反编译重新验证。
| TpuVersion / family | Target class | CMEM size (B) | Word / granule (B) | MemBanks(kCmem) | CMEM ISA opcodes | BW VMEM→CMEM (GB/s) | InitialDmaLatency (kCmem, ns) |
|---|---|---|---|---|---|---|---|
| Dragonfish (DF) | DragonfishTarget | chip_parts (≈ 0) | chip_parts | n/a (LogFatal) | none | 0 (base, unmodelled) | 240 (inherited) |
| Jellyfish (JF) | JellyfishTarget | chip_parts (≈ 0) | chip_parts | n/a (LogFatal) | none | 0 (base) | 240 (constant) |
| Pufferfish (PXC, TPU v4) | PufferfishTarget | chip_parts (non-zero) | ~16 (Cmq16B) | 32 | dedicated PXC slot + VS + Misc | 1121 | 50 |
| Viperfish (VFC) | ViperfishTarget | chip_parts (= 0) | chip_parts | n/a (LogFatal) | emitters only, lower to VL/VS | 0 (base) | 1200 / 0 (lite) |
| Ghostlite (GLC / glc, v6e) | GhostliteTarget | chip_parts (= 0) | chip_parts | n/a (LogFatal) | none (no gxc::glc::isa::*Cmem*) | 0 (base) | 1200 |
| 6acc60406 (GFC / gfc, TPU7x) | GhostliteTarget | chip_parts (= 0) | chip_parts | n/a (LogFatal) | none (no gxc::gfc::isa::*Cmem*) | 0 (base) | 1200 |
GOTCHA(字面字节大小为 LOW)— 字面的 per-codename CMEM 字节大小位于嵌入的
chip_parts.binarypbproto 的TpuMemoryParts记录中,尚未从 binary 中提取;C++ 只是从Target+0x460盲读。Pufferfish 的 word/granule “16 B” 是从Cmq16BIndirectStateFactorytemplate-parameter 名称推断的,不是从 proto 读取的。公开 Pufferfish 材料以 per-TensorCore-MiB 量级描述 CMEM,但重新实现者应把字面 size 和 word 视为chip_parts提供的数据,而不是 binary-derived constants。NOTE — Pufferfish 发布了两个 sub-variants,二者都在同一个
PufferfishTargetC++ class 背后承载完整 CMEM 逻辑:pfc::b0(canonical Pufferfish-A)和plc(Pufferfish-Lite),只通过它们的CmemIndirectStateFactory<…Cmq16BIndirectStateFactory>specialization 以及(可能的)不同chip_parts.binarypbCMEM size 区分。C++ Target class 不在二者之间分支。
为什么只有 Pufferfish
专用 CMEM bundle slot 存在,是因为只有 Pufferfish 建模了 CMEM。结构性原因(反编译确认):只有 PufferfishTarget 把 MemBanks(kCmem) override 为真实值,也只有 PufferfishTarget 将 LocalDmaBandwidth*Cmem virtuals 从 base 0.0 改写。专用 cmem_load slot 与 bundle 中的 vector_load slot 分离,因此一次 CMEM read 和一次 VMEM read 可在同一 cycle co-issue,也就是 v4 双操作数获取 datapath。位精确 slot 布局见 slot-cmem-load-pf.md。
Pufferfish CMEM cost-model immediates 由反编译的 movabs/return 函数体重新解码(IEEE-754 doubles):
Pair (PufferfishTarget::…) | Addr | Raw immediate | Value (GB/s) |
|---|---|---|---|
LocalDmaBandwidthVmemToCmem | 0x1d4943e0 | 0x4091840000000000 | 1121.0 |
LocalDmaBandwidthCmemToVmem | 0x1d494440 | 0x40A2460000000000 | 2339.0 |
LocalDmaBandwidthCmemToSmem | 0x1d494480 | 0x4041000000000000 | 34.0 |
LocalDmaBandwidthSmemToCmem | 0x1d4944e0 | 0x4041000000000000 | 34.0 |
LocalDmaBandwidthCmemToHbm | 0x1d494420 | 0x4090E00000000000 | 1080.0 |
LocalDmaBandwidthCmemToCmem | 0x1d494460 | 0x4092A40000000000 | 1193.0 |
InitialDmaLatencyInNs(kCmem) | 0x1d493d00 | table [555.0, 50.0][ms==4] | 50 ns |
这种非对称(读侧 2339 GB/s vs. 写侧 1121 GB/s)反映了 CMEM 物理总线的读路径大约拥有两倍线宽;50 ns startup 比 555 ns VMEM/HBM startup 低一个数量级,反映了 CMEM 的 per-tile-resident 短总线。完全不存在 LocalDmaBandwidthHbmToCmem accessor;HBM↔CMEM 流量按 VMEM 桥接公式建模(HBM→VMEM latency + VMEM→CMEM bandwidth)。
3. 常量打包 — 什么进入 CMEM 以及如何进入
目的
CMEM 是 compile-time-known、read-mostly 数据的 “tile-resident operand store”。本节说明放置标准(MSA 选择打包什么)和填充路径(字节如何到达那里)。读取这些字节的 load 的 bit-level encoding 位于 ISA 页面。
被打包的内容
根据 PXC ISA opcode family、xla_tpu_cmem_* flag family 和 runtime error strings 恢复:
| 打包内容 | 为什么用 CMEM | 来源证据 |
|---|---|---|
| 固定 shape 模型的 Convolution-filter / matmul weights | 程序启动时流入一次,之后多次读取以供给 MXU operand pipe | 主要的 kDmaHbmToCmem → TensorCoreCmemLoad 流程 |
| Look-up tables(activation, saturation, quantisation) | materialise-once, read-many-per-element | LUT placement;高 CMEM read BW |
| Indirect-state descriptor blocks | 驱动 vectorised reads 的 indirect-address resolution | CmemIndirectState(16-B Cmq16B records) |
| All-reduce staging buffers | 在 collectives 期间为 operand staging 释放 VMEM | FLAGS_xla_tpu_scoped_cmem_for_all_reduce @ 0x223b8de8 |
| MXU result direct-to-CMEM | 绕过 matmul output 的 VMEM 往返 | kVectorCmemResult(CreateVectorCmemResult @ 0x1d4d99a0) |
| HLO output buffers(experimental) | 将配置比例的 CMEM 用于 top-level outputs | FLAGS_xla_tpu_experimental_cmem_fraction_for_hlo_outputs @ 0x223b8cc8 |
| CMEM stack scalars(loop counters) | 运行时可变;由 load-and-pop 流式读取 | kCmemStackOffset, kVectorCmemLoadAndPop |
In-CMEM copy spans (CmemSpan) | sliding-window sequential reads | FLAGS_xla_tpu_allow_in_cmem_copy @ 0x223b30d0(默认关闭) |
MSA 放置决策
打包由 Memory-Space Assignment pass 决定,也就是放置 VMEM 的同一个 kAlternate-tier coloring(overview.md §4),并受与 xla_jf_vmem_* 一一对应的 per-tier xla_tpu_cmem_* flag family 门控。总开关是 FLAGS_xla_tpu_cmem_memory_space_assignment (0x223c1750);字节上限是 FLAGS_xla_tpu_max_cmem_used_by_memory_space_assignment (0x223ae230);prefetch/eviction caps、repack/retry counts 和 overlap ratios 构成其余 family(0x223c0250 … 0x223c1e78)。
两层拉扯(由 CmemSizeBytes() > 0 反编译门控,见下):
| HloValue characteristic | 胜出 |
|---|---|
| MXU primary operand(matmul A/B),需要 VS-slot ports | 该 codename 的 FastMemorySpace() — VF/GL 上为 VMEM,JF 上为 HBM,PF 上为 CMEM(见下面逐 codename 拆解) |
| 固定 shape conv 的 weight tile;LUT;quant table(read-mostly, small) | CMEM(高 read BW,专用 bundle slot)— 仅 Pufferfish |
| Activation tile(随 batch 改变) | VMEM |
| All-reduce staging | 若 xla_tpu_scoped_cmem_for_all_reduce 则 CMEM,否则 VMEM |
| HLO top-level output | 默认 HBM;若 …cmem_fraction_for_hlo_outputs > 0 则 CMEM |
| 任何地方都没有 live-range headroom | HBM(spill, fetch on demand) |
FastMemorySpace() 是逐 codename 且经反编译验证的:JellyfishTarget::FastMemorySpace() (0x1d491a20) 返回 kHbm(=1)(Jellyfish 没有片上 fast operand tier);ViperfishTarget (0x1d49c3c0) 和 GhostliteTarget (0x1d499000) 都返回 kVmem(=3);而让整个 CMEM datapath 存在的关键一项,PufferfishTarget::FastMemorySpace() (0x1d495f00) 返回 kCmem(=4)。在 Pufferfish 上,CMEM 就是 fast tier:单条 mov $0x4,%al; ret。因此 MSA 只在 Pufferfish 上偏向把 read-mostly tiles 放入 CMEM,因为 active Target 同时宣称 kCmem fast space 和非零 LocalDmaBandwidthCmemToVmem。
NOTE(CONFIRMED gate)— 任何宣称零 CMEM 的 codename 都会短路整个 CMEM 放置路径。反编译的
LloInstruction::CreateVectorCmemResult(0x1d4d99a0) 断言parent->module()->target().CmemSizeBytes() > 0,否则LogMessageFatal;因此除非 active Target 具有非零 CMEM,否则 CMEM-result write 不可达。相同不变量也保护 MSA,并伴随 rodata diagnostic"CMEM is not supported."。省略CmemSizeBytes() > 0前置条件的重新实现,会把 CMEM 放置错误路由到无法支撑它的 codename。
填充路径
CMEM 由 program-prologue DMA 填充,而不是在 NEFF / image load 时填充。编译后的 XDB 程序把 CMEM image 声明嵌入为 ProgramMemoryMetadata_Allocation 条目,memory_space = kCmem,与 VMEM/HBM/SMEM 完全一样;CreateFromProto (0x1c631f20) 将它们转化为 runtime allocator offsets。字节随后通过编译后的 prologue 到达:
| 填充机制 | Emitter | Cost-model BW (PF) |
|---|---|---|
| HBM→CMEM bulk fill(weights, LUTs) | LloRegionBuilder::DmaHbmToCmemInBytes @ 0x1d576e60(kDmaHbmToCmem) | VMEM-bridged(无 direct HbmToCmem BW) |
| VMEM→CMEM staged fill | LloRegionBuilder::DmaVmemToCmemInBytes @ 0x1d576c80 | 1121 GB/s |
| In-program VPU store | TensorCoreVectorStore_CmemStore / …NoOffset(折叠进 VS slot) | (VS write port) |
| MXU result direct write | kVectorCmemResult(CreateVectorCmemResult @ 0x1d4d99a0) | (result-buffer drain) |
| SMEM→CMEM scalar staging | DmaSmemToCmemInBytes @ 0x1d577220(只有这个方向有 emitter;没有 DmaCmemToSmemInBytes) | 34 GB/s |
bulk fill 后,CmemIndirectState ctor 会在 image 头部构建 indirect-state vector,使 VPU bundle slot 能对 resident tiles 发出 TensorCoreCmemLoad。回写到 HBM 的 eviction(MSA spill path)使用 DmaCmemToHbmInBytes (0x1d577040)。
GOTCHA — read-only 是约定,不是硬件写保护。 CMEM “read-mostly” 只是一种编译器分类:ISA 具有显式 CMEM write opcodes(
VectorCmemStore,VectorCmemStoreNoOffset),有七条 DMA write paths 以 CMEM 为目标,MXU result drain 也会写它。LSRA-v2 将 compile-time-constant CMEM loads 视为 rematerialisable,MSA 将 read-mostly tiles 偏向 CMEM,但如果有 bug 的程序覆盖了 constant region,后续读取会被静默破坏;不会有硬件 fault。保护完全在 SSA / dataflow 层级。
耗尽处理
编译时 CMEM 耗尽模式(来自 runtime error strings):
- 请求大小超过容量 —
result.memory_space_assignment_size_in_bytes <= target.UserAllocationSharedMemoryLimitBytes(MemorySpace::kCmem)(0x1d616680);违反时LogMessageFatal("Requested Cmem size for memory space assignment (…)")。 - Target 宣称零 CMEM — 上述
CmemSizeBytes() > 0gate;发出"CMEM is not supported."并跳过 CMEM(或在 custom-call 要求 CMEM 时编译失败)。 - 越界 byte address — 每次发出 CMEM operand 时都断言
byte_address < target().CmemSizeBytes();违反时LogMessageFatal。 - MSA 无法放置 — 最多重试
xla_tpu_cmem_max_retries次,然后 fallback 到 HBM 并记录软 diagnostic"Ignoring cmem allocation: …"/"Ignoring cmem allocation storage"。 - CmemSpan 被禁用 —
cmem_indirect_state_factory.h中的use_cmem_span_ == true/!use_cmem_span_不变量;当xla_tpu_allow_in_cmem_copy关闭却请求 span 时,会以"Disabled cmem span"LogFatal。
运行时耗尽走标准 BestFitAllocator::Allocate ResourceExhaustedError 路径(hbm-allocator.md),这种情况很少见,因为 CMEM image 在编译时已完全 materialised,并在加载时 replay。
交叉引用
- overview.md — 六区域 memory-space taxonomy、
MemorySpaceenum(kCmem=4)、共享BestFitAllocator,以及本页针对 CMEM 专门化的 compile-time→runtime hand-off - smem-scalar-memory.md — sibling 片上 scalar tier(
kSmem=5);SMEM↔CMEM 34 GB/s staging pair,以及缺少CmemWordSizeLog2的对比 - vmem-allocator.md — CMEM 在 MSA 中竞争的
kAlternatefast tier;逐代 VMEM word/bankConfig - hbm-allocator.md — CMEM 共享的通用 best-fit allocate/deallocate 算法;运行时
ResourceExhaustedError路径 - tpu-buffer-layout.md — 逻辑 XLA buffer 如何映射到这些层级中的物理 offsets
- slot-cmem-load-pf.md — 位精确的 Pufferfish
cmem_loadbundle slot(本页引用的读取访问路径) - bundle-pf-51b.md — 专用 CMEM-load slot 所在的 51-byte Pufferfish TensorCore bundle
- memory-space-enum.md — ISA / operand-tag 层级的 LLO
MemorySpaceenum - msa-overview.md — 通过
xla_tpu_cmem_*flag family 为 CMEM 着色的 placement pass - back to index — Part X — On-Chip Memory & DMA