JXC 系列(Jellyfish、Dragonfish)
地址适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id
89edbbe81c5b328a958fe628a9f2207d)。其他版本会有所不同。
摘要
JXC 是 libtpu 仍然携带的四个 TPU HAL 系列中最早的一个。一个 C++ 类 tpu::(anonymous namespace)::TpuHalJxcHardwareFactory 服务两代芯片:Jellyfish(TpuVersion::kJellyfish = 0)和 Dragonfish(TpuVersion::kDragonfish = 1)。该工厂是一个很薄的 16 字节对象,唯一按系列定制的行为是分配正确的 HAL 实现;区分 Jellyfish 与 Dragonfish 的所有内容都通过嵌入的 TpuChipParts proto 数据驱动,而不是通过 C++ 类型。
JXC 的定义性架构特征,也是它锚定子核心分类的原因,是它没有 fetch/load-core 拆分。后续每个系列(PXC、VXC、GXC)都会把每个核心的指令流划分为 fetch-core 和 load-core 子命名空间,而 JXC 的驱动层是单一融合的数据流。它在 asic_sw::driver::deepsea::jxc:: 下的驱动子命名空间按引擎块组织(dfc、jfc、registers、snap、*_trace_entry 集合),而不是按 fetch/load 角色组织。两代的编译器侧 ISA 位于 platforms_deepsea::jellyfish::isa,而不在任何 jxc::isa 命名空间中。
本页遵循与 PXC、VXC 和 GXC 系列页面相同的语法:工厂绑定、构造路径、子命名空间名册,以及按代号区分的差异。所有四个系列共享的抽象基类链(TpuHalFactory → TpuHalHardwareFactoryBase → leaf)见 HAL 系列。
对于重新实现,契约是:
- 单类 / 双版本注册模型:一个 vtable,两个 16 字节实例,在对象偏移
+8处以TpuVersion为键。 - 5 槽工厂 vtable,以及生成 208 字节
TpuHalJxcHardwareImpl的CreateImpl分配器。 - 构造链 HardwareImpl → CommonHelper → Chip → Core,以及穿入每个核心的
JfDmaIssuerDMA 引擎。 - 驱动子命名空间名册,以及明确事实:没有 fetch/load 拆分,也没有
jxc::isa。
| 工厂类 | tpu::(anonymous namespace)::TpuHalJxcHardwareFactory(anon-ns) |
| 服务的 TpuVersions | 2 — kJellyfish (0), kDragonfish (1) |
| 工厂 vtable / vptr | _ZTV 0x215fe530 / 已安装 vptr 0x215fe540 |
| 工厂 typeinfo | _ZTI 0x215fe568(__si 基类 → TpuHalHardwareFactoryBase 0x21d343f8) |
| HAL impl 类 / 大小 | TpuHalJxcHardwareImpl, 208 B (0xD0), vtable 0x215fe580 |
| 初始化模块 | google_init_module_tpu_hal_jxc_hardware_impl @ 0x213e9d80 (2× Register) |
| Fetch/load 拆分 | 无 — 融合数据流(JXC 的定义性特征) |
| DMA 引擎 | JfDmaIssuer(每核心独立对象) |
工厂绑定与注册
目的
该工厂在 dlopen 时选择给定 TpuVersion 将实例化哪一个 HAL 实现。JXC 是唯一一个工厂类注册到多个版本的系列,因为 Jellyfish 和 Dragonfish 在架构上足够接近,可以共享一个 HAL 实现。(xla_* 标志前缀证实了这种亲缘关系:根本不存在 xla_df_ 前缀,Dragonfish 完全复用 Jellyfish 的 xla_jf_ 标志。)
入口点
google_init_module_tpu_hal_jxc_hardware_impl (0x213e9d80)
├─ operator new(0x10) ── factory instance #1 (16 B)
│ f0[+8] = 0 (kJellyfish) ; f0[+0] = vptr 0x215fe540
│ TpuHalFactory::Register(kHardware, 0, f0) (0x1fbb16a0)
└─ operator new(0x10) ── factory instance #2 (16 B)
f1[+8] = 1 (kDragonfish) ; f1[+0] = vptr 0x215fe540 (SAME vtable)
TpuHalFactory::Register(kHardware, 1, f1)
```text
### 算法
```c
function google_init_module_tpu_hal_jxc_hardware_impl(): // 0x213e9d80
// Two registry entries, one shared vtable. The instances differ
// ONLY in the TpuVersion stored at +8.
for version in {0 /*kJellyfish*/, 1 /*kDragonfish*/}:
f = operator_new(0x10) // 16-byte factory object
f[+8] = version // u32 TpuVersion key
f[+0] = &JxcFactory_vtable + 0x10 // installed vptr 0x215fe540
s = TpuHalFactory::Register(kHardware /*0*/, version, unique_ptr(f))
CHECK(s == OK) // fail strings 0x94a3e44 (kJellyfish), 0x94a4057 (kDragonfish)QUIRK — 不存在类级别的 Jellyfish-vs-Dragonfish 分派。两个 16 字节实例指向完全相同的 vtable
0x215fe540,只在+8处存储的TpuVersionu32 上不同。两个 CHECK 字符串按字节确认了std::make_unique<TpuHalJxcHardwareFactory>(...kJellyfish)和(...kDragonfish),也就是说 JXC 工厂构造器确实接受TpuVersion参数,不同于 PXC 的无参 ctor。按代号区分的行为(核心数、MXU 形状、HBM 上限)稍后从TpuChipParts解析。
函数图
| 函数 | 地址 | 角色 |
|---|---|---|
google_init_module_tpu_hal_jxc_hardware_impl | 0x213e9d80 | 2× Register (v0, v1) |
TpuHalFactory::Register | 0x1fbb16a0 | 注册表插入 [platform][version] |
TpuHalFactory::Get | 0x1fbb19c0 | 运行时在 mutex 下查找注册表 |
TpuHal::Create | 0x1e814180 | 公共入口:Get → Create → bind profiler |
工厂 vtable
目的
该工厂公开抽象的 5 槽 TpuHalFactory 接口。JXC 只覆盖两个槽;另外三个槽与 PXC 和 VXC 指向的字面函数地址完全相同,即共享基类 Create/CanCreate,而不是按系列复制。
Vtable 布局
| vaddr | 槽位 | 解析为 | 基类/覆盖 |
|---|---|---|---|
| 0x215fe540 | 0 — ~TpuHalFactory() D2 | 0x0e723a80 (ret) | 继承 |
| 0x215fe548 | 1 — ~TpuHalJxcHardwareFactory() D0 | 0x0e723aa0 | 覆盖 |
| 0x215fe550 | 2 — HardwareFactoryBase::Create(wq) | 0x1e80f560 | 继承 |
| 0x215fe558 | 3 — HardwareFactoryBase::CanCreate() | 0x1e80f520 | 继承 |
| 0x215fe560 | 4 — TpuHalJxcHardwareFactory::CreateImpl(wq) | 0x0e723ac0 | 覆盖 |
槽 1(deleting destructor)是 tpu::(anonymous namespace)::TpuHalJxcHardwareFactory::~TpuHalJxcHardwareFactory(0x0e723aa0),在 operator delete(this, 0x10) 内联后只是裸 free(this),这证明工厂对象是 16 字节。槽 2 是 GoF 模板方法:Create 调用槽 3(CanCreate),随后在成功时调用槽 4(CreateImpl),否则构建 NotFoundError。槽 3 读取工厂在 +8 处存储的 TpuVersion,并将其与 ScanHardwareDevices(0x1fba53c0)匹配。
算法 — CreateImpl
function TpuHalJxcHardwareFactory::CreateImpl(out, this, wq): // 0x0e723ac0
version = *(u32*)(wq + 8) // TpuVersion read from the work-queue arg, *((_DWORD*)wq+2)
obj = operator_new(0xD0) // 208 B = TpuHalJxcHardwareImpl
TpuHal::TpuHal(obj, version, wq) // base ctor stores wq + version into the TpuHal sub-object
*(void**)(obj + 0) = &JxcImpl_vtable + 0x10 // plant 0x215fe580 → vptr 0x215fe590
*(void**)(obj + 0xC8) = nullptr // CommonHelper slot (qword index 25), null until CreateAndInitializeChips
out.value = obj ; out.status = OK
return out
```text
> **NOTE —** JXC 的 `CreateImpl` 从 **work-queue 参数**的 `+8`(`*((_DWORD*)wq + 2)`)读取它传给 `TpuHal` 基类 ctor 的 `TpuVersion`,而不是从工厂自身存储的 `this+8` 键读取。这与 VXC 使用的机制相同(`*((unsigned int*)wq + 2)`):这两个携带版本的系列都从 work queue 获取版本。只有 PXC 因服务单一世代,才把字面量 `2` 硬编码进 ctor 调用。(初始化模块写入 `this+8` 的工厂自身 `TpuVersion` 用于 `CanCreate` 与 `ScanHardwareDevices` 匹配;它不是 `CreateImpl` 转发的值。)208 字节 impl 和 qword 索引 25(`+0xC8`)处的 helper 槽由 JXC 和 PXC 共享;VXC 的 impl 是 216 字节(`operator new(0xD8)`,在 `+0xD0` 处有额外 flag 字节)。完整的 impl 覆盖表见 [HAL 工厂覆盖矩阵](hal-factory-override-matrix.md)。
---
## 工厂以下的构造链
### 目的
工厂只返回 HAL 对象。芯片/核心图在 `TpuHalJxcHardwareImpl::CreateAndInitializeChips`(impl vtable 槽 20,@ 0x0e723c20)中惰性构建,该函数在 `Initialize` 期间调用。
### 入口点
```text
TpuHalJxcHardwareImpl::CreateAndInitializeChips (0x0e723c20)
├─ TpuChipParts::CoreCount / SharedMemoryCount ── data-driven constraints
├─ tpu::CreateFishTopology (0x1fc57c60) ── Jellyfish-class BarnaCore mesh
├─ jxc::DriverFactory::Create (0x0e778a40) ── per-device jxc::DriverInterface
├─ TpuHalJxcCommonHelper (24 B, 0x0e725820) ── stored at impl+0xC8
└─ helper->CreateChips (0x0e726a40)
└─ TpuChipJxcDriverImpl (432 B, 0x0e727f80)
└─ core-factory lambda
└─ TpuCoreJxcDriverImpl (824 B, 0x0e733760) ── takes a JfDmaIssuer*注意事项
JXC 的构造路径是四个系列中最重的(一个很大的 CreateAndInitializeChips 函数体,函数跨越了 tpu_hal_jxc_hardware_impl.cc 的大部分内容,其 source line 69–142 可在 fatal-log site annotations 中看到)。它是唯一一个先通过独立的 jxc::DriverFactory::Create 为每个设备构建驱动集,并通过 CreateFishTopology 网格构建器构建拓扑,然后才把结果交给 TpuHalJxcCommonHelper::InitializeDrivers 的系列;后续系列把按设备驱动构造直接折叠进自己的 helper 中,不再有单独的工厂或 fish-topology 构建器。JXC 在该路径中强制三个硬编码上限,每个上限都有不同的 fatal/error 字符串:最多 2 TensorCores("Jellyfish Hardware only supports at most 2 TensorCore.",CoreCount(...,0) >= 3 guard,line 71)、最多 2 BarnaCores("… 2 Barnacore.",CoreCount(...,1) >= 3,line 78),以及 HBM 上限 2("TPU platform only supports up to two HBMs.",SharedMemoryCount(...,0) >= 3,line 83)。这三个 “two” 限制都是烘入消息文本中的 JXC 专属字面量,而 PXC/VXC 会在运行时格式化它们的上限。
GOTCHA — 按核心构造器接受一个
JfDmaIssuer*(Jellyfish 系列 DMA 引擎,ctor @ 0x0e73aea0),这是每个核心单独创建的独立对象。这是 JXC 独有的:PXC、VXC 和 GXC 没有独立的 DMA-issuer 类,它们把 DMA 折叠进按系列的驱动(TpuPxcDriver/TpuVxcDriver)中。假设较新系列也有 DMA-issuer 对象的重新实现将找不到这样的符号。
驱动子命名空间名册
asic_sw::driver::deepsea::jxc:: 命名空间是 JXC 无拆分性质的最强证据。符号表确认的直接子命名空间按引擎块和 trace-entry 类型组织,不是按 fetch/load 角色组织:
| 子命名空间 | 角色 |
|---|---|
jxc::dfc | dataflow controller 引擎(1991 个符号) |
jxc::jfc | Jellyfish core 引擎(988 个符号) |
jxc::registers | register-block 定义(330 个符号) |
jxc::snap | snapshot / checkpoint 支持(241 个符号) |
jxc::jellyfish_performance_counters | gen-0 perf counters |
jxc::dragonfish_performance_counters | gen-1 perf counters |
jxc::*_trace_entry | profiler trace-entry 类型(见下文) |
*_trace_entry 系列包括 bcs_internal、brn_fabric_sync、brn_sync_wait、cs_internal、cs_external_sync_flag_update、hbm_mux_switch、hib_request、hib_interrupt、hib_hbm_write、hib_sync_update、ici_packet 以及 nf_* 集合;这些是引擎块事件记录,不是独立命名空间。
NOTE — 不存在独立的
jxc::bcs/brn/hbm/hib/ici/isa命名空间。这些 token 是 trace-entry 类型名称中的前缀(例如bcs_internal_trace_entry、ici_packet_trace_entry)。两代的编译器侧 ISA 位于platforms_deepsea::jellyfish::isa(mangledplatforms_deepsea9jellyfish3isa;例如BarnaCoreAddressHandlerProgram、ProgramFacade、BundleFacade),反映了 deepsea 伞形结构:其中jellyfish::是所有世代共享的编译器基命名空间。QUIRK — JXC 没有
jxc::profiler::TraceEntry类。子核心分类归组的具名profiler::TraceEntry事件类只存在于 fetch/load 拆分的系列中。JXC 的 profiler 支持通过按引擎的*_trace_entry类型实现。因此,尽管 JXC 是一个 HAL 系列,它并不是 trace-entry 子核心之一。
按代号区分的差异
Jellyfish 和 Dragonfish 只在数据上不同,从不在 C++ 类型上不同。二者都会产生相同的 TpuHalJxcHardwareImpl、相同的 TpuChipJxcDriverImpl/TpuCoreJxcDriverImpl,并共享同一个 DMA 描述符模型(V1 jxc::DmaDescriptor,8×32-bit = 32 bytes)。每代都有自己的具名 codec 类 TpuCodecJellyfish 和 TpuCodecDragonfish(二者都有完整名称和 RTTI 符号),由 TpuCodec::Create 的 case 0/1 选择,但这些是 codec 对象,不是 HAL 类型。
| 维度 | Jellyfish (v0) | Dragonfish (v1) | 来源 |
|---|---|---|---|
| TpuVersion enum | kJellyfish = 0 | kDragonfish = 1 | TpuVersionToString 0x20b3a480 |
| ToString | "jellyfish" | "dragonfish" | rodata pointer table 0x22011bf0 |
| Codec class | TpuCodecJellyfish(具名) | TpuCodecDragonfish(具名) | symtab;TpuCodec::Create case 0/1 |
| TensorCore / BarnaCore | yes / yes | yes / yes | TpuChipParts (Core.type BARNA_CORE) |
| SparseCore | no | no | TpuChipParts (no SPARSE_CORE Core) |
| Flag prefix | xla_jf_(417 个 flags) | xla_jf_(无 xla_df_) | flag scan |