MXU 延迟:GF (6acc60406)
本页中的所有地址都适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so(buildlibtpu_lts_20260413_b_RC00,BuildID md589edbbe81c5b328a958fe628a9f2207d)。该二进制文件未 strip。section 映射:.text/.rodataVMA == 文件偏移;.data.rel.roVMA − 0x200000 == 文件偏移;.dataVMA − 0x400000 == 文件偏移。所有 cell 整数都直接从 GFMxuLatencyTable构造函数读取。
摘要
本页转储 6acc60406(v7,“GF”)MxuLatencyTable:按 modifier × MxuResource 的 reservation 矩阵,用于给每个 MXU op 持有各内部子单元的时长定价。它是 Viperfish array<int,19> 和 Ghostlite array<int,11> 矩阵的 6acc60406 兄弟,由 MXU 延迟概览 中记录的字节相同模型读取。6acc60406 和 Ghostlite 共享形状(array<int,11>、相同 modifier key 类型、相同 GainLatchMode key helper),但不是同一个实例:两个代际由不同构造函数构建(GlcCycleTable vs GfcCycleTable),携带不同的基础 op 延迟成本,并通过不同 accessor 读取 cell。下面的所有内容都是 GF 实例,它由 GfcCycleTable 分配,并由 CHECK 字符串命名 mxu_latency_table_gf.cc 的构造函数构建。
两个事实使 6acc60406 数字值得固定。第一,在 256×256 systolic array 上,每个 matmul 的 hold 是 Viperfish 的一半:bf16 matmul 持有 accumulate 端口 4 个周期(VF:8),因此连续的 bf16 matmul 流以 VF 两倍的 issue 速率流水化。第二,GF lookup 直接按 MxuResource 索引读取 reservation array,即 matmul 吞吐为 array[3]、matpush 吞吐为 array[8],没有 Ghostlite 风格的 default-seed remap。该 lookup 还带有 fp8-fnuz(F8E4M3Fn、F8E5M2)GLM transform 路径,会把 fp8 latch mode 路由到它们自己的 reservation bucket。
本页最后完整反编译 windowing_util::ComputeDmaLevels,因为 6acc60406 matmul 成本会乘以一个 DMA 效率因子,而该因子的输入就是此函数计算的 descriptor-fragment 数。fragment 数会落入 {1.6, 1.3, 1.1, 1.05} 之一(或者对单个连续传输或乘积 > 31 使用 1.0),bucket 逻辑按字节精确。
对于重新实现,契约是:
- GF
MxuLatencyTable对象布局(0xa0字节,map 位于this+0x00/0x20/0x40/0x60/0x80),以及带< 11kNumMxuResources边界的array[res & 0xf] = cycles插入机制。 - 16 行 matmul 和 16 行 matpush reservation,逐 cell 对应,再加两行 Vlxmr 和
MatmulDataFormat → base-latency成本 map(kF32/kBf16= 211,kF8E5M2/kF8E4M3Fn= 204)。 GetResourceUsageopcode 分派(matmul 289/295/301/307;matpush 324–327,带^0xB/|0x30/|0x32GLM 预变换)、直接array[3]/array[8]读取,以及按 dtype 的吞吐数字。ComputeDmaLevels:DmaLevelstruct、contiguity-break level-build 循环、opcode_produced_register_type ∈ {2,4}merge gate,以及 fragment-count → efficiency-multiplier 表。
| 类 | GF/6acc60406 MxuLatencyTable(符号误标;由 GfcCycleTable 分配) |
| 对象 | 0xa0 B,位于 GfcCycleTable this+0x18;值类型为 array<int,11> |
| Ctor | @0x1c8bb1c0 — 填充 Matpush(+0x00)、Matmul(+0x20)、Vlxmr(+0x40)、MatmulDataFormat→cost(+0x80) |
| Lookup | @0x1c8bdb20 — 直接 array[3](matmul)/ array[8](matpush);无 remap |
| Insert helpers | matpush @0x1c8bc2e0、matmul @0x1c8bc540、vlxmr @0x1c8bc760 — array[res & 0xf] = cy |
| CT dispatch | GfcCycleTable::GetCyclesForThroughputHelper @0x1c89f400 |
| 资源数 | MxuResource::kNumMxuResources = 11 — CHECK 锚定(> 0xA → fatal) |
| 吞吐(bf16 / fp8) | matmul array[3] = 4 / 8 · matpush array[8] = 2 / 4 |
| 基础 op 延迟 | kBf16/kF32 = 211 · kF8E5M2/kF8E4M3Fn = 204 |
ComputeDmaLevels | @0x1c86a9e0 · efficiency bucket {1.6, 1.3, 1.1, 1.05},1.0 默认(也用于乘积 > 31) |
对象布局与构建
目的
GF 表在 GfcCycleTable 构造时构建一次。cycle table 分配两个堆对象:一个 0x30 字节的 GhostlitePerformance 表,位于 this+0x10(Performance: GF 的按 opcode 网格),以及一个 0xa0 字节的 MxuLatencyTable,位于 this+0x18。两者都由各自的构造函数填充;本页覆盖第二个。
// GfcCycleTable::GfcCycleTable @0x1c89eec0
v4 = operator new(0x30u); sub_1C8D3740(v4); // GhostlitePerformance grid → this+0x10
v6 = operator new(0xA0u); sub_1C8BB1C0(v6); // MxuLatencyTable → this+0x18
```text
### 结构
构造函数 `@0x1c8bb1c0` 对五个 Abseil flat-hash-map 和一个 count word 做零初始化,然后插入每一行:
```text
MxuLatencyTable (0xa0 bytes, at GfcCycleTable + 0x18)
this + 0x00 flat_hash_map<MatpushModifier, array<int,11>> ── latch / matprep
this + 0x20 flat_hash_map<MatmulModifier, array<int,11>> ── matmul
this + 0x40 flat_hash_map<VlxmrModifier, array<int,11>> ── vector-latch-into-MRB
this + 0x60 (Matres map slot — NOT populated by the GF ctor)
this + 0x80 flat_hash_map<MatmulDataFormat, int> ── base op latency; count word = 1注意 — 与 Ghostlite 构造函数(
@0x1c8b2920,data-drivenSetReservations<Modifier>+insert_range)不同,GF 构造函数通过三个 direct-write helper 内联写入 reservation array,并且没有构建单独的 Matres map(对 Matres helper 的调用为零)。+0x60slot 被清零并保持为空。照搬 GL build path 的重新实现会发出 GF 从未拥有的 Matres map。
一行如何构建
每个 map value 都是一个 array<int,11>,对每个 (resource, cycles) 对执行 array[resource & 0xf] = cycles 填充,并且 resource 被硬性限制在 kNumMxuResources:
// matpush insert @0x1c8bc2e0 / matmul insert @0x1c8bc540 (identical mechanism)
function insert(key, pairs[]):
array<int,11> res_vector = {0}; // zero-init all 11 slots
for (resource, cycles) in pairs:
if (resource > 0xA) // > 10 → fatal
LogFatal("resource_index < to_underlying(MxuResource::kNumMxuResources)");
res_vector[resource & 0xF] = cycles;
target_map.try_emplace(key, res_vector);
```text
`> 0xA` 边界就是宽度为 `11` 的 CHECK;同一个 `< 11` guard 会在读取侧(如下)于 `mxu_latency_table_gf.cc:415` 再次出现。一行未命名的任何 resource 都持有 0 个周期。
---
## Matmul Reservation 行
### 目的
matmul 家族由 32 位 `MatmulModifier` 作为 key,其中 `byte[0]` 是 `MatmulDataFormat` code(`1`、`2`、`9`、`0xa`),`byte[1]` 是 transpose flag,`byte[2]` 是 high-variant bit。构造函数插入 16 个 key;`GetResourceUsage` 读取 cell `array[3]`(matmul-accumulate 吞吐端口)。
### 各行(全部 16 个 key,逐 cell)
reservation triple 对格式 1/2 是 `{res3, res9, res2}`,对格式 9/0xa 是 `{res3, res9}`,已在 `@0x1c8bb7c9..0x1c8bbb31` 的构造函数中按字节确认。
| `MatmulModifier` key | format | `res2`(issue 阶段) | `res3`(**thru**) | `res9`(acc latch) |
|---|---|---|---|---|
| `0x00000001` `0x00000101` `0x00010001` `0x00010101` | 1 (bf16) | 16 | **4** | 3 |
| `0x00000002` `0x00010002` | 2 (bf16-alt) | 20 | **8** | 7 |
| `0x00000102` `0x00010102` | 2, transpose | 16 | **4** | 3 |
| `0x00000009` `0x00010009` | 9 (F8E5M2) | — | **8** | 7 |
| `0x00000109` `0x00010109` | 9, transpose | — | **2** | 1 |
| `0x0000000a` `0x0001000a` | 0xa (F8E4M3Fn) | — | **8** | 7 |
| `0x0000010a` `0x0001010a` | 0xa, transpose | — | **2** | 1 |
`res3` 是 `GetResourceUsage` 对 matmul 返回的值;`res2` 是更大的 issue-stage hold(16/20 cy),会门控 issue cursor;`res9` 是次级 accumulate latch。
> **怪异点 —** fp8 格式的 transpose 变体(`...0109`、`...010a`)把 matmul hold 降到 `{res3:2, res9:1}`,这是表中*最便宜*的 matmul 行:转置 fp8 matmul 复用已加载的 staging 路径,定价几乎免费。非 transpose fp8 行最贵(`res3:8`)。
---
## Matpush Reservation 行
### 目的
matpush(latch / matprep)家族由 `MatpushModifier` 作为 key,其低三字节为 `{[0]=GainLatchModeToMatmulDataFormat(mode), [1]=transpose, [2]=1}`,高字节携带 MSR(matrix-staging-register)变体(`0x01` vs `0x03`)。构造函数插入 16 个 key;`GetResourceUsage` 读取 cell `array[8]`。
### 各行(全部 16 个 key)
reservation 会随格式变宽,落入三组值:`narrow` `{res5/4:1, res7/6:1, res8:2, res10:7}`、`mid` `{:3, :2, res8:4, res10:9}`、`wide` `{:7, :6, res8:8}`,已在 `@0x1c8bb28d..0x1c8bb737` 按字节确认。
| `MatpushModifier` key | variant | staging A · B | `res8`(**thru**) | `res10`(latch) | width |
|---|---|---|---|---|---|
| `0x..010001` | v1/v3 | 1 · 1 | **2** | 7 | narrow |
| `0x..010101` | v1/v3, xpose | 3 · 2 | **4** | — | mid |
| `0x..010002` `0x..010009` `0x..01000a` | v1/v3 | 3 · 2 | **4** | 9 | mid |
| `0x..010102` `0x..010109` `0x..01010a` | v1/v3, xpose | 7 · 6 | **8** | — | wide |
> **陷阱 —** staging-port *索引*取决于构建该行所用的 MSR 变体。构造函数为一个 MSR 选择 `res4`/`res6`,为另一个选择 `res5`/`res7`(`mxu_latency_table_gf.cc:94` 处有按变体的 `Unexpected MSR` CHECK 守护该选择器)。lookup 读取的吞吐 cell 始终是 `res8`;移动的是 staging hold。把 staging 索引视为跨变体固定会把 hold 放错位置。
---
## 按格式的吞吐 — Conv `R[0]`/`R[1]` 输入
`GetResourceUsage` 在构建 lookup key 时强制 transpose 为 0,因此卷积成本模型读取非 transpose 行。`GfcCycleTable::GetCyclesForThroughputHelper` `@0x1c89f400` 把每个 cost-table `Instruction`(CT ordinal)绑定到一个 LLO opcode、一个 resource index 和一个 transpose flag:
| CT | LLO opcode | family | key fmt | res read | cycles |
|---|---|---|---|---|---|
| 0 | 289 (`0x121`) | matmul | 1 (bf16) | `array[3]` | **4** |
| 1 | 295 (`0x127`) | matmul | 2 | `array[3]` | **8** |
| 2 / 4 | 301 (`0x12d`) | matmul | 9 (F8E5M2) | `array[3]` | **8** |
| 3 | 307 (`0x133`) | matmul | 0xa (F8E4M3Fn) | `array[3]` | **8** |
| 5 | 324 (`0x144`) | matpush | 1 (bf16, direct GLM) | `array[8]` | **2** |
| 6 | 326 (`0x146`) | matpush | GLM `^0xB` (transpose flip) | `array[8]` | per fmt |
| 7 / 9 | 327 (`0x147`) | matpush | GLM `\|0x30` → fmt 9 | `array[8]` | **4** |
| 8 | 325 (`0x145`) | matpush | GLM `\|0x32` → fmt 0xa | `array[8]` | **4** |
matpush transpose CT(11–15)以 `sub_1C8BDB20(a1, op, opcode, 8, 1)` 的形式重新进入 `sub_1C8BDB20`,即 resource `8`、`latch_mode = 1`,从而选择转置(`wide`)值集(`res8 = 8`)。matmul CT(0–4)的 CT→opcode 绑定是根据 helper 传入的 resource index(`3`)和 transpose(`0`),以及分派消费的 opcode 推断;matpush opcode(324–327)在 helper 和 `sub_1C8BDB20` 中均按字节确认。
> **6acc60406 vs VIPERFISH —** 6acc60406 thru(matmul) bf16 = **4**,fp8 = **8**;thru(matpush) bf16 = **2**,fp8 = **4**。Viperfish(见 [VF](mxu-latency-vf.md))是 matmul bf16 = 8 / int8 = 32,matpush 2 / 8。6acc60406 matmul hold 是 VF 的一半:256×256 systolic array 使每周期 MAC 速率翻倍,因此同一个 op 占用 accumulate 端口的周期更少。matpush narrow hold 不变(2),wide hold(8)等于 VF int8-wide cell。
基础 op 延迟是位于 `this+0x80` 的单独 `MatmulDataFormat → int` map,由构造函数的四个 `try_emplace` CHECK 字符串命名:
| `MatmulDataFormat` | 基础延迟 |
|---|---|
| `kF32`, `kBf16` | **211** |
| `kF8E5M2`, `kF8E4M3Fn` | **204** |
这些是 v7 按格式的 op 延迟;v6e(Ghostlite)构造函数为同样格式存储 192/182,这是证明两个表是不同实例的最清晰单个数字。
---
## Lookup
### 算法
`GetResourceUsage` `@0x1c8bdb20`(误标为 `raw_hash_map::at`)是读取路径。它边界检查 resource,按 opcode 分派到一个 family,构建 key,查找行,并读取 cell:
```c
function GF_MxuLatencyTable_GetResourceUsage(out, this, instr, res, latch_mode): // @0x1c8bdb20
if res > 0xA: // mxu_latency_table_gf.cc:415
LogFatal("mxu_resource_idx < to_underlying(MxuResource::kNumMxuResources)")
switch (instr.opcode):
case 289: key = MatmulModifier{fmt=1}; map = this+0x20 // matmul
case 295: key = MatmulModifier{fmt=2}; map = this+0x20
case 301: key = MatmulModifier{fmt=9}; map = this+0x20
case 307: key = MatmulModifier{fmt=10}; map = this+0x20
case 324: key = MatpushKey(latch_mode); map = this+0x00 // matpush
case 325: key = MatpushKey(latch_mode | 0x32); map = this+0x00 // → fp8-fnuz (F8E4M3Fn)
case 326: key = MatpushKey(latch_mode ^ 0x0B); map = this+0x00 // transpose flip
case 327: key = MatpushKey(latch_mode | 0x30); map = this+0x00 // → fmt 9
default: return MakeErrorImpl("Unsupported opcode: ...") // :455
entry = map.find(key)
if not entry: throw out_of_range // raw_hash_map::at
array<int,11> res_vector = entry.value // vmovups: [rdx+8] matmul / [rdx+4] matpush
out = res_vector[res] // DIRECT — no remapmatmul key 是 {fmt, 0, 0, 0}(transpose 强制为 0)。matpush key 由三个共享 helper 组装:GainLatchModeToMatmulDataFormat @0x1d629260(byte[0])、LatchModeIsTranspose @0x1d628ea0(byte[1])和 LatchOpcodeToMsr(0x91) @0x1c8a1300(byte[3]);byte[2] 是常量 1。对 opcode 0x91,LatchOpcodeToMsr 返回 0。
与 GHOSTLITE 对比 — GF 读取是对 CT helper 传入的 resource 直接执行
array[res](matmul 为 3,matpush 为 8),没有变换。Ghostlite lookup@0x1c8b7560则会在读取前播种默认值(res4 → idx3、res9 → idx9)。两个代际共享构造函数形状和 key helper,但读取索引和 seed remap 不同,必须按代际绑定。这就是res-remap 3/8区别:GF 在索引 3 和 8 上是 direct。
matpush 的 vmovups [rdx+4] 与 matmul 的 vmovups [rdx+8] 反映了不同 key 宽度(MatpushModifier 的 value 前有 4 字节,MatmulModifier 前有 8 字节)。整个 array<int,11> 会先复制到栈上再索引。
Vlxmr 行
this+0x40 处的 Vlxmr map 携带两行,由 sub_1C8BC760(0, &unk_B43CD6C, …) 和 sub_1C8BC760(257, &unk_B43CD74, …) 插入(key 0x0 和 0x101,已在 ctor 中按字节确认)。insert helper 遍历 (int resource, int cycles) pair stream,并应用同样的 resource < 11 边界(mxu_latency_table_gf.cc:50 处 CHECK)。@0xb43cd6c 的第一个 pair 读取为 {res0:2}(按字节确认)。key 0x101 的完整逐行 pair 集在此处未验证,因为 iterator 边界无法仅从 rodata 静态固定;兄弟 Vlxmr 形状见 MXU Latency: GL (Ghostlite)。
函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
GfcCycleTable::GfcCycleTable | 0x1c89eec0 | 分配 0x30 perf + 0xa0 MxuLatency |
GF MxuLatencyTable ctor | 0x1c8bb1c0 | 填充 16 matpush + 16 matmul + 2 vlxmr + cost map |
GF MxuLatencyTable::GetResourceUsage | 0x1c8bdb20 | opcode 分派 + find + 直接 array[res] |
| matpush insert helper | 0x1c8bc2e0 | array[res & 0xf] = cy,< 11 边界 |
| matmul insert helper | 0x1c8bc540 | 同上,MatmulModifier map |
| vlxmr insert helper | 0x1c8bc760 | 来自 rodata pair 的 VlxmrModifier 行 |
GfcCycleTable::GetCyclesForThroughputHelper | 0x1c89f400 | CT → opcode/res/transpose 分派 |
GainLatchModeToMatmulDataFormat | 0x1d629260 | matpush key byte[0] |
LatchModeIsTranspose | 0x1d628ea0 | matpush key byte[1] |
LatchOpcodeToMsr | 0x1c8a1300 | matpush key byte[3];(0x91) → 0 |
ComputeDmaLevels — 绑定到 Matmul 成本的 Fragment 数
目的
卷积 / windowed-transfer 成本路径会把其带宽项乘以一个 DMA 效率因子,该因子的输入是窗口分解出的 descriptor fragment 数。windowing_util::ComputeDmaLevels @0x1c86a9e0 计算该分解。结果供给 WindowCyclesGenericTargetAgnostic @0x14552180,后者把 fragment 数转换为效率乘数。
DmaLevel struct 与 level-build 循环
ComputeDmaLevels 返回一个 std::vector<DmaLevel>,每个元素 24 字节:
struct DmaLevel { // 24 B; vector stride lea[rax+rax*2]<<3
long axis; // +0x00 first window-axis index of this level
long count; // +0x08 init 1, then count *= window_stride[axis] per merged axis
long flags; // +0x10 zero-init; level marker, not read by the cost path
};
```text
该函数首先 CHECK 窗口的逐轴 inline vector(`window_bounds`、`pad_high`、`pad_low`,以及 dynamic-base 第二数组)都具有相同 rank,然后当窗口的 `+0x338` 配置标量为 `≥ 2` 时裁剪连续 minor dim(row-major 最内层 run 不计作自己的 level):
```c
rank = window_bounds.size()
CHECK(base_bounds.size() == rank && pad_high.size() == rank && pad_low.size() == rank)
N = rank - (WD[+0x338] >= 2 ? 1 : 0) // minor-dim trimlevel-build 循环从每个 axis 开始一个新的 DmaLevel,并在所有连续性条件都成立时把后续 axis 合并进去:
for axis in 0 .. N: // outer: start a new level
level = {axis, count=1, flags=0}
for r in axis+1 .. N: // inner: try to merge axis r
if elemental_stride[r] != 1: break
operand = stride_level_operand[r] // WD + 0xe0 [r], an LloValue*
if operand:
if operand.opcode >= 0x1cd: fatal()
rt = opcode_produced_register_type[operand.opcode]
if rt != 2 && rt != 4: fatal() // ProducesSreg() || ProducesVreg()
contiguous = llo::KnownEq(window_stride[r], operand)
else:
contiguous = (window_stride[r] == base_bounds[r])
if not contiguous: break
if pad_low[r] != 0 || dilation[r] != 0: break
level.count *= window_stride[r] // "access_multiplier"
emit(level) // a finalized contiguity break
```text
> **注意 —** `+0xe0` 逐轴第二数组(`stride_level_operand`)是 DMA-level *descriptor* operand,不同于 `window_stride`(后者驱动字节数)。它的 register class 会门控 merge:LLO value 必须产生 **Scalar**(`opcode_produced_register_type == 2`,`ProducesSreg()`)或 **Vector**(`== 4`,`ProducesVreg()`);predicate(1)、mask(3)或无结果 op(0)会使门控失败并强制产生 contiguity break。`llo_util.h:35` 处的 CHECK(`value->ProducesSreg() || value->ProducesVreg()`)准确命名了这一点。规范卷积 stride operand(`kScalarAddressCalculation` `@0x86` 等)全都是 Scalar,因此可合并;mask-typed stride operand 会使 DMA fragment 化。
发出的 `DmaLevel` 数等于 contiguity break 数;它们的 `count` 字段乘积就是 fragment 数。
### fragment 数 → 效率乘数
`WindowCyclesGenericTargetAgnostic` `@0x14552180` 读取 level vector,并按字节精确地把 fragment 乘积 `v18`(merge 循环中的运行中 `access_multiplier`)分 bucket:
| fragment product `v18` | 乘数 | rodata |
|---|---|---|
| `≤ 1` level(无 fragment) | **1.0** | `@0xa2df230` |
| `== 1` | **1.6** | `@0xa2d71a0` |
| `∈ [2, 3]` | **1.3** | `@0xa2d71a8` |
| `∈ [4, 7]` | **1.1** | `@0xa2df4c8` |
| `∈ [8, 31]` | **1.05** | `@0xa2df2a8` |
| `> 31` | **1.0**(落到默认值) | `@0xa2df230` |
四个读取的 double 都已在 `.rodata` 中按字节确认:`1.0`(`@0xa2df230`)、`1.6`(`@0xa2d71a0`)、`1.3`(`@0xa2d71a8`)、`1.1`(`@0xa2df4c8`)、`1.05`(`@0xa2df2a8`)。`{1.6, 1.3}` 对是 `@0xa2d71a0` 处的 2 项表,由 `setge(v18 ≥ 2)` 索引;`1.1` 和 `1.05` 是独立常量。返回的带宽放入值是 `(byte_count · elem_size / bytes_per_cycle) · multiplier + residual`。
> **陷阱 —** fragment 乘积 `> 31` 不会收到惩罚乘数:该分支(`if (v18 > 31)`)跳过 bucket 表,并保留 `1.0` 默认值。`@0xa2df1b0` 处的 `2003.0` 常量(按字节确认)**不是** fragment-count bucket;它在函数入口由*元素类型*谓词选择(window descriptor operand 存在且 `(*(int16*)(op+11) & 0x7C) == 0x10`),独立于 `ComputeDmaLevels`,并且缩放的是 `bytes_per_cycle` 除数,而不是 fragment 乘数。不要把 `2003.0` 绑定到 fragment 数。
>
> **怪异点 —** 单个连续传输(`≤ 1` level)的乘数是 `1.0`,但恰好为 `1` 的 fragment 乘积(一个 level,其合并后的 element-count 乘积为 1)是 `1.6`。这是两条不同路径:`≤ 1`-level 默认值(`v60 <= 1`)会在 bucket 表之前短路;`v18 == 1` bucket 只有在 level vector 非平凡时才到达。重新实现必须保留两者。
---
## Worked Example — 6acc60406 bf16 Conv Deposit
对于 6acc60406 bf16 卷积,按格式的 MXU reservation 读取现在是数值化的:
- `R[0]` matpush = matpush_count · thru[CT5](bf16) = matpush_count · `array[8]` = matpush_count · **2**。
- `R[1]` matmul = op_count · thru[CT0](bf16) · 0.5 / Target / EPF = op_count · `array[3]` · 0.5 / … = op_count · **4** · 0.5 / …。
- `R[2]` Xlu = `4` · ChunksPerTile · rem(`GhostlitePerformance` 网格 cell,[Performance: GF](performance-gf-ghperf.md))。
对于 fp8(`F8E5M2`/`F8E4M3Fn`),`R[0]` = 4 且 `R[1]` = 8,是 bf16 hold 的两倍。若卷积输入窗口 fragment 成 2 个 DMA level,并且每 level element 乘积为 3(具有非 unit stride 的 3-tap kernel axis),`ComputeDmaLevels` 返回 2 个 level,`v18 = 3`,带宽放入值乘以 `1.3`;完全连续的 load 乘以 `1.0`;fragment 乘积 `> 31` 也回退到 `1.0`(无 fragment-count 惩罚,避开重度 strided 布局来自更大的字节数,而不是乘数)。
---
## 相关组件
| 名称 | 关系 |
|---|---|
| `mxu-latency-overview` | 共享模型、key scheme,以及 `GetResourceUsage` 读取路径 |
| `mxu-latency-gl` | Ghostlite `array<int,11>`,相同形状、不同 ctor、192/182 基础延迟 |
| `mxu-latency-vf` | Viperfish `array<int,19>`,matmul hold 翻倍 |
| `matmul-mode-modifiers` | modifier ordinal、format code、GLM transform |
| `performance-gf-ghperf` | 携带 conv `R[2]` Xlu cell 和相同按 dtype 量级的 GF 网格 |
| `window-description-cost` | 消费 `ComputeDmaLevels` 的 windowed-transfer 成本路径 |
---
## 交叉引用
- [MXU 延迟概览](mxu-latency-overview.md) — `MxuResource` 模型、key 构造,以及字节共享的 `GetResourceUsage`
- [MXU Latency: GL (Ghostlite)](mxu-latency-gl.md) — v6e `array<int,11>`;GF 缺少的 `res4→3`/`res9→9` seed remap
- [MXU Latency: VF](mxu-latency-vf.md) — Viperfish `array<int,19>`;half-VF matmul hold 对比
- [MatmulMode & Modifiers](matmul-mode-modifiers.md) — `MatpushModifier`/`MatmulModifier` ordinal,以及 `GainLatchMode` → format jump table
- [Performance: GF (GhPerf 465×31)](performance-gf-ghperf.md) — 6acc60406 occupancy 网格和 conv `R[2]` Xlu = 4 cell
- [MxuOpHoldIssues Stall Recurrence](mxu-opholdissues-stall.md) — reservation array 如何变成 issue stall
- [Resource Enum (23-slot)](resource-enum.md) — 更高层的 `ResourceVector`,不同于 MXU 内部的 `MxuResource`
- [Window Description Cost](window-description-cost.md) — 调用 `ComputeDmaLevels` 的 windowed-transfer 成本路径
- [MXU Slot](../isa/slot-mxu.md) — 这些 op 定价的 LLO MXU instruction slot
- [Matprep / IAR / Latch](../isa/slot-matprep-iar-latch.md) — matpush 家族背后的 matprep / latch op