调度表分类(全面普查)
本页上的所有地址、计数和部分名称适用于
libtpu-0.0.40-cp314轮中的libtpu.so,构建 ID89edbbe81c5b328a958fe628a9f2207d(轮/METADATA/__init__版本为0.0.40;固定到构建 ID,这是明确的)。其他版本会有所不同。这是叙述 调度表分类 的详尽机器式伴侣;要了解每个课程的“原因”,请阅读家长内容。
摘要
libtpu.so 是一款 745 MB PJRT 插件,通过将 XLA、MLIR、LLVM、TensorFlow、TPU asic_sw ISA 后端、oneDNN、abseil、protobuf、gRPC 和一长尾主机库静态链接到一个位置无关的共享对象中而构建。该联合中几乎每个 C++ 类都是多态的,因此二进制文件带有大量的调度结构:40,313 个函数指针表(Itanium-ABI vtables、MLIR Op-Model 数组、类型擦除池、PMU C 表)保存 516,323 个函数指针,加上结构上独立的 33,016 个已编译的开关跳转表,保存 4,673,757 个 case 条目。父页面将函数指针表分为 19 个结构类别,并讲述每个类别的故事。本附录是完整的参考:每个类的计数、类所在的部分、其跨步/条目类型签名、最大的单个表带地址以及交换机跳转表大小分布。
文件映像中未填充函数指针表。在 1,069,659 次搬迁中,924,033 人居住在 .data.rel.ro;每个 vtable 槽在磁盘上为零,加载器在加载时通过 R_X86_64_RELATIVE 减少写入实际目标。 IDA 的表 sidecar 已经通过其重定位解析了每个槽,因此下面的每个表条目计数和第一个符号标识是从解析的目标中读取的,而不是从文件字节中读取的。最重要的结构事实是 39,244 / 40,313 比率:二进制文件携带 39,244 个 _ZTV vtable 组(经过 nm 验证),因此调度总体绝大多数是重新定位的 vtable,其余部分由大约 1,069 个非 vtable 调度结构(abseil 策略 thunk、libpfm4 C 表、成员指针数组)组成。
此页面是普查,而不是重新实施指南。它不会重新解释 Itanium vtable ABI、RTTI→vtable 绑定链或任何层次结构的每插槽语义 — 这些属于 RTTI / Vtable普查 和 多态入口点。它提供的是工具作者需要对二进制文件的调度表面进行“索引”的完整枚举:表属于哪个类、它有多大以及异常值在哪里。
| 函数指针表 | 40,313 / 516,323 条目 |
| 切换跳转表 | 33,016 / 4,673,757 例 |
| RTTI 记录 | 160,351(_ZTV vtable 组 = 39,244) |
| 搬迁 | 1,069,659(.data.rel.ro 中的 924,033) |
| 部分分割(表) | 38,664 .data.rel.ro / 1,442 .data / 207 .rodata |
| 最大单桌 | 0x223393a0 — 2,595 个条目(UniqueFunctionBase、.data) |
| 最大的单个开关 | 0x11cc4900 — 40,813 例 (AMDGPUMCCodeEmitter::getBinaryCodeForInstr) |
| 课程 | 19(功能指针)+ 13(开关),覆盖率99.6% |
这次人口普查修复了什么
行走 libtpu.so 调度面的工具必须:
- 区分这两个群体。 40,313 个函数指针表和 33,016 个开关表是位于不同部分的不相交的结构对象。一个简单的“40,313 个调度表”数字并没有分割两个重复计数,而是错误地标记了所有内容。
- 在符号上键入 MLIR Op-Model 类,而不是大小。 大小 23 是 Op-Model 指纹,但 79 个不相关的 23 方法 vtable 在数量上一致。分类器必须键入
RegisteredOperationName::Model<Op>符号。 - 将软类边界视为依赖于分类器。 硬结构锚点(部分分割、大小 23 计数、最大表、开关最大值)再现为数字。每个类的 计数 取决于 thunk 前缀 (
_ZThn/_ZTv)、本地范围 (_ZZ) 和std::符号的标准化方式;下图带有相应的置信标签。
普查表 — 函数指针调度类
19个类别覆盖40,313张牌桌的99.6%; 157 (0.4%) 是 IDA 自动命名的 (sub_/nullsub_) 或没有可恢复所有者的纯虚拟表。每个类的“Stride”都是统一的 8 个字节(void(*)() 槽)——区别在于条目类型(重定位代码指针、ICF 折叠转发器、ABI thunk 或 C 函数指针),在详细信息部分中为每个类给出。 “顶表”是最大的单个表,其第一个解析符号将其放入类中。
| ID | 级 | 计数 | % | 部分 | 顶表(地址 — 条目) |
|---|---|---|---|---|---|
| E | TPU ISA 编码器/克隆 vtable (asic_sw) | 9,932 | 24.6% | .data.rel.ro | 0x21e0d0a0 — 674 |
| A | MLIR Op Model<> 阵列(尺寸 23) | 6,085 | 15.1% | .data.rel.ro | size-23 指纹 — 23 |
| F | mlir:: vtable(非 Op 模型) | 4,270 | 10.6% | .data.rel.ro | 0x21c2d030 — 108 |
| I | llvm:: vtables(TargetLowering,通过) | 2,611 | 6.5% | .data.rel.ro | 0x2186b0c0 — 336 |
| D | oneDNN / Xbyak JIT vtables | 2,289 | 5.7% | .data.rel.ro | 0x21b6e048 — 29 |
| G | xla:: / stablehlo:: vtables | 2,154 | 5.3% | .data.rel.ro | 0x21cc6358 — 266 |
| H | tensorflow:: / tsl:: vtables | 2,153 | 5.3% | .data.rel.ro | 0xa304280 — 89 |
| P | Abseil 哈希容器策略 thunk | 2,066 | 5.1% | .data.rel.ro | 0x21c1d590 — 447 |
| O | 长尾命名空间 vtable | 1,866 | 4.6% | .data.rel.ro | 0x21865d20 — 256 |
| K | libc++ std:: thunks | 1,802 | 4.5% | .data.rel.ro | 0x21c0c0c8 — 231 |
| N | TPU 运行时/分析器 vtable | 1,130 | 2.8% | .data.rel.ro | 0x21ca92b0 — 61 |
| M | gRPC / grpc_core vtables | 931 | 2.3% | .data.rel.ro | 0x21f874e0 — 30 |
| C | libpfm4 PMU 事件表 | 833 | 2.1% | .data(突变) | 0x222684d8 — 10 |
| L | protobuf 消息/描述符 vtable | 712 | 1.8% | .data.rel.ro | 0x220387e8 — 117 |
| Z1 | 匿名命名空间静态助手 | 698 | 1.7% | .data.rel.ro | 0xa30af90 — 165 |
| B | LLVM UniqueFunctionBase 池 | 591 | 1.5% | .data(突变) | 0x223393a0 — 2,595 |
| R | C 运行时/Rust I/O 和编解码器表 | 33 | 0.1% | .data.rel.ro | 0x21fbfee8 — 30 |
| Q | 绳索 AnyInvocable 调用者重击 | 2 | 0.0% | .rodata | 0xa30c788 — 4 |
| Z | 未分类(IDA 自动命名) | 157 | 0.4% | .data.rel.ro | 0x21c3c558 — 345 |
注意 — B 类 (
UniqueFunctionBase) 表计数为 586–591,具体取决于符号前缀标准。严格的“第一个解析符号是UniqueFunctionBase”标准产生 586 个表/11,516 个条目;扩大到包括unique_function模板拼写,结果为 591 / 11,591。0x223393a0和.data的 2,595 名参赛者的顶级桌无论哪种方式都是恒定的。边界情况是两个.data.rel.ro和一个.rodata表,其第一个槽解析为池体之前的非UniqueFunctionBase基础。注意 — Op-Model size-23 指纹准确再现:6,129 个表有 23 个条目; 6,050 个包含
RegisteredOperationName::Model插槽; 79 是仅在数量上一致的 23 方法 vtable(例如xla::MegaScalePjRtDevice、23 插槽PjRtDevice系列)。 A 类以型号符号为键,因此不会错误地存储 79;其 6,085 计数是所有尺码的模型人口,而不仅仅是 23 尺码。
E — TPU ISA 编码器/克隆 Vtable (asic_sw)
签名
表数量最大的类别(9,932;24.6%),也是 TPU 代码生成器的结构核心。每个表都是 asic_sw::deepsea::<cluster>::isa::* 指令编码器的 vtable,其中 <cluster> 按芯片代数和通道簇进行分区。条目类型:将代码指针重新定位到每个簇的编码/克隆体中;中等步长 6(典型的编码器声明 ~6 个虚拟方法),带有宽 TensorCoreVectorAluCompact 系列表的重尾。
人口按泳道聚类进行分区。两个 gxc 簇(gfc ≈ 2,290,glc ≈ 2,270)占主导地位并且接近对称,这表明每个 ISA 操作码都有一个配对的编码/克隆 vtable; vxc 和 pxc 紧随其后,jxc 是退化对。近对称性是重新实现者的核心观察结果:编码器计数大约是每代操作码计数的 2 倍,而不是 1 倍。
最大的桌子
addr entries first symbol (TensorCoreVectorAluCompact family)
0x21e0d0a0 674 asic_sw::deepsea::gxc::gfc::isa::TensorCoreVectorAluCompact
0x21dc35a8 623 asic_sw::deepsea::gxc::glc::isa::TensorCoreVectorAluCompact
0x21e03370 620 asic_sw::deepsea::gxc::gfc::isa::TensorCoreVectorAluCompact
0x21df9ce0 620 asic_sw::deepsea::gxc::gfc::isa::TensorCoreVectorAluCompact
0x21df04c0 620 asic_sw::deepsea::gxc::gfc::isa::TensorCoreVectorAluCompact
0x21dba8a8 566 asic_sw::deepsea::gxc::glc::isa::TensorCoreVectorAluCompact
0x21db1f30 566 asic_sw::deepsea::gxc::glc::isa::TensorCoreVectorAluCompact
0x21da9788 566 asic_sw::deepsea::gxc::glc::isa::TensorCoreVectorAluCompact
0x21d816c8 403 asic_sw::deepsea::vxc::isa::TensorCoreVectorAluCompact
0x21d7b5b0 383 asic_sw::deepsea::vxc::isa::TensorCoreVectorAluCompact
```text
620/623/674 宽表簇是 `TensorCoreVectorAluCompact` 编码器 — 具有最大操作码变体扇出的矢量 ALU 指令类。这些是 [多态入口点](../forensics/polymorphic-entry-points.md) 中记录的 `IsaEmitter` 152 槽纯接口的具体每代填充。
---
## A — MLIR 运算 `Model<>` 阵列
### 签名
6,085 张桌子 (15.1%)。每个都是一个 `mlir::RegisteredOperationName::Model<Op>` 数组 - MLIR 对每个注册操作实现一次的类型擦除操作接口调度。规范实例有 23 个槽(`OperationName::Impl::~Impl`、`Model::~Model`,然后是 21 个接口方法:`foldHook`、`getCanonicalizationPatterns`、`hasTrait`、解析/打印/验证、固有属性访问器和 9 个属性管理槽)。入口类型:大量 ICF 折叠 - 大多数接口方法槽通过 5 字节 `jmp` 转发器指向共享规范主体,因此数千个不同的操作共享一个物理 `isCompatibleReturnTypes` 主体。
> **QUIRK —** 23 号指纹是必要的,但还不够。 6,129 个表正好有 23 个条目;其中 79 个是普通的 23 方法 vtable,而不是 Op-Model。仅按规模进行的普查就将 A 级的数量多出了 79 个,并悄悄错误地记录了 `PjRtDevice` 系列。 `RegisteredOperationName::Model` 符号上的按键;尺寸 23 是一个提示,而不是测试。
### 最大的桌子
```text
addr entries note
0xa305350 113 tensorflow::OpOrArgNameMapper (a 23-fingerprint-adjacent .rodata case)
size-23 ×6050 the canonical Model<Op> ABI — the dominant arityA 类的不同寻常之处在于它是一个近乎均匀的群体:其中位数为 23,方差很小,因为每个注册的操作都实现相同的 ABI。该类很大count(每个操作一个),但不同的代码很便宜(ICF 折叠了接口体)。有关 ICF 如何填充此类的信息,请参阅 调度表分类。
F — mlir:: Vtable(非 Op 型号)
签名
4,270 个表 (10.6%):每个“不是”Op-Model 数组的 mlir:: 多态对象 — 传递、方言、接口概念、属性/类型存储、重写模式。条目类型:重定位代码指针,在多重继承过程和模式类中具有重要的 _ZThn/_ZTv thunk 分数。中位步幅为 8。
最大的桌子
addr entries note
0x21c2d030 108 mlir:: interface/pass object (widest non-Model mlir vtable)
```text
两个结构上中心的 F 级基础是 `mlir::Pass`(13 个插槽,CRTP 合约,其中具体通行证仅填充 `runOnOperation`)和 `mlir::Pattern`(二进制中第二宽的继承树)。它们的每插槽 ABI 在 [RTTI / Vtable普查](../forensics/rtti-vtable-census.md) 中行走。
> **注意 —** F 是中等置信度计数,因为 `mlir::` 命名空间前缀会吸引 thunk 前缀符号,其所属命名空间必须在分桶之前标准化。一旦前缀标准化,大约有 310 个这样的 thunk 属于 F,而不是属于未分类的桶。
---
## I — `llvm::` Vtables
### 签名
2,611 个表 (6.5%):LLVM 代码生成对象 — `TargetLowering`、SelectionDAG 节点、旧版 `Pass`/`FunctionPass`/`MachineFunctionPass` 梯形图、`MCStreamer`、诊断。入口类型:重定位代码指针;该类拥有二进制文件中最宽的非池虚表。
### 最大的桌子
```text
addr entries first symbol
0x2186b0c0 336 llvm::TargetLowering
0x21866ed8 336 llvm::TargetLowering
0x218567b0 336 llvm::TargetLoweringllvm::TargetLowering(336 个插槽,3 个实例)是 I 类中最广泛的真正 vtable — 每个后端目标都会覆盖的与目标无关的降低接口。 llvm::MCStreamer(164 个原始插槽)是最大的单目标流媒体系列。遗留传递阶梯(Pass 16 → FunctionPass/ModulePass 17 → MachineFunctionPass 21)是此类的继承主干。
D — oneDNN / Xbyak JIT Vtables
签名
2,289 个表(5.7%):oneDNN JIT 原始 vtable(约 1,692)加上 Xbyak 代码生成器 vtable(约 546),联合报告,因为它们形成一棵物理继承树 - 每个 JIT 内核继承 jit_generator(一个 Xbyak CodeGenerator)加上一个内核接口,因此该类处于主导地位通过多重继承二级碱基重击。条目类型:重定位代码指针,具有任何类中最重的 _ZThn 此调整 thunk 浓度(二进制文件的 3,016 个非虚拟 ABI thunk 中的约 1,376 个是 dnnl::impl::cpu::x64::*)。
最大的桌子
addr entries note
0x21b6e048 29 dnnl JIT primitive vtable (widest in class)
```text
> **明白了 —** D 类 vtable 插槽经常保存 `_ZThn` 这个调整 thunk,而不是直接保存方法体。调用这样的槽位于 8-12 字节存根中,该存根通过(负)字节偏移量调整 `this` 并尾部跳转到共享基体。假定 vtable 槽指向最终方法的导航器将错误解析此类中的每个辅助基槽。二进制文件中最大的 thunk 扇入目标 `jit_generator::~D2` 收集了 281 个析构函数 thunk。
---
## G — `xla::` / `stablehlo::` V表
### 签名
2,154 个表 (5.3%):XLA 编译器和 jellyfish 后端 — `HloInstruction`(18 个插槽,67 个派生 vtable)、`xla::cpu::Thunk`(8 个插槽,24 个派生)、HLO pass 系统、`OpEmitter` 和每代`Target` 描述符。条目类型:重定位代码指针。
### 最大的桌子
```text
addr entries first symbol
0x21cc6358 266 xla::jellyfish::JellyfishTarget
0x21cc6bd0 266 xla::jellyfish::JellyfishTarget
0x21cc74e8 266 xla::jellyfish::Target
0x21cc7da8 266 xla::jellyfish::Target
0x21cc8728 266 xla::jellyfish::Target
0x21cc90a8 266 xla::jellyfish::Target
0x21cce6b0 266 xla::jellyfish::Target注意 — 在
0x21cc6358–0x21cce6b0处,恰好有 7 个 266 槽表(2JellyfishTarget+ 5Target),通过枚举每个 266 条目记录来确认。这些是安装每代成本模型的每代目标描述符。请参阅 每代函数调度程序 了解如何通过手写的GoogleInitializer转发器到达它们。
H — tensorflow:: / tsl:: V表
签名
2,153 个表 (5.3%):TensorFlow grappler 转置器、运算内核、运行时对象和 tsl 支持库。入口类型:重定位代码指针; OpKernel 7槽底座(Compute纯槽2)是结构根。
最大的桌子
addr entries first symbol
0xa304280 89 tensorflow::grappler::Conv2DBackpropFilterTransposer
0xa304e30 70 tensorflow::grappler::BiasAddGradTransposer
0xa304bb0 70 tensorflow::grappler::BiasAddGradTransposer
```text
抓斗转置器(`.rodata` 驻留)是最宽的 H 级工作台 — 每个转置器都带有完整的布局转换接口。
---
## P — Abseil 哈希容器策略 thunk
### 签名
2,066 个表 (5.1%):`flat_hash_set`/`flat_hash_map`/`node_hash_*` 的类型擦除策略调度。每个 hashmap 实例化都通过 `container_internal` 策略表进行路由;该类由单个全局 thunk 表控制,该表扇出到每个 hashmap 实例。条目类型:成员指针/策略 thunk(不是经典的 vtable)。
### 最大的桌子
```text
addr entries first symbol
0x21c1d590 447 absl::container_internal::GetRefForEmptyClass注意 —
0x21c1d590处的 447 个条目GetRefForEmptyClass表是全局平面哈希策略 thunk — 一张表扇出 447 个不同的哈希图实例。一旦每个raw_hash_set策略 thunk 被正确地存储而不是集中到长尾中,P 类总计 2,066 表 - 如果错过了这些 thunk,那么这个计数很容易低于一个数量级。
O — 长尾命名空间 Vtable
签名
1,866 个表 (4.6%):大约 150 个小型命名空间 — Eigen、OR-tools (operations_research)、RE2、riegeli、ANTLR、ICU 等几十个 — 每个都贡献少量 vtable。条目类型:重定位代码指针。这是命名命名空间分类的残余:任何具有非大桶之一的分解命名空间的东西。置信度较低,因为 K (libc++) 和 Z1(匿名)的边界依赖于分类器。
最大的桌子
addr entries note
0x21865d20 256 long-tail named-namespace vtable
0xa303ec0 111 Eigen::internal::general_matrix_vector_product
```text
---
## K — libc++ `std::` thunk
### 签名
1,802 个表 (4.5%):`std::__u::`(libc++ 内联命名空间)调度 — `shared_ptr` 放置主体、`__function::__policy_func` 类型擦除、排序/访问调度程序。入口类型:重定位代码指针和ICF折叠转发器。
### 最大的桌子
```text
addr entries first symbol
0x21c0c0c8 231 std::__u::__variant_detail::__visitation::__base::__dispatcher注意 — 231 插槽
__variant_detail::__dispatcher是std::variant访问表 — 每种替代类型一个插槽。 K 类取决于正确的_ZNSt符号路由:如果解析错误,St修饰前缀会将 ~422 个 std 表路由到未分类存储桶中,而不是 K。
N — TPU 运行时/分析器 Vtable
签名
1,130 个表 (2.8%):TPU HAL 运行时 — TpuHal/TpuCore/TpuChip/TpuCodec 硬件抽象、xprof 分析器、superpod 和stream_executor 对象。入口类型:重定位代码指针;每代HAL家族都住在这里。
最大的桌子
addr entries note
0x21ca92b0 61 TPU runtime / HAL object (widest in class)
```text
结构上中心的 N 类层次结构是 `TpuHal<F>HardwareImpl`(23 插槽,每代 `{Jxc,Pxc,Vxc}` 叶)、`TpuCodec`(6 插槽,共享基本析构函数的 5 个命名编解码器)和 `CycleTable`(5 插槽成本模型,完全覆盖每个插槽)一代)。 `CycleTable` 系列位于连续地址(`0x21c1ffc8` `JfCycleTable` … `0x21c201d8` `GfcCycleTable`,每个地址 5 个插槽);它们的每插槽 ABI 和覆盖矩阵位于 [每代函数调度程序](../forensics/per-gen-function-dispatcher.md) 中。
---
## C — libpfm4 PMU 事件表
### 签名
833 个表 (2.1%),**全部位于 `.data`**(运行时可变,不是 vtable):主机 CPU 性能计数器采样路径的每个微架构 PMU 事件查找表。条目类型:C 函数指针/结构表,而不是 C++ vtable。这是完全位于可变 `.data` 中的两个类之一。
### 最大的桌子
```text
addr entries note
0x222684d8 10 pfm_* per-microarch PMU event table833 计数精确再现,并且区域居住地(.data,全部 833)是人口普查中最干净的单类锚点:第一个符号为 pfm_* 的表位于 .data 中的概率为 1。
L — Protobuf 消息/描述符 Vtable
签名
712 个表 (1.8%):proto2 消息反射、描述符和 MapEntry vtable,以及 TcParser 快速路径表。条目类型:重定位代码指针。这些为恢复的 FileDescriptorProto 池后面的 protobuf 反射层的内存中调度提供数据。
最大的桌子
addr entries first symbol
0x220387e8 117 proto2::internal::TcParser::FastV8S1 (parse fast-path)
```text
---
## Z1 — 匿名命名空间静态助手
### 签名
698 个表 (1.7%):本地翻译单元 `_GLOBAL__N_` 帮助程序、传递和 lambda 调度 — 匿名命名空间中的任何内容。条目类型:重定位代码指针。从长尾 (O) 中分离出来,因为匿名命名空间符号没有可恢复的所属命名空间,并且必须按其 `_GLOBAL__N_` / `(anonymous)` 前缀进行分类。信心低。
### 最大的桌子
```text
addr entries note
0xa30af90 165 (anonymous)::NVVMReflect / ::MCAsmStreamer-class helperB — LLVM UniqueFunctionBase 池
签名
约 591 个表 (1.5%),.data 中的运行时可变:llvm::detail::UniqueFunctionBase 类型擦除池 — 不是 vtable。每个都是类型擦除的可调用对象池(仅移动 std::function 类似物)。条目类型:运行时可变的可调用槽。此类保存整个二进制文件中最大的单个表。
最大的桌子
addr entries first symbol
0x223393a0 2595 UniqueFunctionBase<LogicalResult(Operation*, ArrayRef<Attribute>, ...)>
0x22337a90 360 UniqueFunctionBase pool
0x2233e500 291 UniqueFunctionBase pool
0x22354c00 201 UniqueFunctionBase pool
0x22303670 168 UniqueFunctionBase pool
0x22338760 162 UniqueFunctionBase pool
```text
> **QUIRK —** `0x223393a0` 上的 2,595 个条目表是统一的 MLIR Op 验证/解析/打印类型擦除调度池 — 单个 `UniqueFunctionBase` 保存 2,595 个可调用项,是第二大表的 4 倍多。它位于 `.data` 中,而不是 `.data.rel.ro` 中,因为池在运行时发生变化(可调用对象在方言注册期间安装),因此它不是加载时重定位常量。对 `.data.rel.ro`(95.9% 的表所在)进行过滤的普查完全忽略了这个类和 libpfm4 类。
---
## R、Q、Z — 尾类
三个小班完成99.6%的覆盖率。
**R — C 运行时/Rust I/O 和编解码器处理程序表 (33)。** cURL (`Curl_nghttp2_*`)、BoringSSL 连接过滤器 (`ssl_cf_*`)、zstd (`ZSTD_*`)、hwloc 和 Rust v0-mangled (`_RNv*`) 处理程序表。这些是真实的调度结构,而不是蹦床误报。顶部表 `0x21fbfee8` — 30 个条目。
**Q — 下降 `AnyInvocable` 调用者重击 (2)。** `absl::functional_internal::InvokeObject<...>` 类型擦除调用者重击。顶层表 `0xa30c788` — 4 个条目,`.rodata` 常驻。
**Z — 未分类 (157)。** 纯虚拟表和 IDA 自动命名 (`sub_`/`nullsub_`) 表,没有可恢复的符号所有者。最大的是 `0x21c3c558`(345 个条目,第一个槽 `sub_1CDA77A0`)——一个宽表,其所有者可以通过将槽目标与 `.text` 函数范围匹配来恢复,而不是从符号中恢复。
> **注意 —** 157 (0.4%) 处的 Z 残差是当前基于符号的分类器的下限。解决它进一步需要地址带 → `.text`-所有者匹配而不是符号分解。单个 345 条目 `sub_` 命名的表使 Z 的表观最大值远远超出了其典型的 6 条目中位数。
---
## 交换机跳转表分布
33,016 个已编译的开关跳转表在结构上与 40,313 个函数指针表分开:它们是通过 `.lrodata` 偏移表间接进行的 LLVM 降低的 `switch` 语句,而不是重定位函数指针数组。他们总共拥有 4,673,757 个案例条目,每次切换的中位数为 18 个案例。
### 尺寸分布
通过对每个交换机的案例计数进行存储:
| 箱数桶 | 开关 | 累计 |
|-------------------|---------:|-----------:|
| 1–4 | 2,681 | 2,681 |
| 5–8 | 10,148 | 12,829 |
| 9–16 | 2,857 | 15,686 |
| 17–32 | 4,213 | 19,899 |
| 33–64 | 4,063 | 23,962 |
| 65–128 | 3,150 | 27,112 |
| 129–256 | 3,070 | 30,182 |
| 257–512 | 1,301 | 31,483 |
| 513–1024 | 625 | 32,108 |
| 1025–4096 | 720 | 32,828 |
| 4097+ | 188 | 33,016 |
该分发是急剧前载的:所有交换机 (12,829) 中的 39% 有 8 个或更少的案例 - 这些是小型枚举/状态调度。只有 188 个开关 (0.6%) 超过 4,096 个案例,但这些少数人在 467 万个案例总数中所占的份额不成比例。仅 5-8 个存储桶(10,148 个开关)就是单一模式,反映了二进制文件普遍存在的小型枚举调度。
### 最大开关
```text
cases addr function
40813 0x11cc4900 (anon)::AMDGPUMCCodeEmitter::getBinaryCodeForInstr
7529 0x1fe5edc0 asic_sw::driver::deepsea::gxc::glc::profiler::PerformanceCounterNameToString
7529 0x1fe57d40 asic_sw::...::PerformanceCounterNameToString
7529 0x1fe50f80 asic_sw::...::PerformanceCounterNameToString
7529 0x1fe4a0c0 asic_sw::...::PerformanceCounterNameToString
7529 0x1fe432e0 asic_sw::...::PerformanceCounterNameToString注意 — 最大开关 —
AMDGPUMCCodeEmitter::getBinaryCodeForInstr和0x11cc4900中的 40,813 个案例 — 是 TableGen 生成的指令编码器调度,而不是手写开关。它比整个函数指针表总体的最大表 (2,595) 大一个数量级,这就是为什么必须分别对两个总体进行普查的原因。PerformanceCounterNameToString集群(多个 7,529 例交换机,每代一个)是每代性能计数器枚举 → 字符串调度。
开关类按所属命名空间进行细分:asic_sw ISA 编码/解码操作码开关占主导地位(约 11,746 个表,约 394 万个案例 - 占所有开关案例的 84%),其次是其他命名命名空间开关、LLVM IR/codegen 和 XLA HLO 操作码开关。仅存在约 12 个文字 TpuVersion 枚举开关 - 每代调度由并行 vtable 系列(上面的 E/G/N 类)承载,而不是通过打开生成枚举来承载。请参阅 每代函数调度程序。
验证锚
本页上的每个图都以表、开关、RTTI 和固定边车为基础。硬锚点,确认准确:
function-pointer tables = 40,313 ; entries sum = 516,323
section split = 38,664 .data.rel.ro / 1,442 .data / 207 .rodata
size-23 tables = 6,129 ; with Model entry = 6,050 ; without = 79
largest table = 0x223393a0 = 2,595 entries (UniqueFunctionBase, .data)
.data population = 1,442 = 833 libpfm4 + ~586 UniqueFunctionBase + ~24 other
abseil policy = 0x21c1d590 = 447 entries (GetRefForEmptyClass)
asic_sw widest = 0x21e0d0a0 = 674 (TensorCoreVectorAluCompact, gxc/gfc)
266-slot Target tables = exactly 7 @ 0x21cc6358 … 0x21cce6b0
llvm widest = 0x2186b0c0 = 336 (TargetLowering, 3 instances)
RTTI records = 160,351 (nm) ; _ZTV vtable groups = 39,244
fixups = 1,069,659 (924,033 in .data.rel.ro)
switch jump tables = 33,016 ; cases sum = 4,673,757 ; median 18
largest switch = 0x11cc4900 = 40,813 cases (AMDGPUMCCodeEmitter)
```text
每个类的软计数(E、F、I、D、H、K、M、N、O、Z1)在 ±100 级别上依赖于分类器,因为它们取决于如何将 thunk 前缀和本地范围符号规范化到其所属的命名空间中;他们相应地具有中/低信心。上面的结构锚具有高置信度并可再现到数字。
## 交叉引用
- [调度表分类](../forensics/dispatch-table-taxonomy.md) — 策划的叙事父级; 19 个类中每个类的“原因”以及填充它们的 ICF 机制
- [RTTI / Vtable普查](../forensics/rtti-vtable-census.md) — 填充 A/F/G/I/N 类的中央层次结构的每插槽 ABI 遍历
- [每代函数调度程序](../forensics/per-gen-function-dispatcher.md) — 每代 vtable 系列(CycleTable、TpuCodec、7 个目标描述符)如何替换 `TpuVersion` 开关
- [多态入口点](../forensics/polymorphic-entry-points.md) — thunk/ICF转发层; 17,002 个重定位槽如何指向转发存根而不是方法主体
- [RTTI 命名空间普查](rtti-namespace-census.md) — 并行命名空间级 RTTI 细分(同级附录)
- [符号命名空间索引](symbol-namespace-index.md) — 每类第一符号分类基础的命名空间前缀索引(同级附录)