Performance:VF
本页所有地址都适用于来自
libtpu-0.0.40-cp314wheel 的libtpu.so(构建libtpu_lts_20260413_b_RC00,BuildID md589edbbe81c5b328a958fe628a9f2207d)。该二进制未被 stripped;下面每个符号都是 demangled C++ 名称。段映射:.text/.rodataVMA == 文件偏移;.data.rel.roVMA − 0x200000 == 文件偏移。
摘要
本页转储 Viperfish(v5/v5e)的 ViperfishPerformance 对象:逐指令延迟数组,以及为每条 LLO 指令占用每个 intra-op 微流水线端口多少周期定价的 Instruction × Resource 占用网格。它是 performance-overview 中记录的网格家族在 VF 上的具体化,也就是 Pufferfish、Viperfish、Ghostlite 和 6acc60406 共享的堆延迟数组 + 堆二维 vector<int> 网格,并由逐字节相同的 GetResourceUsage 读取。Viperfish 位于资源数量演进的中间(7 → 7 → 20 → 28 → 31 → 31):它把 Pufferfish 的 20 列网格加宽了 8 列,主要是 4 阶段 matprep 吞吐组和 transpose-binary 结果子阶段。
参考框架是 LLVM SchedMachineModel:GetLatency(instr) 返回指令的流水线深度(调度器把真依赖边抬高到的值),GetResourceUsage(instr, res) 返回 instr 占用功能单元端口 res 的周期数。VF 网格是通过读取填充它的构造函数恢复出来的,即 ViperfishPerformance::ViperfishPerformance @0x1c8c4840,其中包含一个 new 0x600 延迟数组(384 个 int32)和一个 new 0x2400 网格(384 行 × 24 字节 vector<int>,每行 new 0x70 = 28 个 int32),而不是来自 .td 文件。延迟数组(先 memset 为 0xff,随后每个槽位都被覆盖)和 378 个已填充网格单元格都来自构造函数的 762 次 DWORD 立即数写入(384 个延迟 + 378 个网格),逐字节精确。
本页记录对象布局和 GetResourceUsage 读取路径(24 字节行步幅、两个边界检查)、按占用者 LLO 类命名的 28 个资源列、写入列(res 0x0e,即 conv R[2] Xlu 项,由 GetXluPathReservation 读取)、延迟数组直方图(121/131 matmul/matprep 基础延迟),以及 LLO opcode 如何通过 GetViperfishInstruction 和 MXU latch-mode 扇出到达网格行。最后说明该网格如何与单独的 MxuLatencyTable 保留矩阵共存。
对重新实现而言,契约是:
ViperfishPerformance对象布局:堆延迟数组(384 个 int32)+ 堆二维网格(384 × 28),包含精确大小和[this+0x18]/[this+0x20]网格指针/计数。GetResourceUsage(instr, res)读取路径:两个边界检查,24 字节(3 × a2 << 3)行步幅。- 按占用者命名的 28 个资源列,以及 Xlu/matrix-result 写入列(res 0x0e)及其
GetXluPathReservation访问器。 - LLO opcode 如何到达网格行(
GetViperfishInstruction、matmul/matprep latch-mode WORD 表扇出),以及吞吐单元格如何与MxuLatencyTable共存。
| 类 | xla::viperfish::ViperfishPerformance |
| 构造函数 | ViperfishPerformance::ViperfishPerformance @0x1c8c4840(new 0x600 latency,new 0x2400 grid,row new 0x70) |
| 读取路径 | ViperfishPerformance::GetResourceUsage @0x1c8cbc40 · GetLatency @0x1c8cbc20 · GetResources @0x1c8cbc00 |
| 资源数量 | 28(行宽 new 0x70 = 28 int32;GetResources count 0x1c) |
| 延迟行 | 384(new 0x600;memset 0xff,全部被覆盖) |
| 网格 | 384 行 × 28 宽;128 行中的 378 个已填充单元格 |
| 写入列 | res 0x0e(14),即 conv R[2] Xlu 项,matrix-result ops 的 cell = 8 |
kResources 顺序 | @0xb43cda8({0..27} 的 28 B 排列) |
| Opcode → 行 | GetViperfishInstruction @0x1c8a3300(jt @0xb43a104,idx = op−1) |
| Xlu 访问器 | LatencyTableViperfish::GetXluPathReservation @0x1c8a3200(res = 0xe) |
| EUP push / pop 延迟 | push(instr 0xcc..0xd2)= 6,pop(instr 0x168)= 1 |
对象布局
目的
ViperfishPerformance 从两个堆对象回答调度器的两个逐指令问题:流水线深度(GetLatency)和逐端口占用(GetResourceUsage)。这两个对象分别是一个按 Instruction 索引的扁平延迟数组,以及一个每条指令一行 vector<int> 的二维网格。
结构
该布局是共享的网格家族布局(performance-overview),带有 VF 的具体大小:
struct ViperfishPerformance { // built by ctor @0x1c8c4840
int32* latency; // +0x00 ; new 0x600 (384 int32), memset 0xff
u64 latency_size; // +0x08 ; = 384
u64 latency_cap; // +0x10 ; = 384
vector<int>* grid; // +0x18 ; new 0x2400 (384 × 24-byte vector<int>)
u64 grid_outer_count; // +0x20 ; = 384 (the GetResourceUsage outer bound)
u64 grid_outer_cap; // +0x28 ; = 384
// each row (24-byte std::vector<int>): { int* data (new 0x70 = 28 int32, zero-init), size=28, cap=28 }
};
```text
构造函数正好发出 **762 次 DWORD 立即数写入**,即 384 个延迟 + 378 个网格单元格。写入数量就是完整性证明:每个 `mov DWORD PTR [rax+off], imm` 都按它加载的基址分类为 `[rbx]`(延迟基址)或 `[r12]`(网格基址,`r12 = [rbx+0x18]`),并且没有任何非 `rax` 基址的 DWORD-imm 写入。不同于 Ghostlite/`6acc60406` 的未定价行会保留 `0xff` memset 默认值,**每个** VF 延迟槽位(0..383)都被显式覆盖;`0xff = 255` 默认值不会保留。
> **特性 —** VF Performance 构造函数 `@0x1c8c4840` 不能生成 Hex-Rays 伪代码(它太大,并且混合了 VEX 写入),因此此处单元格值来自对其 762 次 DWORD 立即数写入的逐字节 objdump 解码,并通过写入数量恒等式(`762 = 384 + 378`)交叉校验。*读取路径* `GetResourceUsage` 和 `GetResources` 可以干净地反编译,并确认 28 宽 / 384 行形状;单元格整数是 objdump 级别,而不是 Hex-Rays 级别,但通过写入计数方法具有 HIGH 置信度。
---
## GetResourceUsage 读取路径
### 目的
`GetResourceUsage(instr, res)` 是吞吐模型和 Xlu 保留访问器读取网格单元格的唯一访问器。它在 PF/VF/GL/GF 间逐字节相同:两个边界检查和一个由 `lea` 计算的 24 字节行步幅。
### 算法
反编译中已按字节确认:
```c
function ViperfishPerformance::GetResourceUsage(perf, instr, res): // @0x1c8cbc40
if perf.grid_outer_count <= instr: // [perf+0x20] = 384 ; outer bound
BUG() // ud2
grid = perf.grid // [perf+0x18]
v4 = 3 * instr // row index ×3 ...
if perf.grid[v4].size <= res: // [grid + 8*v4 + 8] ; inner bound = 28 (row width)
BUG()
return *(int*)(perf.grid[v4].data + 4*res) // [grid + 8*v4] + 4*res = grid[instr][res]3 * instr 后接 8 * 索引,就是 24 字节 std::vector<int> 步幅({int* data, u64 size, u64 cap})。GetLatency(instr) @0x1c8cbc20 是更简单的同级函数,即由 [perf+0x8] 界定的 latency[instr]。GetResources() @0x1c8cbc00 返回 &kResources(.rodata 字节数组 @0xb43cda8,按填充顺序列出 28 个列索引)。
陷阱 — 外层索引是逐代的
ViperfishPerformance::Instruction,不是原始 LLO opcode。映射由GetViperfishInstruction@0x1c8a3300完成(jt@0xb43a104,idx = op−1,边界 0x1a9),而 MXU band 会通过二级 latch-mode WORD 表(@0xb43b140,valid-latch mask0x3ffcc03)把单个 matmul/matprep opcode 扇出到多个 ordinal。直接用 LLO opcode 索引网格的重新实现会误读每个 MXU 行。
matrix-result / Xlu 写入列
有一列保存 convolution 成本模型作为其 R[2] 项读取的 matrix-result(Xlu)吞吐。在 Viperfish 上它是 res 0x0e(14),由专用访问器确认:
function LatencyTableViperfish::GetXluPathReservation(this, value): // @0x1c8a3200 (verified)
if value.opcode == 139: // kVectorSetPermutePattern, handled directly
return (value[+0x40] != 0) ? 8 : 1
instr = GetViperfishInstruction(value)
return ViperfishPerformance::GetResourceUsage(this.perf /* [this+0x1d0] */, instr, 14) // res 0x0e
```text
`res = 0x0e` 立即数已按字节确认(`GetResourceUsage(*(this+58*8), instr, 14)`),permute-pattern opcode 139(`kVectorSetPermutePattern`)返回硬编码的 `8`/`1`。Xlu 写入列跨代追踪 MXU 几何:res 6 PF → **res 0x0e VF** → res 0x0f GL → res 0x10 GF;已填充单元格对于 VF matrix-result/transpose-result 类是 `8`(与下面的 `kVectorMatres` r22 单元格一致)。
---
## 28 个资源列
### 目的
网格的内层轴是 `ViperfishPerformance::Resource` 枚举:28 个 intra-op EUP/MXU/Xlu 微流水线保留端口。二进制中没有 `Resource::ToString`,因此列按功能命名,即依据哪些 LLO 指令类向各列写入周期,外层索引是通过 `GetViperfishInstruction` 解析并与 `LloOpcodeName::opcode_name` `@0x21ccfef0` 交叉连接的 opcode。这些名称在*含义*上足以用于重新实现(每列保留哪个物理端口),但不是字面符号名。
### 列
`kResources` `@0xb43cda8` 是 28 字节遍历顺序:`13 18 1a 19 08 02 03 16 09 0a 04 05 06 07 0b 12 0f 14 1b 0c 10 01 15 0d 11 17 00 0e`(`{0..27}` 各出现一次)。按主导占用者为每列命名:
| col | cells | val(s) | occupant LLO band(分类器命名) | physical reservation port |
|---|---|---|---|---|
| r0 | 2 | 2 | low-ordinal MXU/setup band(ins 0x0, 0x2) | MXU/setup 地址端口 A |
| r1 | 2 | 2,3 | `kDmaGeneral..`(ins 0x38) | DMA 地址/发射端口 |
| r2 | 27 | 7 | MXU matmul band 0xd4..0x106(MatmulPackedMsk/Lmr) | MXU matmul prep/issue 端口 |
| r3 | 51 | 8,16,32 | MXU matmul/matprep band | **MXU matmul 吞吐端口**(×51) |
| r4 | 38 | 4,5 | matprep band + DoneWithGains/LoadLmr(0xd5..0x10a) | MXU matprep 吞吐 stage A |
| r5 | 38 | 12,13 | 同一 band | MXU matprep 吞吐 stage B |
| r6 | 38 | 20,21 | 同一 band | MXU matprep 吞吐 stage C |
| r7 | 38 | 28,29 | 同一 band | MXU matprep 吞吐 stage D |
| r8 | 2 | 32 | `kVectorLoadLmr`(0x109..0x10a) | LMR / gain-load 端口 |
| r9 | 16 | 2,6 | result-pop FIFO band(0x10b..0x11a) | MXU/EUP result-pop FIFO stage A |
| r10 | 16 | 1,5 | 同上 | result-pop FIFO stage B |
| r11 | 16 | 3,7 | 同上 | result-pop FIFO stage C |
| r12 | 9 | 41,48 | `kVectorPermute/Rotate/BroadcastLane`(0x11b..) | cross-lane result stage A |
| r13 | 14 | 52,57,59 | 同上 + reduce band | cross-lane / reduce result stage B |
| **r14** | 23 | 8,16 | TransposeBinary(0x123)/Permute/Rotate/Broadcast | **Xlu / matrix-result 写入**(conv `R[2]`) |
| r15 | 5 | 109,117 | `kVectorTransposeBinary`(0x11f..0x127) | transpose-binary result sub-stage A |
| r16 | 5 | 112,120 | 同上 | transpose-binary result sub-stage B |
| r17 | 3 | 7,15 | 同上 | transpose-binary result sub-stage C |
| r18 | 5 | 24 | `kVector{Add,Max,Min,..}ReduceF32`(0x12e..0x132) | reduce-result 端口 |
| r19 | 1 | 3 | `kVectorCcfPush`(0x134) | CCF push 端口 |
| r20 | 1 | 1 | `kVectorPrng`(0x13e) | PRNG 端口 |
| r21 | 14 | 1 | `kVectorSyncFlag*/kVectorWait*/SfrfPush`(0x13f..) | sync-flag / wait / SFRF 端口 |
| r22 | 1 | 8 | `kVectorMatres`(0x169) | matrix-result(Matres)端口 |
| r23 | 1 | 8 | `kVectorXlaneResult/Transpose-result`(0x16a) | cross-lane / transpose result 端口 |
| r24 | 1 | 3 | `kVectorCcfPop`(0x16b) | CCF pop 端口 |
| r25 | 4 | 5 | `kVectorStoreEvenOddSublanes`(0x174..0x177) | sublane-store 端口 |
| r26 | 6 | 6 | barnacore/store band(0x178..0x17d) | sublane-store / scatter 端口 |
| r27 | 1 | 3 | `kVectorSetRngSeed`(0x17f) | RNG seed 端口 |
列填充量(cells/col)总和为 378:`r0:2 r1:2 r2:27 r3:51 r4:38 r5:38 r6:38 r7:38 r8:2 r9:16 r10:16 r11:16 r12:9 r13:14 r14:23 r15:5 r16:5 r17:3 r18:5 r19:1 r20:1 r21:14 r22:1 r23:1 r24:1 r25:4 r26:6 r27:1`。
> **注意 —** `ViperfishPerformance::Resource` 枚举(28 列)不同于 23 槽逐 bundle `ResourceVector`([`resource-enum`](resource-enum.md)),是一个*不同且更低层*的枚举;它也不同于 [`mxu-latency-vf`](mxu-latency-vf.md) 中 19 值 `MxuResource`,是*第三个*枚举。这里的网格为 intra-op 微流水线阶段占用定价;`ResourceVector` 是逐 bundle 累加器;`MxuResource` 是 MXU 内部保留端口集合。同一个成本模型里有三条资源轴,混淆它们是核心陷阱。`kResources` 字节数组给出的是该网格的列遍历顺序,不是 `ResourceVector` 槽位顺序。
### VF 相对 Pufferfish 的加宽方式
Viperfish 在 Pufferfish 的 20 列基础上增加了 8 列:4 阶段 matprep 吞吐组(r4..r7,承载 `{4,12,20,28}` 和 `{5,13,21,29}` 的 step-8 占用)以及 transpose-binary 结果子阶段(r15..r17),再加上 CCF push/pop(r19/r24)。matmul 吞吐表示本身也加宽了:PF 上单列(res 9,96 个单元格)变成 VF 上的 res r3(51 个单元格)加 4 阶段 matprep 组。
> **特性 —** r4..r7 matprep 阶段承载 `{4,5}/{12,13}/{20,21}/{28,29}` 取值对,即 step-8 斜坡 `{4,12,20,28}`(及其 `+1` 伴随值 `{5,13,21,29}`)。同一个 `{5,13,21,29}` 斜坡也出现在 [`mxu-latency-vf`](mxu-latency-vf.md) 的 `MxuResource` overrun-check 插入中(`AddOverrunCheckReservations`),反映 matprep 吞吐阶段和 MSR overrun-check 端口是同一个逐 K-tile latch 流水线的两个成本模型视图。它们是*不同表中的不同枚举*,不要用其中一个索引另一个。
---
## 延迟数组
### 目的
`latency[instr]` 是指令的流水线深度,即真依赖边权重。VF 构造函数先把数组 memset 为 `0xff`,随后覆盖全部 384 个槽位(默认值不会保留)。
### 直方图
384 个条目有 19 个不同取值:
```text
1: 148 2: 113 131: 27 121: 25 7: 18 8: 14 6: 8 3: 5
164: 5 115: 5 114: 4 9: 3 5: 2 4: 2 30: 1 122: 1 0: 1
36: 1 49: 1有意义的簇:
1/2(148+113):便宜的 vector/scalar/sync ops。131/121:MXU matmul / matprep 基础延迟(systolic 流水线深度;MxuLatencyTable保留数组说明这些周期中各 MXU 子端口被占用多少)。7:matprep;8:result-pop;6:EUP push 延迟(instr 0xcc..0xd2;pop instr 0x168 = 1)。164:transpose-binary;115:reduce;114/122:permute/rotate/broadcast。36:CCF push;0:一个 MXU-setup ordinal;49:单个 op。
注意 — VF 上的 EUP push→pop 边是延迟 6(push)/ 1(pop),并且 VF 只通过延迟数组为 EUP push 定价;push 行不保留网格单元格(
ViperfishTarget::VectorEupReservationCycles@0x1d49b060= 1,全速率)。这与 Pufferfish 不同,后者的 EUP push 还会保留网格端口 r2/r3,并以半速率运行(VectorEupReservationCycles= 2)。重新实现不能假设 VF 上的 EUP push 由网格定价。
Opcode → 网格行
分类器
GetViperfishInstruction @0x1c8a3300 通过跳转表 @0xb43a104(idx = op−1,边界 0x1a9)把 LLO opcode 映射到网格行 Instruction ordinal。大多数 opcode 直接映射(mov ax, IMM16);MXU band 是例外。matmul 分支 @0x1c8a3373 读取二级 latch-mode WORD 表 @0xb43b140(valid-latch mask 0x3ffcc03),把单个 matmul/matprep opcode 扇出到约 0x60 个 band ordinal(VF Instruction 0xd4..0x106 + 0x10b..0x11a)。因此,一个 vmatmul/vmatprep LLO opcode 会变成多个网格行,每个 (opcode, latch_mode/MatmulDataFormat) 对对应一行。
网格外层索引就是已定价行的 opcode(每个已填充行都会解析到一个一致的、由分类器命名的 LLO opcode),但该映射是逐代分类器,而不是原始 opcode 空间。MXU band 的逐 ordinal (opcode, latch_mode) 解码是作为 latch-mode 分类器机制读取的,而不是逐 ordinal 枚举;band 身份(matmul/matprep)、其基础延迟(121/131)和吞吐单元格(r3 {8,16,32}、r4..r7 4 阶段)都是逐字节精确的。
与 MxuLatencyTable 共存
该网格中的 matmul 吞吐单元格(res r3 = 每个 MatmulDataFormat 的 {8,16,32},即 fmt1=8、fmt2=16、fmt6/int8-x8=32;r4..r7 为 4 阶段 matprep 占用)重复了也存在于单独 MxuLatencyTable 保留矩阵中的 matmul-rate 数值。这两个成本表共存并为不同事物定价:该网格为按 Instruction ordinal 键控的 intra-op 微流水线端口占用定价;MxuLatencyTable 为按 MatmulDataFormat/GainLatchMode 修饰符键控的 MXU 子资源占用定价。基础 op 延迟(121/131)在这个延迟数组中;逐 MxuResource 的 hold-cycle 向量在 array<int,19> 中。
注意 —
{8,16,32}matmul rate 在两个表中都按字节确认,而吞吐路径读取的是MxuLatencyTable,不是这个网格。 网格 col-r3 单元格{8,16,32}已在ViperfishPerformance构造函数@0x1c8c4840中按字节锚定(mov DWORD PTR [data+0xc], 8/0x10/0x20,matmul band 中共 51 个单元格)。相同三元组也在MxuLatencyTable构造函数@0x1c8a52c0中作为每种格式的{MxuResource 15 (MatmulAccA) → 8/16/32}独立按字节锚定(发出key=15, value=8,然后=16,再=32的行)。成本模型的 matmul 吞吐路径VfCycleTable::GetCyclesForThroughput(CT 0)→MxuLatencyTable::GetResourceUsage(0xd4, res 3, 0)会把res 3 → array[15]重映射,并返回该保留单元格;因此被消费的{8,16,32}来自MxuLatencyTable,而此网格的 r3 保存了一个镜像,matmul/matprep 吞吐路径对 CT-class 0/1/4 不读取它。重新实现必须填充两者,但要把 matmul-rate 消费者接到MxuLatencyTable的array[15]。注意 — 并行的
opcode_produced_register_type表(@0x223a16c0,byte[461])及其驱动的 convolution-window DMA-level merge gate 是跨代不变的;它们记录在performance-overview中,并原样适用于 VF,因为它们按原始 LLO opcode 键控,而不是按逐代Instructionordinal 键控。
资源数量上下文
VF 的 28 列位于跨代演进中:
| Gen | Codename | Resource cols | latency rows | grid cells | populated rows | EUP push lat | Xlu deposit col |
|---|---|---|---|---|---|---|---|
| PF | Pufferfish | 20 | 336 | 265 | 180 | 7 | res 6(conflict-penalty) |
| VF | Viperfish | 28 | 384 | 378 | 128 | 6 | res 0x0e(GetXluPathReservation) |
| GL | Ghostlite | 31 | 476 | 358 | 132 | 13/14 | res 0x0f |
| GF | 6acc60406 | 31 | 465 | 285 | 92 | 12 | res 0x10 |
该枚举从 PF → VF → GL 加宽为 20 → 28 → 31:VF 增加了 4 阶段 matprep 组(r4..r7)+ transpose-binary 结果子阶段(r15..r17)+ CCF push/pop;GL/GF 增加了 BF16-EUP AndPop FIFO 深度 + BarnaCore 尾部。matmul 吞吐端口发生移动(PF 单列 res 9 → VF 中 4 阶段组上的 res 3),Xlu 写入列跟随 MXU 几何变化(res 6 → 0x0e → 0x0f → 0x10)。
相关组件
| 名称 | 关系 |
|---|---|
performance-overview | 网格家族对象布局、共享的 GetResourceUsage 读取路径,以及 opcode_produced_register_type gate |
mxu-latency-vf | 与此网格共存的单独 MxuLatencyTable array<int,19> 保留矩阵 |
resource-enum | 23 槽逐 bundle ResourceVector,不同于此处的 28 列 Resource 枚举 |
performance-pf / -gl-ghperf / -gf-ghperf | 20 / 31 / 31 列同族网格 |
slot-mxu | matmul/matprep band 行定价的 LLO MXU opcode |
交叉引用
- Performance Family Overview:网格家族对象布局、逐字节相同的
GetResourceUsage、资源数量演进,以及opcode_produced_register_type - MXU Latency: VF:
ViperfishMxuLatencyTablearray<int,19>保留矩阵;此处的 matmul 吞吐单元格是它的网格类比物 - MXU Latency Overview:与此网格共存的
MxuResource保留模型 - Performance: PF:VF 加宽的 20 列 Pufferfish 网格,以及它的 conflict-penalty Xlu 定价
- Performance: GL (GhPerf 476×31):Ghostlite v6e 网格,Xlu 写入 res 0x0f
- Performance: GF (GhPerf 465×31):
6acc60406(TPU7x)网格,Xlu 写入 res 0x10 - Resource Enum (23-slot):逐 bundle
ResourceVector,不同于此处的 28 列Resource微流水线枚举 - MatmulMode & Modifiers:MXU band 行扇出的
MatmulDataFormatcode - MXU Slot:matmul/matprep 列保留的物理 MXU 子单元
- Decode-Side: VF / GXC:生成
GetViperfishInstruction所分类 opcode 的 VF MXU bundle decode - MxuOpHoldIssues Stall Recurrence:延迟数组和保留矩阵共同驱动的背靠背 stall