Skip to content

TfTpu_Initialize Bootstrap

本页上的所有地址都适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build libtpu_lts_20260413_b_RC00,build-id md5 89edbbe81c5b328a958fe628a9f2207d,781,691,048 字节,ELF x86-64 DYN,未 strip;反混淆后的 C++ 符号按原文引用)。其他版本会有所不同。

摘要

PJRT_Plugin_Initialize(PJRT slot 8)是框架侧需要按下的唯一按钮,但它触发的工作是 TPU driver bootstrap:解析 flag 字符串、获取跨进程锁,并运行 Google module-init DAG,最终执行那些 dlopen 时构造函数风暴只记录下来的 HAL/platform 注册。这个 bootstrap 是一条短而明确的调用链:TryAcquireTpuLockGetLibTpuInitArgumentsInitializeDriverInitGoogleExceptChangeRootAndUserRealInitGoogleGoogleInitializer::RunInitializers;它完全幂等:InitializeDriver 内部单个函数静态 has_initialized 字节会让第一次之后的每次调用都成为 no-op。本页负责说明这条链。PJRT 侧 gate(struct_size 兼容性检查、kPjRtCApiTpuInitType selector、error-wrapper boxing)见 module-init-plugin-discovery.md §3,这里只做概要;本页新增的是 InitializeDriver内部、option ingest 的内部,以及 TfTpu_*ApiFn() C-API 函数指针表的角色。

对重实现者来说,决定性的结构事实是:不存在一个单一的 TfTpu_Initialize orchestrator 在一个函数体里构建 runtimeTfTpu_Initialize 这个名字确实是一个真实导出的 C 符号,位于 0xe6f54a0,导出为 @@VERS_1.0,10 字节,但它只是一个两条指令的 tail-shim,直接转发到 tpu::driver::InitializeDriver @ 0x204cecc0;二进制实际通过 PJRT 路径(PJRT_Plugin_Initialize)到达 InitializeDriver,而不是通过 TfTpu_InitializeInitializeDriver 本身只做三件事:把默认 Cloud-TPU flags 合入 argv,把该 argv 交给 Google 的 InitGoogle flag-parse-and-run-modules 机制,并注册少量 telemetry gauges。所有对顺序敏感的事情都发生在 RunInitializers 内部,按拓扑依赖顺序执行,并与 C++ static-init 顺序解耦。这是经典的 Google base/init_google 模式:加载时注册,首次 init 时运行。

第三个主题,即 TfTpu_*ApiFn() 表,是 bootstrap 对 runtime 其余部分重要的原因。除 PJRT 外,libtpu 还携带一个第二套更老的 C-ABI surface:StreamExecutor TPU shim,它通过原始 C 函数指针结构体分发(stream_executor::tpu::ExecutorApiFn()OpsApiFn()ProfilerApiFn())。每个 accessor 都是一个 leak-on-exit Meyers singleton,持有 TfTpu_*Fn 名册。bootstrap 的 RunInitializers 会运行 RegisterTpuPlatform;该函数会读取 ExecutorApiFn()(经由 IsStreamExecutorEnabled),并且如果表的第一个 slot 非空,就在 PJRT 下安装 StreamExecutor TpuPlatform。因此 bootstrap 正是两套 C-ABI surface 被接线到一起的时刻。

对重实现来说,契约是:

  • InitializeDriver 函数体has_initialized once-guard、"./tpu_driver" 合成 argv[0]AppendNewCloudTPUArgsvector<string>char** argv 物化、InitGoogleExceptChangeRootAndUser(name="N/A", &argc, &argv, change_root=0) 调用,以及四个 telemetry 注册。
  • option ingestGetLibTpuInitArguments 读取 env LIBTPU_INIT_ARGS,按空格拆分,构建 vector<string> 再构建 vector<char const*>RealInitGoogle 通过 ParseCommandLineNonHelpFlags 消费它(--xla_* / TPU_* absl-flag 解析),这些 flag 由 dlopen 构造函数风暴预注册。
  • ApiFn 表:三个 stream_executor::tpu::*ApiFn() Meyers singletons,以及在 DAG 运行期间 gate StreamExecutor TpuPlatform 安装的 IsStreamExecutorEnabled / IsInitialized slot-0 探测。
