MXU 延迟:GL (Ghostlite)
本页所有地址均适用于来自
libtpu-0.0.40-cp314wheel 的libtpu.so(构建libtpu_lts_20260413_b_RC00,BuildID md589edbbe81c5b328a958fe628a9f2207d)。该二进制未剥离符号 — 每个符号都是反混淆后的 C++ 名称。.text/.rodataVMA == 文件偏移;.data.rel.roVMA − 0x200000 == 文件偏移。
摘要
xla::ghostlite::MxuLatencyTable 是 mxu-latency-overview 中按代际 MXU 预留模型的 Ghostlite(TpuVer 4,v6e)实例。基础 GhostlitePerformance 网格(performance-gl-ghperf)给出某个 MXU op 的总流水线延迟,而此表给出它的占用 — 对每个 (opcode-modifier, MxuResource) 对,表示该 op 在途期间,一个内部 MXU 子单元(gain array、矩阵暂存寄存器、矩阵结果缓冲区读端口)被占用多少周期。每个 bundle 的停顿递推会读取该值单元,以决定下一个 MXU op 在可以发射前必须等待多久。
Ghostlite 的资源集合比 Viperfish 更窄:预留向量是 std::array<int,11>,而 Viperfish 是 array<int,19>。边界检查字面量也相应为 11(MxuResource::kNumMxuResources)而不是 19。查找函数 GetResourceUsage @0x1c8b7560 以 Ghostlite 专用 opcode 集对两个族进行键控 — MatmulModifier(this+0x20 处的 matmul map)和 MatpushModifier(this+0x00 处的 latch/matprep map)— 通过三个共享的 GainLatchMode helper 构造 modifier key,find 对应行,并返回 array[resource]。两个按资源的默认值会短路查找:resource==4 → 3 和 resource==9 → 9 会在任何 map 读取前播种 latch/matmul-issue 槽。
本页的决定性结构事实是 GL-vs-GF 构造函数分裂。Ghostlite(v6e)和 6acc60406(GF 代)共享 array<int,11> 形状、四种 modifier 类型以及三个 GainLatchMode key helper — 但它们是两个不同的对象,由两个不同构造函数构建,并带有两套不同的基础延迟值。GL 的 ctor @0x1c8b2920 是数据驱动的:它用模板化的 SetReservations<Modifier> 调用填充 map,将稀疏 flat_hash_map<MxuResource,int> 稠密化为 array<int,11>。GF 的 ctor @0x1c8bb1c0 是内联的:它直接写入 array[res & 0xf] = cy,并且完全不构建 Matres map。基础 matmul 延迟不同 — GL 对 bf16/F32 定价为 192,对 fp8 定价为 182;GF 为 211/204 — 所以这两代不是一个共享实例。本页记录 GL;GF 对偶页见 mxu-latency-gf。
对重新实现而言,契约是:
- Ghostlite
MxuLatencyTable对象:this+0x00处的flat_hash_map<MatpushModifier, array<int,11>>,this+0x20处的flat_hash_map<MatmulModifier, array<int,11>>,以及后续偏移处的Vlxmr/Matresmap,外加按资源的默认 keyres4→3、res9→9。 - 预留体:matpush
{2,1,1}/{4,3,2}/{8,7,6}的按宽度缩放三元组、Vlxmr/Matresrodata 集,以及SetReservations如何将它们稠密化为稠密向量。 GetResourceUsage(instr, resource)查找:GL opcode → 族 → modifier key →find→ 边界检查resource < 11→array[resource]。- GL/GF ctor 分裂:数据驱动的
SetReservations(GL)对比内联直接写入(GF),以及分歧的192/182对比211/204基础延迟,因此重新实现应为每个硅代保留一个 ctor。
| 类 | xla::ghostlite::MxuLatencyTable |
| GL ctor | MxuLatencyTable::MxuLatencyTable @0x1c8b2920 — 数据驱动的 SetReservations;operator new 0xA0 |
| GL 查找 | MxuLatencyTable::GetResourceUsage @0x1c8b7560 — 默认值 res4→3、res9→9 |
| 预留向量 | std::array<int,11>(MxuResource::kNumMxuResources = 11) |
| 所属 CycleTable | GlcCycleTable @0x1c89e7e0 — this+0x18 处的 MXU 表(new 0xA0) |
| MXU 对偶 | MxuLatencyTable1(MXU1,第二实例)— 同一类,不同 map 集 |
| GF 对应项 | GF(6acc60406)ctor @0x1c8bb1c0,查找 @0x1c8bdb20 — 内联构建,211/204 |
| 源文件 | …/target/ghostlite/mxu_latency_table_gl.cc(CHECK/LogFatal 锚点) |
对象布局
目的
该表在 GlcCycleTable 构造时构建一次,只持有查找过程要读取的按实例 hash map。每个 map 都把一个小的 modifier struct 映射到一个稠密 array<int,11>,其中保存按资源的占用周期。
结构
GlcCycleTable::GlcCycleTable @0x1c89e7e0 用 operator new(0xA0) 分配该表并存放在 this+0x18,同时在 this+0x10 处放置一个 GhostlitePerformance(new 0x30):
function GlcCycleTable_ctor(this, target): // @0x1c89e7e0
this.vtable = off_21C20158
this.target = target // [this+0x08]
this.perf = new GhostlitePerformance() // [this+0x10] — new 0x30; @0x1c8cbc80
this.mxu = new MxuLatencyTable() // [this+0x18] — new 0xA0; @0x1c8b2920
```text
这个 `0xA0` 字节的 `MxuLatencyTable` 主体是在固定偏移处的一组 Abseil flat hash map,由查找传给 `find` 的 C++ key *类型*区分,而不是由判别字段区分:
```text
MxuLatencyTable (0xA0 bytes, at GlcCycleTable + 0x18)
this + 0x00 flat_hash_map<MatpushModifier, array<int,11>> ── latch / matprep ops
this + 0x20 flat_hash_map<MatmulModifier, array<int,11>> ── matmul ops
this + 0x40 flat_hash_map<VlxmrModifier, array<int,11>> ── vector-latch-into-MRB ops
this + 0x60 flat_hash_map<MatresModifier, array<int,11>> ── matrix-result-read ops
this + 0x80 matmul_latencies_ (MatmulDataFormat → total-latency int)matpush map 地址 this+0x00 会作为裸 a2/this 直接读入 find<MatpushModifier>;matmul map 地址 this+0x20 是 find<MatmulModifier>(a2 + 32, …) — 两者都在 GetResourceUsage @0x1c8b7560 中按字节确认。this+0x80 处的 matmul_latencies_ map 是按 MatmulDataFormat 的总延迟,独立于按资源的占用向量(下面的 192/182 值)。
怪异点 — 值
array<int,11>会用原始vmovupsload 从 bucket 中读出,在索引前把全部 44 字节复制到栈上。matmul 读取是vmovups [rdx+8](8 字节MatmulModifierkey 位于值之前);matpush 读取是vmovups [rdx+4](4 字节MatpushModifierkey)。如果重新实现假设统一 key 宽度,就会在两个族中的一个上从错误偏移读取数组。这与 Viperfish 约定相同;只是N从 19 缩小到 11。
行的构建方式 — SetReservations
GL 用模板化的 SetReservations<Modifier>(MatpushModifier @0x1c8b5d80、VlxmrModifier @0x1c8b5f60、MatresModifier @0x1c8b6140)填充每个 map。每次调用都接收 modifier key 和一个稀疏 flat_hash_map<MxuResource,int>(“此 op 占用资源 k 持续 c 周期”的集合),将一个稠密 array<int,11> 清零初始化,把稀疏单元复制进去,并 try_emplace 结果:
function SetReservations<Modifier>(key, resource_to_cycles): // GL @0x1c8b5d80 (matpush)
array<int,11> result_vector = {0} // vxorps-zeroed 44-byte vector
for (resource_index, cycles) in resource_to_cycles: // SOO-iterated flat_hash_map
CHECK(resource_index < 11) // "resource_index < to_underlying(
// MxuResource::kNumMxuResources)" — gl.cc:60
result_vector[resource_index & 0xF] = cycles
CHECK(resource_map->try_emplace(key, result_vector).second) // gl.cc:63 — keys are unique
```text
两个 CHECK 都在 `SetReservations<MatpushModifier> @0x1c8b5d80` 中按字节确认:边界 `*v7 > 0xA` 会在 `gl.cc:60` 触发 `MakeCheckOpString(idx, 11, "resource_index < to_underlying(MxuResource::kNumMxuResources)")`,唯一 key CHECK `try_emplace(...).second` 会在 `gl.cc:63` 触发。清零初始化意味着**该 op 未命名的任何资源占用 0 周期** — 它不会施加停顿。ctor `@0x1c8b2920` 发出六次 `SetReservations<MatpushModifier>` 调用(latch-mode key 变体 `+1`、`+257`、`+2`、`+258`、base、`|0x100`),两次 `SetReservations<VlxmrModifier>`(key `0`、`257`),以及八次 `SetReservations<MatresModifier>`(key `1..8`)。
---
## 预留体
### 目的
`array<int,11>` 中的整数就是吞吐模型:每个 MXU 子资源在每个 op 中被占用多少周期。它们随数据路径宽度缩放,因此窄格式 push 的背靠背发射能以接近发射速率流水化,而宽 x8 push 会限流该流。
### Matpush(latch / matprep)— 按宽度缩放的三元组
matpush 主体是一个三资源预留 `{R_0, R_a, R_b}`,其数值随 `MatmulDataFormat` 宽度缩放。值集与 Viperfish 上看到的 `{2,1,1} → {4,3,2} → {8,7,6}` 递进相同 — GL 在 ctor 中把这些三元组暂存于 `[rbp-0x7c]/[rbp-0x74]/[rbp-0x6c]`(`@0x1c8b2a72/2f9a/39fa`),然后送入 `SetReservations`:
| matpush 格式 / pass | 预留三元组 |
|---|---|
| bf16 single(format 1) | `{2, 1, 1}` |
| bf16 transposed / doubled | `{4, 3, 2}` |
| int8 x8(4-byte-plane quad) | `{8, 7, 6}` |
首个元素是 gain-array 占用;另外两个是矩阵暂存寄存器 A/B 占用。`{2,1,1}` bf16 集意味着一个 bf16 matpush 只占用其暂存寄存器 1 个周期,因此 bf16 latch 流能以约 1 周期发射流水化,而约 192 周期的延迟会隐藏在 systolic 深度中。`{8,7,6}` int8-x8 集 — bf16 占用的四倍 — 反映四个 byte-plane latch 序列,并将 x8 流限流到约 bf16 发射速率的四分之一。
### Vlxmr 和 Matres — rodata 集
`Vlxmr`(vector-latch-into-MRB)和 `Matres`(matrix-result-read)族从 `.rodata` pair 数组取得其预留:
| 族 | key | 预留 | rodata |
|---|---|---|---|
| `Vlxmr` | `0` | `{res0: 2}` | `@0xb43bfc0` |
| `Vlxmr` | `257`(MSR `0x101`) | `{res0: 2, res1: 49}` | `@0xb43bfc8` |
| `Matres` | `1,2,3,4` | `{res4: 2}` | `@0xb43bfd8` |
| `Matres` | `5,6,7,8` | `{res4: 1}` | `@0xb43bfe0` |
MSR 驱动的 matpush 遍历读取 `@0xb43bfb4` 处的 GL `kMsrs` 列表 `{1,2,3,3,4,5,6,7,8}`;内联 matpush 值集字节位于 `@0xb43bfe8`,为 `{0,0,1,1,9,0,3,7,a,8,a,4,3,3,3,3,1,1,2,2,3,3}`。这些是 v6e 专用的 MxuResource 索引 — `array<int,11>` 资源编号不同于 Viperfish 的 `array<int,19>`,因此某个索引处的*物理*子单元并不在两代之间共享。
> **注意 —** MxuResource enum 在二进制中**没有** `ToString`;索引 `0..10` 在全程都以数字使用。它们是 MXU 内部子单元(gain array、暂存寄存器 A/B、MRB 读端口、matmul-issue 槽),不同于 [`resource-enum`](resource-enum.md) 的更高层 23 槽 `ResourceVector`。GL 的索引到物理单元绑定只能按位置确定(MEDIUM)。
---
## 查找
### 算法
`GetResourceUsage @0x1c8b7560` 带有干净的符号 `xla::ghostlite::MxuLatencyTable::GetResourceUsage(GhostlitePerformance::Instruction, Resource, bool)`。它在任何 map 读取前取得默认值,按 GL opcode 分派族,构建 key,并读取单元:
```c
function MxuLatencyTable::GetResourceUsage(this, instr, opcode, resource, latch_mode): // GL @0x1c8b7560
// 1. Per-resource default fallback, before the table lookup.
if resource == 4: default_cycle = 3 // GL latch/issue-slot seed
elif resource == 9: default_cycle = 9 // GL matmul-issue slot seed
else: return InvalidArgument("Unsupported kind of resource") // gl.cc:442
// 2. Select family + build key from the GL opcode.
switch (opcode):
case 292: key = MatmulModifier{format=1}; map = this+0x20 // matmul
case 298: key = MatmulModifier{format=2}; map = this+0x20
case 310: key = MatmulModifier{format=6}; map = this+0x20
case 347: key = MatpushKey(latch_mode); map = this+0x00 // matpush base
case 349: key = MatpushKey(latch_mode ^ 0xB); map = this+0x00 // transposed path
case 356: key = MatpushKey(latch_mode | 0x14); map = this+0x00 // wide x8 path
case 358: key = MatpushKey(latch_mode | 0x18); map = this+0x00 // wide x8 (alt)
default: LogFatal("Unsupported opcode") // gl.cc:478
// 3. find + bounds-check + read.
entry = map.find(key)
if entry not found: throw out_of_range // raw_hash_map::at
array<int,11> res_vector = entry.value // vmovups copy, key-width-dependent offset
CHECK(resource < 11) // v9 >= 0xB → BUG()
return res_vector[resource]MatpushKey 是 { byte[0]=GainLatchModeToMatmulDataFormat(mode), byte[1]=LatchModeIsTranspose(mode), byte[2]=3, byte[3]=LatchOpcodeToMsr(0x95) },由三个共享 helper GainLatchModeToMatmulDataFormat @0x1d629260、LatchModeIsTranspose @0x1d628ea0 和 LatchOpcodeToMsr @0x1c8a1300 组装。对 latch mode 的 opcode 专用预变换(^0xB、|0x14、|0x18)会把同一物理 latch 路由到转置或宽预留 bucket。
陷阱 — GL opcode 不是 Viperfish opcode。VF 在 opcode
230(case212/218)上匹配 matmul,在267/271/277上匹配 matpush;而 GL 在292/298/310上匹配 matmul,在347/349/356/358上匹配 matpush — 且 GL 增加了 Viperfish 没有的第四个 matpush case(358,mode | 0x18)。GL 的LatchOpcodeToMsr实参是0x95(VF:0x8F),key byte[2] 是3(VF byte[3] 保存 MSR)。按每代的 opcode 列表绑定族,绝不要按硬编码常量绑定。注意 — 按资源的默认 key 是按代际定义的:Viperfish 默认值是
res3→15/res11→0;Ghostlite 是res4→3/res9→9,已在@0x1c8b7560按字节确认(a4==4 → v9=3,a4==9 → v9=9)。重新实现必须从 GL 查找读取 GL 的默认资源 key;GL 整数矩阵反映的是 11 资源索引。
函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
ghostlite::MxuLatencyTable::MxuLatencyTable | 0x1c8b2920 | GL ctor — 数据驱动的 SetReservations;matmul_latencies_ 192/182 |
ghostlite::MxuLatencyTable::GetResourceUsage | 0x1c8b7560 | GL 查找 — 默认值 res4→3、res9→9;边界 < 11 |
ghostlite::SetReservations<MatpushModifier> | 0x1c8b5d80 | 稠密化 {res→cy} → array<int,11>;CHECK < 11(gl.cc:60),try_emplace(gl.cc:63) |
ghostlite::SetReservations<VlxmrModifier> | 0x1c8b5f60 | vlxmr 族行构建器 |
ghostlite::SetReservations<MatresModifier> | 0x1c8b6140 | matres 族行构建器 |
GlcCycleTable::GlcCycleTable | 0x1c89e7e0 | 所属 CycleTable — 连接 GL perf(+0x10)+ MXU 表(+0x18) |
GainLatchModeToMatmulDataFormat | 0x1d629260 | matpush key byte[0] — 与 VF/GF 共享 |
LatchModeIsTranspose | 0x1d628ea0 | matpush key byte[1] — 共享 |
LatchOpcodeToMsr | 0x1c8a1300 | matpush key byte[3] — GL 实参 0x95 |
GF(6acc60406)ctor | 0x1c8bb1c0 | 分歧的对偶 — 内联构建,211/204 |
GF(6acc60406)GetResourceUsage | 0x1c8bdb20 | GF 查找 — mxu_latency_table_gf.cc,无 res4/res9 重映射 |
GL-vs-GF 构造函数分裂
目的
Ghostlite(v6e)和 6acc60406(GF 代)看起来像一个族 — 相同的 array<int,11> 形状、相同的四种 modifier 类型、相同的 GainLatchMode key helper — 但它们是两个不同对象,由两个不同构造函数构建,并带有两个不同值集。把它们当作一个共享实例的重新实现,会把每个 6acc60406 matmul 都定错价。
共享项与分歧项
GL (Ghostlite, v6e) GF (`6acc60406`)
owning CycleTable GlcCycleTable @0x1c89e7e0 GfcCycleTable @0x1c89eec0
MxuLatency ctor @0x1c8b2920 @0x1c8bb1c0
GetResourceUsage @0x1c8b7560 @0x1c8bdb20
─────────────────────────────────────────────────────────────────────────────
SHARED : object size 0xA0; array<int,11>; MatmulModifier/MatpushModifier/
VlxmrModifier/MatresModifier; GainLatchModeToMatmulDataFormat /
LatchModeIsTranspose / LatchOpcodeToMsr; matpush {2,1,1}/{4,3,2}/{8,7,6}.
DIVERGE : ctor mechanism, base op-latency, opcode set, default-resource handling.
```text
这些分歧已按字节确认:
- **构建机制。** GL 的 ctor `@0x1c8b2920` 是数据驱动的:`SetReservations<Modifier>` 将 `flat_hash_map<MxuResource,int>` 稠密化为向量(6× matpush、2× vlxmr、8× matres)。GF 的 ctor `@0x1c8bb1c0` 是内联的:按 modifier 的 helper 直接写 `array[res & 0xf] = cy`(`cmp al,0xa` 边界),并且**不**构建 `Matres` map — GF ctor 中完全没有出现 `SetReservations`。
- **基础 op 延迟**(`matmul_latencies_`,`this+0x80` 处按 `MatmulDataFormat` 的总延迟)。GL 的 ctor 发出 loop-keyed 的 `matmul_latencies_.try_emplace(format, 192)` 和 `try_emplace(format, 182)`(`@0x1c8b3092/3205`)。GF 的 ctor 显式命名格式 — `try_emplace(MatmulDataFormat::kF32, 211)`、`(kBf16, 211)`、`(kF8E5M2, 204)`、`(kF8E4M3Fn, 204)`(`@0x1c8bb486/592/699/804`)。因此 GL 对 bf16/F32 定价为 **192**,对 fp8 定价为 **182**;GF 为 **211/204**。
- **Opcode 集 + 默认处理。** GL 基于 opcode `292/298/310`(matmul)和 `347/349/356/358`(matpush)键控,在查找前播种 `res4→3`/`res9→9`,并读取 `array[resource]`(带 seed-default 短路)。GF 基于 `289/295/301/307`(matmul,格式 `1/2/9/10`)和 `324..327`(matpush,带预变换 `|0x32`、`^0xB`、`|0x30`)键控,先 CHECK 边界 `mxu_resource_idx < 11`(`gf.cc:415`),并且直接读取 `array[a4]`,**没有** res4/res9 seed 重映射。
| | GL (Ghostlite) | GF (`6acc60406`) |
|---|---|---|
| bf16 / F32 基础延迟 | 192 | 211 |
| fp8(E5M2 / E4M3Fn)基础延迟 | 182 | 204 |
| matmul opcode | 292, 298, 310 | 289, 295, 301, 307 |
| matpush opcode | 347, 349, 356, 358 | 324, 325, 326, 327 |
| matpush key byte[2] / `LatchOpcodeToMsr` 实参 | `3` / `0x95` | `1` / `0x91` |
| 构建 | `SetReservations`(数据驱动) | 内联 `array[res]=cy` |
| `Matres` map | 有(8 个 key) | 无 |
| res4/res9 默认 seed | 有 | 无(直接索引) |
| 源文件 | `mxu_latency_table_gl.cc` | `mxu_latency_table_gf.cc` |
> **注意 —** 现在,延迟所键控的格式序号已经由嵌入源码的 CHECK 字符串直接命名:GF 将 `kF32`/`kBf16` 绑定到 211,将 `kF8E5M2`/`kF8E4M3Fn` 绑定到 204。并行的 GL 对(192/182)在同一个 `MatmulDataFormat` key 列表(`@0x84a2644 = {1,2,3,4}`)上 loop-keyed,因此 GL bf16/F32 → 192,fp8 → 182,映射相同。这两代硅对同一 matmul op 给出不同总延迟 — 这是证明两个 MXU 表不是同一个实例的最强单项证据。
---
## MXU1 对偶
Ghostlite 携带第二个 `MxuLatencyTable` 实例 — MXU1 对偶 — 用于第二个矩阵单元。它是同一个 `xla::ghostlite::MxuLatencyTable` 类,具有相同的 `array<int,11>` 布局和相同的 `GetResourceUsage` 主体;只有填充的 map 集不同,反映第二个 MXU 不同的 gain-array 几何。查找、key 构造、默认资源 seed 和边界检查都相同,因此上面的描述覆盖两个实例。重新实现会实例化该类两次(每个 MXU 一次),并从各自的预留集填充;它不需要第二条代码路径。(MEDIUM — 已确认该对偶是同一类的第二实例;其逐单元值未单独转录。)
---
## 调度器如何消费预留
预留数组由概览页中描述的同两个方法消费:`MxuOpResourceReservations` 累加一个指令窗口内每个 `MxuResource` 的占用,`MxuOpHoldIssues` 根据在途 op 仍占用的资源计算下一个 MXU op 必须等待多少周期 — 也就是 [`mxu-opholdissues-stall`](mxu-opholdissues-stall.md) 的停顿递推。分工类似 LLVM `MCSchedModel`:`GhostlitePerformance` 网格提供延迟(结果何时就绪),此表提供占用(单元何时可供下一个 op 使用)。对背靠背 matmul 流,吞吐由最小空闲资源门控 — bf16 push 持有其暂存寄存器 `{2,1,1}`,能以接近发射速率流水化,同时 192 周期延迟隐藏在阵列深度中;而 int8-x8 push 持有 `{8,7,6}`,会将流限流到该速率的四分之一。
相同的吞吐整数也出现在基础网格中:`GhostlitePerformance` 的 EUP-prep 列带有 `{4 bf16 / 8 fp8}` matmul 量级,因此两张成本表在按 dtype 的吞吐上达成一致 — 见 [`performance-gl-ghperf`](performance-gl-ghperf.md)。
---
## 相关组件
| 名称 | 关系 |
|---|---|
| `mxu-latency-overview` | 共享模型、modifier-key 构造,以及 issue-stall 消费者 |
| `mxu-latency-gf` | `6acc60406`(GF)对偶 — 内联构建,`211/204` 基础延迟 |
| `mxu-latency-vf` | Viperfish(v5p)`array<int,19>` 实例,带 `res3→15`/`res11→0` 默认值 |
| `performance-gl-ghperf` | 476×31 基础网格,其 EUP-prep 列在吞吐整数上保持一致 |
| `matmul-mode-modifiers` | `MatmulMode` 序号、`MatmulDataFormat` 代码,以及 family→reservation 绑定 |
| `mxu-opholdissues-stall` | 消费 `array<int,11>` 行的 issue-stall 递推 |