Target Capability Bitfield(Target+0x628)
本页中的所有地址、偏移和 bit 位置都适用于
libtpu-0.0.40-cp314wheel(BuildID md589edbbe81c5b328a958fe628a9f2207d)中的libtpu.so。其他版本会有所不同。
摘要
xla::jellyfish::Target 在 Target+0x628 处携带一个 64-bit “has-bits” qword。尽管它以完整 uint64_t 读写,对整个 .text 的操作数扫描证明,此构建只设置和测试其中两个 bit:bit-0(mask 0x1)和 bit-2(mask 0x4)。所有其他 bit,包括 bit-1、bit-3 和全部更高 bit,都没有设置点也没有测试点;这个 qword 是一个留有扩展空间的 feature word,但此构建只使用了两个槽位。
该 qword 紧跟在一个两项 inline array 之后,数组元素是continuation-queue scoped-memory-region 描述符(Target+0x580 和 Target+0x5F0)。每个 bit 都是一个描述符的存在标志:bit-0 记录 TensorCore region 已追加,bit-2 记录 SparseCore region 已追加。两个 append 都在同一个 megachip / SparseCore-offload feature-detect 谓词下运行,因此 bit-2 最终成为 Target::IsMegachip() 的有效项,也就是 SparseCore lowering 和 Deepsea compiler driver 中 102 个内联 testb $0x4,0x628 站点读取的 gate。
怪癖 — entry-B 是
GetContinuationQueues(2),而2在运行时TpuCoreTypeenum 中是kSparseCore({kTensorCore=0, kBarnaCore=1, kSparseCore=2},也是tpu::TpuCoreProgramvariant 的替代顺序;IsMegacore在core==2 → "Megacore SparseCore is not supported"上的 fatal-log 也佐证了这一点)。不要把它与chip_parts.binarypb内部使用的 protobufnProto顺序{TENSOR_CORE=1, BARNA_CORE=2, SPARSE_CORE=3}混淆;在那里,2是 BarnaCore。has-bits 字段由运行时 enum 构建,因此 bit-2 是 SparseCore region。
本页记录:
- bit 布局:每个 live bit gate 的能力、它在
Target::Init中的设置位置,以及逐 bit 的 consumer surface。 IsMegachip恒等式:为什么 bit-2 是 megachip/SC-offload has-bit,以及为什么 bit-0 既不属于 megachip 也不属于 megacore。- 后备数据:这些 bit 所标记的两项 continuation-queue scoped-memory-region array,以及设置它们的谓词。
| Bitfield 成员 | Target+0x628 — uint64_t has-bits qword |
| Live bits | bit-0 (0x1)、bit-2 (0x4) — 此构建中其他全部保留/未使用 |
| 设置点(两者) | xla::jellyfish::Target::Init @ 0x1D60FC20 |
| bit-2 accessor | xla::jellyfish::Target::IsMegachip @ 0x10914F60(内联于 102 个 testb $0x4 站点) |
| bit-0 consumer | DeepseaCompilerBase::CompileInternal @ 0x10928B40(gate LloRegionBuilder::ShaltInternal) |
| 后备数组 | continuation-queue scoped-mem descriptors @ Target+0x580 / Target+0x5F0 |
| Simulator fallback | Target+0x540 byte (platform_type == iss) |
Bit 布局 {#bit-layout}
该 qword 是 _has_bits_ 风格的 flags 成员。Bit 编号按 LSB-first:bit-n 的 mask 是 1 << n,因此 bit-0 = 0x1,bit-2 = 0x4,这也是本页每个 or/testb immediate 使用的约定。设置点是 Target::Init 中两段 load-or-store 序列(0x1D611D52 处 or $0x1,%rcx 后接 mov %rcx,0x628(%r12);0x1D612121 处 or $0x4,%rcx 后接 mov %rcx,0x628(%r12));测试点是 testb $imm,0x628(reg)。对 .text 中 offset 0x628 的穷尽操作数扫描只发现这些针对 Target 指针基址寄存器的 immediate:or $0x1 一次,or $0x4 一次,testb $0x1 两次,testb $0x4 102 次。任何地方都没有出现 $0x2、$0x8 或更高 mask。
易错点 — 对
testb $0x1,0x628的原始操作数 grep 会返回三个命中,但其中一个(0xFE3B600,位于PostorderDFSVisitor::PostOrderDFSVisit内)是testb $0x1,0x628(%rsp),也就是刚好位于 frame offset0x628的 stack local,而不是Target字段。只有两个基于%r12/%r14的读取(0x10928083、0x1090EB6E)是真正的 bit-0 测试。102 个testb $0x4站点全部基于指针寄存器,这组中没有%rsp/%rbpfalse positive。
| bit | mask | 语义 / 名称 | 设置点(Target::Init) | consumers(测试点) |
|---|---|---|---|---|
| 0 | 0x1 | TensorCore continuation-queue scoped-memory region 存在(entry-A) | 0x1D611D52(or $0x1),在 entry-A append 之后 | 2 个真实 testb $0x1,0x628 读取;有效 reader DeepseaCompilerBase::CompileInternal @ 0x10928083 → gate LloRegionBuilder::ShaltInternal |
| 1 | 0x2 | reserved / unused in v0.0.40 | (从未设置) | (从未测试) |
| 2 | 0x4 | megachip / SparseCore-offload capability has-bit,即 Target::IsMegachip() 的有效项 | 0x1D612121(or $0x4),在 entry-B append 之后 | testb $0x4,0x628 ×102 = 内联 IsMegachip();SC lowering、CompileSparseCorePrograms、EmitSparseCoreAsyncStart/Done、IsValidReduceScatterForSparseCoreOffload、Deepsea Lower/RunBackend/MakeAot |
| 3+ | 0x8+ | reserved / unused in v0.0.40 | (从未设置) | (从未测试) |
注意 — qword 通过 REX.W (
mov) 加载和存储,也就是 64-bit,因此物理上还有 62 个 flag 的空间。bits 1 和 3+ 是源代码中已死,还是为后续 silicon generation 前向保留,仅凭这个二进制无法区分;可以确定的是 v0.0.40 恰好驱动其中两个。
Bit-2 == IsMegachip()
102 个 testb $0x4,0x628 站点都是 Target::IsMegachip 的内联副本。该 accessor 按 byte 精确读取为三项合取:
char Target::IsMegachip(Target *this): // sub_10914F60
cfg = *(TpuChipConfig**)(*(void**)(this+0x3B8) + 0x18); // Target+0x3B8 -> deref -> +0x18 chip config
if (!cfg->Megachip() // TpuChipConfig+0x9 (byte)
|| *(int32*)(cfg+0x94) <= 0) // TpuChipConfig+0x94 = CoresPerChip(kSparseCore)
return 0
if ((this[0x628] & 4) == 0) // bit-2 of the has-bits qword
return this[0x540] // platform_type == iss fallback byte
return 1 // bit-2 set: megachip
```text
因此 bit-2 *就是* megachip capability:当某个 part 的 chip config 声明 `Megachip()`、至少有一个 SparseCore,并且 `Target::Init` 谓词设置了 bit-2 或者平台是 `iss` simulator(`Target+0x540`)时,该 part 就是 megachip。即使硬件谓词没有设置该 bit,simulator 路径也会强制采用该能力。`Megachip()` 本身是一次 one-byte 读取:
```c
bool TpuChipConfig::Megachip(TpuChipConfig *this): // sub_20AFCC00
return *((uint8_t*)this + 9) // TpuChipConfig+0x9为什么 bit-2 不是 IsMegacore
Target::IsMegacore 是另一个 accessor,完全不触碰 Target+0x628:
bool Target::IsMegacore(Target *this, TpuCoreType core): // sub_13699EE0
if (core == kSparseCore=2)
LOG(FATAL) << "Megacore SparseCore is not supported." // target.h:1210
cfg = *(TpuChipConfig**)(*(void**)(this+0x3B8) + 0x18); // Target+0x3B8 -> deref -> +0x18 (same chain as IsMegachip)
if (!cfg->Megacore()) // TpuChipConfig+0x8 (byte)
return 0
if (core >= 3) BUG()
return *(int32*)(cfg + 0x7C + core*12) >= 2 // per-core count: TpuChipConfig+0x7C + core*12
```text
它读取 `TpuChipConfig+0x8` 处的 *Megacore* flag 和 `+0x7C+core*12` 处的逐核心计数,不引用 has-bits qword。Bit-2 只属于 megachip;bit-0 两者都不属于,它是下文描述的 TensorCore continuation-queue presence flag。
| accessor | VA | 读取 `Target+0x628`? | 公式 |
|---|---|:--:|---|
| `Target::IsMegachip` | `0x10914F60` | yes(bit-2) | `Megachip ∧ CoresPerChip(SC)>0 ∧ ((+0x628 & 4) ∨ +0x540)` |
| `Target::IsMegacore` | `0x13699EE0` | no | `Megacore ∧ CoresPerChip(core) ≥ 2` |
---
## 后备数据:Continuation-Queue Scoped-Memory Regions
这两个 bit 是两项 inline array 中 continuation-queue scoped-memory-region 描述符的存在标志。`Target::Init` 在 `Target+0x580`..`Target+0x627` 构建这些描述符,has-bits qword 紧接在 entry B 的 vector 之后。每个描述符宽 `0x70` bytes:
| entry | presence bit | `name` (`std::string`) | `MemorySpace` (int32) | `std::vector<MemoryPart>` `{begin,end,cap}` | source |
|---|---|---|---|---|---|
| A | bit-0 (`0x1`) | `Target+0x580` | `Target+0x59C` | `+0x5A0` / `+0x5A8` / `+0x5B0` | `GetContinuationQueues(kTensorCore=0)` |
| B | bit-2 (`0x4`) | `Target+0x5F0` | `Target+0x60C` | `+0x610` / `+0x618` / `+0x620` | `GetContinuationQueues(kSparseCore=2)` |
每个 entry 都通过复制逐核心 continuation-queue list 构建;该 list 是 `TpuChipConfig::GetContinuationQueues` 返回的 `0x30`-byte-stride source array,随后被复制到 `0x1C`-byte-stride `MemoryPart` vector,并通过 `TpuSharedMemoryTypeToMemorySpace`(`0x1D6224E0`)映射每个元素的 shared-memory type。每次 append 后,对应 bit 都被 OR 到 `Target+0x628`。`GetContinuationQueues` 是一个小型 presence-gated lookup:
```c
auto TpuChipConfig::GetContinuationQueues(TpuChipConfig *this, TpuCoreType core): // sub_20AFCCC0
if (!_bittest64(this[0xC8], core)) // presence bitmask at TpuChipConfig+0xC8
return {nullptr, 0}
if (core >= 3) BUG()
return this[0x80 + core*0x18] // EnumMap base +0x80, stride 0x18append 谓词(两个 entry 共用)是 megachip / SparseCore-offload feature-detect,形状与 IsMegachip 相同:Megachip() ∧ CoresPerChip(kSparseCore)>0 ∧ ((Target+0x628 & 4) ∨ Target+0x540) ∧ continuation_queue[0]==2。
怪癖 — 描述符数组只存在于 C++ 运行时。
Target::ToArgumentsProto(0x1D60F560)不会序列化Target+0x540..Target+0x628区域,因此它没有 protobufFieldDescriptor。逐 entry 布局({std::string, MemorySpace int32, std::vector<MemoryPart>},0x70-byte stride)和GetContinuationQueues(core)source 是 byte-exact 的,但 C++ 成员名称是从 source getter 归因而来,不是从 descriptor 恢复的。重新实现应把该 qword 视为运行时状态,而不是 wire state。
Bit-0:TensorCore Continuation-Queue Presence
当 entry A,也就是从 GetContinuationQueues(kTensorCore=0) 构建的 region,被追加时,bit-0 在 Target::Init(0x1D611D52)中被设置。它正好在两个真实 testb $0x1,0x628 站点被读取(第三个语法匹配 0xFE3B600 是 %rsp stack local,不是这个字段;见 Bit 布局 中的易错点)。有效 reader 是 DeepseaCompilerBase::CompileInternal(0x10928083):该测试后面是跨过 call LloRegionBuilder::ShaltInternal(0x1D520D20)的 jne,因此 bit-0 已设置会跳过 shalt-region emission,而 bit-0 清除会调用 ShaltInternal。因此 bit-0 gate 的是是否为 TensorCore continuation-queue capability 发出 stall/halt region。第二个读取点是 TpuCompactionIsaEmitterCodegen::Create(0x1090EB6E),它同样 guard 相同的 emission,并且紧跟在内联 TpuChipConfig::Megachip 检查之后。
SparseCore-Offload 覆盖旋钮
TpuCompilationEnvironment(TCE)中的两个编译期旋钮会覆盖 bit-2/megachip gate 建立的硬件默认值。两者都是 xla::jellyfish 命名空间中的 getter,接收一个 ObjectView<TpuCompilationEnvironment> 和一个 TpuTopology&,读取单个 TCE proto 字段,并在该字段保留为 AUTO 时回退到 generation default。因为 ObjectView byte-offset 等于 TCE _impl_ struct offset,也等于 _InternalSerialize field-write offset,所以每个 struct offset 都与恢复出的 proto field number 一一对应。
char ShouldEnableConcurrentSparseCoreOffloading(ObjectView<TCE> env, // sub_1D6B6F80
TpuTopology &topo, bool force_off):
hw = (topo.chip_parts->version == 5) & ~force_off // chip_parts+0 == TpuVersionProto 5 (ghostlite/v6e)
p = env[0x458] ?: &AutoProto_globals_ // TCE +0x458 = field 923
v = AutoOr<bool>::FromProtoOrDie(p) // ret = AUTO?0 : (value | 0x100)
if ((v & 0x100) == 0) v = hw // no explicit value -> hw default
return v & 1
char EnableSparseCoreOffloadQueuingInLhs(ObjectView<TCE> env, TpuTopology &topo): // sub_1D6B81E0
hw = (topo.chip_parts->version == 5) // chip_parts+0 == TpuVersionProto 5 (ghostlite/v6e)
p = env[0x730] ?: &AutoProto_globals_ // TCE +0x730 = field 1021
v = AutoOr<bool>::FromProtoOrDie(p)
if ((v & 0x100) == 0) v = hw
return v & 1
```text
覆盖机制是 `AutoOr<bool>::FromProtoOrDie`(`0xF795300`):它读取 `AutoProto+0x1C` 处的 `AutoProto` state word;state `0`(AUTO/unset)返回 `0`,因此 `& 0x100` 测试失败并采用硬件默认值;任何其他 state 返回 `value | 0x100`,因此 bit-8 标记“存在显式值”,bit-0 携带 bool,可在两个方向覆盖 chip-gen default。
```c
int64 AutoOr<bool>::FromProtoOrDie(AutoProto *a1): // sub_F795300
if (a1[0x1C/4] == 0) return 0 // AUTO: no presence -> 0
val = AutoOrTypeTraits<bool>::FromAutoProto(a1) // (LOG(FATAL) on conversion error)
return val | 0x100 // bit-8 = present, bit-0 = valuegetter (xla::jellyfish::) | VA | TCE offset | field # | TCE field name | hardware default |
|---|---|---|---|---|---|
ShouldEnableConcurrentSparseCoreOffloading | 0x1D6B6F80 | +0x458 | 923 | xla_tpu_enable_concurrent_sparse_core_offloading | (proto_version==5: ghostlite/v6e) && !force_off |
EnableSparseCoreOffloadQueuingInLhs | 0x1D6B81E0 | +0x730 | 1021 | xla_tpu_enable_sparse_core_offload_queuing_in_lhs | proto_version==5 (ghostlite/v6e) |
注意 — field numbers(923、1021)来自
TpuCompilationEnvironment::_InternalSerialize(0x1DB41DC0)中每个InternalWriteMessage调用前的mov $field#,%ediimmediate:0x1DB50028加载0x458然后写 field0x39B(923),0x1DB50DBE加载0x730然后写 field0x3FD(1021),因此 struct-offset ↔ field-number 绑定是直接的,不是推断的。version == 5比较反汇编为针对TpuTopology+8 -> chip_parts+0的cmpl $0x5,(%rax)(0x1D6B6F8C)。该字段携带TpuVersionProto(1-based,即 proto field-1 的值,也是chip_parts.binarypbblob 开头的值),不是 0-based 内部TpuVersion;因此5解析为 ghostlite (TPU v6e),6将是6acc60406。0-based↔1-based 对照见 Codename 矩阵。四个 sibling SC-offload knobs 共享相同的AutoOr<bool>模式,每个都由同一 serializer 中的0xNNN(%r14)load +mov $field#,%edipair 确认:field 930(disable_sparse_core_collective_offload_remover,+0x490→0x3A2)、853(enable_hbm_test_buffer_for_sc_collective_offload,+0x2E0→0x355)、857(enable_outfeed_sanity,+0x2E8→0x359)、959(xla_shardy_options,+0x568→0x3BF)。
相关组件
| 名称 | 关系 |
|---|---|
Target::Init (0x1D60FC20) | 在追加两个 continuation-queue regions 后设置 bit-0 / bit-2 |
Target::IsMegachip (0x10914F60) | 读取 bit-2;102 个内联 testb $0x4 站点就是它的函数体 |
TpuChipConfig::GetContinuationQueues (0x20AFCCC0) | 被复制到 regions 中的逐核心 queue list 的来源 |
AutoOr<bool>::FromProtoOrDie (0xF795300) | 两个 SC-offload knobs 的 override decode |
TpuCompilationEnvironment::_InternalSerialize (0x1DB41DC0) | 将 TCE struct offsets 映射到 proto field numbers |
交叉引用
- TpuChipConfig — gate 读取其
Megachip/CoresPerChip/GetContinuationQueues字段的 chip-config 对象 - Codename 矩阵 —
TpuVersion↔ codename 映射;消除version == 5SC-offload default 的歧义 - TPU Compilation Environment — TCE proto,其中 fields 923 / 1021 覆盖 bit-2 硬件默认值
- chip_parts.binarypb Decode — proto
nProtocore 顺序(TENSOR_CORE=1, BARNA_CORE=2, SPARSE_CORE=3),不能与运行时TpuCoreTypeenum(kSparseCore=2)混淆;也包含version==5 → ghostlite/v6e映射