Skip to content

HAL 工厂覆盖矩阵

地址适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so。其他版本会有所不同。

摘要

TPU HAL 工厂框架按 TpuVersion 分两个阶段分派。第一阶段从注册表中选择一个工厂对象;第二阶段运行该工厂的 CreateImpl 来构建每个家族的 impl 对象,后者随后携带自己的虚方法特化。本页列出两个层面的覆盖矩阵:一个五槽工厂 vtable(形状一致,两个家族专属 slot)和一个二十三槽 impl vtable(大多继承,按家族有三到八个覆盖)。两个矩阵都足够小,可以完整展示;有意思的轴是工厂类(Jxc / Pxc / Vxc)和 vtable slot

这个框架是带有模板方法变化的经典抽象工厂。TpuHalFactory 是纯虚接口;TpuHalHardwareFactoryBase 是具体中间层,它一次性实现 CreateCanCreate,并把 CreateImpl 留作唯一的按家族 hook。因为基类完成所有编排,叶子工厂只覆盖析构函数和 CreateImpl——五个 vtable slot 中有三个指向继承的基类代码。真正的按世代逻辑位于下一层,即工厂分配的 impl 对象中;即便在那里,覆盖集合也主要由析构函数、每个具体子类都必须填充的两个纯虚 hook(TypeCreateAndInitializeChips),以及少量 teardown/configuration 尾部 slot 构成。

因此,对重新实现者来说重要的分派维度不是孤立地看“家族 X 覆盖了哪个方法”,而是整条链:TpuVersion → registry → factory instance → CreateImpl → impl class → impl vtable。工厂选择是数据(注册表查找);impl 特化是 C++ 虚分派。任何 impl 方法内部都不存在第三个基于 TpuVersion 的内部 switch——VXC 通过一条完全相同的代码路径服务三个代号。

对于重新实现,契约是:

  • 工厂 vtable 形状(5 个 slot)以及哪两个是家族专属。
  • TpuHal 基 vtable(23 个 slot),包括迫使每个具体 impl 覆盖它们的两个 __cxa_pure_virtual slot。
  • 按家族划分的 impl 覆盖矩阵(factory × slot),带覆盖地址和覆盖数量。
  • 两阶段分派机制,以及不存在任何按代号内部 switch。