Bootstrap gatepjrt::tpu_plugin::PJRT_Plugin_Initialize @ 0xe6a9d00(303 B),PJRT slot 8
Driver bring-uptpu::driver::InitializeDriver @ 0x204cecc0(1764 B)
TfTpu_Initialize 符号@ 0xe6f54a0(10 B,@@VERS_1.0)— 2 指令 tail-shim → InitializeDriver(备用入口,不是 PJRT 路径)
Option ingesttensorflow::tpu::GetLibTpuInitArguments @ 0x20ccca20(851 B),env LIBTPU_INIT_ARGS
Lock gatetensorflow::tpu::TryAcquireTpuLock @ 0x20ccbc40(3531 B),env TPU_LOAD_LIBRARY
Flag parse + DAG runRealInitGoogle @ 0x210ae860ParseCommandLineNonHelpFlags + GoogleInitializer::RunInitializers @ 0x210b2d20
幂等 guardInitializeDriver::has_initialized(函数静态字节 @ 0x225899e0.bss
Init-type selectorkPjRtCApiTpuInitType(静态 = 2@ 0x22255b40.data
ApiFn 表ExecutorApiFn @ 0x20819360OpsApiFn @ 0x10900e80ProfilerApiFn @ 0x10900ea0(Meyers singletons)
置信度CONFIRMED(byte-anchored vs decompile),除非某行或 callout 另有说明

1. 进入 InitializeDriver 的两个入口

目的

tpu::driver::InitializeDriver @ 0x204cecc0 是实际的 driver bootstrap 函数体。有两个不同的调用方会到达它;重实现者必须理解它们是进入同一个幂等函数的并行入口,而不是分层调用栈。

入口点

text
PATH A — the PJRT path (the one the framework drives)
  PJRT_Plugin_Initialize  0xe6a9d00  (slot 8)
    ├─ ActualStructSizeIsGreaterOrEqual("PJRT_Plugin_Initialize_Args", 27, 16, args->struct_size)
    ├─ if kPjRtCApiTpuInitType != 0:                       (statically 2)
    │    ├─ TryAcquireTpuLock("PJRT_Plugin_Initialize_Args")   0x20ccbc40  ── env TPU_LOAD_LIBRARY
    │    ├─ GetLibTpuInitArguments(&argv_vec)                  0x20ccca20  ── env LIBTPU_INIT_ARGS
    │    └─ InitializeDriver(flag=1, argc, argv,
    │                        init_type_is_2 = (kPjRtCApiTpuInitType == 2))   0x204cecc0
    └─ else: return NULL  (init-type 0 → no-op)

PATH B — the TfTpu_Initialize alternate entry
  TfTpu_Initialize  0xe6f54a0   (10 B, 2 instructions)
    mov $0x1, %ecx                                            (hardcodes 4th arg init_type_is_2 = true)
    jmp tpu::driver::InitializeDriver                         0x204cecc0   (tail-jump; rdi/esi/rdx from caller)
```text

> **NOTE —** 页面标题命名了 `TfTpu_Initialize`,但实际活跃路径是 Path A。`TfTpu_Initialize @ 0xe6f54a0` 确实是一个 10 字节的 forwarding shim:它的整个函数体只有两条指令,`mov $0x1, %ecx` 然后 `jmp InitializeDriver`。它唯一做的事情就是把第 4 个参数(`InitializeDriver(bool, int, char const**, bool)` 的 `bool init_type_is_2`,通过 `%ecx` 传递)硬编码为 `1`;另外三个参数(`rdi`/`esi`/`rdx` = driver_flag, argc, argv)从调用方原样透传,且 `jmp`(不是 `call`)使其成为没有自身栈帧的 tail-shim。(IDA C 重建会把硬编码的 `%ecx` 渲染成一个假的 `&dword_0+1` argv 指针;反汇编才是权威:`%ecx` 是最后的 `bool`,不是 argv。)它存在的目的,是让 legacy `tensorflow/core/tpu/` 调用方(它们把 driver bring-up 拼写为 `TfTpu_Initialize`,就像 legacy StreamExecutor C-ABI 把所有东西都拼成 `TfTpu_*`)到达 PJRT gate 到达的同一个函数体。重实现可以导出其中一种或两种拼写;两者都必须汇入由同一个 `has_initialized` 字节保护的单个 `InitializeDriver`,否则同时触碰*两个* surface 的进程会双重初始化。

### 算法

```c
function InitializeDriver(bool driver_flag, int argc, char const** argv_in, bool init_type_is_2):   // 0x204cecc0
    // (a) hard idempotence gate — first instruction
    if driver_flag == 0 || (has_initialized & 1) != 0:    // function-static byte
        return                                             // already up, or disabled

    // (b) synthesize argv[0] and fold in Cloud-TPU defaults
    args = new vector<string>()
    args[0] = "./tpu_driver"                               // 24-B std::string, SSO inline
    AppendNewCloudTPUArgs(&args, argc, argv_in)            // 0x204c7340 — append Cloud-TPU flags + caller argv

    // (c) flatten vector<string> -> char**  (SSO-aware: byte-23 sign bit = heap/inline)
    n   = args.size()
    cargv = malloc(8 * (n + 1))                            // +1 for the NULL terminator
    for i in 0..n:
        cargv[i] = args[i].is_long() ? args[i].heap_ptr : &args[i].inline_buf  // byte 23 < 0 ⇒ heap
    cargv[n] = NULL

    // (d) parse flags + run the module DAG (the real work)
    InitGoogleExceptChangeRootAndUser("N/A", 3, &n, &cargv, change_root=0)    // 0x210b0180
    //   → RealInitGoogle:  ParseCommandLineNonHelpFlags(&n, &cargv)          // the --xla_*/TPU_* parse
    //   → RealInitGoogle:  GoogleInitializer::RunInitializers("module")      // *** runs HAL + platform ***
    free(cargv)

    // (e) telemetry gauges
    RegisterLibtpuGaugeTelemetry("megascale.error.detected.gauge", 30, 1)
    RegisterMegascaleErrorHandler("megascale.error.detected.gauge")
    RegisterLibtpuGaugeTelemetry("slice.error.detected.gauge", 26, 1)
    if EnableRuntimeUptimeTelemetry():                                       // anon-ns predicate
        InitializeUptimeMetricViaEnvironmentVariables(0, 26)

    // (f) latch the guard, free the temporary vector<string>
    has_initialized = 1
    destroy(args)                                          // frees each long string then the buffer
    return

GOTCHA — 合成的 argv[0] 是字符串字面量 "./tpu_driver",写作一个 24 字节 inline std::string(decompile 显示 strcpy(v7, "./tpu_driver") 写入一个 operator new(0x18) slot,并带有 0x0C 的 size byte)。随后 RealInitGoogle 会把它当作 SetProgramUsageMessage 中的程序名,以及日志里的 argv[0]。如果重实现者传入宿主进程真实的 argv[0],就会改变 absl 看到的程序名,并可能改变 flag-file / usage 行为;libtpu 有意伪造一个稳定名称,让 TPU driver 对命令行的视图独立于嵌入进程。

函数映射

函数地址大小角色
tpu::driver::InitializeDriver0x204cecc01764 Bbootstrap 函数体(guard、argv、InitGoogle、telemetry)
TfTpu_Initialize0xe6f54a010 B2 指令 tail-shim(mov $1,%ecx; jmp)→ InitializeDriver(legacy/备用入口)
tpu::driver::AppendNewCloudTPUArgs0x204c7340将 Cloud-TPU 默认 flags 合入 argv vector<string>
InitGoogleExceptChangeRootAndUser0x210b01808 B薄 wrapper → RealInitGoogle(…, change_root=0)
RealInitGoogle0x210ae860largeflag parse + RunInitializers + 进程级 init
GoogleInitializer::RunInitializers0x210b2d20拓扑 module-DAG 运行(PHASE B)
RegisterLibtpuGaugeTelemetry注册一个命名 telemetry gauge
RegisterMegascaleErrorHandler安装 Megascale error-detection handler
EnableRuntimeUptimeTelemetry控制 uptime metrics 的 anon-ns predicate

注意事项

has_initialized 字节是 InitializeDriver唯一的幂等保证;PJRT gate 的 TryAcquireTpuLock once-lock 和 DAG 自己的逐模块运行状态是独立的、分层的 guard。因此 bootstrap 在三个独立层面上都是幂等的:重新调用 PJRT_Plugin_Initialize 是一个快速 no-op,因为锁已经持有,并且 has_initialized 已设置,并且每个 module 的运行状态都是 DONE。重实现若丢掉三者之一,在常规单线程 init 下仍然安全,但会在其他 guard 所覆盖的某个并发或重复 init 场景下失去幂等性。


2. Option Ingest:LIBTPU_INIT_ARGS 与 Flag Parse

目的

TPU runtime 几乎完全由 absl command-line flags 配置,但 plugin .so 没有自己的命令行。libtpu 会从环境变量伪造一个命令行。GetLibTpuInitArguments @ 0x20ccca20LIBTPU_INIT_ARGS 转换为 argv 风格的向量;InitializeDriver 前置 argv[0] 和 Cloud-TPU defaults;RealInitGoogle 将结果交给 ParseCommandLineNonHelpFlags,由它绑定到 dlopen 构造函数风暴预注册的 absl flag tables。

算法

c
function GetLibTpuInitArguments() -> {vector<string> store, vector<char const*> argv}:  // 0x20ccca20
    s = getenv("LIBTPU_INIT_ARGS")                 // str @ file 0x918c880
    if s == NULL:
        return { {}, {} }                          // empty argv

    // (a) split the env string on ' ' (space char, 0x20) into string_views
    views = absl::StrSplit(string_view(s, strlen(s)), ByChar(' '), AllowEmpty)

    // (b) deep-copy each view into an owned std::string (24-B SSO records, NUL-terminated)
    store = vector<string>()
    for v in views:
        store.push_back(string(v.data, v.len))     // long strings heap-alloc; short ones inline

    // (c) materialize a parallel vector<char const*> pointing at each owned string's data
    argv = vector<char const*>()
    for str in store:
        argv.push_back(str.is_long() ? str.heap_ptr : &str.inline_buf)

    return { store, argv }                          // store owns the bytes; argv is the C view
```text

> **NOTE —** 拆分使用单个空格和 `AllowEmpty`,不是 shell 风格 tokenizer:没有引号处理,没有 escape 处理,也不按 tab/newline 拆分。`LIBTPU_INIT_ARGS="--xla_tpu_foo=1  --bar"` 中的双空格会在两个 flag 之间产生一个空字符串 token。Cloud-TPU production 会把该变量设为以空格拼接的 `--xla_*` / `--tpu_*` flag 列表;重实现者必须复现这种*纯空格拆分*,因为任何本身包含空格的 flag 值都会被拆成多个 token,并且很可能被拒绝。

### parse 如何消费它

`InitializeDriver` 构造最终的 `char**`:`["./tpu_driver", <Cloud-TPU defaults…>, <LIBTPU_INIT_ARGS tokens…>, NULL]`,并把 `&argc`/`&argv` 传给 `InitGoogleExceptChangeRootAndUser`,后者转发到 `RealInitGoogle @ 0x210ae860`。在那里,flag parse 是 `ParseCommandLineNonHelpFlags(&argc, &argv, remove_flags)`(non-help variant,因此这里不会特殊处理 `--help`),并被 `GoogleInitializer::Require("command_line_flags_parsing")` 和 `Require("command_line_flags_parsed")` module gate 包围。无法识别的 flags 由 absl flag 机制处理,而不是由 libtpu 直接处理。

> **QUIRK —** flag *registry* 在 `dlopen` 时构建,而不是在这里构建。`--xla_*` / `TPU_*` flags 之所以存在,是因为数百个 `_GLOBAL__sub_I_*_flags.cc` 静态构造函数在 `INIT_ARRAY` 风暴期间运行并填充了 absl flag tables(`debug_options_flags.cc`、`deepsea_platform_flags.cc`,以及 `_GLOBAL__sub_I_tpu_platform_registration.cc` 注册的逐模块 `FLAGS_tf_jf_*` 定义)。`ParseCommandLineNonHelpFlags` 只是把值*绑定到*这个已存在的 registry。重实现者不能把 flag *注册*推迟到 init time,同时还期望 init-time parsing 成功;当 `RealInitGoogle` 运行时,registry 必须已经填充。因此可识别 flag name 的集合由构造函数风暴定义([module-init-plugin-discovery.md](module-init-plugin-discovery.md) §2.2),而不是由本函数定义。

### `RealInitGoogle` 除 parse 外还做什么

`RealInitGoogle` 是完整的 `InitGoogle` 函数体,而不只是 flag parser。在 parse 前后,它会运行标准 Google 进程 bring-up:`InitializeSymbolizer`、`StartUpWallTimer`、kernel-version logging、一个 `mlock_style` flag switch(对 code pages 执行 `mlockall`)、`nice` priority adjustment、terminate-handler / signal-handler installation、对 `.data` 和 `.text` 进行 hugepage remapping、RCU domain init,以及 CPU/wall profiler registration;随后调用 `GoogleInitializer::RunInitializers("module")`(DAG run),最后把 `init_google_state = 2` 并通知 `InitGoogleDoneNotification`。就 bootstrap 目的而言,这些事情中只有两个重要:flag parse 和 DAG run。其余内容作为周边 `InitGoogle` 行为记录在这里,以便重实现者知道它们发生在 TPU bootstrap *内部*,并不能单独调用。

---

## 3. DAG Run:注册变成执行的地方

### 目的

`GoogleInitializer::RunInitializers("module") @ 0x210b2d20` 从 bootstrap 尾部的 `RealInitGoogle` 内被调用;这里才会按拓扑依赖顺序真正*运行* HAL factories、XLA target functors,以及构造函数风暴只是*注册*下来的 StreamExecutor `TpuPlatform`。本页不重新说明 DAG 机制本身,那在 [module-init-plugin-discovery.md](module-init-plugin-discovery.md) §3;本页负责其边界:bootstrap 是触发器,而它运行的其中一个 module 会接入 §4 的 ApiFn 表。

### 运行内容

```text
RealInitGoogle  0x210ae860
  └─ GoogleInitializer::RunInitializers("module")   0x210b2d20      *** PHASE B ***
       └─ drive registered modules in topological dep order:
            google_init_module_tpu_hal_{jxc,pxc,vxc,glc,gfc}_*
              → TpuHalFactory::Register(PlatformType, TpuVersion, factory)  0x1fbb16a0
                 (register per-TpuVersion; NO silicon scan yet)
            google_init_module_xla_target_{jellyfish,…,ghostlite}
RegisterTargetCreationFunctor(N, …)
            google_init_module_tpu_platform   0x213eabc0  (jmp)
              → RegisterTpuPlatform   0xe99a3a0   ── reads ExecutorApiFn() (§4),
                                                     installs StreamExecutor TpuPlatform
            … all other registered modules in dep order …

QUIRK — 这里仍然不会触碰 silicon。HAL factories 按 (PlatformType, TpuVersion) 注册;选择实际 TpuVersion 的 PCI-device-ID scan 要再过两个阶段才运行,位于 PJRT_Client_Create(slot 15)内部。因此 bootstrap 结束后,runtime 拥有完整填充的factory registry 和完整填充的 flag state,但还没有选定 device。TpuVersion detection 被推迟:首次 init 时注册(这里),首次 client 时检测。


4. TfTpu_*ApiFn() 函数指针表

目的

除 PJRT 外,libtpu 还携带 legacy StreamExecutor TPU C-ABI:194 个导出的 Tpu<Class>_<Method> 符号(@@VERS_1.0;例如 TpuExecutor_* ×25、TpuTransferManager_* ×19、TpuStream_* ×8,等等),通过原始 C 函数指针结构体分发。dispatch indirection 是一小族 accessor 函数,每个都返回一个进程全局表。bootstrap 是这些表变得相关的地方:RunInitializers 步骤会运行 RegisterTpuPlatform,该函数读取 executor 表,以决定是否安装 StreamExecutor platform。表的内容(逐名册的 TfTpu_*Fn slot-by-slot map)由 shim overview 负责:../shim/overview.md;本节只负责它们的形状、存储,以及 bootstrap 如何探测它们。

Accessor 是 Meyers singletons

c
// Each is a one-line return-address-of-a-function-local-static — leak-on-exit, no destructor.
TfTpu_ExecutorApiFn* stream_executor::tpu::ExecutorApiFn():    // 0x20819360
    return &ExecutorApiFn::executor_api_fn                      // process-global table

TfTpu_OpsApiFn*      stream_executor::tpu::OpsApiFn():          // 0x10900e80
    return &OpsApiFn::ops_api_fn

TfTpu_ProfilerApiFn* stream_executor::tpu::ProfilerApiFn():     // 0x10900ea0
    return &ProfilerApiFn::profiler_api_fn
```text

这三个都与 PJRT `pjrt_api` singleton 使用同一习惯用法:函数局部 static,其 storage 位于 `.bss`/`.lbss`,并通过地址返回。一旦填充,它们在进程生命周期内不可变,并且无锁读取。该表是一个平坦的 C 函数指针数组:每个 roster entry 一个 slot;因此通过它进行 dispatch 就是一次间接调用,成本模型与 legacy `c_api_decl.h` surface 完全相同。

### Bootstrap 如何探测 executor 表

`RegisterTpuPlatform @ 0xe99a3a0`(在 DAG 内运行,§3)根据 executor 表是否 live 来 gate platform installation:

```c
function RegisterTpuPlatform():                          // 0xe99a3a0
    fn = stream_executor::tpu::ExecutorApiFn()            // 0x20819360 — the table
    if IsStreamExecutorEnabled(fn)                        // 0x20819380 — probe + handshake
       and !tpu_platform_registered:                      // byte guard @ 0x224c5388
        p = new tensorflow::tpu::TpuPlatform()            // 0xe999960, sizeof 0x98
        PlatformManager::RegisterPlatform(p)              // 0x1d0fe120
        tpu_platform_registered = 1
    return 1

function IsStreamExecutorEnabled(table):                 // 0x20819380
    if table[0] == NULL: return 0                         // slot 0 = init fn-ptr unset ⇒ disabled
    handle = table[0](table)                              // call init fn; returns an opaque handle
    if handle == NULL: return 0
    table[1](handle)                                      // call finalize fn (slot+8) on the handle
    return 1

function IsInitialized(table):                           // 0x208193c0
    return table[0] != NULL                               // cheap liveness probe — slot 0 non-null

GOTCHA — executor 表通过 slot 0 非空来 dispatch,而不是通过单独的 "enabled" flag。IsInitialized 是廉价探测(table[0] != 0);IsStreamExecutorEnabled 是较重的探测:它实际调用 slot 0(一个返回 opaque handle 的 init thunk),然后对该 handle 调用 slot 1(finalize thunk),把一次干净的往返视为 shim 已接线的证据。重实现者填充这些表时,必须让 slot 0 保持 NULL 以保持 StreamExecutor off(此时 RegisterTpuPlatform 不注册任何东西,PJRT 独立存在),或者用可工作的 init/finalize pair 填充 slot 0 以将其切换为 on。不存在第三种状态。

函数映射

函数地址角色
stream_executor::tpu::ExecutorApiFn0x20819360返回 &executor_api_fn(Meyers singleton,executor roster table)
stream_executor::tpu::OpsApiFn0x10900e80返回 &ops_api_fn(Meyers singleton,ops roster table)
stream_executor::tpu::ProfilerApiFn0x10900ea0返回 &profiler_api_fn(Meyers singleton,profiler roster table)
stream_executor::tpu::IsStreamExecutorEnabled0x20819380slot-0 探测 + init/finalize handshake(gate TpuPlatform
stream_executor::tpu::IsInitialized0x208193c0廉价的 table[0] != NULL liveness probe
tensorflow::tpu::RegisterTpuPlatform0xe99a3a0读取 executor 表,安装 StreamExecutor TpuPlatform

注意事项

重实现者必须把握的一点是:InitializeDriver 不会填充这些表。它运行 DAG,而 DAG 运行 RegisterTpuPlatform,后者读取一个已经填充的 ExecutorApiFn()。表的填充路径(哪个 TfTpu_*Fn setter 写入这些 slot,以及何时写入)本页没有追踪;这是 ../shim/overview.md 负责的独立问题。这里由字节确认的是消费侧:accessor 形状、slot-0 dispatch 规则,以及 RegisterTpuPlatform 在 bootstrap 期间执行的 handshake。最终位于 PJRT 下方的 SE platform,以及它如何服务 Tpu*_* exports,见 ../pjrt/stream-executor-host-interpreter.md

NOTE — 在刚加载的 libtpu 中,观察到 executor 表的 slot 0 为空(.bss singleton 在加载时被零填充,且没有 static ctor 写入它)。是否有任何路径会在 RegisterTpuPlatform 运行前填充它,从而决定 StreamExecutor TpuPlatform 是否会在 PJRT-only configuration 中安装,本页没有追踪(对 populated-vs-empty 结果为 LOW confidence;probe logic 为 CONFIRMED)。PJRT stack 并不需要它:PJRT 直接到达 driver core,而 Tpu*_* exports 会独立包装同一个 backing implementation。


5. Bootstrap Once-Guards

目的

bootstrap 通过叠加三个独立的 once 机制来保证可重入安全。只复现 PJRT gate 或只复现 driver guard 的重实现,会得到不同的幂等性轮廓。

Guard位置地址 / token重新调用时跳过什么
absl::Mutex once-lockTryAcquireTpuLock::muguard 0x225925d0 / obj 0x225925c8跨进程 acquisition;第二次调用会看到锁已持有
函数静态字节InitializeDriver::has_initialized0x225899e0.bss整个 InitializeDriver 函数体(argv 构建、InitGoogle、telemetry)
absl::Mutex + 逐模块 run-stateGoogleInitializer::RunInitializersinside 0x210b2d20重新运行任何状态已是 DONE 的 module
函数静态字节RegisterTpuPlatform::tpu_platform_registered0x224c5388重新安装 StreamExecutor TpuPlatform
__cxa_guard for InitGoogleDoneNotificationinside RealInitGoogleguard in .bss重新启用 init-done notification
init-type selectorkPjRtCApiTpuInitType(= 2)0x22255b40.data如果它为 0,则跳过整个 bring-up
env gateTPU_LOAD_LIBRARY(位于 TryAcquireTpuLockstr @ file 0x887356a— 控制是否尝试获取锁
env argsLIBTPU_INIT_ARGS(位于 GetLibTpuInitArgumentsstr @ file 0x918c880— 提供 flag 字符串

NOTE — kPjRtCApiTpuInitType.data 中静态为 2;init-type 2 走完整 bring-up(InitializeDriver(…, init_type_is_2 = true)),init-type 0 让 PJRT_Plugin_Initialize 成为 no-op。init-type 2 与假设中的 1 是否会改变 InitializeDriver 的行为,本页没有追踪;init_type_is_2 参数会被计算并传入,但反编译的 InitializeDriver 函数体在追踪区域内没有明显基于它分支(对 init-type 改变 driver path 为 LOW confidence;静态 selector 值 2 和透传为 CONFIRMED)。


相关组件

组件关系
PJRT_Plugin_Initialize @ 0xe6a9d00PJRT 侧 gate;调用进入此 bootstrap(完整 gate 见 module-init-plugin-discovery.md §3)
tpu::driver::InitializeDriver @ 0x204cecc0本页负责的 bootstrap 函数体
TfTpu_Initialize @ 0xe6f54a0进入同一个 InitializeDriver 的 legacy/备用 10 字节 tail-shim 入口
GetLibTpuInitArguments @ 0x20ccca20LIBTPU_INIT_ARGS option ingest
RealInitGoogle @ 0x210ae860flag parse + module-DAG run + 进程 bring-up
GoogleInitializer::RunInitializers @ 0x210b2d20执行已注册 modules 的 DAG run(PHASE B)
ExecutorApiFn / OpsApiFn / ProfilerApiFnStreamExecutor C-ABI dispatch tables(Meyers singletons)
RegisterTpuPlatform @ 0xe99a3a0读取 executor 表,在 PJRT 下安装 SE TpuPlatform

交叉引用