Skip to content

TpuChipConfig

本页中的所有地址和偏移均适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(BuildID md5 89edbbe81c5b328a958fe628a9f2207d)。其他版本会有所不同。

摘要

一个 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 在启动时填充它的字段块,一组很小的访问器(LaneCountSublaneCountChunksPerTileHbmSizeBytesTensorCoreFrequencyInMegaHertz,等等)从中读取单个字段。这些访问器就是成本模型、ISA 发射器和 tiling pass 调用的 API;下面的偏移映射让来自 Target 实例的结构体 dump 可读。

对于重新实现,契约是:

  • TpuChipConfig::Create 路径:version+variant → kChipConfigAliases 查找 → embed://tpu_chip_config/…ReadBinaryProtoFromProto
  • 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.ccCreate alias-log 第 368 行)
别名映射kChipConfigAliasesgtl::flat_map<TpuVersionAndVariant, …>,4 个条目)
模式标志Megacore +8 (0x20AFCA00), Megachip +9 (0x20AFCC00), TcControl +10 (0x20AFCC20)
几何描述符Target+0x3B8tpu::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:// 机制,但位于不同翻译单元:Createtpu_chip_config.cc 中,DefaultsForVersiontpu_chip_parts.cc 中(其 fatal-log 字符串引用 tpu_chip_parts.cc:341,343,345)。

算法

c
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=10`、`BARNA_CORE=21`、`SPARSE_CORE=32`(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=128sublane=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 矩阵宽度。

c
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 几何和寄存器计数