成本模型日志
地址适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so(BuildID md589edbbe81c5b328a958fe628a9f2207d)。该二进制文件未 strip — 下方每个符号都是解混淆后的 C++ 名称。.text/.rodataVMA == 文件偏移;.data.rel.roVMA - 0x200000 == 文件偏移。其他版本会不同。
摘要
xla_tpu_impure_cost_model_logging_options 是控制 TPU 编译器逐 op 成本模型是否把自身工作转储到编译日志中的唯一开关。它是一个带副作用的可观测性标志:开启它不会改变发出的程序,只会改变 JAX 用户在成本分析输出中看到的内容。这种 "impure" 性质正是它在类型系统中位于当前位置的原因。它的值类型是 AutoOr<CostModelLoggingOptions>,即一个双字段 bool proto,但不同于此构建中的其他 330 个 AutoOr 标志,它不是 TpuCompilationEnvironment (TCE) AutoProto 字段 — 它通过普通的 absl::GetFlag 路径读取,因此永远不会进入经哈希、缓存、可复现编译的表面。它是第 31 个 AutoOr 类型,也是唯一位于 0x12fc____ 段而不是 0x1d7_____ jellyfish 段中的类型。
熟悉 abseil flags 的读者应把它映射到 ABSL_FLAG(AutoOr<T>, …) 惯用法:AutoOr<T> 是三态(AUTO / present-T),FlagImpl+0x58 缓存当前值指针,而 GetFlag 会从该指针上掩掉 2 位 init-lock 标签。它与普通 flag 的差异在于 AutoOr 包装器(一个 cmpb $0,+0x28 has-byte 测试,用于选择 AUTO 还是已存储的子消息),以及这个特定 flag 的消费者是成本模型构建器,而不是 TCE resolver。本页覆盖三件事:(1) 以 CreateCostModelWindowSettingDelegator 为中心的 flag 存储→解析→消费→日志路径;(2) 两个布尔值实际上会让 OpCostManager 分析日志输出什么;(3) 启用日志后用于序列化和解析成本值的 UnparseFloatingPointVal / SimpleAtod 浮点文本语法 — 重新实现者必须完全匹配的边界 token(inf、nan、科学计数法、十六进制浮点)。
对重新实现而言,契约是:
CostModelLoggingOptions2-bool proto 布局,以及AutoOr<CostModelLoggingOptions>打包方式(present 字节、has 字节、子消息)。- 非 TCE 解析路径:内联的
FlagImpl+0x58/FlagImpl::ReadGetFlag惯用法,以及它为什么绕过 TCE AutoProto resolver 家族。 - 消费者接线:
CreateCostModelWindowSettingDelegator及其逐HloInstruction闭包,包括 field#2 双窗口成本门控。 enable_analysis_logging(field#1) 和log_codegen_and_non_codegen_window_costs_in_analysis(field#2) 会导致OpCostManager输出什么。- 浮点文本往返语法:
UnparseFloatingPointVal<T>最短%.*g渲染并重新解析验证,以及SimpleAtod/SimpleAtof摄入时的 inf/nan/hex/overflow 边界行为。
| Flag 对象 | FLAGS_xla_tpu_impure_cost_model_logging_options @ 0x22318950 |
| Flag 类型 | AutoOr<CostModelLoggingOptions>(第 31 个 AutoOr 类型;非 TCE) |
| FlagOps | FlagOps<AutoOr<CostModelLoggingOptions>> @ 0x12fc0e00 |
| 默认值生成器 | AbslFlagDefaultGenFor…::Gen @ 0x12fc1260 → AUTO |
| AbslUnparseFlag | xla::jellyfish::AbslUnparseFlag(AutoOr<…> const&) @ 0x12fd01a0 |
| 解析位置 | RunMemorySpaceAssignment @ 0x12fc3080(快速 0x12fc440b / 慢速 0x12fc46d3) |
| 消费者 | CreateCostModelWindowSettingDelegator @ 0x1304e100 |
| 消费者闭包 | 逐 HLO DelegationInfo 调用器 @ 0x1304ff00 |
| 窗口选择器 | ShouldUseCodegenWindows @ 0x130d3d40 |
| 日志表面 | OpCostManager::AnalysisLoggingColumns @ 0x1e474c00 / AnalysisLoggingLine @ 0x1e475d20 |
| 浮点 unparse | UnparseFloatingPointVal<float> @ 0x21113460 / <double> @ 0x211135a0 |
| 浮点摄入 | SimpleAtof @ 0x21171440 / SimpleAtod @ 0x21171580 |
CostModelLoggingOptions Proto
目的
CostModelLoggingOptions 是一个双字段、全 bool 的消息。它唯一的职责是在一个 AutoOr flag 中携带两个开关,用来控制成本模型日志的详细程度。schema 从生成的 _InternalSerialize 和 TcParseTable 中恢复;两个字段名(enable_analysis_logging、log_codegen_and_non_codegen_window_costs_in_analysis)都作为 .rodata 描述符字符串逐字出现。
// xla::jellyfish::CostModelLoggingOptions
message CostModelLoggingOptions {
optional bool enable_analysis_logging = 1; // value byte @ +0x18
optional bool log_codegen_and_non_codegen_window_costs_in_analysis = 2; // value byte @ +0x19
}
// InternalMetadata @ +0x08 ; has-bits uint32 @ +0x10 (bit0=field#1, bit1=field#2)
```text
### 编码
字节布局已由 `CostModelLoggingOptions::_InternalSerialize` @ `0x1db24760` 确认。生成代码读取 `*((DWORD*)this + 4)`(偏移 `+0x10`)处的 has-bits word,然后对 field#1(wire tag `0x08`)发出 `this+24`(`+0x18`)处的字节,对 field#2(wire tag `0x10`)发出 `this+25`(`+0x19`)处的字节:
```c
function _InternalSerialize(this, out): // sub_1DB24760
hasbits = *(u32*)(this + 0x10)
if (hasbits & 1) && *(u8*)(this + 0x18) == 1: // field#1 set & true
emit 0x08, *(u8*)(this + 0x18) // tag, value
if (hasbits & 2) && *(u8*)(this + 0x19) == 1: // field#2 set & true
emit 0x10, *(u8*)(this + 0x19) // tag, valueTcParseTable _table_ @ 0x21cfa1e8(大小 0x78)以 has_bits_offset 0x10(第一个 dword)开头 — 除了这两个布尔字段之外没有其他字段。Clear 位于 0x1db24740。
注意 — 这两个布尔值是独立的可观测性级别,而不是计数。Field#1 (
enable_analysis_logging) 打开逐 op 成本转储。Field#2 (log_codegen_and_non_codegen_window_costs_in_analysis) 是一个拓宽器:它让转储同时输出 codegen-window 和 good-enough-window 两种成本变体,使逐 op 的窗口策略差异可见。除非 field#1 也被设置,否则 field#2 没有效果 — 见消费者闭包。
AutoOr 存储和非 TCE 解析路径
目的
该 flag 将其值存储为 AutoOr<CostModelLoggingOptions> — 一个三态包装器,要么是 AUTO 哨兵,要么是一个 present 的 CostModelLoggingOptions。让这个 flag 在结构上独特的是它的解析方式:通过普通 abseil GetFlag 惯用法(FlagImpl+0x58 缓存指针),而不是通过 AutoOr<T>::FromProtoOrDie TCE resolver。二进制中没有 AutoOr<CostModelLoggingOptions>::FromProtoOrDie,也没有 AutoOrTypeTraits<CostModelLoggingOptions>::FromAutoProto 符号 — 330 个 TCE AutoProto 字段所使用的整个 FromProto resolver 家族对该类型都不存在。这种缺失就是 "impure" flag 的二进制指纹。
AutoOr 布局
AutoOr<message> 布局直接从 AbslUnparseFlag @ 0x12fd01a0 读取,该函数基于 has-byte 做门控并复制变体:
| 字段 | 偏移 | 含义 |
|---|---|---|
| 子消息体 | +0x00 | 嵌入的 CostModelLoggingOptions(或 const Msg* 变体) |
| variant index | +0x20 | variant<Msg, const Msg*> 判别器 |
| has byte | +0x28 | 0 => AUTO / 默认;非零 => present message |
默认值生成器确认了 AUTO:
function AbslFlagDefaultGenFor…::Gen(this): // sub_12FC1260
*(u8*)(this + 0x00) = 0 // present/body byte
*(u8*)(this + 0x28) = 0 // has byte = 0 ⇒ AUTO
```text
### 解析算法
`RunMemorySpaceAssignment` @ `0x12fc3080`(`BuildOpCostManager` 调用者)在 `0x12fc440b` 以内联方式读取 flag,使用规范的 `GetFlag(FLAGS_…)` 序列:
```c
function ResolveCostModelLoggingOptions(): // inline @ 0x12fc440b
p = *(void**)(FLAGS_…cost_model_logging_options + 0x58) // FlagImpl+0x58 cached ptr
if (p & 3) != 0: // 2-bit absl init-lock tag set
goto slow // 0x12fc46d3: FlagImpl::Read @0x21111940
autoor = (AutoOr<CostModelLoggingOptions>*)(p & ~3) // mask tag bits
if *(u8*)(autoor + 0x28) == 0: // has byte == 0
return AUTO/empty default // use the default-instance
idx = *(u8*)(autoor + 0x20) // variant index @ +0x20
return copy_sub_message(autoor) // pass to delegator builder0x12fc46d3 处的慢路径调用 absl::flags_internal::FlagImpl::Read(void*) @ 0x21111940(懒惰 first-touch 初始化器)。这是普通的 abseil 模式;唯一的 AutoOr 特有部分是 cmpb $0,+0x28 has-byte 测试和 +0x20 变体复制。
怪癖 — 这个 flag 的类型是
AutoOr,但不存在于 1121 字段的TpuCompilationEnvironment::_table_(@0x21cfa9e0)中。此构建中的其他每个AutoOrflag(330 个)都是通过FromProtoOrDie解析的 TCE AutoProto 字段。假设“所有AutoOrflags 都是 TCE 字段”的重新实现者会寻找一个并不存在的 resolver。xla_tpu_impure_*前缀标记了有意排除在经哈希/缓存的确定性 TCE 表面之外的 flag,因为它们改变的是编译器可观测性,而不是编译结果。
Unparse — AUTO -> "auto"
AbslUnparseFlag(AutoOr<CostModelLoggingOptions> const&) @ 0x12fd01a0 是往返的 OUT 半边。如果 has-byte(+0x28)被设置,它会分派到 proto2::Message::AbslUnparseFlagImpl(TextFormat,带 text:/serialized:/base64: fallback);否则,它会从一个懒惰静态 absl::NoDestructor<std::string> 构造字面量 "auto",该静态对象通过 __cxa_guard + PlacementImpl 从所有 AutoOr unparse 实例共享的 "auto" 源字面量构造一次:
function AbslUnparseFlag(out, autoor): // sub_12FD01A0
if *(u8*)(autoor + 0x28): // has byte set
return Message::AbslUnparseFlagImpl(out, …) // text:/serialized:/base64:
once: AutoFlagValue = NoDestructor<string>("auto") // __cxa_guard-guarded
return copy(out, AutoFlagValue) // "auto"
```text
### 函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
| `FlagOps<AutoOr<CostModelLoggingOptions>>` | `0x12fc0e00` | flag 存储 TypeId(FlagImpl `+0x20`) |
| `AbslFlagDefaultGenFor…::Gen` | `0x12fc1260` | 设置 present `+0x00`=0、has `+0x28`=0 → AUTO |
| `AbslUnparseFlag(AutoOr<…>)` | `0x12fd01a0` | AUTO→`"auto"`,present→TextFormat |
| `RunMemorySpaceAssignment` | `0x12fc3080` | 解析位置(快速 `0x12fc440b` / 慢速 `0x12fc46d3`) |
| `FlagImpl::Read` | `0x21111940` | 懒惰 first-touch 慢路径初始化器 |
---
## 消费者 — CreateCostModelWindowSettingDelegator
### 目的
解析后的 `CostModelLoggingOptions` 由 `CreateCostModelWindowSettingDelegator` @ `0x1304e100` 消费。它构造一个名为 `"CostModelWindowSettingDelegator"` 的 `OpCostManager::CalculationNode`,逐 HLO instruction 决定应计入哪一种窗口成本策略 — 并且在启用日志时同时计入*两者*,从而让分析转储展示差异。
### 签名和捕获
函数签名(由解混淆符号确认)是:
```c
CreateCostModelWindowSettingDelegator(
string_view name,
CostModelFlagOptions const& flag_opts,
CostModelLoggingOptions const& log_opts, // the resolved AutoOr value
unique_ptr<CalculationNode> codegen_node, // "CostModelWithCodegenWindows"
unique_ptr<CalculationNode> good_enough_node) // "CostModelWithGoodEnoughWindows"它构造一个 AnyInvocable 闭包,按值捕获 CostModelFlagOptions(捕获 +0x00)和 CostModelLoggingOptions(捕获子对象 +0x48,因此 field#2 在 msg+0x19 处的字节落在捕获 +0x61),以及两个子 calculation node。两个子节点名称字符串是 "CostModelWithCodegenWindows" 和 "CostModelWithGoodEnoughWindows";delegator 节点名是 "CostModelWindowSettingDelegator";它路由的叶子成本源是 "TpuHloCostAnalysis" — 见 TpuHloCostAnalysis。
消费者闭包(逐 HLO) {#the-consumer-closure-per-hlo}
逐 HloInstruction 调用器 @ 0x1304ff00 是一个 RemoteInvoker,返回 CalculationNode::DelegationInfo,并接受 (HloInstruction const&, bool)。该 bool 是一个“是否为 analysis-logging pass”的标志 — 它与 field#2 组合后触发双重 push。下方的 cap 是 lambda 捕获结构(其第一个 qword 被加载到 v7 = *a2):cap+0x00 是 CostModelFlagOptions,cap+0x48 是 CostModelLoggingOptions,cap+0x68/cap+0x70 是两个捕获的子 CalculationNode 指针。result 是返回的 DelegationInfo,在 result+0x00(codegen)和 result+0x18(good-enough)处有两个 vector<uint64>。反编译体:
function WindowSettingClosure(cap, hlo, is_logging_pass): // sub_1304FF00
result = {} // zero two slot vectors @ +0x00,+0x18
if ShouldUseCodegenWindows(hlo, cap.flag_opts): // sub_130D3D40
result.codegen.push_back(cap + 0x68) // charge codegen node ptr
if !is_logging_pass: return result
if *(u8*)(cap + 0x61) == 0: return result // field#2 clear (cap+0x48 +0x19)
result.good_enough.push_back(cap + 0x70) // ALSO charge good-enough node ptr
else:
result.codegen.push_back(cap + 0x70) // charge good-enough node ptr
if is_logging_pass && *(u8*)(cap + 0x61):
result.good_enough.push_back(cap + 0x68) // ALSO charge codegen node ptr
return result
```text
> **陷阱 —** 反编译器把 `cap+0x68`、`cap+0x70` 和 field#2 字节 `cap+0x61` 都渲染为相对于同一基址寄存器(`v7`),这会让两个 `push_back` 参数看起来像是从 `HloInstruction` 读取。它们并不是:`v7` 是*捕获*结构,`+0x68`/`+0x70` 是被推入结果向量(`_RDI` 和 `_RDI+3`)的两个捕获子节点指针,`+0x61` 是捕获的 `CostModelLoggingOptions` 内部的 field#2(捕获 `+0x48` + 消息字节 `+0x19` = `+0x61`)。`HloInstruction&` 作为转发参数传入,并被直接传给 `ShouldUseCodegenWindows`。捕获布局由 `CreateCostModelWindowSettingDelegator` @ `0x1304e100` 固定,它对捕获执行 `operator new(0x78)`,并把 `CostModelFlagOptions` 复制到 `+0x00`、`CostModelLoggingOptions` 复制到 `+0x48`、子指针复制到 `+0x68`。
净行为:field#2 清除时,每个 op 只计入一种窗口成本变体(由 `ShouldUseCodegenWindows` 选择的那一种)。field#2 设置**且** logging pass 活跃时,两种变体都会被计入,因此分析日志可以打印逐 op 的 codegen-vs-good-enough 成本差异。
### 窗口选择器 — ShouldUseCodegenWindows
`ShouldUseCodegenWindows` @ `0x130d3d40` 决定资格。它从 `CostModelFlagOptions` 读取一个 repeated fusion-window enum 列表(指针/计数在 `+0x30` 附近),并对每个 enum 值按 HLO fusion kind 走 jump-table:
```c
function ShouldUseCodegenWindows(hlo, flag_opts): // sub_130D3D40
if (hlo.flags & 1) == 0: return false // not a fusion
list = flag_opts.window_kinds_ptr; n = flag_opts.window_kinds_count
for kind in list[0..n]:
switch kind:
case 0: return true // sentinel/terminator
case 1: if hlo.IsOutputFusion(): return true // @0x1e5a2fc0
case 2: if fusion_util::IsConvLowerable(hlo): return true // @0x14553620
case 3: if hlo.IsLoopFusion(): return true // @0x1e5a2fa0
return falseNeverUseCodegenWindows @ 0x130d3e80 是取反/覆盖的 sibling,也从 BuildOpCostManager 调用。
函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
CreateCostModelWindowSettingDelegator | 0x1304e100 | 构建 delegator 节点;按值捕获 CostModelLoggingOptions |
window-setting closure (RemoteInvoker) | 0x1304ff00 | 逐 HLO DelegationInfo;field#2 (+0x61) 门控双重计费 |
ShouldUseCodegenWindows | 0x130d3d40 | codegen-window 资格(fusion-kind jump-table) |
NeverUseCodegenWindows | 0x130d3e80 | 取反/覆盖 sibling |
CostModelLoggingOptions ctor (capture) | 0x1db24640 | 将消息复制到捕获 +0x48 |
会记录什么
Field#1 — enable_analysis_logging
设置 field#1 时,成本模型运行会通过两个 OpCostManager 方法发出一个逐 op 表格转储:
OpCostManager::AnalysisLoggingColumns() const@0x1e474c00— 发出表头行(列标签:cost-metric IDs)。OpCostManager::AnalysisLoggingLine(CostMetricId const&, CalculationNode::Result const&) const@0x1e475d20— 每个(cost metric, HLO op)发出一行,读取每个 calculation node 产生的Result。
因此 field#1 的可观测副作用是:对每个 HLO op,把每个 calculation node(TpuHloCostAnalysis、codegen-window 节点、good-enough-window 节点)产生的成本值转储到编译日志。发出的代码不会改变 — 这是纯粹的编译期可观测性。
Field#2 — log_codegen_and_non_codegen_window_costs_in_analysis
Field#2 会拓宽这些行。如消费者闭包所示,它让 window-setting delegator 在分析 pass 中同时计入 codegen-window 和 good-enough-window 成本,因此每个日志行都携带两种变体,逐 op 的 codegen-vs-good-enough 差异可见。
注意 — field#1 锁存到逐 pass “发出
AnalysisLoggingColumns/Line” 决策中的确切OpCostManager成员偏移此处没有固定下来(delegator 捕获整个消息;门控日志发出的 field#1 读取点位于OpCostManagermetric-value / compute 路径中,即GetMetricValue@0x1e475160/ComputeSeconds@0x1e475a40)。Field#1 启用转储,field#2 扩宽转储;精确的 latch 偏移是这里唯一未闭合的接缝。
函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
OpCostManager::AnalysisLoggingColumns | 0x1e474c00 | 表头行(列标签) |
OpCostManager::AnalysisLoggingLine | 0x1e475d20 | 每个 (metric, HLO) 一行 |
OpCostManager::GetMetricValue | 0x1e475160 | metric 读取路径(field#1 latch — 未追踪) |
OpCostManager::ComputeSeconds | 0x1e475a40 | 逐 op seconds 计算(未追踪) |
浮点文本语法
记录的成本值是 float 和 double,它们会两次跨越文本边界:由 UnparseFloatingPointVal<T> 序列化输出,再由 SimpleAtof/SimpleAtod 解析回来。这与任何 AutoOr<float>/AutoOr<double> knob 使用的是同一种 float-flag 语法,而其边界 token(inf、nan、科学计数法、十六进制浮点)正是天真的重新实现会产生分歧的地方。
Unparse — 最短往返 %.*g
UnparseFloatingPointVal<float> @ 0x21113460 和 <double> @ 0x211135a0 会渲染出重新解析后得到完全相同 bit pattern 的最短十进制。算法是先尝试低精度、再验证、再提升:
function UnparseFloatingPointVal<float>(value): // sub_21113460
s = FormatPack("%.*g", 6, value) // 6 sig-figs (try short)
if (bits(value) & 0x7FFFFFFF) >= 0x7F800000: // exponent all-ones = inf/nan
return s // accept libc %g "inf"/"-inf"/"nan", SKIP verify
if SimpleAtof(s, &v) && v == value: // vucomiss exact reparse check
return s // 6 sig-figs reparses exactly
return FormatPack("%.*g", 9, value) // FLT_DECIMAL_DIG = 9, guaranteed exact
```text
`<double>` 相同,只是精度为 15 然后 17(`DBL_DECIMAL_DIG = 17`),inf/nan 测试为 `bits & 0x7FFFFFFFFFFFFFFF >= 0x7FF0000000000000`,并用 `SimpleAtod` + `vucomisd` 做重新解析验证。
> **怪癖 —** 精度常量是从反汇编中逐字节走读得到的:float 路径在 `0x21113474` 处为短尝试具现化 `movq $0x6,-0x68(%rbp)`,在 `0x2111352b` 处为 fallback 具现化 `movq $0x9,-0x68(%rbp)`;double 路径具现化 `$0xf` (15) @ `0x211135b4` 和 `$0x11` (17) @ `0x2111367d`。反编译 C 把精度渲染成字面量 `4`,因为这个 `4` 是传给 `FormatPack` 的 `mov $0x4,%edx` *参数数量*,不是 `%.*g` 精度 — 精度被放在栈上 `-0x68` 处的 format-arg pack 中,而反编译器把它折叠掉了。应信任反汇编的 `0x6`/`0x9` 和 `0xf`/`0x11`,而不是渲染出的 `4`。
结果是:如果一个 `float` 的最近 6 位十进制已经能精确重新解析(例如存储的 `1.10000002f`,其最短拼写是 `1.1`),它会打印 `"1.1"`。需要全部 9 位的值会 fallback 到 9 位有效数字。没有尾随零噪声;使用规范的 `%g` 拼写,而 `inf`/`-inf`/`nan` 会通过 exponent-all-ones 绕过路径直接从 libc `%g` 发出,不尝试重新解析。
### 摄入 — SimpleAtof / SimpleAtod
`SimpleAtof` @ `0x21171440` 和 `SimpleAtod` @ `0x21171580` 将 string-view 解析为 float/double。`SimpleAtod` 的反编译确认了四阶段语法:
```c
function SimpleAtod(begin, end, out): // sub_21171580
*out = 0
strip leading ws while kPropertyBits[c] & 8 // table @ 0xbe7fb70, bit 0x8 = whitespace
strip trailing ws while kPropertyBits[c] & 8
if empty: return false // nothing left
if *p == '+': // bare-sign guard
if length==1 || p[1]=='-': return false
p++ // skip the '+'
q = from_chars(p, end, out, /*fmt=*/3) // @0x2116a340, chars_format = general (3)
if errc(q) == 22 || q.ptr != end: // 22 = invalid_argument; or trailing garbage
return false
if errc(q) == 34: // 34 = result_out_of_range (overflow)
clamp *out to ±inf // sign via vucomisd vs ±1.0 constants
return true // full-consume, value (or clamped inf) storedfrom_chars 使用 chars_format = 3 = scientific | fixed(general 格式)调用。hex bit(0x4)未设置,因此 from_chars 内部的 hex-float 分支(test $0x4,%cl @ 0x2116a373/0x2116a380)永远不会被走到:0x/0X 前缀会导致解析失败,而不是被当成十六进制解析。
陷阱 — 两个
errc码很容易调换。errc(q) == 22是std::errc::invalid_argument— 硬拒绝(函数返回false)。errc(q) == 34是std::errc::result_out_of_range— 溢出情形,会被接受:*out被夹到±inf(符号通过针对qword_A2DF230/qword_A2DE728处±1.0常量的vucomisd选择),函数返回true。SimpleAtod@0x21171580和SimpleAtof@0x21171440共享这个完全相同的!=22 && ptr==end、然后==34结构。
边界 Token 表
任何 float/double AutoOr knob 值可接受/拒绝的 token 集(确切的 inf/nan 关键字拼写集合取决于 abseil 的 from_chars 关键字路径接受什么):
| Token | 摄入 | Unparse 渲染 |
|---|---|---|
auto | AUTO 哨兵 | "auto" |
1.5 / -0.25 | OK(general) | 最短 %g(6/15 然后 9/17 位有效数字) |
1e9 / 1E-3 | OK(scientific) | 最短 %g |
inf / -inf / Infinity | OK → ±inf | "inf" / "-inf" |
nan / NAN / nan(0x1) | OK → nan(payload) | "nan" |
overflow(例如 1e400) | OK → CLAMP 到 ±inf | "inf" / "-inf" |
0x1.8p3 / 0x10(hex-float) | REJECT(fmt 没有 hex bit) | n/a(从不存储) |
"" / "+" / "-" / " " | REJECT(空 / 裸符号) | n/a |
| leading/trailing whitespace | 被剥离(kPropertyBits & 0x8) | n/a |
陷阱 — float/double AutoOr knobs 接受
inf/nan,并把溢出夹到 ±inf,但拒绝十六进制浮点 — 不同于整数 AutoOr knobs,后者通过safe_strto*_base接受0x基数。把所有 numeric knobs 都路由到一个解析器的重新实现者,会错误地把0x10作为 float knob 的16.0接受。还要注意整数侧的基数不对称:int knobs 摄入 hex,但始终以十进制 unparse。float unparse 从不产生基数歧义(始终是%g十进制)。
函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
UnparseFloatingPointVal<float> | 0x21113460 | 最短 %.*g 6→9,inf/nan 绕过,重新解析验证 |
UnparseFloatingPointVal<double> | 0x211135a0 | 最短 %.*g 15→17,inf/nan 绕过 |
SimpleAtof | 0x21171440 | WS-strip + sign-guard + from_chars(fmt=3) float |
SimpleAtod | 0x21171580 | WS-strip + sign-guard + from_chars(fmt=3) double |
from_chars (float) | 0x2116ada0 | general 格式;hex bit 清除;±inf clamp 常量 |
from_chars (double) | 0x2116a340 | general 格式;nan@plt 关键字路径 |
kPropertyBits | 0xbe7fb70 | ASCII 属性表;bit 0x8 = whitespace |
Sibling 非 TCE AutoOr Flags
xla_tpu_impure_cost_model_logging_options 是恰好五个不是 TCE AutoProto 字段的 AutoOr 类型 flag 之一。其他四个共享“通过 GetFlag 读取,而不是通过 TCE resolver 读取”的性质。这里列出它们,是因为枚举 AutoOr flag 表面的重新实现者必须将它们纳入考虑 — 完美的 330 ↔ 330 AutoOr ↔ AutoProto 恒等关系恰好有这五个残余项。
| Flag | FlagOps | 内部类型 | 默认值 | 消费者 |
|---|---|---|---|---|
xla_tpu_impure_cost_model_logging_options | 0x12fc0e00 | CostModelLoggingOptions | AUTO | CreateCostModelWindowSettingDelegator @ 0x1304e100 |
xla_tpu_impure_use_iteration_mask | 0x1d6b5840 | bool | AUTO (=ON) | ShouldUseIterationMask @ 0x1d6b5dc0 |
xla_tpu_comparison_mode_target_module_regex | 0x1d700400 | string | AUTO | EnableComparisonMode @ 0x1d6b8ec0(RE2 vs module name) |
xla_tpu_enable_lem_scheduler | 0x1d6b5840 | bool | AUTO | registry-mediated(无直接 FLAGS_ xref) |
xla_tpu_explicit_evict_memory_limit_kib | 0x1d700120 | int64 | AUTO | registry-mediated(无直接 FLAGS_ xref) |
注意 —
xla_tpu_impure_use_iteration_mask的极性是 AUTO=ON:它的消费者读取FlagImpl+0x58,执行and $0x101 ; cmp $0x100 ; setne— 除非用户显式设置=false,否则为 true,并且还会由 TC version ≥ 3 门控。enable_lem_scheduler和explicit_evict_memory_limit_kib在.text中没有直接lea FLAGS_…引用;它们的有效读取通过某个内联GetFlag<T>路径经由 absl flag registry 进行,静态 FLAGS_ 地址扫描无法定位。
相关组件
| 组件 | 关系 |
|---|---|
| TpuHloCostAnalysis | delegator 路由的叶子成本源("TpuHloCostAnalysis");它的 float costs 就是日志语法序列化的内容 |
| 成本模型概览 | 逐代成本模型架构,其 OpCostManager 运行被记录的 calculation-node 树 |
| 学习型成本模型客户端 | sibling AutoOr<message> 成本模型 knob(EmitterLearnedCostModelOptions);为什么发布的模型是数据表驱动 |
| Resource Enum(23 槽) | 成本值最终归约到的 ResourceVector 模型 |
交叉引用
- TpuHloCostAnalysis — field#1 设置时被转储的 HLO 成本叶子,其 flop/byte/transcendental floats 会被输出
- 成本模型概览 — 三家族成本模型架构,以及承载 delegator 节点的
OpCostManager - 学习型成本模型客户端 — 另一个非默认
AutoOr<message>成本 knob,以及 data-table-vs-ML 状态 - Resource Enum(23 槽) — 计算已记录逐 op 成本所依据的 resource-cycle 模型
- AutoOr Unparse — 完整
AbslUnparseFlag<AutoOr<T>>家族,本浮点 unparse 是其中一支 - AutoOr Parse Grammar —
ParseAutoOrFromString摄入分派器和 AUTO 哨兵 - Registry-Mediated Flags —
enable_lem_scheduler/explicit_evict_memory_limit_kibsibling 非 TCE flags - Flag Families —
xla_tpu_impure_*可观测性 flag 类,以及 TCE-vs-non-TCE 存储拆分