TpuConfigurationApi
本页所有地址均适用于来自
libtpu-0.0.40-cp314wheel 的libtpu.so(构建libtpu_lts_20260413_b_RC00,build-id md589edbbe81c5b328a958fe628a9f2207d,781,691,048 字节,ELF x86-64 DYN,未 stripped;IDA 恢复的 C 名称和反修饰后的 C++ 符号均按原文引用)。.textVMA 等于文件偏移。其他版本会不同。
摘要
TpuConfigurationApi_* 是分布式 TPU 宿主配置的 C-ABI 正面接口:它负责把一机架 TPU 芯片启动为一个可寻址的 pod,并负责宿主进程对该 pod 发出的查询。开源 TensorFlow tpu_configuration_ops kernel(ConfigureDistributedTPU、WaitForDistributedTPU、_InitializeHostForDistributedTPU、_SetGlobalTPUArray、_DisconnectHostFromDistributedTPUSystem)正是通过这个表面调用,方式与这些 kernel 调用 TpuExecutor_* 进行设备工作完全一样。TfTpu_Initialize Bootstrap 是进程内驱动初始化(单个节点加载 libtpu 驱动核心),而此集群是跨宿主 pod 配置:它协商全局 TPU 数组,等待每个宿主加入,并向运行时暴露每个宿主的容量。
从结构上看,该集群有两层。下层是一组 extern "C" 自由函数,即本页负责的 C-ABI 名册;每个函数都是薄桥,将扁平 op-args 结构解组为真实 C++ 调用,并把生成的 absl::Status 加输出数组重新编组出去。上层是这些桥委托到的 tensorflow:: 命名空间 C++ 自由函数(tensorflow::ConfigureDistributedTpu、tensorflow::WaitForDistributedTpu 等);它们承载真实 mesh 逻辑,由 runtime/pod 页面负责,不在这里负责。名册按领域清晰分为五个 *Op_DoWork 动作(configure / wait / init-host / set-global-array / disconnect)、三个 pod/cache 查询(HasTPUPodState、TpusPerHost、TpuMemoryLimit,以及 compilation-cache server-address 三件套)和两个数组释放辅助函数(FreeCharArray、FreeInt32Array)。
这是一个名册页面。它清点 C-ABI 函数、它们的实现符号 + 地址、每个 *Op_DoWork 读取的 op-args 布局,以及每个桥委托到的 C++ 入口。它不重新推导 ApiFn/不透明句柄 ABI 模型(由 The TfTpu C-API Shim负责)、驱动 bootstrap(由 TfTpu_Initialize Bootstrap负责)或 megascale collective bring-up(由 Megascale Bootstrap负责)。它负责 TpuConfigurationApi_* 名册和 distributed-pod-config 入口映射。
对于重新实现,契约是:
- 名册:约 13 个
extern "C"自由函数、它们的地址,以及每个函数桥接到哪个 C++ 入口。 - op-args ABI:每个
*Op_DoWork接收一个指向扁平结构的指针,其固定字节偏移保存输入(int32 数组 + 长度、string-view ptr + length、flags)和输出槽(status-cell ptr、*out_sizeptr、**out_arrayptr)。桥不拥有策略;它只复制字段、调用并写回。 - status/output-array 协议:每个动作都通过把
absl::status_internal::StatusRep*存入调用方拥有的 status cell 来返回其absl::Status(遵循 refcount 纪律),并发出一个堆分配的输出数组(int32[]或 NUL 结尾char[]),调用方必须通过FreeInt32Array/FreeCharArray释放。
源文件(按 .rodata) | learning/45eac/tfrc/executor/stream_executor/tpu_config_c_api.cc |
| 名册规模 | 约 13 个 extern "C" 自由函数(5 个动作、6 个查询、2 个释放辅助函数) |
| 动作地址块 | 0xe8cd400–0xe8cdb80(五个 *Op_DoWork) |
| 查询/释放地址块 | 0xe8cdbc0–0xe8cdf80(TpuConfigurationApi_*) |
| 到达方式 | ExecutorApiFn() 表(device-runtime 访问器)— 见 overview |
| 跨接缝状态类型 | 写入调用方 status cell 的 absl::status_internal::StatusRep* |
| 输出所有权 | callee 用 operator new / array new 分配;调用方通过 Free{Char,Int32}Array 释放 |
| 证据等级 | 已按 IDA 反编译逐字节确认;名册计数 CERTAIN |
范围 —
*ApiFn访问器/探测模型和不透明句柄(ToC/FromC/Destroy)约定在 The TfTpu C-API Shim 中;本页只记录搭载这些表的TpuConfigurationApi_*集群。对比 TfTpu_Initialize Bootstrap:那是单节点驱动初始化;这里是多宿主 pod 配置。
1. 名册
三个区域,一张表。“Impl symbol + address” 是 libtpu.so 中的 extern "C" 桥(IDA 恢复名称);“Bridges to” 是它委托到的 tensorflow:: C++ 自由函数。桥地址来自反编译符号地址后缀(_0xADDR.c);它们是精确的。
动作(*Op_DoWork)
| C-ABI 函数 | 地址 | 桥接到(tensorflow::) | 角色 |
|---|---|---|---|
ConfigureDistributedTpuOp_DoWork | 0xe8cd400 | ConfigureDistributedTpu(0xe975cc0) | 从此宿主的芯片列表协商全局 TPU mesh;发出序列化 pod topology |
WaitForDistributedTpuOp_DoWork | 0xe8cd640 | WaitForDistributedTpu(0xe9767c0) | 阻塞直到每个宿主的 per-core mapping 都到达;发出合并后的 mesh-common-state blob |
InitializeHostForDistributedTpuOp_DoWork | 0xe8cd9a0 | InitializeHostForDistributedTpu(0xe9771c0) | 将此宿主绑定进已配置 pod;发出本地 core-id int32 数组 |
SetGlobalTPUArrayOp_DoWork | 0xe8cda80 | SetGlobalTPUArray(0xe977880) | 把 pod-wide topology proto(字符串)安装进全局状态;仅 status |
DisconnectDistributedTpuChipsOp_DoWork | 0xe8cdb80 | DisconnectDistributedTpuChips(0xe977aa0) | 将宿主从 pod 中拆离;仅 status |
查询(pod state + compilation-cache server)
| C-ABI 函数 | 地址 | 桥接到(tensorflow::) | 角色 |
|---|---|---|---|
TpuConfigurationApi_HasTPUPodState | 0xe8cdca0 | HasTPUPodState(0xeaa17c0),经由 GetTPUConfigResourceMgr(0x10854020) | 谓词:config ResourceMgr 中是否注册了 pod-state resource? |
TpuConfigurationApi_TpusPerHost | 0xe8cdc00 | TpusPerHost(0xe9742a0) | Out-param int32:连接到此宿主的 TPU 芯片数 |
TpuConfigurationApi_TpuMemoryLimit | 0xe8cdc40 | TpuMemoryLimit(0xe974440) | Out-param int64(一个 tsl::gtl::IntType<Bytes_tag_>):每 core HBM 字节预算 |
TpuConfigurationApi_RemoteCompilationCacheSizeInBytes | 0xe8cdcc0 | 读取 FLAGS_tpu_remote_compilation_cache_size_bytes | Out-param int64:远程 compile-cache 最大大小;CHECK ptr 非空且值 >= 0 |
TpuConfigurationApi_CompilationCacheServerAddressFromConfig | 0xe8cdda0 | 解析 tensorflow::tpu::TPUHostConfiguration proto | 从序列化 TPUHostConfiguration 解码 compile-cache server 地址;发出 char[] |
TpuConfigurationApi_GetServerAddressAndPort | 0xe8cdf80 | GetServerAddressAndPort(0xe975a60) | 从 FLAGS_uberdriver_port + FLAGS_tpu_hostname_override 解析 compile-cache server host:port;发出 char[] |
释放辅助函数
| C-ABI 函数 | 地址 | 函数体 | 角色 |
|---|---|---|---|
TpuConfigurationApi_FreeCharArray | 0xe8cdbc0 | if (p) free(p); | 释放查询产生的 char[] |
TpuConfigurationApi_FreeInt32Array | 0xe8cdbe0 | if (p) free(p); | 释放动作产生的 int32[] |
注意 — 文件字符串
tpu_config_c_api.cc(可在RemoteCompilationCacheSizeInBytes的CHECK位置第 158 行和CompilationCacheServerAddressFromConfig错误位置第 175 行看到)确认所有三个三件套都位于一个翻译单元。*Op_DoWork符号在 IDA 中没有TpuConfigurationApi_前缀,但它们共享同一个源文件和相同的 op-args 桥接模式,因此这里把它们作为一个集群记录。陷阱 — 两个释放辅助函数是原始
free(),不是 array-delete。它们释放的数组由动作内部的operator new/operator new[]产生(例如InitializeHostForDistributedTpuOp_DoWork执行**(a1+48) = operator new(4*n)),然后作为普通指针交回。重新实现者必须用释放方式与free兼容的分配器(malloc-backedoperator new)来分配输出数组,并且不得运行析构函数:这些是 PODint32/char缓冲区。只通过这些辅助函数释放;绝不要delete[]它们。
2. Op-Args ABI
每个 *Op_DoWork 都接收一个指向扁平 op-args 结构的指针,开源 kernel 会在调用前填充它,并在调用后读取它。桥没有策略:它从固定偏移复制输入,调用 C++ 入口,然后把 status 和输出数组写回固定偏移。接缝上没有 C++ 类型,只有 args 指针、其中的 POD 标量,以及写入 status cell 的 StatusRep*。
ConfigureDistributedTpuOp_DoWork(0xe8cd400)
最丰富的布局。输入是此宿主的芯片坐标 int32 数组;输出是序列化 pod-topology 字节字符串。
// op-args struct read by ConfigureDistributedTpuOp_DoWork(a1)
struct ConfigureArgs {
/* +0 */ void* self; // op object (unused by bridge)
/* +16 */ uint64_t num_chips; // length of the int32 array (a1+16)
/* +24 */ int32_t* chip_array; // host chip coords (a1+24)
/* +32 */ int64_t arg3; // span/extra (>=0 guarded) (a1+32)
/* +40 */ void* arg4; // string_view-ish input (a1+40)
/* +48 */ uint64_t* out_size; // *out_size = topology length (a1+48)
/* +56 */ char** out_blob; // *out_blob = new char[size] (a1+56)
/* +64 */ StatusRep** status_cell; // result Status (a1+64)
};
function ConfigureDistributedTpuOp_DoWork(args): // sub_e8cd400
chips = copy_int32_array(args.chip_array, args.num_chips) // grows a vector, may realloc
status = tensorflow::ConfigureDistributedTpu( // 0xe975cc0
chips, args.num_chips, args.arg4, args.arg3, &out)
store_status(args.status_cell, status) // refcount discipline, §3
n = small_string_size(out)
*args.out_size = n
*args.out_blob = operator new(n)
memmove(*args.out_blob, small_string_data(out), n)
free_temporaries(chips, out)
```text
芯片数组复制循环(第 40–77 行)是手工内联的 `std::vector<int>` grow:它会把容量翻倍,防护 `0x3FFFFFFFFFFFFFFF` 元素计数上限,并在溢出时抛出 `vector<int>::__throw_length_error` / `__throw_bad_array_new_length`。输出 blob 处理(第 109–135 行)读取 small-string-optimization 判别位(`v25` 符号位),以选择返回 topology 字节的内联存储还是堆存储,即把标准 `absl`/`std::string` SSO 布局作为原始 `data`+`size` 跨过去。
### `WaitForDistributedTpuOp_DoWork`(`0xe8cd640`)
输入是一个 **2-D** 结构:每宿主 `int32` vector 的 vector(从每个宿主收集的 per-core mappings)。桥把它重建为 `vector<vector<int>>`,调用 `WaitForDistributedTpu`,并发出合并后的 mesh-common-state blob。
```c
// op-args struct read by WaitForDistributedTpuOp_DoWork(a1)
struct WaitArgs {
/* +16 (a1[2]) */ uint64_t num_hosts; // outer dimension
/* +24 (a1[3]) */ uint64_t cores_per_host;// inner dimension
/* +32 (a1[4]) */ int32_t** host_arrays; // num_hosts pointers to int32[]
/* +40 (a1[5]) */ void* mesh_state; // TpuMeshCommonState* (in/out)
/* +48 (a1[6]) */ uint64_t* out_size;
/* +56 (a1[7]) */ char** out_blob;
/* +64 (a1[8]) */ StatusRep** status_cell;
};
function WaitForDistributedTpuOp_DoWork(args): // sub_e8cd640
mappings = vector<vector<int>>(args.num_hosts) // __append reserves outer
for h in 0 .. num_hosts: // nested grow loops
for c in 0 .. cores_per_host:
mappings[h].push_back(args.host_arrays[h][c])
status = tensorflow::WaitForDistributedTpu( // 0xe9767c0
mappings.data, mappings.size, args.mesh_state, &out)
store_status(args.status_cell, status)
emit_char_blob(args.out_size, args.out_blob, out)
destroy(mappings) // frees every inner vector怪异点 — 内层循环的 trip count 在内层 body 每次迭代都会从
args.cores_per_host(v2[3])重新读取(第 117 行),而不是缓存一次。反编译显示当计数瞬时为零时有一个while (!v6)skip。重新实现者应把cores_per_host视为权威内层边界,但必须容忍运行时修改它:二进制选择防御性重读,而不是快照。
InitializeHostForDistributedTpuOp_DoWork(0xe8cd9a0)
两个字符串加两个 bool 输入;int32[] 输出(本地 core ids)。
// op-args struct read by InitializeHostForDistributedTpuOp_DoWork(a1)
struct InitHostArgs {
/* +16 */ int64_t tpu_topology_len; // (>=0 guarded)
/* +24 */ char* tpu_topology; // serialized topology string_view
/* +32 */ uint8_t enable_whole_mesh; // bool
/* +33 */ uint8_t is_master; // bool
/* +40 */ uint64_t* out_size; // # of core ids
/* +48 */ int32_t** out_core_ids; // *out = new int32[out_size]
/* +56 */ StatusRep** status_cell;
};
function InitializeHostForDistributedTpuOp_DoWork(args): // sub_e8cd9a0
status = tensorflow::InitializeHostForDistributedTpu( // 0xe9771c0
args.tpu_topology, args.tpu_topology_len,
args.enable_whole_mesh, args.is_master, &core_ids)
store_status(args.status_cell, status)
n = core_ids.size
*args.out_size = n
*args.out_core_ids = operator new(4 * n) // int32[n]
memmove(*args.out_core_ids, core_ids.data, 4 * n)
free(core_ids.data)
```text
### `SetGlobalTPUArrayOp_DoWork`(`0xe8cda80`)
纯 string-in / status-out 桥,显式进行 SSO-aware 字符串物化。
```c
function SetGlobalTPUArrayOp_DoWork(len, data, status_cell): // sub_e8cda80
// build a NUL-terminated std::string from (data, len), SSO for len <= 0x16
s = make_string(data, len)
status = tensorflow::SetGlobalTPUArray(s) // 0xe977880
store_status(status_cell, status)
if heap_allocated(s): free(s.data)注意 — 与其他动作不同,
SetGlobalTPUArray和DisconnectDistributedTpuChips把它们的 status cell 作为直接参数(a3/a2),而不是位于 op-args 结构的某个偏移处。它们不产生输出数组,只产生 status,因此签名更简单:分别是(len, data, StatusRep**)和(self, StatusRep*-cell)。status 协议(§3)相同。
DisconnectDistributedTpuChipsOp_DoWork(0xe8cdb80)
最薄的动作:一次委托调用加 status 存储。
function DisconnectDistributedTpuChipsOp_DoWork(self, status_cell): // sub_e8cdb80
status = tensorflow::DisconnectDistributedTpuChips(self, status_cell) // 0xe977aa0
store_status(status_cell, status) // in place at *status_cell
```text
---
## 3. Status 与输出数组协议
两个约定由集群中的每个函数共享,也是重新实现者最需要做到 bit-exact 的部分。
### Status:`StatusRep*` 写入调用方 cell,并遵守 refcount 纪律
`absl::Status` 作为单个指针 `absl::status_internal::StatusRep*` 跨越接缝。桥会用标准 `absl::Status` move/ref 协议把它写入调用方拥有的 cell;所有五个动作以及携带 status 的三个查询中,此模式完全相同:
```c
// store_status(cell, new_rep) — the inlined idiom in every bridge
function store_status(StatusRep** cell, StatusRep* new_rep):
old = *cell
if (new_rep != old):
*cell = new_rep
if ((old & 1) == 0): // low bit set => "inlined OK", nothing to unref
StatusRep::Unref(old)
else: // same rep: drop the extra reference we hold
if ((new_rep & 1) == 0):
StatusRep::Unref(new_rep)怪异点 —
StatusRep*的低位是标签,不是地址位。bit 0 置位的值是内联状态(OK sentinel 或小型内联 code),它不拥有堆StatusRep,绝不能Unref;每个分支在调用StatusRep::Unref前都会防护(ptr & 1) == 0。把 cell 当作普通指针并无条件 unref 的重新实现者会破坏 OK sentinel 的 refcount。GetServerAddressAndPort还显示了acquire 侧:当它存储一个借用的 rep 时,会先_InterlockedIncrementrefcount(第 96 行),证明 cell 会取得一个 owning reference。
输出数组:callee 分配,caller 释放
三个产生数组的函数(Configure、WaitFor、InitializeHost)和两个产生字符串的查询(CompilationCacheServerAddressFromConfig、GetServerAddressAndPort)遵循同一形态:把元素/字节计数写入 *out_size,用 operator new 分配缓冲区,复制进去,然后返回。调用方之后通过 FreeInt32Array(用于 int32[] 输出)或 FreeCharArray(用于 char[] 输出)释放它。对于字符串输出,分配大小是 out_size + 1,复制使用 strncpy,即发出的 char[] 以 NUL 结尾,且 out_size 不包含终止符(见 CompilationCacheServerAddressFromConfig 第 76–81 行、GetServerAddressAndPort 第 112–117 行)。
陷阱 —
int32[]输出按operator new(4 * n)定大小(字节数 =4 * element_count),但*out_size被设置为n(元素数),不是字节数。FreeInt32Array完全忽略 size(只是裸free(p)),所以这种不匹配对释放无害;但用out_size约束循环的重新实现者必须把它视为元素数,而计算原始new大小的一方必须乘以 4。
4. Distributed-Pod 配置入口映射
自上而下读取,该集群就是一个宿主在 TPU pod 内的生命周期。下面的映射为每个阶段列出调用进入的开源 op-kernel、C-ABI 桥,以及承载逻辑的 C++ 入口。
TF op kernel (open source) C-ABI bridge (this binary) C++ entry (this binary, runtime/pod owned)
───────────────────────────────── ───────────────────────────────────── ──────────────────────────────────────────
ConfigureDistributedTPU ──▶ ConfigureDistributedTpuOp_DoWork ──▶ tensorflow::ConfigureDistributedTpu 0xe975cc0
(0xe8cd400) └─ builds global mesh, emits topology blob
_SetGlobalTPUArray ──▶ SetGlobalTPUArrayOp_DoWork ──▶ tensorflow::SetGlobalTPUArray 0xe977880
(0xe8cda80) └─ installs pod-wide topology proto
_InitializeHostForDistributedTPU──▶ InitializeHostForDistributedTpuOp.. ──▶ tensorflow::InitializeHostForDistributedTpu 0xe9771c0
(0xe8cd9a0) └─ binds host, returns local core ids
WaitForDistributedTPU ──▶ WaitForDistributedTpuOp_DoWork ──▶ tensorflow::WaitForDistributedTpu 0xe9767c0
(0xe8cd640) └─ barrier across hosts, merges mesh state
[runtime queries, any time] ──▶ TpuConfigurationApi_HasTPUPodState ──▶ tensorflow::HasTPUPodState 0xeaa17c0
(0xe8cdca0) └─ via GetTPUConfigResourceMgr 0x10854020
──▶ TpuConfigurationApi_TpusPerHost ──▶ tensorflow::TpusPerHost 0xe9742a0
──▶ TpuConfigurationApi_TpuMemoryLimit ──▶ tensorflow::TpuMemoryLimit 0xe974440
_DisconnectHostFromDistributed.. ──▶ DisconnectDistributedTpuChipsOp.. ──▶ tensorflow::DisconnectDistributedTpuChips 0xe977aa0
(0xe8cdb80) └─ removes host from pod
```text
这个顺序是多宿主 launcher 复现的契约:一个宿主配置全局数组,每个宿主设置它并在本地初始化,所有宿主在 wait barrier rendezvous,随后运行时在整个 session 中查询 pod state 和 per-host capacity,最后任一宿主断开连接。compile-cache 三件套(`RemoteCompilationCacheSizeInBytes`、`CompilationCacheServerAddressFromConfig`、`GetServerAddressAndPort`)与 bring-up 序列正交:它解析*编译缓存服务器*所在位置,由 `FLAGS_tpu_remote_compilation_cache_size_bytes`、`FLAGS_uberdriver_port`、`FLAGS_tpu_hostname_override` 以及序列化 `tensorflow::tpu::TPUHostConfiguration` proto 驱动。
> **注意 —** `HasTPUPodState` 是唯一通过 resource manager 而不是直接自由函数的查询:桥首先调用 `tensorflow::GetTPUConfigResourceMgr`(`0x10854020`)获取 config `ResourceMgr`,然后调用 `tensorflow::HasTPUPodState(rmgr)`(`0xeaa17c0`)。pod-state 对象是在该 manager 中按 key 注册的 resource;“has pod state” 就是 “resource 存在”。这就是宿主区分 “pod already configured” 与 “fresh bring-up” 的方式。
>
> **怪异点 —** `RemoteCompilationCacheSizeInBytes` 不调用 `tensorflow::` 入口,而是读取一个进程全局。它首先在 out-pointer 为空时 `CHECK` 失败(`tpu_config_c_api.cc:158` 处的 LogMessageFatal),然后返回缓存值(初始化后为 `unk_2225C260`)或实时 flag `FLAGS_tpu_remote_compilation_cache_size_bytes`,并在结果为负时再次 `CHECK` 失败(`:161`)。这是一个有硬前置条件的查询,不是可返回 status 的可失败调用:其签名中没有 status cell。
---
## 相关组件
| 名称 | 关系 |
|---|---|
| `tensorflow::ConfigureDistributedTpu / WaitForDistributedTpu / InitializeHostForDistributedTpu / SetGlobalTPUArray / DisconnectDistributedTpuChips` | 五个 `*Op_DoWork` 桥委托到的 C++ 自由函数;承载 mesh 逻辑 |
| `tensorflow::GetTPUConfigResourceMgr` | 解析 `HasTPUPodState` 探测的 config `ResourceMgr` |
| `tensorflow::tpu::TPUHostConfiguration`(proto) | 由 `CompilationCacheServerAddressFromConfig` 解析,以提取缓存服务器地址 |
| `absl::status_internal::StatusRep` | refcounted status 对象,其指针跨接缝进入调用方 status cell |
| `ExecutorApiFn()` table | 到达这些 C-ABI 入口所经由的 device-runtime 函数指针结构 |
| `FLAGS_uberdriver_port / FLAGS_tpu_hostname_override / FLAGS_tpu_remote_compilation_cache_size_bytes` | compile-cache 查询读取的进程 flags |
## 交叉引用
- [The TfTpu C-API Shim](overview.md) — 此集群搭载的 `*ApiFn` 访问器模式和不透明句柄约定;列出九个集群中 `TpuConfigurationApi_*` 的名册映射
- [TfTpu_Initialize Bootstrap](../lifecycle/tftpu-initialize-bootstrap.md) — *进程内驱动*初始化;与本页的*跨宿主 pod*配置对比
- [Megascale Bootstrap](../megascale/bootstrap/overview.md) — 分层位于 pod 配置之上的 collective-runtime bring-up
- [TpuPlatform & TpuNodeContext](tpu-platform-and-topology.md) — `TpuPlatform::TpusPerHost` / `TpuMemoryLimit` 是这里同名查询的 SE-object-model sibling
- [TpuExecutor 名册](tpu-executor-roster.md) — 同一批 op kernel 为设备工作调用的 per-device runtime C-ABI 集群
- [back to index](../index.md) — Part III — Tpu C-Shim Layer