TpuChipConfig
本页中的所有地址和偏移均适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so(BuildID md589edbbe81c5b328a958fe628a9f2207d)。其他版本会有所不同。
摘要
一个 TPU 世代有两种嵌入式 proto 描述,而且很容易混淆。chip_parts(见 chip_parts.binarypb 解码)描述硅片的能力几何,即内存大小、MXU 维度和时钟。TpuChipConfig 描述某个特定 (version, variant) 组合的运行时模式:bounce buffer、sync-flag 资源以及设备端传输窗口。TpuChipConfig::Create 解析一个 embed://tpu_chip_config/<version>_chip_configs_<alias>.binarypb 资源,把它解析成 TpuChipConfigProto,并物化为驱动层用来配置每核队列和 DMA 缓冲区的 TpuChipConfig 对象。
本页记录这条解析与物化路径,并另行记录解码后的能力常量经由 xla::jellyfish::Target 对象到达的消费表面。Target 是运行时硬件抽象对象;chip_parts 在启动时填充它的字段块,一组很小的访问器(LaneCount、SublaneCount、ChunksPerTile、HbmSizeBytes、TensorCoreFrequencyInMegaHertz,等等)从中读取单个字段。这些访问器就是成本模型、ISA 发射器和 tiling pass 调用的 API;下面的偏移映射让来自 Target 实例的结构体 dump 可读。
对于重新实现,契约是:
TpuChipConfig::Create路径:version+variant →kChipConfigAliases查找 →embed://tpu_chip_config/…→ReadBinaryProto→FromProto。TpuChipConfig对象头:HAL 会分支检查的+8/+9/+10处三个模式布尔值(Megacore/Megachip/TcControl),以及按运行时{kTensorCore=0, kBarnaCore=1, kSparseCore=2}枚举索引的每核EnumMap<TpuCoreType, …, 3>表。Target字段块:哪个结构体偏移保存每个解码后的chip_parts常量,以及读取它的访问器。- 消费者:几何访问器(
LaneCount/SublaneCount/ChunksPerTile/VexMatrixWidthToSyU32)以及调用它们的对象(成本模型、ISA 发射器、拓扑)。
| 配置解析器 | tpu::TpuChipConfig::Create @ 0x20AE98E0 |
| 配置解析函数 | tpu::TpuChipConfig::FromProto @ 0x20AEA100 |
| 配置构造函数 | tpu::TpuChipConfig::TpuChipConfig @ 0x20AF6300 |
| 源文件 | learning/45eac/tpu/runtime/topology/tpu_chip_config.cc(Create alias-log 第 368 行) |
| 别名映射 | kChipConfigAliases(gtl::flat_map<TpuVersionAndVariant, …>,4 个条目) |
| 模式标志 | Megacore +8 (0x20AFCA00), Megachip +9 (0x20AFCC00), TcControl +10 (0x20AFCC20) |
| 几何描述符 | Target+0x3B8 → tpu::TpuTopology* |
| 能力字段块 | Target+0x438..+0x510(由 TpuChipParts::FromProto 填充) |
TpuChipConfig::Create
目的
Create 为一个 (version, variant) 组合取得模式配置:TpuChipConfigProto 枚举 SharedMemoryRegion 记录和 SyncFlag 记录(由 FromProto 解析),驱动用它们为每个核心布置 bounce buffer 和 sync-flag 资源。它是 chip_parts 的能力几何解析器 TpuChipParts::DefaultsForVersion (0x20B1B040) 的模式配置对应物。二者是有意平行的设计:同样的形状,同样的 embed:// 机制,但位于不同翻译单元:Create 在 tpu_chip_config.cc 中,DefaultsForVersion 在 tpu_chip_parts.cc 中(其 fatal-log 字符串引用 tpu_chip_parts.cc:341,343,345)。
算法
StatusOr<TpuChipConfig> TpuChipConfig::Create(TpuVersion v, string_view variant, // sub_20AE98E0
string_view config_variant):
// 1. Resolve a (version, variant) alias to a config-variant name.
key = TpuVersionAndVariant{v, variant}
hit = kChipConfigAliases.find(key) // 4-entry flat_map of TpuVersionAndVariant
if hit and bcmp(hit->value, config_variant) != 0: // alias differs from requested
LOG(INFO) << "Resolved chip config alias " << config_variant << "->" << hit->value
<< " for " << v << ", " << variant // tpu_chip_config.cc:368
alias = hit->value // (logged only when the alias renames the request)
else:
alias = config_variant // no alias / identity: use config_variant verbatim
// 2. Build the embed:// resource path and read it.
name = AsciiStrToLower(TpuVersionToString(v))
if variant.non_empty(): StrAppend(&name, "_", variant)
filename = CatPieces("embed://tpu_chip_config/", name, "_chip_configs_", alias, ".binarypb")
status = tsl::ReadBinaryProto(Env::Default(), filename, &proto) // tpu_chip_config.cc:379-383
if status != Ok:
return StatusBuilder(...) << "Failed to obtain chip config \"" << alias
<< "\" for version " << v << ", variant \"" << variant << "\""
return TpuChipConfig::FromProto(proto) // sub_20AEA100
```text
> **怪异点 —** 这里的 `embed://` scheme 是 `tpu_chip_config/`,而 `DefaultsForVersion` 中是 `tpu_chip_parts/`;后缀是 `_chip_configs_<alias>.binarypb`(注意复数以及 alias 槽位),而不是 `_chip_parts.binarypb`。这两个解析器面向不同的资源族。`chip_config` blob 是嵌入式 TOC 中的 `*_chip_configs_*.binarypb` 条目;不要把它们和九个 `*_chip_parts.binarypb` 能力 blob 混为一谈。与 `DefaultsForVersion` 不同,`Create` 失败时返回 `Status`,而不是 `CHECK` 失败:缺失配置是可恢复的,缺失能力描述则是致命的。
### FromProto 物化的内容
`TpuChipConfig::FromProto` (`0x20AEA100`) 遍历 `TpuChipConfigProto`,迭代其中的 `SharedMemoryRegion` repeated 字段和 `SyncFlag` repeated 字段,把每个条目插入 `TpuChipConfig` 的 `flat_hash_map<TpuSharedMemoryOnChip, BounceBuffer>` 和 sync-flag-resource 表。`TpuChipConfig` 构造函数 (`0x20AF6300`) 接收该 map、三个前置布尔值以及每核布局。结果对象由 `TpuPxcDriver::InitializeCores` (`0xE806500`) 和 `TpuChipCommonImpl::RegisterContinuationQueueConfigs` (`0xE72B340`) 消费,用来配置硬件队列;它是一个*资源*对象,而不是能力 `Target`。
### TpuChipConfig 对象头
构造后对象的前 11 个字节是固定头部,构造函数从其前置标量实参写入(`0x20AF6300` 存储 `a2`→`+0`、`a3`→`+8`、`a4`→`+9`、`a5`→`+10`),三个单行 const 访问器暴露三个模式标志。这些是重新实现必须逐字节复现的每配置布尔值,因为 HAL 会在启动时据此分支:
| 偏移 | 访问器 (VA) | 类型 | 保存内容 |
|---:|---|---|---|
| +0x00 | (constructor `a2`) | int64 | 前置标量字(每配置计数) |
| +0x08 | `Megacore` (`0x20AFCA00`) | bool | megacore 模式(名称已确认;语义为推断) |
| +0x09 | `Megachip` (`0x20AFCC00`) | bool | megachip 模式(名称已确认;语义为推断) |
| +0x0A | `TcControl` (`0x20AFCC20`) | bool | TensorCore-control 模式(名称已确认;语义为推断) |
每个访问器字面上都是 `return *((uint8_t*)this + N)`:`Megacore` 读取 `+8` (`0x20AFCA00`),`Megachip` 读取 `+9` (`0x20AFCC00`),`TcControl` 读取 `+10` (`0x20AFCC20`)。字节位置和访问器符号来自反汇编,精确到字节;每个模式的*含义*(megacore 作为两个 TensorCore 融合拓扑,megachip 作为多 die 单设备拓扑)是标准 TPU 解释,是推断而非由此二进制直接证明。`xla::jellyfish::Target::IsMegachip` (`0x10914F60`) 通过 `Target` 在 `Target+0x3B8→+0x18` 持有的配置指针(`*(TpuChipConfig**)([Target+0x3B8]+24)`)消费 `+9` 字节,并且还要求 `[Target+0x3B8]+148` 计数为正;因此 megachip 并行编译同时需要 `Megachip` 字节置位以及描述符计数非零。
> **怪异点 —** 这三个字节是 `TpuChipConfig` *资源*对象上的模式状态,不是能力几何。它们不位于本页同时映射的 `Target` 字段块中;不要在 `Target` 偏移处寻找 `Megachip`。选择加载*哪个*配置 blob 的选择器是传给 `Create` 的 variant 字符串,而该 blob 内的 megacore/megachip 布尔值就是 `Megacore()`/`Megachip()` 随后暴露的内容。
### 每核布局的键控
在头部之后,构造函数存储一长串按核心类型划分的表:`EnumMap<TpuCoreType, vector<InfeedQueue>, 3>`、`EnumMap<TpuCoreType, vector<ContinuationQueue>, 3>`、`EnumMap<TpuCoreType, vector<OutfeedQueue>, 3>`、`EnumMap<TpuCoreType, UserInterrupts, 3>` 等等(可在构造函数的 mangled 签名中看到)。每一个都是 arity 为 3 的 `EnumMap`,按运行时 `tpu::TpuCoreType` 枚举索引。该枚举是 `{kTensorCore=0, kBarnaCore=1, kSparseCore=2}`;`TpuCoreTypeFromProto` (`0x20B36840`) 将 wire 值 `TENSOR_CORE=1→0`、`BARNA_CORE=2→1`、`SPARSE_CORE=3→2`(proto 值减一,其他值会在 `tpu_chip_enums.cc:301` 触发 fatal `"Invalid core type"`)。想索引每核队列表的重新实现必须使用这个从 0 开始的运行时枚举,而不是从 1 开始的 proto 枚举。
---
## Target 字段块
来自 `chip_parts` 的能力常量不在 `TpuChipConfig` 中;它们位于 `xla::jellyfish::Target` 对象中,并由 `TpuChipParts::FromProto` (`0x20B1B400`) 和 `TpuMemoryParts::FromProto` (`0x20B333A0`) 在启动时填充。每个常量都有固定结构体偏移,由单行访问器读取。下面的偏移映射逐字节读取自访问器反汇编(例如 `HbmSizeBytes` 字面上是 `return *((int64_t*)this + 138)`,即 `Target+0x450`)。
| Target 偏移 | 访问器 (VA) | 类型 | 保存内容 |
|---:|---|---|---|
| +0x398 | `Target::TpuVersionToString` (`0x12772CC0`) | int32 | `tpu_version` (0..5 → jellyfish/dragonfish/pufferfish/viperfish/ghostlite/`6acc60406`) |
| +0x3B8 | `LaneCount`/`SublaneCount`/… (`0x1D60F400`) | `TpuTopology*` | 几何描述符指针 |
| +0x3B8→+0x198 | `LaneCount` (`0x1D60F400`) | int64 | `lane_count`(所有世代 =128) |
| +0x3B8→+0x1A0 | `SublaneCount` (`0x1D60F300`) | int64 | `sublane_count`(所有世代 =8) |
| +0x450 | `HbmSizeBytes` (`0x1D615320`) | int64 | HBM 大小(v7x: 102,005,473,280) |
| +0x458 | `VmemSizeBytes` (`0x1D615E00`) | int32 | VMEM 大小(v7x: 67,108,864) |
| +0x460 | `CmemSizeBytes` (`0x1D615E20`) | int64 | CMEM 大小(v7x: 0) |
| +0x468 | `SflagSizeBytes` (`0x1D615E60`) | int32 | SFLAG 大小(v7x: 16,384) |
| +0x470 | `SmemSizeBytes` (`0x1D615E40`) | int32 | SMEM 大小(v7x: 1,048,576) |
| +0x50C | `VmemWordSizeBytes` (`0x1D617300`) | int32 | VMEM 字大小(v7x: 512) |
| +0x90C | `TensorCoreFrequencyInMegaHertz` (`0x1D615B60`) | int32 | TC 频率 MHz(v7x: 1900) |
| +0x910 | `HbmFrequencyInMegaHertz` (`0x1D615BA0`) | int32 | HBM 频率 MHz(v7x: 7200) |
这些偏移直接来自访问器函数体:`LaneCount` 返回 `*(int64_t*)(*((void**)this + 119) + 408)`,其中 `this+119*8 = Target+0x3B8` 是 `TpuTopology*`,而 `+408 = +0x198` 是其中的 `lane_count`。`SublaneCount` 读取同一描述符上的 `+416 = +0x1A0`。`HbmSizeBytes` 是 `*((int64_t*)this + 138) = Target+0x450`;`VmemSizeBytes` 是 `*((int32_t*)this + 278) = Target+0x458`;`SmemSizeBytes` 是 `+284 = +0x470`;`SflagSizeBytes` 是 `+282 = +0x468`;`VmemWordSizeBytes` 是 `+323 = +0x50C`;`TensorCoreFrequencyInMegaHertz` 是 `+579 = +0x90C`;`HbmFrequencyInMegaHertz` 是 `+580 = +0x910`。`+0x3B8` 描述符的完整布局见 [TpuTopology 结构体](tpu-topology-struct.md)。
> **注意 —** `Target+0x398` 处的 `tpu_version` 是驱动每个 dispatch 的单一按版本开关:MSA 家族选择、循环展开策略和每 codename 的 `*Target` vtable。`+0x438..+0x510` 处的能力常量以及 `+0x3B8` 处的几何是*数据*;`+0x398` 是选择哪个 `chip_parts` blob 填充它们的*选择器*。
---
## 几何访问器及其消费者
### ChunksPerTile
`Target::ChunksPerTile` (`0x1D60F2C0`) 是派生几何值的典型例子:它将 `lane_count` 除以 `sublane_count`。
```c
int64 Target::ChunksPerTile(): // sub_1D60F2C0
topo = *((void**)this + 119) // Target+0x3B8
lane = *(int64_t*)(topo + 0x198) // lane_count
sublane = *(int64_t*)(topo + 0x1A0) // sublane_count
return lane / sublane // 128 / 8 = 16 on every gen in this build当两个操作数都能放入 32 位时会走 32 位快速路径(它们确实可以),所以除法是无符号 32 位除法。每个世代都是 lane=128、sublane=8,因此 ChunksPerTile() == 16,即每个 HBM tile 有十六个 8×128 lane-chunk。HardwareLayout pass 从同两个字段标记 Tile(SublaneCount(), LaneCount()) = Tile(8, 128)。
VexMatrixWidthToSyU32
pxc::mnemonics::VexMatrixWidthToSyU32(每个 VEX 指令族一个特化,例如 0x1D2C20A0)是 ISA 发射器侧的 lane 几何消费者。它把 TensorCore-vector 指令上的 VexMatrixWidth 枚举转换成要编码的具体 SyU32 矩阵宽度。
uint32 VexMatrixWidthToSyU32(const Instr* a1): // sub_1D2C20A0 (one of several specializations)
switch (a1->vex_matrix_width): // a1[7]
case 0: return 128 // the default full MXU lane width
case 1: return a1->width_field[0] // explicit per-operand widths
case 2: return a1->width_field[1]
...
case 7: return a1->width_field[6]
default: LOG(FATAL) << "Invalid VexMatrixWidth value" // pf_proto_to_env_utils.h:1550
```text
> **怪异点 —** `case 0` 返回字面量 `128`,不是从 `Target` 读取的值。MXU lane 宽度在 ISA 发射器 helper 中硬编码,因为它是不变量:本构建中每个世代的 `lane_count` 都是 128。非零 case 从指令读取显式宽度字段,用于 segmented/transpose VEX 变体。只根据 `Target::LaneCount` 驱动矩阵宽度的重新实现这里仍会得到 128,但会漏掉每操作数覆盖 case。
### 谁读取配置
解码后的常量扇出到三个消费者层:
- **成本模型。** `NodeCost` 以 `cycles × trip / (TensorCoreFrequencyInMegaHertz() × 1e6)` 计算 wall-clock 时间,读取 `Target+0x90C`。内存成本读取 `HbmSizeBytes`/HBM 带宽和 granule。见 [成本模型概览](../cost/overview.md)。
- **ISA 发射器。** `VexMatrixWidthToSyU32` 和 bundle 编码器读取 lane/sublane 几何和寄存器计数,以选择指令编码。见 [ISA 概览](../isa/overview.md)。
- **拓扑 / tiling。** `LaneCount`/`SublaneCount`/`ChunksPerTile` 供给 `HardwareLayout` tile 标记和 layout-assignment tiling pass。见 [TpuTopology 结构体](tpu-topology-struct.md)。
---
## 相关组件
| 名称 | 关系 |
|---|---|
| `TpuChipParts::DefaultsForVersion` | `tpu_chip_parts.cc` 中的平行能力解析器;`embed://tpu_chip_parts/…_chip_parts.binarypb`,缺失时 fatal |
| `TpuChipParts::FromProto` | 填充本页访问器读取的 `Target+0x438..+0x510` 能力块 |
| `TpuChipConfig::FromProto` | 将模式配置(SharedMemoryRegion / SyncFlag)解析为资源对象 |
| `TpuChipConfig::Megacore` / `::Megachip` / `::TcControl` | 配置对象上 `+8`/`+9`/`+10` 模式字节访问器 |
| `Target::IsMegachip` | 读取配置的 `Megachip` 字节(经由 `Target+0x3B8→+0x18`)以门控 megachip 并行编译 |
| `TpuPxcDriver::InitializeCores` | 消费 `TpuChipConfig` 资源对象以配置每核队列 |
| `xla::jellyfish::Target` | 其字段块和访问器在本页映射的运行时 HAL 对象 |
## 交叉引用
- [chip_parts.binarypb 解码](chip-parts-binarypb.md) — 其解码字段填充本页映射的 Target 块的能力 blob
- [每 Codename 常量表](per-codename-hw-constants.md) — 落到这些 Target 偏移中的每代值
- [Codename 矩阵](tpu-version-codename-matrix.md) — TpuVersion ↔ codename 映射(`Target+0x398` 选择器)
- [每代对比矩阵](../appendix/per-gen-comparison-matrix.md) — 跨页面汇总的每代对比
- [TpuTopology 结构体](tpu-topology-struct.md) — lane/sublane 访问器读取的 `Target+0x3B8` 几何描述符
- [成本模型概览](../cost/overview.md) — 读取 `TensorCoreFrequencyInMegaHertz`、HBM 大小/带宽和 granule
- [ISA 概览](../isa/overview.md) — 通过发射器读取 lane/sublane 几何和寄存器计数