Skip to content

MXU 延迟:GL (Ghostlite)

本页所有地址均适用于来自 libtpu-0.0.40-cp314 wheel 的 libtpu.so(构建 libtpu_lts_20260413_b_RC00,BuildID md5 89edbbe81c5b328a958fe628a9f2207d)。该二进制剥离符号 — 每个符号都是反混淆后的 C++ 名称。.text/.rodata VMA == 文件偏移;.data.rel.ro VMA − 0x200000 == 文件偏移。

摘要

xla::ghostlite::MxuLatencyTablemxu-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>。边界检查字面量也相应为 11MxuResource::kNumMxuResources)而不是 19。查找函数 GetResourceUsage @0x1c8b7560 以 Ghostlite 专用 opcode 集对两个族进行键控 — MatmulModifierthis+0x20 处的 matmul map)和 MatpushModifierthis+0x00 处的 latch/matprep map)— 通过三个共享的 GainLatchMode helper 构造 modifier key,find 对应行,并返回 array[resource]。两个按资源的默认值会短路查找:resource==4 → 3resource==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/Matres map,外加按资源的默认 key res4→3res9→9
  • 预留体:matpush {2,1,1}/{4,3,2}/{8,7,6} 的按宽度缩放三元组、Vlxmr/Matres rodata 集,以及 SetReservations 如何将它们稠密化为稠密向量。
  • GetResourceUsage(instr, resource) 查找:GL opcode → 族 → modifier key → find → 边界检查 resource < 11array[resource]
  • GL/GF ctor 分裂:数据驱动的 SetReservations(GL)对比内联直接写入(GF),以及分歧的 192/182 对比 211/204 基础延迟,因此重新实现应为每个硅代保留一个 ctor。
xla::ghostlite::MxuLatencyTable
GL ctorMxuLatencyTable::MxuLatencyTable @0x1c8b2920 — 数据驱动的 SetReservationsoperator new 0xA0
GL 查找MxuLatencyTable::GetResourceUsage @0x1c8b7560 — 默认值 res4→3res9→9
预留向量std::array<int,11>MxuResource::kNumMxuResources = 11)
所属 CycleTableGlcCycleTable @0x1c89e7e0this+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 @0x1c89e7e0operator new(0xA0) 分配该表并存放在 this+0x18,同时在 this+0x10 处放置一个 GhostlitePerformancenew 0x30):

c
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+0x20find<MatmulModifier>(a2 + 32, …) — 两者都在 GetResourceUsage @0x1c8b7560 中按字节确认。this+0x80 处的 matmul_latencies_ map 是按 MatmulDataFormat延迟,独立于按资源的占用向量(下面的 192/182 值)。

怪异点 —array<int,11> 会用原始 vmovups load 从 bucket 中读出,在索引前把全部 44 字节复制到栈上。matmul 读取是 vmovups [rdx+8](8 字节 MatmulModifier key 位于值之前);matpush 读取是 vmovups [rdx+4](4 字节 MatpushModifier key)。如果重新实现假设统一 key 宽度,就会在两个族中的一个上从错误偏移读取数组。这与 Viperfish 约定相同;只是 N 从 19 缩小到 11。

行的构建方式 — SetReservations

GL 用模板化的 SetReservations<Modifier>MatpushModifier @0x1c8b5d80VlxmrModifier @0x1c8b5f60MatresModifier @0x1c8b6140)填充每个 map。每次调用都接收 modifier key 和一个稀疏 flat_hash_map<MxuResource,int>(“此 op 占用资源 k 持续 c 周期”的集合),将一个稠密 array<int,11> 清零初始化,把稀疏单元复制进去,并 try_emplace 结果:

c
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 @0x1d629260LatchModeIsTranspose @0x1d628ea0LatchOpcodeToMsr @0x1c8a1300 组装。对 latch mode 的 opcode 专用预变换(^0xB|0x14|0x18)会把同一物理 latch 路由到转置或宽预留 bucket。

陷阱 — GL opcode 不是 Viperfish opcode。VF 在 opcode 230(case 212/218)上匹配 matmul,在 267/271/277 上匹配 matpush;而 GL 在 292/298/310 上匹配 matmul,在 347/349/356/358 上匹配 matpush — 且 GL 增加了 Viperfish 没有的第四个 matpush case(358mode | 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=3a4==9 → v9=9)。重新实现必须从 GL 查找读取 GL 的默认资源 key;GL 整数矩阵反映的是 11 资源索引。

函数映射

函数地址作用
ghostlite::MxuLatencyTable::MxuLatencyTable0x1c8b2920GL ctor — 数据驱动的 SetReservationsmatmul_latencies_ 192/182
ghostlite::MxuLatencyTable::GetResourceUsage0x1c8b7560GL 查找 — 默认值 res4→3res9→9;边界 < 11
ghostlite::SetReservations<MatpushModifier>0x1c8b5d80稠密化 {res→cy}array<int,11>;CHECK < 11(gl.cc:60),try_emplace(gl.cc:63)
ghostlite::SetReservations<VlxmrModifier>0x1c8b5f60vlxmr 族行构建器
ghostlite::SetReservations<MatresModifier>0x1c8b6140matres 族行构建器
GlcCycleTable::GlcCycleTable0x1c89e7e0所属 CycleTable — 连接 GL perf(+0x10)+ MXU 表(+0x18
GainLatchModeToMatmulDataFormat0x1d629260matpush key byte[0] — 与 VF/GF 共享
LatchModeIsTranspose0x1d628ea0matpush key byte[1] — 共享
LatchOpcodeToMsr0x1c8a1300matpush key byte[3] — GL 实参 0x95
GF(6acc60406)ctor0x1c8bb1c0分歧的对偶 — 内联构建,211/204
GF(6acc60406GetResourceUsage0x1c8bdb20GF 查找 — mxu_latency_table_gf.cc,无 res4/res9 重映射

GL-vs-GF 构造函数分裂

目的

Ghostlite(v6e)和 6acc60406(GF 代)看起来像一个族 — 相同的 array<int,11> 形状、相同的四种 modifier 类型、相同的 GainLatchMode key helper — 但它们是两个不同对象,由两个不同构造函数构建,并带有两个不同值集。把它们当作一个共享实例的重新实现,会把每个 6acc60406 matmul 都定错价。

共享项与分歧项

text
                       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 递推 |