PXC 家族 (Pufferfish)
地址适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so (build-id
89edbbe81c5b328a958fe628a9f2207d)。其他版本会有所不同。
摘要
PXC 是单一代号家族:tpu::(anonymous namespace)::TpuHalPxcHardwareFactory 只服务一个硅代际,即 Pufferfish (TpuVersion::kPufferfish = 2)。因为它只服务一个版本,所以它是四个家族中最容易推理的一个:一个工厂实例、一次 Register 调用,以及一个将版本字面量 2 硬编码而不是在运行时读取的 CreateImpl。
PXC 在子核心分类中的位置很关键:它是第一个将每个核心的指令流拆分为 fetch-core 和 load-core 的家族。在 JXC 仍然使用单一融合数据流的地方,PXC 引入了 asic_sw::driver::deepsea::pxc::pfc (Pufferfish fetch-core) 和 pxc::plc (Pufferfish load-core),作为不同的子命名空间。这种拆分延续到 VXC 和 GXC,使 PXC 成为后续每个家族的架构模板。PXC 还携带家族级的 pxc::isa 命名空间和 pxc::profiler 命名空间,这是第一个在自身家族标签下拥有 HAL-driver ISA 命名空间的家族。
本页遵循与 JXC、VXC 和 GXC 页面相同的语法。工厂的 vtable 形状与其他家族逐字节相同;差异在于版本处理、DMA 模型以及更重的 helper。共享的基类链见 HAL 家族。
对重新实现而言,契约是:
- 单版本注册:一个工厂实例、一次
Register调用、CreateImpl硬编码version = 2。 - 5 槽工厂 vtable (形状与 JXC/VXC 相同) 以及 208 字节的
TpuHalPxcHardwareImpl。 - 构造链 HardwareImpl → CommonHelper (48 B) → Chip (408 B) → Core (800 B),其中 DMA 折叠进
tpu::TpuPxcDriver,没有单独的 DMA-issuer 对象。 pxc::pfc/pxc::plc的 fetch/load 拆分,以及pxc::isa/pxc::profiler命名空间。
| 工厂类 | tpu::(anonymous namespace)::TpuHalPxcHardwareFactory (anon-ns) |
| 服务的 TpuVersions | 1 — kPufferfish (2) |
| 工厂 vtable / vptr | _ZTV 0x216085c8 / 已安装 vptr 0x216085d8 |
| 工厂 typeinfo | _ZTI 0x21608600 (__si base → TpuHalHardwareFactoryBase 0x21d343f8) |
| HAL impl 类 / 大小 | TpuHalPxcHardwareImpl, 208 B (0xD0), vtable 0x21608618 |
| Init 模块 | google_init_module_tpu_hal_pxc_hardware_impl @ 0x213e9ec0 (1× Register) |
| Fetch/load 拆分 | 第一个带有该拆分的代际 — pxc::pfc + pxc::plc |
| DMA 引擎 | 集成到 tpu::TpuPxcDriver (无 issuer 对象); DmaDescriptorV2 |
工厂绑定与注册
目的
PXC 工厂将 TpuVersion::kPufferfish 绑定到它的 HAL 实现。因为 Pufferfish 是 PXC 处理的唯一代号,注册只有一次调用,是四个家族中最精简的。
入口点
google_init_module_tpu_hal_pxc_hardware_impl (0x213e9ec0)
└─ operator new(0x10) ── single factory instance (16 B)
f[+8] = 2 (kPufferfish) ; f[+0] = vptr 0x216085d8
TpuHalFactory::Register(kHardware, 2, f) (0x1fbb16a0)
CHECK(s == OK) // string 0x94acd7e
```text
### 算法
```c
function google_init_module_tpu_hal_pxc_hardware_impl(): // 0x213e9ec0
f = operator_new(0x10) // 16-byte factory object
f[+8] = 2 // kPufferfish (movl $0x2,0x8(%rax))
f[+0] = &PxcFactory_vtable + 0x10 // installed vptr 0x216085d8
s = TpuHalFactory::Register(kHardware /*0*/, 2, unique_ptr(f))
if s != OK: LogMessageFatal(CHECK string @0x94acd7e)怪癖 — 0x94acd7e 处的 CHECK 字符串是
std::make_unique<tpu::TpuHalPxcHardwareFactory>(),没有参数;PXC 工厂构造函数不接收TpuVersion,因为没有任何需要消歧的内容。对比 JXC 和 VXC,它们的 CHECK 字符串会把代号传给make_unique。烘入二进制的源路径是learning/45eac/tpu/runtime/hal/internal/pxc/tpu_hal_pxc_hardware_impl_registration.cc(string 0x877b845)。
函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
google_init_module_tpu_hal_pxc_hardware_impl | 0x213e9ec0 | 单次 Register (v2) |
TpuHalFactory::Register | 0x1fbb16a0 | 注册表插入 (共享) |
TpuHalFactory::Get | 0x1fbb19c0 | 运行时查找 (共享) |
TpuHal::Create | 0x1e814180 | 公共入口 (共享) |
工厂 vtable
目的
PXC 的工厂 vtable 在形状上与 JXC 逐字节相同:两个家族特有 override (D0 dtor、CreateImpl) 和三个继承槽,它们的地址是 JXC 与 VXC 指向的完全相同的函数。
Vtable 布局
| vaddr | 槽 | 解析为 | 基类/override |
|---|---|---|---|
| 0x216085d8 | 0 — ~TpuHalFactory() D2 | 0x0e723a80 (ret) | INHERITED |
| 0x216085e0 | 1 — ~TpuHalPxcHardwareFactory() D0 | 0x0e7f8260 | OVERRIDE |
| 0x216085e8 | 2 — HardwareFactoryBase::Create(wq) | 0x1e80f560 | INHERITED |
| 0x216085f0 | 3 — HardwareFactoryBase::CanCreate() | 0x1e80f520 | INHERITED |
| 0x216085f8 | 4 — TpuHalPxcHardwareFactory::CreateImpl(wq) | 0x0e7f8280 | OVERRIDE |
槽 1 编码 operator delete(this, 0x10);工厂是 16 字节,与四个家族都相同。
算法 — CreateImpl
function TpuHalPxcHardwareFactory::CreateImpl(out, this, wq): // 0x0e7f8280
version = 2 // HARDCODED kPufferfish (mov $0x2,%esi)
obj = operator_new(0xD0) // 208 B = TpuHalPxcHardwareImpl
TpuHal::TpuHal(obj, 2, wq) // base ctor 0x1e811c00: wq→+0x68, version→+0x78
*(void**)(obj + 0) = &PxcImpl_vtable + 0x10 // plant 0x21608618 → 0x21608628
*(void**)(obj + 0xC8) = nullptr // CommonHelper slot, null until init
out.value = obj ; out.status = OK
return out
```text
> **注意 —** PXC 的 `CreateImpl` 是唯一一个硬编码自身版本 (`mov $0x2`) 的实现。它既不读取工厂的 `+8`,也不读取 work-queue。结果在功能上等同于 JXC 读取 `factory+8` (注册键同样是 `2`),但源操作数不同:PXC 烘入了字面量。
### 注意事项
`TpuHalPxcHardwareImpl` override 了一个 JXC 没有的槽:槽 8,`GetConfiguredProperties` (@ 0x0e7f82e0),它尾调用到 `this+0xC8` 处的 helper。PXC impl override 数量为 7 (槽 0、1、2、8、19、20、21)。完整的 23 槽 impl 表见 [HAL 工厂 Override 矩阵](hal-factory-override-matrix.md)。
---
## 工厂下方的构造链
### 目的
PXC 的 `CreateAndInitializeChips` (impl vtable 槽 20, @ 0x0e7f8300) 明显比 JXC 更精简 (~1.8 KB vs ~5 KB)。它不调用 `DriverFactory`,也不调用拓扑构建器;driver 和拓扑构造被折叠进一个无参数的 `InitializeDrivers`。
### 入口点
```text
TpuHalPxcHardwareImpl::CreateAndInitializeChips (0x0e7f8300)
├─ TpuChipParts::CoreCount / SharedMemoryCount ── data-driven constraints
├─ TpuHalPxcCommonHelper (48 B, 0x0e7f8b60) ── stored at impl+0xC8
├─ helper->InitializeDrivers() (0x0e7f8b80) ── NO ARGS; builds TpuPxcDriver vector
└─ helper->CreateChips (0x0e7f9a00)
└─ TpuChipPxcDriverImpl (408 B, 0x0e7fa5a0) ── single int + unique_ptr<TpuPxcDriver>
└─ core-factory lambda (0x0e7fd3c0)
└─ TpuCorePxcDriverImpl (800 B, 0x0e7ffd40) ── 6-arg ctor, NO DMA-issuer注意事项
PXC 的 CommonHelper 是 48 字节 (JXC 为 24),因为它拥有一个 std::vector<unique_ptr<tpu::TpuPxcDriver>> (由 D0 dtor 在 free(helper, 0x30) 之前释放 helper+0x18/+0x28 处的 vector 证明)。chip ctor 接收一个 int (JXC 接收两个) 和一个 unique_ptr<TpuPxcDriver> (JXC 接收一个 driver-interface 加一个 register-interface)。core ctor 接收 6 个参数且没有 DMA-issuer;对比 JXC 的 8 参数 core ctor 及其 JfDmaIssuer*。
陷阱 — PXC 在二进制中任何位置都没有
PfDmaIssuer符号。Pufferfish 的 DMA 直接构建在tpu::TpuPxcDriver中 (ReadFromMemoryHelper0x0e80f220、WriteToMemoryHelper0x0e80bd80、OnChipTransfer0x0e8139a0、InjectFishDescriptors0x0e80a3a0)。片上队列模型是asic_sw::deepsea::pxc::{DirectWrite,Debug,Infeed,Magic,Outfeed}QueueDescriptor的std::variant,硬件 descriptor 是 V2DmaDescriptorV2(≥96 字节、4 级 strided),也是第一个 V2 使用者。编译器侧 builder 是xla::pufferfish::PufferfishDmaDescriptorState,其CreateForViperfish方法表明 V2 状态会向前共享到 Viperfish。
Driver 子命名空间清单
asic_sw::driver::deepsea::pxc:: 是第一个携带 fetch/load 拆分的家族命名空间。符号表确认的直接子命名空间如下:
| 子命名空间 | 作用 |
|---|---|
pxc::pfc | Pufferfish fetch-core — fetch 侧指令流 |
pxc::plc | Pufferfish load-core — load 侧指令流 |
pxc::isa | 家族级 ISA (137K 符号) |
pxc::profiler | 家族级 profiler (8125 符号),持有 TraceEntry 类 |
pxc::internal | 内部 driver helper |
fetch-core 下还有更多命名空间:pxc::pfc::isa (46K 符号,包含 pxc::pfc::isa::BarnaCoreChannelBundle、VectorBase)、pxc::pfc::profiler 和 pxc::pfc::b0 (寄存器块命名空间)。load-core 携带 pxc::plc::profiler。位于 fetch-core 的 ISA 之下的 BarnaCore bundle 类型确认 Pufferfish 是最后一个搭载 BarnaCore 的家族;它在 VXC 中退役。
怪癖 — 命名的
profiler::TraceEntry事件类位于家族级 (pxc::profiler::TraceEntry,3087 个 token 出现),不在pfc或plc之下。pxc::pfc::profiler/pxc::plc::profiler子命名空间反而持有 control-interface 和 limits-factory 类 (TracemarkLimitsFactory、EveryoneTraceControlFactory)。这不同于 VXC/GXC,后两者的TraceEntry类是按子核心划分的。因此 PXC 是子核心分类中的 trace-entry 家族之一,但 trace entry 的粒度是家族级。
按代号的区分
Pufferfish 有芯片变体 (B0 Mfg / B0 Water / B0 Air),它们通过 TpuChipParts::variant_name() (0x20b1eb40) 在同一 impl 内复用。它们不是单独的 TpuVersion 值,也不会改变工厂或 vtable;variant name 只为 census 报告和人类可读命名 (TpuVersionAndVariantToHumanReadableName, 0x20b3b040) 而读取,在 CreateAndInitializeChips 中未观察到按变体分支的代码。
| 轴 | Pufferfish (v2) | 来源 |
|---|---|---|
| TpuVersion enum | kPufferfish = 2 | TpuVersionToString 0x20b3a480 |
| ToString | "pufferfish" | rodata |
| 外部名称 | "TPU v4" (lite 变体: "TPU v4 lite") | 命名路径 |
| Codec 类 | TpuCodecPufferfish (具名) | TpuCodec::Create 0x1e835fa0 case 2 |
| TensorCore / BarnaCore | 有 / 有 (最后一代 BarnaCore) | TpuChipParts |
| SparseCore | 无 | TpuChipParts |
| Flag 前缀 | xla_pf_ (仅 3 个 flag;大多共享 xla_jf_) | flag 扫描 |
注意 — 很小的
xla_pf_数量 (3 个 flag) 表明 Pufferfish 仍然接近 Jellyfish 的 flag 基础;它共享大部分xla_jf_。架构断裂 (fetch/load 拆分、DMA-in-driver、V2 descriptor) 是结构性的,而不是通过 flag 暴露的。