VfCycleTable
地址适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so。其他版本会有差异。该二进制文件未被 strip,下面的每个符号都是解修饰后的 C++ 名称。.textVMA == 文件偏移;.rodataVMA == 文件偏移(section0x84a0000);.data.rel.roVMA − 0x200000 == 文件偏移。
摘要
xla::jellyfish::VfCycleTable 是 Viperfish(TpuVersion 3,v5e)成本模型的吞吐量半边。它是第一个家族形态发生变化的 CycleTable 子类:JfCycleTable 通过一个扁平字节偏移 LUT 从单个 Performance 网格读取 cycle 数,而 VfCycleTable 将 MXU 类路由到第二个对象,即 viperfish::MxuLatencyTable,只有 vector/matrix-result 类会访问 ViperfishPerformance 网格。因此,单个 GetCyclesForThroughput 函数体不是 LUT 读取,而是一个 32 分支 switch,它把每个 cycle 类适配成针对两个协作子表的三种调用形态之一。本页是该 switch 的字节级转录:完整的 32 项 cycle-class → (instr, resource, transpose) 表、每个分支如何包装 MxuLatencyTable::GetResourceUsage 或 ViperfishPerformance::GetResourceUsage,以及把 cycle 整数暴露出来的 StatusOr 解包。
需要带走的设计事实:一个 VfCycleTable 持有两个子表指针,而不是一个。它的构造函数(@0x1c89e120)在 +0x10 分配一个 ViperfishPerformance(new 0x30),并在 +0x18 分配一个 MxuLatencyTable(new 0xA0),二者均由其拥有。matmul/matpush 类(0x00–0x10)通过 +0x18 调用 MxuLatencyTable::GetResourceUsage(instr, res, transpose);matrix-result / cross-lane 类(0x17,0x1b–0x1f)通过 +0x10 调用 ViperfishPerformance::GetResourceUsage(instr, 0xe)+1。这就是相对 JF 的结构反转:JF 中 matmul cycle 来自扁平 Performance 网格;这里它们来自按 (MatmulModifier × MxuResource) 索引的 reservation 矩阵,吞吐量整数就是 MXU-latency reservation 模型暴露的同一个数,只是通过 res → array-index 重映射读取,而不是作为扁平单元格读取。
重新实现者必须遵守的契约:
GetCyclesForThroughput(cls)是一个switch,默认返回1。cls >= 0x20以及每个未定价分支都返回默认的1cycle;只有 matmul/matpush 和 matrix-result 分支读取子表。- matmul/matpush 的 "resource" 参数是 resource-index 重映射,不是 cycle 种子。
MxuLatencyTable::GetResourceUsage将res 3 → array index 15(MatmulAccA),将res 0xb → array index 0(MatpushPushPort);其他任何res都是InvalidArgument。返回的 cycle 是每个 modifier 的std::array<int,19>reservation 行中的array[remapped_index]。 - 吞吐量整数是匹配的 MXU-latency reservation 行中的
array[15](matmul)或array[0](matpush)。 分派(res 3 → array[15],res 0xb → array[0])已经由字节确认,三个吞吐量单元格也锚定到 ctor(matmularray[15]={8,16,32},matpusharray[0]=4);完整的每个MatmulModifier矩阵由 MXU-latency / Performance: VF 页面负责(见下方 NOTE (VF-CT-1))。 GetResource(cls)并未被 VF 覆盖。 它是与 JF 和所有其他代共享的、代不变的CycleTable::GetResource(@0x1c89ce20,扁平 LUT@0xb438aec)。- Transcendentals 绕过 switch,通过标量虚函数覆盖:
EstimateSinCosCost = 154,EstimateTanCost = 170。
| 类 | xla::jellyfish::VfCycleTable — 服务 TpuVersion 3(Viperfish v5e) |
| 吞吐量读取器 | VfCycleTable::GetCyclesForThroughput(Instruction) @0x1c89e2c0(vtable slot +0x10) |
| 分派 | 32 分支 switch(跳转表 @0xb438490,32 × i32 self-relative);cls >= 0x20 → 1 |
ViperfishPerformance* | 保存在 VfCycleTable+0x10(new 0x30);由 mxres 类读取 |
MxuLatencyTable* | 保存在 VfCycleTable+0x18(new 0xA0);由 matmul/matpush 类读取 |
| MXU 读取 | viperfish::MxuLatencyTable::GetResourceUsage(instr, res, transpose) @0x1c8ae5c0 → StatusOr<int> |
| mxres 读取 | viperfish::ViperfishPerformance::GetResourceUsage(instr, 0xe) @0x1c8cbc40,+1 |
| res→index 重映射 | res 3 → array[15](MatmulAccA),res 0xb → array[0](MatpushPushPort);否则 InvalidArgument |
| Reservation 数组 | std::array<int,19> — 边界 index >= 0x13 → BUG() |
| 资源读取器 | CycleTable::GetResource(Instruction) @0x1c89ce20(代不变;没有 VF 覆盖) |
| Transcendentals | EstimateSinCosCost @0x1c89e480 = 154;EstimateTanCost @0x1c89e4a0 = 170 |
| 置信度 | CONFIRMED(字节锚定、反编译验证),除非某行另有说明 |
对象布局 — 两个被拥有的子表
VfCycleTable 构造函数(@0x1c89e120)最清楚地说明了 v4→v5 的形态变化。它存储 vtable 和 Target*,然后 new 出并拥有两个不同的子表:
// xla::jellyfish::VfCycleTable::VfCycleTable(const Target&) @0x1c89e120 (decompiled, exact)
void VfCycleTable(VfCycleTable *this, const Target *target) {
*((_QWORD *)this + 1) = target; // this+0x08 = Target*
*(_QWORD *)this = off_21C200D8; // this+0x00 = vtable
memset(this + 0x10, 0, 0x10); // zero the two sub-table ptrs
auto *perf = (ViperfishPerformance *)operator new(0x30);
ViperfishPerformance::ViperfishPerformance(perf);
swap_and_free(this + 0x10, perf); // this+0x10 = ViperfishPerformance*
auto *mxu = (MxuLatencyTable *)operator new(0xA0);
MxuLatencyTable::MxuLatencyTable(mxu);
swap_and_free(this + 0x18, mxu); // this+0x18 = MxuLatencyTable*
}
```text
| Offset | 字段 | 拥有对象 | 读取方 |
|--------|-------|----------|---------|
| `+0x00` | vtable `off_21C200D8` | — | 虚分派 |
| `+0x08` | `const Target*` | 借用 | device-detail 访问器 |
| `+0x10` | `ViperfishPerformance*`(`new 0x30`) | 拥有(`default_delete`) | mxres 类 `0x17`,`0x1b`–`0x1f` |
| `+0x18` | `MxuLatencyTable*`(`new 0xA0`) | 拥有(`~MxuLatencyTable` + `free`) | matmul/matpush 类 `0x00`–`0x10` |
> **QUIRK — matmul cycle 不再位于 `Performance` 网格中。** 从 [JF](jf-cycletable.md) 移植的重新实现者会在 `ViperfishPerformance` 中寻找 MXU 吞吐量单元格,但不会以吞吐量形式找到它们。在 VF 上,matmul/matpush 吞吐量是位于 `+0x18` 的独立 `MxuLatencyTable` 的 `array[15]`/`array[0]` *reservation* 单元格。位于 `+0x10` 的 `ViperfishPerformance` 网格只为 matrix-result / cross-lane(Xlu)类查询。两个对象,两种读取策略,一个 `GetCyclesForThroughput`。
---
## 吞吐量读取路径 — `GetCyclesForThroughput`
`VfCycleTable::GetCyclesForThroughput`(`@0x1c89e2c0`)对 cycle-class 序号做 `switch`(通过跳转表 `@0xb438490` 限定 `cls < 0x20`;其他任何值落到 `default` 并返回 `1`)。每个被定价的分支分派为三种形态之一:
- **(a) MXU** — `+0x18` 处的 `MxuLatencyTable::GetResourceUsage(instr, res, transpose)`。返回 `absl::StatusOr<int>`;cycle 是 payload。
- **(b) mxres / Xlu** — `+0x10` 处的 `ViperfishPerformance::GetResourceUsage(instr, 0xe)`,**再加 1**。
- **(c) default / fatal** — `return 1`,或对类 `0x0a` / `0x10` 执行 `LogMessageFatal("Unsupported PushGainsS4.")`。
反编译函数体规范化为这三种形态如下(十六进制类序号;反编译输出中为十进制):
```c
// xla::jellyfish::VfCycleTable::GetCyclesForThroughput(Instruction cls) @0x1c89e2c0
// (decompiled, exact dispatch; instr/res shown in hex)
int64 GetCyclesForThroughput(VfCycleTable *this, int cls) {
switch (cls) {
// ---- (a) matmul: MxuLatencyTable @ this+0x18, res 3 -> array[15] = MatmulAccA ----
case 0x00: return mxu_thru(this, 0xd4, /*res*/3, /*xpose*/0); // matmul' rate = THRU(CT0)
case 0x01: return mxu_thru(this, 0xda, 3, 0); // matmul'' rate
case 0x04: return mxu_thru(this, 0xe6, 3, 0); // matmul base rate
// ---- (a) matpush: MxuLatencyTable @ this+0x18, res 0xb -> array[0] = MatpushPushPort ----
case 0x05: return mxu_thru(this, 0x10b, /*res*/0xb, 0); // matpush rate
case 0x06: return mxu_thru(this, 0x10f, 0xb, 0); // matpush' rate
case 0x09: return mxu_thru(this, 0x115, 0xb, 0); // matpush'' rate
case 0x0b: return mxu_thru(this, 0x10b, 0xb, /*xpose*/1); // matpush rate (transposed)
case 0x0c: return mxu_thru(this, 0x10f, 0xb, 1); // matpush' rate (transposed)
case 0x0f: return mxu_thru(this, 0x115, 0xb, 1); // matpush'' rate (transposed)
// ---- (c) fatal ----
case 0x0a:
case 0x10:
LogFatal("Unsupported PushGainsS4.", /*cycle_table.cc:682*/);
// ---- (b) mxres / Xlu: ViperfishPerformance @ this+0x10, res 0xe, +1 ----
case 0x17: return VfPerf_GetResourceUsage(this, 0x128, 0xe) + 1; // mxres-class
case 0x1b: return VfPerf_GetResourceUsage(this, 0x12e, 0xe) + 1; // reduce-window Xlu
case 0x1c: return VfPerf_GetResourceUsage(this, 0x11f, 0xe) + 1; // THE conv MXRES/Xlu
case 0x1d: return VfPerf_GetResourceUsage(this, 0x123, 0xe) + 1;
case 0x1f: return VfPerf_GetResourceUsage(this, 0x12a, 0xe) + 1;
// ---- (c) default ----
default: return 1; // 0x02,0x03,0x07,0x08,0x0d,0x0e,0x11-0x16,0x18-0x1a,0x1e, cls>=0x20
}
}mxu_thru 包装了反编译中每次调用 MxuLatencyTable::GetResourceUsage 之后的 StatusOr 解包:调用会向栈临时对象写入 {status_qword, int_payload} 对;读取器测试 status != 1(status 1 是 OK 哨兵),若状态为坏,则设置 code 55 并调用 absl::internal_statusor::ThrowBadStatusOrAccess。OK 路径返回 int payload。
// the StatusOr<int> unwrap repeated after every MxuLatencyTable::GetResourceUsage (decompiled, exact)
int mxu_thru(VfCycleTable *this, uint16_t instr, int res, bool xpose) {
StatusOrPair tmp; // {qword status, dword int}
MxuLatencyTable::GetResourceUsage(&tmp, *(MxuLatencyTable**)(this + 0x18), instr, res, xpose);
if (tmp.status != 1) // status 1 == OK
ThrowBadStatusOrAccess(/*code*/55); // bad-status path
return tmp.int_payload;
}
```text
> **NOTE — status 哨兵 `1` 表示 OK,而不是失败。** 反编译中的 `if (v12 != 1)` 分支是*坏状态*分支,因为 `GetResourceUsage` 写入 `*(_QWORD*)result = 1` 来标记有效的 `StatusOr` payload。把 `!= 1` 读成 "ok" 的重新实现者会把解包逻辑反转。实践中,坏路径对这些被定价类不可达(modifier 映射总是包含这些分支构造的键);`throw` 的存在是为了把缺失 reservation 暴露为硬失败,而不是静默零值。
>
> **GOTCHA — `+1` 只在 mxres 分支上。** matrix-result / cross-lane 类(`0x17`,`0x1b`–`0x1f`)返回 `ViperfishPerformance::GetResourceUsage(instr, 0xe) + 1`,即网格单元格*加一*。matmul/matpush 分支没有 `+1`;它们原样返回 reservation 单元格。把 `+1` 提取到公共尾部的重新实现会让每个 MXU 类都多算一个 cycle。(`+1` 是 mxres 路径折入吞吐量的 issue-slot 开销;MXU reservation 已经包含自己的占用。)
---
## 32 项 Cycle-Class 表
完整跳转表(`@0xb438490`,32 × i32 self-relative)解码为 `(handler, call, role)`。类序号是 `CycleTable::Instruction`,即所有代共享的密集 `0x00..0x20` 枚举(见 [CycleTable Family](cycletable-family.md));role 标签是代稳定的类角色。下面每一行都已对照 `@0x1c89e2c0` 的反编译验证。
| CT | handler | dispatch | 角色 / 值 |
|---:|---------|----------|--------------|
| `0x00` | `1c89e2e5` | `MxuLat.GetResourceUsage(0xd4, res3, false)` | matmul' rate = `array[15]` = **THRU(CT0)** |
| `0x01` | `1c89e380` | `MxuLat.GetResourceUsage(0xda, res3, false)` | matmul'' rate = `array[15]` |
| `0x02` | `1c89e310` | `return 1` | matprep 默认 |
| `0x03` | `1c89e310` | `return 1` | matprep 默认 |
| `0x04` | `1c89e363` | `MxuLat.GetResourceUsage(0xe6, res3, false)` | matmul base rate = `array[15]` |
| `0x05` | `1c89e394` | `MxuLat.GetResourceUsage(0x10b, res0xb, false)` | matpush rate = `array[0]` |
| `0x06` | `1c89e3a3` | `MxuLat.GetResourceUsage(0x10f, res0xb, false)` | matpush' rate = `array[0]` |
| `0x07` | `1c89e310` | `return 1` | 默认 |
| `0x08` | `1c89e310` | `return 1` | 默认 |
| `0x09` | `1c89e325` | `MxuLat.GetResourceUsage(0x115, res0xb, false)` | matpush'' rate = `array[0]` |
| `0x0a` | `1c89e42c` | `LogMessageFatal`(`cycle_table.cc:682`) | 不支持(`PushGainsS4` abort) |
| `0x0b` | `1c89e354` | `MxuLat.GetResourceUsage(0x10b, res0xb, TRUE)` | matpush rate(转置) |
| `0x0c` | `1c89e3d1` | `MxuLat.GetResourceUsage(0x10f, res0xb, TRUE)` | matpush' rate(转置) |
| `0x0d` | `1c89e310` | `return 1` | 默认 |
| `0x0e` | `1c89e310` | `return 1` | 默认 |
| `0x0f` | `1c89e334` | `MxuLat.GetResourceUsage(0x115, res0xb, TRUE)` | matpush'' rate(转置) |
| `0x10` | `1c89e42c` | `LogMessageFatal` | 不支持(`PushGainsS4t` abort) |
| `0x11` | `1c89e310` | `return 1` | vector µop 默认 |
| `0x12` | `1c89e310` | `return 1` | 默认 |
| `0x13` | `1c89e310` | `return 1` | 默认 |
| `0x14` | `1c89e310` | `return 1` | 默认 |
| `0x15` | `1c89e310` | `return 1` | 默认 |
| `0x16` | `1c89e310` | `return 1` | 默认(reduce-window `R[5]` CT 0x16) |
| `0x17` | `1c89e346` | `VfPerf.GetResourceUsage(0x128, res0xe) + 1` | mxres-class 吞吐量 |
| `0x18` | `1c89e310` | `return 1` | 默认 |
| `0x19` | `1c89e310` | `return 1` | 默认 |
| `0x1a` | `1c89e310` | `return 1` | 默认 |
| `0x1b` | `1c89e410` | `VfPerf.GetResourceUsage(0x12e, res0xe) + 1` | reduce-window Xlu(CT 0x1b) |
| `0x1c` | `1c89e317` | `VfPerf.GetResourceUsage(0x11f, res0xe) + 1` | **THE conv MXRES/Xlu(CT 0x1c)** |
| `0x1d` | `1c89e405` | `VfPerf.GetResourceUsage(0x123, res0xe) + 1` | mxres-class |
| `0x1e` | `1c89e310` | `return 1` | 默认 |
| `0x1f` | `1c89e372` | `VfPerf.GetResourceUsage(0x12a, res0xe) + 1` | mxres-class |
> **QUIRK — `0x0a`/`0x10` 在 VF 上是 fatal,但在后续代上不是。** `PushGainsS4` / `PushGainsS4t` 类在 Viperfish 上会命中 `LogMessageFatal`("Unsupported PushGainsS4.",`cycle_table.cc:682`)。Ghostlite(`GlcCycleTable`)helper 将同样的序号映射到第四个 matpush 变体(`instr 0x166`),而 `6acc60406`(`GfcCycleTable`)helper 将它们变成可恢复错误字符串(`"Unsupported Matrix Operand type:"`),而不是硬 abort。把 VF fatal 原样移植到 v6 表的重新实现会在这些代合法定价的类上崩溃。
这 18 个被定价分支覆盖三个连续带:matmul(`0x00`/`0x01`/`0x04`)、matpush forward + transposed(`0x05`/`0x06`/`0x09`/`0x0b`/`0x0c`/`0x0f`),以及 matrix-result/Xlu(`0x17`/`0x1b`/`0x1c`/`0x1d`/`0x1f`)。其他全部内容,包括整个 vector-µop 带 `0x11`–`0x16` 和 `0x18`–`0x1a`,都返回默认 `1`。conv cost emitter 正好取其中三个:`thru(CT 0)`(matmul rate)、`thru(CT 5)`(matpush rate)和 `thru(CT 0x1c)`(Xlu / matrix-result-read rate)。
---
## Matmul/Matpush 桥接 — `MxuLatencyTable::GetResourceUsage`
matmul/matpush 分支是本页的架构核心:它们表明 VF 吞吐量数字就是 [MXU-latency reservation model](mxu-latency-vf.md) 暴露的*同一个整数*。`viperfish::MxuLatencyTable::GetResourceUsage(instr, res, transpose)`(`@0x1c8ae5c0`)**不是**按 `res` 键控的扁平查找。`res` 参数是一个*种子*,用于选择每个 modifier reservation 数组中要返回的单元格:
```c
// xla::viperfish::MxuLatencyTable::GetResourceUsage(Instruction instr, Resource res, bool xpose)
// @0x1c8ae5c0 (decompiled, exact dispatch)
StatusOr<int> GetResourceUsage(MxuLatencyTable *this, uint16_t instr, int res, uint8_t xpose) {
uint8_t array_index;
if (res == 3) array_index = 15; // res 3 -> MatmulAccA
else if (res == 0xb) array_index = 0; // res 0xb -> MatpushPushPort
else return InvalidArgument("Unsupported kind of resource", // mxu_latency_table_vf.cc
/*line 547*/);
Modifier key;
switch (instr) {
// --- matmul: MatmulModifier{[0] = format}, find in map @ this+0x20 ---
case 0xd4: key = MatmulModifier{ .fmt = 1 }; break; // bf16
case 0xda: key = MatmulModifier{ .fmt = 2 }; break;
case 0xe6: key = MatmulModifier{ .fmt = 6 }; break; // int8 / x8
// --- matpush: MatpushModifier via GLM transform, find in map @ this+0x00 ---
case 0x10b: key = MatpushModifier(GLMToFormat(xpose), LatchModeIsTranspose(xpose),
LatchOpcodeToMsr(0x8F)); break; // direct GLM
case 0x10f: key = MatpushModifier(GLMToFormat(xpose ^ 0xB), ...); break; // XOR 0xb
case 0x115: key = MatpushModifier(GLMToFormat(xpose | 0x14), ...); break; // OR 0x14
default: LogFatal("Unsupported opcode", /*mxu_latency_table_vf.cc:578*/);
}
array<int,19> row;
if (!map.find(key, &row)) ThrowStdOutOfRange("raw_hash_map<>::at");
if (array_index >= 0x13) BUG(); // array<int,19> bound
return StatusOr<int>{ ok, row[array_index] }; // <-- the throughput cycle
}matmul map 位于 this+0x20,以 MatmulModifier{format} 为键;matpush map 位于 this+0x00,键是在每条 instr 的 GainLatchMode 变换(0x10b direct,0x10f XOR 0xb,0x115 OR 0x14)和 LatchOpcodeToMsr(0x8F) 之后的 MatpushModifier。返回的 cycle 是 row[array_index],即 matmul 的 row[15](MatmulAccA)或 matpush 的 row[0](MatpushPushPort)。
吞吐量整数 — 与 reservation 矩阵相同的数字
路径已由字节确认:GetResourceUsage 返回它在 MXU-latency 映射中找到的每个 MatmulModifier / 每个 MatpushModifier reservation array<int,19> 的 row[15](matmul,MatmulAccA)或 row[0](matpush,MatpushPushPort)。每个单元格的值按 MatmulDataFormat 区分:
thru(CT 0) = matmul rate(array[15] = MatmulAccA) | 值 |
|---|---|
bf16(instr 0xd4,fmt 1) | 8 |
fmt 2(instr 0xda) | 16 |
int8 / x8(instr 0xe6,fmt 6) | 32 |
thru(CT 5) = matpush rate(array[0] = MatpushPushPort) | 值 |
|---|---|
| 所有格式(标准) | 4 |
| f32,非转置(半成本) | 2 |
NOTE (VF-CT-1) — 单元格量级已由字节锚定。 reservation 行由
MxuLatencyTable构造函数(@0x1c8a52c0)以{Modifier, array<int,19>}对insert_range构建,而不是扁平 rodata 表;但相关单元格已通过 ctor 追踪并确认:matmularray[15](MatmulAccA)项写入15 → 8(fmt 1,ctor L1466/1467)、15 → 16(fmt 2,L1946/1947)和15 → 32(fmt 6,L2855/2856 与 L3287/3288),所以按MatmulDataFormat的thru(CT 0) = {8,16,32}已 CONFIRMED。同一个{8,16,32}三元组也镜像在ViperfishPerformance网格列 r3 中(见 Performance: VF);这里的吞吐量路径通过res 3 → array[15]消耗MxuLatencyTable副本。matpusharray[0](MatpushPushPort,由thru(CT 5)读取)对每种格式都是扁平 4(ctor L683-688 / L722-726 构建{key0→4, …}),仅在 f32-no-transpose 半成本情形下降到2(L650-655),也就是说 matpush reservation 是扁平{4,3,2}行,不是按格式递增的{2,4,8}。本页拥有的字节确认分派是thru(CT 0)读取row[15],thru(CT 5)读取row[0];完整的每个MatmulModifier矩阵位于 MXU-latency: VF。GOTCHA —
res 3并不索引 slot 3。res参数命名的是概念(matmul-accumulate 与 matpush-push-port),GetResourceUsage会把它转换到具体的子端口列(3 → 15,0xb → 0)。把res当作直接数组索引的重新实现会读到错误列(row[3]和row[11],而不是row[15]/row[0]),并静默返回不同的 reservation 单元格。传入此函数的合法res值只有3和0xb;其他任何值都是InvalidArgument。
资源侧 — CycleTable::GetResource(代不变)
VfCycleTable 没有覆盖 GetResource。反编译中没有 VfCycleTable::GetResource 符号;某个类的资源 lane 来自代不变的 CycleTable::GetResource(@0x1c89ce20),即与 JF 使用的相同扁平 LUT:
// xla::jellyfish::CycleTable::GetResource(Instruction cls) @0x1c89ce20 (decompiled, exact, shared)
int GetResource(CycleTable *this, int cls) {
return dword_B438AEC[cls]; // resLUT @0xb438aec, 33 × int32, values 0..6
}
```text
随后 cost lambda 执行 `ResourceVector[GetResource(cls)] += (double)GetCyclesForThroughput(cls)`,与 JF 完全相同。`resLUT` 将 matmul 带 `0x00`–`0x04` 映射到 `R[1] Matmul`,将 latch 带 `0x05`–`0x10` 映射到 `R[0] Matpush`,并将 matrix-result / cross-lane 类(`0x17`,`0x1b`–`0x1f`)映射到 `R[2] Xlu`。因此 VF switch 以不同于 JF 的方式*定价* cycle(两个子表而不是一个扁平网格),但把 cycle *放置*到相同的 23 槽 [`ResourceVector`](resource-enum.md) lane。吞吐量定价逻辑是代私有的;资源冲突记账是共享的。
> **NOTE — `MxuLatencyTable` 的 `array<int,19>` 和 `ResourceVector`(23 槽)是不同向量。** 由 `MatmulAccA`/`MatpushPushPort` 索引的 19-int reservation 行是 [MXU-latency](mxu-latency-vf.md) 的 op 内微端口数组(每个 MXU 子流水端口一个 int)。23 槽 [`ResourceVector`](resource-enum.md) 是调度器用 `MaxResourceCycles` 归约的 bundle-issue 累加器。`GetResourceUsage` 读取前者来产生一个数字;`GetResource` 命名后者中的一个槽来沉积这个数字。不要混淆这两个索引空间。
---
## Transcendentals — 标量虚函数覆盖
VF 上的 transcendental 成本完全绕过 switch。`VfCycleTable` vtable 带有两个标量 `const` 虚函数覆盖,返回与 operand 大小无关的固定估计:
```c
int64 VfCycleTable::EstimateSinCosCost(...) @0x1c89e480 { return 154; } // sin / cos
int64 VfCycleTable::EstimateTanCost(...) @0x1c89e4a0 { return 170; } // tan这些是跨代 transcendental 表中的 Viperfish 项(JF/PF = 198/219,VF = 154/170,GL/GF = 142/151),反映 XLU 流水线随代际加速。完整的每代表位于 Per-Opcode Cycle Constants。
VF vs JF — 形态变化
这两个表回答相同的两个问题(GetCyclesForThroughput、GetResource)并馈入相同的 ResourceVector,但读取方式完全不同:
| 轴 | JfCycleTable(TpuVersion 0/1) | VfCycleTable(TpuVersion 3) |
|---|---|---|
| 持有的子表 | +0x10 处一个 Performance* | +0x10 处 ViperfishPerformance* 以及 +0x18 处 MxuLatencyTable* |
GetCyclesForThroughput 形式 | 扁平 offsetLUT[cls] 字节偏移读取 | 跨三种调用形态的 32 分支 switch |
| MXU matmul/matpush cycle | Performance 网格中的扁平单元格(8/1) | 通过 res→index 重映射读取 MxuLatencyTable::GetResourceUsage reservation 单元格 |
| matrix-result / Xlu cycle | Performance 网格中的扁平单元格 | ViperfishPerformance::GetResourceUsage(instr, 0xe) + 1 |
| priced-class 选择器 | 字面 33-bit mask 0x19FFC0821 | switch 分支本身 |
| 不支持的类 | 落到默认 1 | 0x0a/0x10 是 LogMessageFatal |
GetResource | 共享的 CycleTable::GetResource | 共享的 CycleTable::GetResource(无覆盖) |
| transcendentals | 198 / 219 | 154 / 170 |
| matmul rate 来源 | Performance 网格中的扁平单元格 | 匹配的 MxuLatencyTable reservation 行的 array[15] |
变化的是路径:VF 将 matmul 吞吐量从扁平网格移到每个 MatmulModifier reservation 矩阵(在 array[15] 读取),从而能够按 MatmulDataFormat 变化,而不需要每种格式一个独立扁平单元格。具体的每格式量级(array[15]={8,16,32},matpush array[0]=4)锚定到 ctor,并与 MXU-latency: VF 共同拥有(见 NOTE (VF-CT-1))。Pufferfish(TpuVersion 2)是中间形态,首次引入了 switch-over-GetResourceUsage 形态;VF 通过 MxuLatencyTable 拆分对其细化。Ghostlite(GlcCycleTable,res4→3/res9→9)和 6acc60406(GfcCycleTable,res3→3/res8→8,不同 opcode 集 0x121..0x147)helper 以每代重映射和 opcode 基址复用 VF 结构。
重新实现配方
一个忠实的 VfCycleTable 需要两个子表加上 switch:
int GetCyclesForThroughput(const VfCycleTable *t, uint32_t cls) {
switch (cls) {
// matmul (res 3 -> MatmulAccA), matpush (res 0xb -> MatpushPushPort)
case 0x00: return mxu(t->mxu /*+0x18*/, 0xd4, 3, 0);
case 0x01: return mxu(t->mxu, 0xda, 3, 0);
case 0x04: return mxu(t->mxu, 0xe6, 3, 0);
case 0x05: return mxu(t->mxu, 0x10b, 0xb, 0);
case 0x06: return mxu(t->mxu, 0x10f, 0xb, 0);
case 0x09: return mxu(t->mxu, 0x115, 0xb, 0);
case 0x0b: return mxu(t->mxu, 0x10b, 0xb, 1);
case 0x0c: return mxu(t->mxu, 0x10f, 0xb, 1);
case 0x0f: return mxu(t->mxu, 0x115, 0xb, 1);
case 0x0a: case 0x10: fatal("Unsupported PushGainsS4."); // cycle_table.cc:682
// mxres / Xlu (ViperfishPerformance @ +0x10, res 0xe, +1)
case 0x17: return vfperf(t->perf /*+0x10*/, 0x128, 0xe) + 1;
case 0x1b: return vfperf(t->perf, 0x12e, 0xe) + 1;
case 0x1c: return vfperf(t->perf, 0x11f, 0xe) + 1; // conv Xlu
case 0x1d: return vfperf(t->perf, 0x123, 0xe) + 1;
case 0x1f: return vfperf(t->perf, 0x12a, 0xe) + 1;
default: return 1; // everything else
}
}
// mxu(): MxuLatencyTable::GetResourceUsage — remap res (3->15, 0xb->0), find modifier, return row[idx].
// GetResource is the gen-invariant CycleTable::GetResource (resLUT @0xb438aec) — no VF override.
// transcendentals bypass the switch: sin/cos -> 154, tan -> 170.
```text
需要嵌入的数据:[`MxuLatencyTable`](mxu-latency-vf.md) reservation 矩阵(四个 `flat_hash_map<Modifier, array<int,19>>` 映射以及 `res→index` 重映射)、[`ViperfishPerformance`](performance-vf.md) `Instruction × Resource` 网格(在列 `0xe` 读取),以及代不变的 `resLUT`(`@0xb438aec`)。有了这三张表和上面的 switch,VF 吞吐量半边就完整了。
---
## 交叉引用
- [CycleTable Family](cycletable-family.md) — 抽象基类、六工厂注册表、按版本分派,以及共享的 33 值 cycle-class 枚举。
- [JfCycleTable](jf-cycletable.md) — 扁平 offset-LUT 前身;本页是其 MxuLatencyTable 路由类比页,也是代不变 `GetResource` / `resLUT` 框架的来源。
- [MXU Latency: VF](mxu-latency-vf.md) — 本页通过 `GetResourceUsage` 读取的 `viperfish::MxuLatencyTable` reservation 矩阵:四个 modifier 映射、`array<int,19>` 行、`res→index` 重映射,以及 matmul/matpush cycle 值。
- [Performance: VF](performance-vf.md) — mxres 类(`0x17`,`0x1b`–`0x1f`)在列 `0xe` 读取的 `ViperfishPerformance` `Instruction × Resource` 网格,以及 `GetResourceUsage` 读取路径。
- [Resource Enum](resource-enum.md) — 23 槽 `ResourceVector`,其头部 `R[0]..R[6]` 由代不变 `resLUT` 发出,以及 `MaxResourceCycles` 重叠归约。
- [Per-Opcode Cycle Constants](per-opcode-cycle-constants.md) — 跨代吞吐量整数和 transcendental 标量表(VF = 154/170)。
- [Performance: VF](performance-vf.md) 和 [MXU Latency: VF](mxu-latency-vf.md) 共同持有 `VfCycleTable` 在 `+0x10` 和 `+0x18` 拥有的两个子表。
- **Binary:** `extracted/libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so`(build-id `89edbbe81c5b328a958fe628a9f2207d`)
- **Index entry:** Part VII — Cost & Latency Model / CycleTable — [返回索引](../index.md)