TpuHal 类层级
地址适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so。其他版本会有所不同。
摘要
TPU 运行时暴露一个芯片代际的四个概念性“产品”——硬件抽象、逐核心执行上下文、成本模型和 ISA 编码器。若重新实现者预期在一个工厂下看到四个并列的 TpuHal* 类,将找不到它们。符号表毫不含糊:实际上只有 TpuHalHardware* 是 tpu::TpuHal* 命名的类。TpuHalCore、TpuHalCostModel 和 TpuHalEncoder 在二进制的符号表中完全不存在——它们是由三个独立类树(tpu::TpuCore、xla::jellyfish::CycleTable、tpu::TpuCodec/isa::Encoder)承担的角色,HAL 拥有、配对或供给这些类树,但它们不共享 TpuHalFactory 基类,也不是由 HAL 工厂产生。
本页用真实类名、vtable 地址、槽位数量,以及它们之间的单继承边,映射全部四个层级。这四棵树只共享一个轴:tpu::TpuVersion。HAL 工厂通过注册表按它分派;芯片/核心 impl 由 HAL 分配的 family impl 选择;TpuCodec::Create 对它 switch;CycleTable::Create 在 FunctionRegistry 中查找它。理解这四个“产品”只通过 TpuVersion 耦合——并且只有其中一个是 TpuHal 类——是理解为什么各树的 override 矩阵差异如此之大的前提。
Hardware 树是浅层树:TpuHal(抽象)→ TpuHalHardwareImpl(中间层)→ {Jxc,Pxc,Vxc}HardwareImpl(叶子)。Core/Chip 树深一层。CostModel 和 Encoder 树是扁平的(每个叶子都是抽象根的直接子类,没有共享中间层)。所有继承都是单继承(__si_class_type_info);四棵树中没有任何多重继承。
对重新实现而言,契约是:
- 只有
TpuHalHardware*是TpuHal类;其他三个角色是以同一个TpuVersion为键的独立类树。 - Hardware 树的基类/中间层/叶子结构、23 槽 vtable,以及 impl 对象布局(Jxc/Pxc 为 208 B,Vxc 为 216 B;helper 指针位于 +200)。
- 配对的 Core(46/48 槽)和 Chip(25/27 槽)树的深度和槽位数量,以及 CostModel(5 槽)和 Encoder(6/14/20 槽)树。
- 四棵树之间的所有权与数据流耦合关系。
| HAL 对象基类 | tpu::TpuHal (_ZTV @ 0x21d34420, 23 slots, pure at 2 & 20) |
| HAL 中间层 | tpu::TpuHalHardwareImpl (no own _ZTV; _ZTI @ 0x21cc52e0) |
| HAL 叶子 | TpuHal{Jxc,Pxc,Vxc}HardwareImpl (_ZTV 0x215fe580 / 0x21608618 / 0x21cabfc0) |
| Impl 对象大小 | 208 B (Jxc, Pxc) · 216 B (Vxc) · helper pointer at +200 (obj[25]) |
| Core 树 | tpu::TpuCore (46-slot base) → TpuCoreCommonImpl → TpuCoreDriverCommonImpl → 3 leaves (48-slot) |
| Chip 树 | tpu::TpuChip (25-slot base) → TpuChipCommonImpl → TpuChipDriverCommonImpl → 3 leaves (27-slot) |
| CostModel 树 | xla::jellyfish::CycleTable (5-slot) → {Jf,Pf,Vf,Glc,Gfc}CycleTable (flat, 5 leaves) |
| Encoder 树 | tpu::TpuCodec (6-slot) + isa::Encoder (14/20-slot) — not a TpuHal class |
| 共享轴 | tpu::TpuVersion (0..5) |
只有 Hardware 是 TpuHal 类
一次符号扫描即可确定命名问题。二进制中完整的 tpu::TpuHal* 类集合是 Hardware 家族及其支持类;另外三个“产品”名称不存在:
present tpu::TpuHal (abstract HAL object base)
present tpu::TpuHalHardwareImpl (intermediate)
present tpu::TpuHal{Jxc,Pxc,Vxc}HardwareImpl
present tpu::TpuHalFactory (abstract factory interface)
present tpu::TpuHalHardwareFactoryBase (concrete Create/CanCreate)
present tpu::TpuHal{Jxc,Pxc,Vxc}HardwareFactory
present tpu::TpuHal{Jxc,Pxc,Vxc}CommonHelper
present tpu::TpuHalCommonStates (non-polymorphic data cache; no vtable/RTTI)
absent tpu::TpuHalCore — the role is filled by tpu::TpuCore
absent tpu::TpuHalCostModel — the role is filled by xla::jellyfish::CycleTable
absent tpu::TpuHalEncoder — the role is filled by tpu::TpuCodec / isa::Encoder
```text
> **易错点 —** 并不存在“由一个工厂产生的四个 `TpuHal` 并列产品类型”。`TpuHalFactory` 只产生一种对象——`TpuHal{Jxc,Pxc,Vxc}HardwareImpl`。"Core"、"CostModel" 和 "Encoder" 是真实的逐家族/逐代际层级,但它们分别位于 `tpu::`(Core/Chip)、`xla::jellyfish::`(CostModel)和 `tpu::`/`isa::`(Encoder)中——没有任何一个继承自 `TpuHal` 基类,也没有任何一个由 HAL 工厂构建。若重新实现让四者都派生自一个共同的 `TpuHalFactory`,就无法匹配二进制的类图。
---
## 层级 1 — TpuHalHardware(HAL 对象)
这是工厂实际产生的唯一一棵树。三层结构,全程单继承(由 typeinfo+0x10 处的 `__si_class_type_info` 基类指针验证):
```text
(abstract HAL object)
tpu::TpuHal
_ZTV 0x21d34420 _ZTI 0x21d344e8
23 slots; pure-virtual at slot 2 (Type) and slot 20 (CreateAndInitializeChips)
| __si base
(intermediate; no own _ZTV)
tpu::TpuHalHardwareImpl
_ZTI 0x21cc52e0
supplies Type (slot 2 → 0x1d3b5480) and the stricter
ValidateTopology (slot 19 → 0x1d3b54a0)
| __si base (×3)
+-----------------------+-----------------------+
| | |
TpuHalJxcHardwareImpl TpuHalPxcHardwareImpl TpuHalVxcHardwareImpl
_ZTV 0x215fe580 _ZTV 0x21608618 _ZTV 0x21cabfc0
_ZTI 0x215fe648 _ZTI 0x216086e0 _ZTI 0x21cac088
208 B (0xD0) 208 B (0xD0) 216 B (0xD8)
helper @ +200 helper @ +200 helper @ +200, flag byte @ +208
| | |
v v v
TpuHalJxcCommonHelper TpuHalPxcCommonHelper TpuHalVxcCommonHelper
(heap-owned; freed raw (heap-owned) (heap-owned; non-trivial dtor,
in JxcImpl D2) called then freed in VxcImpl D2)Vtable 布局 — 23 个槽位
基类 TpuHal vtable 包含 23 个函数指针槽位。槽位 0/1 是析构函数;槽位 2 和 20 在抽象基类中是 __cxa_pure_virtual;其余 20 个携带具体基类实现。中间层 TpuHalHardwareImpl 让该类对三个家族都可实例化——它填充槽位 2(Type),并提供更严格的槽位 19(ValidateTopology)。完整的逐家族 override 矩阵(每个叶子 override 哪些槽位及其地址)位于 HAL 工厂 Override 矩阵 页面;本页记录布局和对象。
TpuHalHardwareImpl::Type(槽位 2,0x1d3b5480)返回常量 0——即 kHardware product-type 标签,三个家族完全相同。TpuHalHardwareImpl::ValidateTopology(槽位 19,0x1d3b54a0)链式调用 TpuHal::ValidateTopology,随后调用 ScanHardwareDevices,比较检测到的 version 和 TpuChipParts::variant_name 与配置拓扑,并在不匹配时以 "Detected hardware version ... does not match with topology ..." 拒绝。
对象布局
impl 对象由家族 CreateImpl 分配并盖上 vtable,并由其 D2 析构函数销毁。二者都确认了布局:
| 字段 | 偏移 | 类型 | 含义 |
|---|---|---|---|
| vtable 指针 | +0 | void* | 逐家族 impl vtable(off_215FE590 / off_21608628 / off_21CABFD0) |
| 基类状态 | +8 .. | (TpuHal base) | TpuVersion、work-queue、topology 等(由 TpuHal::TpuHal 设置) |
helper | +200 (obj[25]) | TpuHal*CommonHelper* | 堆拥有的 CommonHelper;在 CreateAndInitializeChips 前为 nullptr |
mesh_torn_down flag | +208 | uint8 | 仅 VXC — 保护 PreTearDownChips 避免重复 mesh teardown;208 B 的 Jxc/Pxc 对象中不存在 |
怪异点 — VXC impl 为 216 字节(
operator new(0xD8)),比 208 字节(0xD0)的 Jxc 和 Pxc impl 大 8 字节。额外空间是 +208 处的 flag 字节,VxcImpl::PreTearDownChips(0x1d111720)读取它以跳过重复 mesh teardown。CommonHelper 指针在三者中都保持在 +200(obj[25])。若重新实现假设所有家族都是统一的 208 字节对象,就会写越 Jxc/Pxc 分配边界或少分配 Vxc 对象。
两个 D2 析构函数在释放 helper 时也不同:JxcImpl::~JxcImpl(0x0e724de0)重新植入 vtable,读取 obj[25],将其置空,并直接 free()——JXC helper 是 POD-trivial。VxcImpl::~VxcImpl(0x1d111740)在 free() 前调用 TpuHalVxcCommonHelper::~TpuHalVxcCommonHelper(helper)——VXC helper 有非平凡析构函数。
层级 2 — TpuCore 和 TpuChip(逐核心角色)
"Core" 角色是 tpu::TpuCore:位于芯片上的 TensorCore/BarnaCore 执行上下文。它由芯片(TpuChipCommonImpl::CreateCores)创建,而芯片又由 HAL 的 CommonHelper::CreateChips 创建。Core 树有四层——比 Hardware 深一层——并与同样深的 TpuChip 树配对。
tpu::TpuChip (ROOT) tpu::TpuCore (ROOT)
_ZTV 0x21cad4e8 (25 slots) _ZTV 0x21cad8e8 (46 slots)
| __si | __si
tpu::TpuChipCommonImpl tpu::TpuCoreCommonImpl
_ZTV 0x21cad3d8 _ZTV 0x21cad730
| __si | __si
tpu::TpuChipDriverCommonImpl tpu::TpuCoreDriverCommonImpl
_ZTV 0x215fe828 _ZTV 0x21cacd50 (_ZTI 0x21cacee0)
| __si (×3) | __si (×3)
+--+---+----+ +--+----+----+
Jxc Pxc Vxc Jxc Pxc Vxc
ChipJxcDriverImpl .710 CoreJxcDriverImpl .ea30
ChipPxcDriverImpl .8758 CorePxcDriverImpl .8978
ChipVxcDriverImpl .c0b0 (27 slots) CoreVxcDriverImpl .c2e8 (48 slots)
| TpuChipCommonImpl::GetCore(TpuCoreOnChip) ─┘
```text
Core 叶子的逐家族 override 集合几乎完全是 BarnaCore(SparseCore sequencer / address-handler)编程表面——vtable 槽位 25..38——再加上 host-interrupt 管线(槽位 46、47)。TensorCore 的运行/加载/内存表面完全通用,由 `TpuCoreCommonImpl` / `TpuCoreDriverCommonImpl` 实现一次。PXC 独有地 override 槽位 11(`FlushOutfeedQueues`)。
在 Chip 树中,VXC override 的槽位远多于 JXC 或 PXC(throttle、core-dump、host-sync-flag、init、teardown、continuation-queue)——fabric-attached 的 v3/v4/v5 硅片需要自己的机制,而较旧的 PCIe-attached jxc/pxc 继承通用 `TpuChip` 基类 / `TpuChipCommonImpl`。这对应了 VXC 在 Hardware 树中唯一的槽位 18 override。该层之下还有两个使用同一 Jxc/Pxc/Vxc 模式的辅助逐家族树:`TpuChipProfiler*Impl`(`_ZTV` 0x215fff68 / 0x21609060 / 0x21cb1ce0)和 `TpuCoreDebugInterface*DriverImpl`(`_ZTV` 0x215fee10 / 0x21608c10 / 0x21cac550)。(逐槽 Core/Chip override 细节见:[VXC 家族](vxc-family.md) 和各家族页面。)
---
## 层级 3 — CycleTable(成本模型角色)
"CostModel" 角色是 `xla::jellyfish::CycleTable`——而且它完全不在 `tpu::` HAL 运行时中。它是 XLA 后端中的编译器侧类,附着到 `xla::jellyfish::Target`(每个 `TpuVersion` 一个),不由任何 HAL 对象拥有。该树是扁平的:一个抽象根,没有共享中间层,五个叶子各自完全 override 全部五个槽位。
```text
xla::jellyfish::CycleTable (abstract ROOT; no own _ZTV) _ZTI 0x21c20008
| __si base of all 5 (each is a direct leaf — no intermediate)
+-----------+-----------+-----------+-----------+-----------+
JfCycleTable PfCycleTable VfCycleTable GlcCycleTable GfcCycleTable
v=0,1 v=2 v=3 v=4 v=5
_ZTV 0x21c1ffb8 0x21c20048 0x21c200c8 0x21c20148 0x21c201c8
5 slots, all overridden in every leaf:
slot 0 ~CycleTable D2
slot 1 ~CycleTable D0
slot 2 GetCyclesForThroughput(Instruction) const
slot 3 EstimateSinCosCost() const
slot 4 EstimateTanCost() const分派既不是 switch,也不是 vtable cast,而是 util_registration::FunctionRegistry<TpuVersion, unique_ptr<CycleTable>(const Target&)>。CycleTable::Create(Target const&)(0x1c89cc00)读取 target.tpu_version()(Target+920),并调用注册的 lambda;cycle_table.cc 静态初始化器(0x21353460)注册全部六个键 0..5。数据层是逐代 *Performance latency/resource 数组以及用于时钟频率的嵌入 chip_parts.binarypb——成本模型完全由数据表驱动,没有 learned-model 客户端。
层级 4 — TpuCodec 和 isa::Encoder(编码器角色)
"Encoder" 角色是两个耦合层级,二者都不继承任何 TpuHal 类:公开的逐代号 tpu::TpuCodec(运行时调用的 API)和内部的逐家族/逐核心 isa::Encoder(编解码器驱动的 bit-level worker)。
LEVEL A — public codec (6-slot vtable)
tpu::TpuCodec (abstract ROOT; no own _ZTV) _ZTI 0x21d35858
| __si base of 5 named + 1 anonymous (v=5)
+----------+-----------+-----------+-----------+-----------+----------+
Jellyfish Dragonfish Pufferfish Viperfish Ghostlite (anon v=5)
v=0 v=1 v=2 v=3 v=4 6acc60406
_ZTV.360f0 .35800 .36148 .361a0 .35c00 sub_1E838380 (no _ZTV)
6 slots: D2 (shared base @ 0x1e836100), D0, Encode, Decode, EncodeBundle, DecodeBundle
Factory: TpuCodec::Create(TpuVersion) @ 0x1e835fa0 — jump-table switch on v=0..5
LEVEL B — bit-level worker (14-slot per-family / 20-slot legacy)
platforms_deepsea::jellyfish::isa::Encoder (abstract ROOT; no own _ZTV) _ZTI 0x21cb6a20
| __si
+-- legacy (20 slots): EncoderJf / EncoderDf / EncoderBcsDf
+-- per-family (14 slots): EncoderPf*/EncoderVf*/EncoderGl* (TensorCore / BarnaCore / SparseCore)
each COMPOSES (template, non-virtual) a *CodecBase<...> mixin carrying the
per-codename bundle bit layout (per-generation wire widths owned by the
bundle-model pages; JF output fixed at 41 B / operator new(0x29))
```text
`TpuCodec::Create`(0x1e835fa0)是六 case 跳转表 switch;case 0..4 调用命名的 `CreateTpuCodec<X>` 构造器,case 5 调用匿名命名空间 creator(`sub_1E838380`)——v=5 / 6acc60406 编解码器没有命名 C++ 类,也没有恢复出的 vtable。编解码器通过 `tpu::internal::CreateEncoder{JfDf,Pf,Vf,GlGf}` 驱动匹配的 `isa::Encoder` 叶子,这些函数按 `TpuSequencerType`(不是 `TpuVersion`)分派。
> **注意 —** Encoder 不由 Core 拥有。Codec/Encoder(编译器和序列化层)*产生* bundle 字节,后者成为 `TpuCoreProgram`,随后由 `TpuCore*DriverImpl::LoadProgram` 加载并运行。二者的耦合是数据流(program bytes),不是对象所有权。
---
## 四棵树如何关联
不存在单一线性所有权链。四棵树通过一个共享键(`TpuVersion`)和两种不同机制(组合与数据流)耦合:
```text
TpuHal (HardwareImpl) <- the only TpuHal class; built by TpuHalFactory
└─owns→ N × TpuChip*DriverImpl (CommonHelper::CreateChips) [composition]
└─owns→ M × TpuCore*DriverImpl (TpuChipCommonImpl::CreateCores) [composition]
└─runs→ TpuCoreProgram (LoadProgram → TpuCoreProgramHandleImpl)
TpuCodec (per TpuVersion; static factory, NOT owned by the HAL)
└─drives→ isa::Encoder leaf (per TpuSequencerType)
└─emits→ bundle bytes → TpuCoreProgram [data-flow]
CycleTable (per TpuVersion; attached to xla::jellyfish::Target, NOT owned by the HAL)
└─reads→ per-gen *Performance arrays; consumed during XLA scheduling [compiler-side]Hardware → Chip → Core 是真正的组合链,全部在 tpu:: 运行时中。Encoder 只通过它序列化出的 program bytes 触达 Core。CostModel 两者都不触达——它是由同一 TpuVersion 作为键的编译器侧对象。每棵树分派所依赖的唯一轴都是 tpu::TpuVersion,这正是代号分类(6 代号权威对照)成为整个 target 模型脊柱的原因。
交叉引用
- 6 代号权威对照 —
TpuVersion,全部四个层级分派所依赖的单一轴 - HAL 家族 — 构建 Hardware 树叶子的三个工厂类和五个 init module
- HAL 工厂 Override 矩阵 — Hardware 树完整的 23 槽逐家族 override 矩阵
- JXC 家族 — Jellyfish (v0) + Dragonfish (v1):Jxc impl、chip、core 和 codec 专门化
- PXC 家族 — Pufferfish (v2) 专门化
- VXC 家族 — Viperfish (v3):override 最多 chip/core 槽位的 impl
- GXC 家族 — Ghostlite (v4) + 6acc60406 (v5),共享 VXC impl vtable