kDeviceTypeInfo 规格常量
本页中的所有地址、偏移和字段值均适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so(BuildID md589edbbe81c5b328a958fe628a9f2207d)。其他版本会有所不同。
摘要
xprof::kDeviceTypeInfo (0x1C60480) 是 profiler 的主 per-DeviceType 规格表:一个包含 17 个条目的数组,每个条目都是固定 0x448 字节(1096 字节)的结构体,并直接按 xprof::DeviceType 序号索引。每个条目打包了设备时钟(kHz)、每芯片 core/tile 几何信息、两组 DVFS 频率阶梯,以及大约四十个 IEEE-754 double 形式的分代硬件规格常量,包括按精度划分的峰值计算、有效带宽和按内存空间划分的带宽、延迟、电压,以及固件功耗/热系数。
该表是一个编译期 static const 聚合体,不是运行时填充的结构。它的符号 _ZN5xprofL15kDeviceTypeInfoE 具有内部链接(mangled 名中的 L),位于只读可执行 PT_LOAD 段内的 .lrodata 中,并且 .rela.dyn 扫描在其整个范围内找不到任何重定位,因此它没有指针字段,也没有运行时写入者。字节在链接时即已冻结。Identical-code-folding 最多留下 13 份字节完全相同的数组副本,每份对应一个引用它的模板/pass 实例;每个消费者都通过 GOT 相对的 movabs 基址加 idx * 0x448 读取自己的副本。
本页记录:
- per-
DeviceType结构体:字段偏移映射,并分类为时钟、几何、峰值计算 double、DVFS 阶梯,以及仅 host 侧使用的规格块。 - 生产者:为什么该表是一个冻结的编译期 const,独立于
chip_partscapability blob,并且只在DeviceType序号处与其关联。 - roofline 读取者:每个 profiler 消费者读取哪些字段,以及 device-capability stats 如何写入 XPlane。
DeviceType→ codename 绑定:为每个结构体条目命名的序号到硅代际映射。
| 符号 | _ZN5xprofL15kDeviceTypeInfoE @ 0x1C60480 (.lrodata, internal linkage) |
| 形状 | 17 个条目 × 0x448 B = 18632 B;结束于 0x1C64D48;最多 13 份 ICF 副本 |
| 生产者 | 无 — 编译期 static const;零重定位,没有运行时写入者 |
| 时钟读取者 | GtcSpanConverter (0xF2CB6E0, +0x04);GetJobInfoFromResponse (0xF2C9AC0, +0x04/+0x50/+0x2F8 ×1000) |
| 计算读取者 | XProfTpuCostAnalysis::HandleConvolution (0xF58E7C0, +0x60/+0x78/+0x80) |
| 几何读取者 | HostCoreId::ToDeviceOrdinal (0xF69C580);GetCostAdjustmentFunction (0xF58EFC0, +0x2C4) |
| Codename 绑定 | DeviceTypeFromDeviceIdentifiers (0xF6993A0);DeviceTypeString (0xF69C7C0) |
Per-DeviceType 结构体
该结构体按 DeviceType 序号索引:消费者在边界检查 ordinal < 0x11(否则触发 ud1 trap)之后,计算 base + ordinal * 0x448。GtcSpanConverter 构造函数是规范读取者,并以字节精确方式固定了 stride:
GtcSpanConverter::GtcSpanConverter(DeviceType dt): // sub_F2CB6E0
if (dt >= 0x11) BUG() // 17 entries
base = GOT(0x224C2980) + (-8525971 .. ) // -> kDeviceTypeInfo @ 0x1C60480
converter[0] = base[dt * 274 + 1] // 274 int32 cols = 0x448; col 1 = +0x04 (kHz)
converter[1..3] = 0
```text
`274 * 4 = 0x448`,确认每个条目有 274 个 int32 列。下面的字段偏移映射对每个已填充字段进行分类。状态图例:**C** = 已反汇编出 `.text` 读取者;**P** = 字节精确值,但没有 in-binary 读取者固定;**I** = 语义是根据分代数值缩放并对照独立来源推断出的。
| off | type | field | 含义 / 消费者 |
|---:|---|---|---|
| `+0x00` | i32 | `core_multi_flag` | 由 `GetJobInfoFromResponse` 以 BYTE 读取(`cmp BYTE,1`);在 multi-core / SC 代际上为 1 |
| `+0x04` | i32 | `gtc_freq_khz` | GTC 时钟;`GtcSpanConverter` 除数 + `GetJobInfoFromResponse` ×1000 → Hz |
| `+0x08` | i32 | `gtc_ts_width_bits` | GTC 时间戳宽度 `{48,45,64}`;匹配 trace-codec 的 `GetBits64` 宽度 |
| `+0x0C` | i32 | `cores_per_chip` | `ToDeviceOrdinal`/`HandleConvolution`/`GetCostAdjustment`/utilization 中的除数 |
| `+0x10`/`+0x14` | i32 | `logical_devices_a/b` | `ToDeviceOrdinal` `idiv [+0x10 or +0x14] / [+0x0C]`;`+0x14` = SC 代际上的 SparseCore 数量 |
| `+0x18`/`+0x1C` | i32 | `geom_c` / `tile_count` | 每芯片乘数 / 递增的 tile-engine 数量 |
| `+0x20` | i32 | `sc_present_flag` | 在 45-bit SC 代际(DT10..13)上为 1 |
| `+0x28` | i32[8] | `dvfs_ladder_A_khz` | 8 点频率阶梯,仅 DT12 填充 |
| `+0x50` | i32 | `tensorcore_clk_khz` | TensorCore/计算时钟;`GetJobInfoFromResponse` ×1000 → Hz |
| `+0x58` | f64 | `peak_bf16_per_LD` | per-LD/sustained bf16 速率;没有 in-binary 读取者 |
| `+0x60` | f64 | `peak_flops_bf16` | 按精度划分的峰值(TFLOP/s);`HandleConvolution` + XPlane stat `0x62` |
| `+0x68` | f64 | `peak_flops_int8_v7x` | 仅 v7x 使用的备用 int8 槽位(1992.0) |
| `+0x78` | f64 | `peak_flops_int8/fp8` | 约为 `+0x60` 的 2 倍;`HandleConvolution`(integer/fp8 element types) |
| `+0x80` | f64 | `peak_flops_int4/fp4` | 约为 `+0x60` 的 4 倍;`HandleConvolution`(int4/fp4 element types) |
| `+0xB8`..`+0xC8` | f64 | `eff_hbm_bw_0..2` | 有效 HBM 带宽(GB/s 级);仅 host 侧 |
| `+0xD0` | f64 | `peak_hbm_bw` | HBM 带宽;XPlane stat `0x63`(×1.073741824 GB→GiB)— 与 `chip_parts` HBM TB/s 字节精确一致 |
| `+0xD8`..`+0xF0` | f64 | `mem_latency_0..3` | 延迟/周期类;仅 host 侧 |
| `+0xF8`..`+0x130` | f64 | per-mem-space bandwidth | `+0x100`/`+0x108`(SRAM/VMEM bw,stats `0x66`/`0x67`);`+0x120`/`+0x128`(CMEM bw,stats `0x64`/`0x65`,仅 v4);`+0xF8`/`+0x110`/`+0x118`/`+0x130` 仅 host 侧 |
| `+0x138`..`+0x150` | f64 | `rate_b_0..3` | 次级吞吐率(v4+);仅 host 侧 |
| `+0x178`..`+0x190` | f64 | `rate_c_0..3` | 次级峰值速率表(按精度);仅 host 侧 |
| `+0x2B8` | i32 | `packed_geom` | 打包的 `{a,b,a,b}` 字节描述符;由 `ProcessCounter` 以 BYTE 读取 |
| `+0x2C4` | i32 | `megacore_flag` | `GetCostAdjustment` `cmp BYTE[+0x2C4],1`;XPlane stat `0x6B` (`has_megacore`) |
| `+0x2C8` | i32 | perf-counter-set mask | `ConvertTpuTraceToXPlane` → `GetPerformanceCounterNames<28>` (v7x) |
| `+0x2D0` | i32[8] | `dvfs_ladder_B_khz` | 第二组 8 点阶梯,仅 DT12 填充 |
| `+0x2F8` | i32 | `sparsecore_clk_khz` | SparseCore 时钟;`GetJobInfoFromResponse` ×1000 → Hz |
| `+0x300`/`+0x308` | f64 | `core_voltage/power_0/1` | 电压/功耗类;仅 host 侧 |
| `+0x340` | i32 | `sc_lane_count` | SC 代际上为 16;在 18 个 SparseCore subscriber 站点读取 |
| `+0x348`/`+0x350`/`+0x358` | i32 | perf-counter-set masks | `GetPerformanceCounterNames<28>` (v7x) |
| `+0x360`..`+0x378` | f64 | power/thermal coeffs | `ConvertFirmwareTraceEntriesToXPlane` → `FirmwareEventBuilder` → "power"/"temperature" stats |
| `+0x380`..`+0x398` | u64 | firmware-event ulongs | `FirmwareEventBuilder` `m m m m` 参数(`+0x380` 是第一个 GP 参数) |
| `+0x438`/`+0x440` | i32 | perf-counter-set bases | `+0x438` = ICR set → `GetPerformanceCounterNames<12>`;`+0x440` = CMNUR/HBM set → `<3>`(v7x;仅 DT12 非零) |
> **注意 —** 该表**没有指针字段**(`[0x1C60480, 0x1C64D48)` 范围内零重定位)。设备 codename 字符串和 trace-codec factory 由同一个捕获到的设备身份*分别*作为 key:名称使用 `DeviceTypeString` 的指针数组 `0x21772F00`(按序号索引),codec 使用 per-family `DeviceIdentifiers` `std::map` factory。序号选择时钟/规格(此结构体);PCI tuple 选择 codec。
>
> **注意 —** `+0x438`/`+0x440` 尾部保存的是 v7x perf-counter-set enum 基址,**不是** roofline double。将六个 `GetPerformanceCounterNames` call-site GOT 位移反推回 `base + ordinal*0x448`,可解析出 `+0x438` 是 `<12>` set(ICR/router)基址,`+0x440` 是 `<3>` set(CMNUR/HBM)基址 — 二者仅在 `DeviceType` 12 上非零,高 dword 为零(不是指针)。四个 `<28>`(TensorCore/SparseCore)set 位于 `+0x2C8`/`+0x348`/`+0x350`/`+0x358`。
### DVFS 阶梯
位于 `+0x28` (A) 和 `+0x2D0` (B) 的两组 8 条目 `int32[8]` 阶梯是 kHz 工作点表,*仅*在 DT12(TPU v7x)上填充;更早的代际保持全零,并使用 `+0x50` 和 `+0x2F8` 处的固定标量时钟。未找到遍历任一阶梯的 in-binary 迭代器 — host DVFS/功耗模型会消费它们 — 因此 core-vs-SC 标注是按位置推断的:
- **阶梯 A** (`+0x28`):`{1.60, 1.70, 1.80, 1.90, 2.00, 2.05, 2.10, 2.20}` GHz。最高点高于 v7x TensorCore 时钟(`+0x50` = 1900 MHz)— core/TensorCore-domain 阶梯,带 turbo/boost 状态。(I)
- **阶梯 B** (`+0x2D0`):`{1.40, 1.50, 1.60, 1.75, 1.75, 1.80, 1.85, 1.90}` GHz。其中重复的 1.75 GHz 点等于 v7x SparseCore 时钟(`+0x2F8` = 1750 MHz)— SC/memory-domain 阶梯。(I)
---
## 生产者:冻结的编译期 Const
不存在运行时生产者函数。该符号是 `.lrodata` section(flags `AMSl`,无写位)中的一个大小为 18632 的 `LOCAL OBJECT`,由 `p_flags = R E` 的 `PT_LOAD` 段映射。任何对 `0x1C60480` 的运行时 store 都会在只读可执行段中 fault,并且 `.rela.dyn` 扫描在该表范围内返回零重定位,因此它没有指针字段,加载时也无法 patch。这些字节是由 C++ 前端发出的手写 / codegen 生成的 `static const DeviceTypeInfo[17]`。最多 13 份字节完全相同的副本(每份都通过 per-copy `movabs` 基址 = `copy_VMA − GOT(0x224C2980)` 引用)是不同模板/pass 实例造成的 identical-code-folding 产物。
峰值计算 double 是一个**独立的 xprof 规格表**,不是 `chip_parts` `FlopsPerSecond` 常量的字节冻结副本。与解码后的 `chip_parts` 数值交叉验证显示,bf16 和所有 v5p 槽位都有差异,只有 v6e int8/int4 槽位一致 — 这是因为二者都源自同一个 `systolic_dim² × clk` 硬件谱系,而不是因为其中一个复制了另一个:
| slot | kDeviceTypeInfo (TFLOP/s) | chip_parts /1e12 | ratio | match |
|---|---:|---:|---:|:--:|
| v5p bf16 `+0x60` | 236.7 | 197.0 | 1.20 | no |
| v5p int8 `+0x78` | 466.2 | 394.0 | 1.18 | no |
| v5p int4 `+0x80` | 925.2 | 788.0 | 1.17 | no |
| v6e bf16 `+0x60` | 946.7 | 918.0 | 1.03 | no |
| v6e int8 `+0x78` | 1835.0 | 1835.0 | 1.00 | yes |
| v6e int4 `+0x80` | 3670.0 | 3670.0 | 1.00 | yes |
因此 `chip_parts.binarypb` 是 compiler/`Target` 规格来源,而 `kDeviceTypeInfo` 是并行的 xprof profiler 规格来源;二者只在 `DeviceType` 序号处关联,不能互换使用。
---
## Roofline 读取者
profiler 不在 binary 内求值 roofline;它会把 *roofline 输入* — 一条 device-capability stat 记录 — 写入 XPlane,再由 binary 外的 host xprof/roofline 工具计算上限。读取者如下:
- **时钟 → device-info。** `GetJobInfoFromResponse` (`0xF2C9AC0`) 检查 `core_multi_flag` (`+0x00`),然后将 `gtc_freq_khz` (`+0x04`)、`tensorcore_clk_khz` (`+0x50`) 和 `sparsecore_clk_khz` (`+0x2F8`) ×1000 提升到 `Task` proto 的 `gtc_freq_hz`/`tensor_core_freq_hz`/`sparse_core_freq_hz` 字段中。反编译站点以 `col[1]`=+0x04、`col[20]`=+0x50、`col[190]`=+0x2F8 从 `[base + 1096*ord + col]` 读取,每项都是 `1000LL *`。
- **峰值计算 → cost model。** `XProfTpuCostAnalysis::HandleConvolution` (`0xF58E7C0`) 从 `DBL_MAX` 开始,将每个 conv operand 的 `Shape::element_type` 通过 28 条目跳转表映射为加载 `+0x60`(bf16)、`+0x78`(int8/fp8)或 `+0x80`(int4/fp4),取运行中的 `vminsd`(最慢的 operand 精度主导),然后除以 core 数量。这是 `+0x60`/`+0x78`/`+0x80` 为按精度划分的 peak-FLOPS 表的字节精确证明。
- **几何 → ordinal / cost。** `HostCoreId::ToDeviceOrdinal` (`0xF69C580`) 用 `cores_per_chip` (`+0x0C`) 去除 `logical_devices_a/b` (`+0x10`/`+0x14`),将 `(host, core)` 映射为 device ordinal。`GetCostAdjustmentFunction` (`0xF58EFC0`) 读取 `megacore_flag`(`+0x2C4`,`cmp BYTE,1`)以启用 `AdjustCostForMegacoreFunction`,并读取 `cores_per_chip` (`+0x0C`)。
- **Device-capability XStats → XPlane。** `ConvertTpuTraceToXPlaneV2` 写入 `+0x60`(peak TFLOP/s,stat `0x62`)、`+0xD0`/`+0x100`/`+0x108`/`+0x120`/`+0x128`(按内存空间划分的带宽,stats `0x63`–`0x67`,每个都 ×1.073741824 以将 base-10 GB/s 转为 GiB/s),以及 `+0x2C4`(`has_megacore`,stat `0x6B`)。`ConvertTpuTraceToXPlane` 将六个 perf-counter-set 基址送入 `GetPerformanceCounterNames<N>`:`+0x2C8`/`+0x348`/`+0x350`/`+0x358` 作为四个 `<28>`(TensorCore/SparseCore)set,`+0x438` 作为 `<12>`(ICR/router)set,`+0x440` 作为 `<3>`(CMNUR/HBM)set。`ConvertFirmwareTraceEntriesToXPlane` 将 `+0x360`..`+0x378` double 和 `+0x380`..`+0x398` ulong 送入 `FirmwareEventBuilder`,后者写入 "power"/"temperature" stats。
> **怪癖 —** `+0xD0` HBM-bandwidth 成员经过 ×1.073741824 转换后,与 `chip_parts` HBM 带宽字节精确一致(v7x 3433 → 3686.2 GiB/s = 3.686 TB/s;v6e 1525.5 → 1638.0 GiB/s = 1.638 TB/s)。`+0xB8` 组*不是*权威 HBM-bandwidth stamp — 它是一个单独的有效带宽规格,没有 in-binary 读取者。若重新实现时把 `+0xB8` 当作 HBM peak 读取,就会读错字段。
---
## DeviceType → Codename 绑定
`kDeviceTypeInfo` 索引是 1-based `xprof::DeviceType` enum。`DeviceTypeFromDeviceIdentifiers` (`0xF6993A0`) 将捕获到的 12 字节 PCI tuple(全部 `vendor_id == 0x1AE0`,Google)映射到序号,而 `DeviceTypeString` (`0xF69C7C0`) 将序号映射到公开名称(`return DeviceTypeString[ord-1]`,当 `ord-1 > 0xC` 时默认为 `"Cloud TPU"`)。八个真实硅代际如下:
| ordinal | public name | codename | family | GTC clk (kHz) | ts width | compute clk (kHz) |
|---:|---|---|---|---:|---:|---:|
| 3 | TPU v2 | Jellyfish | `jxc` | 700000 | 48 | 700000 |
| 5 | TPU v3 | Dragonfish | `jxc` | 700000 | 48 | 940000 |
| 7 | TPU v4 | Pufferfish | `pxc::pfc` | 700000 | 48 | 1050000 |
| 8 | TPU v4 Lite | Puffylite | `pxc::plc` | 700000 | 48 | 1050000 |
| 10 | TPU v5 | Viperfish (v5p) | `vxc::vfc` | 800000 | 45 | 1750000 |
| 11 | TPU v5 Lite | Viperlite (v5e) | `vxc::vlc` | 800000 | 45 | 1500000 |
| 12 | TPU v7x | `6acc60406` (gfc) | `gxc::gfc` | 833000 | 45 | 1900000 |
| 13 | TPU v6 Lite | Ghostlite (v6e) | `gxc::glc` | 800000 | 45 | 1750000 |
`DeviceTypeFromDeviceIdentifiers` 依次匹配每个 codename 的 `kXxxChipIdentifiers` tuple(Jellyfish→3、Dragonfish→5、Puffylite→8、三个 Pufferfish B0 SKU→7、四个 Viperlite SKU→11、两个 Viperfish SKU→10),并通过 `IsGlc`→13 和 `IsGfc`→12 分派两个 Ghost family。序号 1/2/4/6/9/14..16 是 host-GPU plane 和 "Cloud TPU" 占位/保留槽位(DeviceType 9 是一个保留的 64-bit-timestamp、1.333 GHz 槽位,没有 PCI tuple)。`DeviceTypeToHardwareType` (`0xF69C7A0`) 确认了这种划分:八个具名代际映射到 hardware-type 3(TPU),占位映射到 0/1,GPU plane 映射到 2。
> **注意 —** profiler 的 `DeviceType` 序号是*第三套*编号,既不同于 `TpuVersion`(0-based internal),也不同于 `TpuVersionProto`(1-based wire)。它以捕获到的 PCI tuple 为 key,而不是以 `TpuVersion` 为 key。使用 [Codename Matrix](tpu-version-codename-matrix.md) 来对齐这三者。
---
## 相关组件
| Name | Relationship |
|---|---|
| `GtcSpanConverter` (`0xF2CB6E0`) | 规范的 `+0x04` GTC-clock 读取者;固定 `0x448` stride 和 17 条目边界 |
| `GetJobInfoFromResponse` (`0xF2C9AC0`) | 将三个时钟 ×1000 提升到 `Task` device-info proto 中 |
| `HandleConvolution` (`0xF58E7C0`) | 为 cost model 读取 `+0x60`/`+0x78`/`+0x80` peak FLOPS |
| `DeviceTypeFromDeviceIdentifiers` (`0xF6993A0`) | PCI tuple → `DeviceType` 序号 → codename 绑定 |
| `FirmwareEventBuilder` (`0xF284D20`) | 消费 `+0x360` power/thermal coefficient bundle |
## 交叉引用
- [Codename 矩阵](tpu-version-codename-matrix.md) — 将 `DeviceType` 序号与 `TpuVersion` 和 codename 名册对齐
- [Per-DeviceType 结构体](../profiling/per-devicetype-struct.md) — 完整的 `0x448` 字段 dump 和 unit/wrap-period 证明
- [kDeviceTypeInfo 生产者 / 读取者](../profiling/kdevicetypeinfo-producer-readers.md) — compile-time-const 生产者论证和 XPlane device-capability stamp 路径
- [v7x Perf-Counters](../profiling/v7x-perf-counters.md) — 拥有 `+0x2C8`/`+0x348`/`+0x350`/`+0x358`/`+0x438`/`+0x440` perf-counter-set 字段和 `DeviceType == 12` gate
- [chip_parts.binarypb](chip-parts-binarypb.md) — 并行的 compiler 侧 per-gen 规格来源;`FlopsPerSecond` 已与 `+0x60`/`+0x78`/`+0x80` 交叉验证