工厂 vtable slot5(D2、D0、CreateCanCreateCreateImpl
家族专属工厂 slot2——slot 1(~Factory D0)、slot 4(CreateImpl
Impl vtable slot23(TpuHal 基类;slot 2 和 20 为 pure)
覆盖数量JXC = 7,PXC = 7,VXC = 8
阶段 1 分派registry lookup TpuHalFactory::Get(v) @ 0x1fbb19c0
阶段 2 分派已分配 TpuHal*HardwareImpl 上的 C++ vtable
按代号内部 switch无(VXC = v3/v4/v5 的单一类)

分派机制

分派分两个阶段,每个阶段都以 TpuVersion 为键,但由两种不同机制实现。

阶段 1——工厂选择(数据驱动)

TpuHalFactory::Get(version)(0x1fbb19c0)在互斥锁保护下读取进程级注册表,并返回为 (kHardware, version) 注册的工厂实例。注册表在加载时由五个 init 模块填充(见 HAL 家族)。这个阶段不是 switch,也不是 vtable cast——它是一次表查找。六个版本键映射到三个工厂类:

来源
TpuVersion key0, 1, 2, 3, 4, 5每个 init 模块中的 Register immediate
Factory classJxc (0,1), Pxc (2), Vxc (3,4,5)每个 Register 中的 make_unique<TpuHal*HardwareFactory>
Factory vtable0x215fe530, 0x216085c8, 0x21cabf70每个 init 模块中写入 object+0 的 vtable

阶段 2——Impl 特化(虚分派)

被选中工厂的 Create(继承自 TpuHalHardwareFactoryBase @ 0x1e80f560)调用该工厂自己的 CanCreate(slot 3)以探测设备可用性,然后在成功时调用该工厂自己的 CreateImpl(slot 4)。CreateImpl 分配 impl 对象,使用来自工厂 +8 的 TpuVersionRegister 时写入的 dword)运行 TpuHal::TpuHal(),并把按家族划分的 impl vtable 写入新对象的 slot 0。从此以后,所有按世代行为都是在 impl vtable 上进行的普通 C++ 虚分派。

陷阱——Create(0x1e80f560)的反编译中,两个间接调用都从第二个参数读取 vtable,而反编译器把它标成 TpuHostWorkQueue*。反汇编解释了这个别名:调用方 TpuHal::Create(0x1e814180)调用 factory_vtable[2](ret, factory, wq),所以在 Create 内部,第二个参数是工厂指针,不是 work-queue;work-queue 是第三个参数。因此 probe(call *0x18(rax) = slot 3)和 build(call *0x20(rax) = slot 4)都会在工厂自己的 vtable 上分派。把 CanCreate/CreateImpl 路由到 work-queue 方法的重新实现不会与二进制匹配。

c
function HardwareFactoryBase::Create(this, factory, wq):  // 0x1e80f560
    if factory->vtable[3](factory):                       // CanCreate — slot 3 (0x1e80f520)
        return factory->vtable[4](this, factory, wq)      // CreateImpl — per-family slot 4
    else:
        return NotFound("No " + device_name + " device found.")   // tpu_hal_hardware_factory_base.cc:22

function JxcFactory::CreateImpl(ret, factory, wq):      // 0x0e723ac0
    v   = factory[2]                                     // TpuVersion at factory+8 (stamped at Register)
    obj = operator new(0xD0)                             // 208 B JxcImpl
    TpuHal::TpuHal(obj, v, wq)                           // base ctor — wq is the genuine work-queue arg
    obj[0]  = &JxcImpl_vtable[+0x10]                     // off_215FE590 — plant impl vtable
    obj[25] = 0                                          // helper @ +200 not yet attached
    ret[1] = obj; ret[0] = OK                            // write StatusOr<unique_ptr> result
    return ret
```text

> **陷阱——** impl ctor 接收的 `TpuVersion` 是从 `factory+8` 读取的(JXC/VXC stub 中的 `*((_DWORD*)factory + 2)`),*不是*从 work-queue 读取——反编译器再次把工厂指针误标成了 `TpuHostWorkQueue*`。`factory+8` 是每个 init 模块在 `Register` 时写入的 dword(见 [HAL 家族](hal-families.md))。work-queue 是单独参数,只转发给基类 ctor。PXC 甚至不读取自己的工厂指针来获取版本:它硬编码字面量 `2`,因为 Pxc 工厂只服务 Pufferfish。

PXC 和 VXC 的 `CreateImpl` 是逐字节相同的形状;只有分配大小、写入的 vtable,以及(对于 PXC)硬编码的 `TpuVersion` 字面量不同。PXC 分配 0xD0208 B)并以版本 `2` 写入 `off_21608628`;VXC 分配 **0xD8216 B)** 并写入 `off_21CABFD0`,还会额外把 +208 的 flag byte 置零。(对象布局见 [TpuHal 类层级](tpuhal-class-hierarchy.md)。)

> **怪癖——** 不存在第三次分派。VXC 通过一个完全相同的 `TpuHalVxcHardwareImpl` 和一个完全相同的 `CreateImpl` 服务 Viperfish、Ghostlite 和 6acc60406(版本 3/4/5)。任何 VXC 方法中都没有 `switch (TpuVersion)`。按代号区分完全被推出 HAL,进入 `TpuChipParts` proto 加载器以及 `TpuCodec` / `CycleTable` 工厂;这些组件都以同一个 `TpuVersion` 为键。

---

## 工厂 Vtable 覆盖矩阵

所有三个叶子工厂共享同一个 vtable 形状:五个函数指针 slot。Slot 023 指向继承的基类代码(complete-object destructor、`Create`、`CanCreate`);只有 slot 1(deleting destructor)和 slot 4(`CreateImpl`)携带家族专属代码。每个家族的 deleting destructor 都只是简单的 `free(this)`——16 字节工厂没有拥有任何成员。

| Slot | 方法 | JXC | PXC | VXC |
|---|---|---|---|---|
| 0 | `~Factory()` D2(complete-obj dtor) | inherited 0x0e723a80 | inherited 0x0e723a80 | inherited 0x0e723a80 |
| 1 | `~Factory()` D0(deleting dtor) | **override 0x0e723aa0** | **override 0x0e7f8260** | **override 0x1d110e80** |
| 2 | `Create(TpuHostWorkQueue*) const` | inherited 0x1e80f560 | inherited 0x1e80f560 | inherited 0x1e80f560 |
| 3 | `CanCreate() const` | inherited 0x1e80f520 | inherited 0x1e80f520 | inherited 0x1e80f520 |
| 4 | `CreateImpl(TpuHostWorkQueue*) const` | **override 0x0e723ac0** | **override 0x0e7f8280** | **override 0x1d110e00** |

每个叶子工厂的 D0 destructor(slot 1)反编译为 `free(this)`——已在上列地址全部验证。Slot 4 的覆盖地址是分派章节中展示了函数体的 `CreateImpl` stub。

---

## Impl Vtable 覆盖矩阵

`TpuHal` 抽象基类声明了 23 个 virtual slot。其中两个是 `__cxa_pure_virtual`,并且**必须**由任何可实例化子类覆盖:slot 2(`Type`)和 slot 20(`CreateAndInitializeChips`)。中间层 `TpuHalHardwareImpl` 填充它能填充的两个 pure-base 方法(slot 2 的 `Type`,以及 slot 19 更严格的 `ValidateTopology`);三个按家族划分的 impl 继承这些实现,并添加各自的析构函数、强制的 `CreateAndInitializeChips`,以及一小组 teardown/configuration slot。

下方矩阵展示每个 slot。标为 “inherited” 的单元指向第二列中的 `TpuHal` 基实现;加粗单元是带地址的家族覆盖。

| Slot | 方法 | Base (`TpuHal`) | JXC | PXC | VXC |
|---|---|---|---|---|---|
| 0 | `~Impl()` D2 | base dtor | **0x0e724de0** | **0x0e7f8a40** | **0x1d111740** |
| 1 | `~Impl()` D0 | base dtor | **0x0e724e40** | **0x0e7f8ac0** | **0x1d1117a0** |
| 2 | `Type() const` | `__cxa_pure_virtual` | mid-base 0x1d3b5480 | mid-base 0x1d3b5480 | mid-base 0x1d3b5480 |
| 3 | `Initialize(TpuHalOptions const&)` | 0x1e8132a0 | inherited | inherited | inherited |
| 4 | `TearDown()` | 0x1e813440 | inherited | inherited | inherited |
| 5 | `topology() const` | 0x1e8140a0 | inherited | inherited | inherited |
| 6 | `host_location() const` | 0x1e814100 | inherited | inherited | inherited |
| 7 | `hal_location() const` | 0x1e814160 | inherited | inherited | inherited |
| 8 | `GetConfiguredProperties() const` | 0x0e724ea0 | inherited | **0x0e7f82e0** | **0x1d110ea0** |
| 9 | `GetChip(int)` | 0x1e811e80 | inherited | inherited | inherited |
| 10 | `GetChip(TpuChipLocation const&)` | 0x1e811e40 | inherited | inherited | inherited |
| 11 | `AllocatePremapped(unsigned long)` | 0x1e8143a0 | inherited | inherited | inherited |
| 12 | `DeallocatePremapped(void*)` | 0x1e8143c0 | inherited | inherited | inherited |
| 13 | `PremappedAllocatorStats() const` | 0x1e8143e0 | inherited | inherited | inherited |
| 14 | `GetPremappedAlignment() const` | 0x1e814420 | inherited | inherited | inherited |
| 15 | `Throttle(TpuChipLocation const&)` | 0x1e814440 | inherited | inherited | inherited |
| 16 | `Unthrottle(TpuChipLocation const&)` | 0x1e814460 | inherited | inherited | inherited |
| 17 | `GetThrottleState(TpuChipLocation const&)` | 0x1e814480 | inherited | inherited | inherited |
| 18 | `WaitForCoreDumpComplete()` | 0x213d7760 | inherited | inherited | **0x1d110f00** |
| 19 | `ValidateTopology()` | 0x1e8139c0 | mid-base 0x1d3b54a0 | mid-base 0x1d3b54a0 | mid-base 0x1d3b54a0 |
| 20 | `CreateAndInitializeChips(TpuHalOptions const&)` | `__cxa_pure_virtual` | **0x0e723c20** | **0x0e7f8300** | **0x1d110f20** |
| 21 | `PreTearDownChips()` | 0x1d3b5a20 (no-op) | **0x0e724da0** | **0x0e7f8a20** | **0x1d111720** |
| 22 | `PostTearDownChips()` | 0x0e7f8b40 (no-op) | **0x0e724dc0** | inherited | inherited |

**覆盖数量:** JXC = 7(slot 01219202122),PXC = 7(slot 0128192021),VXC = 8(slot 012818192021)。

Slot 219 标为 “mid-base”,因为所有三个家族共享*同一个*实现,它们继承自中间层 `TpuHalHardwareImpl`,而不是按家族各自拥有函数体:`TpuHalHardwareImpl::Type`(0x1d3b5480)和 `TpuHalHardwareImpl::ValidateTopology`(0x1d3b54a0)。`Type` 返回常量 `0`(`kHardware` 产品类型标签);`ValidateTopology` 是更严格的版本,它扫描硬件设备,将检测到的 `TpuVersion` 和 `TpuChipParts::variant_name` 与 topology 比较,并发出 “Detected hardware version ... does not match” 诊断。这两者就是中间类的全部存在理由。

### 三个家族真正不同的地方

按覆盖差异读取矩阵,可以隔离出每个家族的特化:

- **三个家族全部**覆盖析构函数(slot 01)、强制的 `CreateAndInitializeChips`(slot 20)以及 `PreTearDownChips`(slot 21 → `{Jxc,Pxc,Vxc}CommonHelper::TearDownMesh`)。这些是每个家族的核心:chip 创建约束检查和 mesh teardown 路径。
- **PXC 和 VXC**覆盖 `GetConfiguredProperties`(slot 8)——二者都委托给各自家族的 `CommonHelper`。JXC 继承基类默认实现(`GetDefaultConfiguredProperties(topology)`)。
- **只有 VXC**覆盖 `WaitForCoreDumpComplete`(slot 18 → `TpuHalVxcCommonHelper::WaitForCoreDumpComplete`)。JXC 和 PXC 继承通用的按 chip 等待循环。这与 VXC 更广泛的 fabric-attached core-dump 机制一致(在其 `TpuChip*` 覆盖集合中也可见)。
- **只有 JXC**覆盖 `PostTearDownChips`(slot 22),即使其函数体与基类 no-op 一样都返回 `1`——源文件显式放置了这个覆盖。

> **注意——** slot 20/21 的覆盖函数体携带该家族的硬编码 core-count 与 HBM 约束以及驱动布线。`JxcImpl::CreateAndInitializeChips`(0x0e723c20)用三个运行时组装的诊断限制 core 数量——TensorCore 限制(前缀 `"Jellyfish Hardware only supports at most "` + count + `" TensorCore."`)、BarnaCore 限制(同一前缀 + count + `" Barnacore."`),以及 HBM 限制(独立字面量 `"TPU platform only supports up to two HBMs."`)——然后驱动 `jxc` deepsea `DriverFactory`。`PxcImpl` 和 `VxcImpl` 携带类似的 Pufferfish / Viperfish 消息及其 `CommonHelper::CreateChips` 路径。约束细节属于各家族页面;本矩阵固定的是 slot 所有权。

`VxcImpl::PreTearDownChips`(0x1d111720)也是读取 216 字节 VXC 对象额外 +208 flag byte 的地方:如果已设置则返回 `1`(mesh 已经 teardown),否则调用 `TpuHalVxcCommonHelper::TearDownMesh(this[25])`。JXC 和 PXC 没有这种 guard byte。

---

## 交叉引用

- [HAL 家族](hal-families.md)——驱动阶段 1 工厂选择的注册表,以及填充注册表的五个 init 模块
- [TpuHal 类层级](tpuhal-class-hierarchy.md)——本矩阵索引到的 vtable 布局、slot 数量和对象大小
- [6 代号权威调和](tpu-version-codename-matrix.md)——两个分派阶段都依据的 `TpuVersion` 键
- [JXC 家族](jxc-family.md)——Jellyfish 和 Dragonfish 的 slot-20/21/22 覆盖函数体
- [PXC 家族](pxc-family.md)——Pufferfish 的 slot-8/20/21 覆盖函数体
- [VXC 家族](vxc-family.md)——Viperfish 的 slot-8/18/20/21 覆盖函数体
- [GXC 家族](gxc-family.md)——Ghostlite 和 6acc60406,分派到同一个 VXC impl vtable