Skip to content

跨 Host Barrier

本页所有地址均适用于来自 libtpu-0.0.40-cp314 wheel 的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d,x86-64,781,691,048 bytes)。其他版本会不同。

摘要

Megascale 跨 host barrier 是 DCN 级别(data-centre-network,host 间)的 rendezvous,多 slice XLA/TPU 作业中的每个 host 都通过它在一个命名点同步。它是一次单独的一元 gRPC 调用 — MegaScaleTransport.Barrier — 汇聚到一个 coordinator 进程;coordinator 统计到达者,并一次性释放所有调用方。这是 host-network barrier;它与片上 SFLAG barrier(Barriers 概览)以及跨 core ICI tree-barrier 是不同机制、位于不同 fabric 范围。那些 barrier 通过 TensorCore sequencer 在 chip / slice 内部运行;本 barrier 通过 gRPC/protobuf 在 host 之间运行。本页内容都不触及 SFLAG — 这里的等待原语是一个 absl::Notification 加上一组 gRPC reply callback vector。

形态是 星形、集中式、一次往返:每个 host 向唯一的 coordinator 端点发送一个 Barrier RPC;coordinator 将每个 (slice_id, host_id) 的到达累计进 flat_hash_set,直到 set 大小等于声明的 participant count,然后向每个排队调用方广播一个缓存的 BarrierResponse。没有 peer-to-peer 阶段,没有 tree reduction,没有 butterfly,也没有 dissemination — 拓扑形状与它共享基类的 topology-discovery rendezvous 完全相同。server 对象 xla::megascale::runtime::BarrierCoordinator(vptr 0x21c9bb700xf8 = 248 bytes)是通用 Coordinator<Req, Resp, CB> 模板的第二个特化;该模板也产生 TopologyCoordinator。它继承了该基类的状态机、pending-callback fan、Notification 和周期性 status alarm(Bootstrap 收敛)。

对于重新实现,契约是:

  • BarrierCoordinator 对象 — 其 0xf8 布局、共享的 Coordinator<> 基类偏移、(slice_id, host_id) tuple set,以及 9 槽 vtable。
  • Barrier RPC 线路格式 — 4 字段 BarrierRequest、仅 id 的 BarrierResponse,以及 server callback chain GrpcAsyncCbServiceImpl::Barrier → OnBarrierRequestReceived → AddRequest
  • 集中式算法 — 按 barrier_id 惰性分配 coordinator、到达记账、count/duplicate 验证、在 seen.size() == num_participants_ 时提前触发,以及 callback fan-out 释放。
  • barrier_id keying 和两种风格 — 以 id 为 key 的 flat_hash_map、带 replay protection 的命名前执行 barrier,以及自动生成的 __global-auto-<N> collective barrier。
  • 超时与失败 — coordinator 侧 没有 timeout;唯一边界是来自 FLAGS_tf_tpu_preexecution_barrier_timeout 的每 RPC gRPC deadline(默认 30 s),带有 10 秒客户端重试循环,以及一条 "Unable to wait for all slices to connect" 析构日志。
Service / method/xla.megascale.runtime.MegaScaleTransport/Barrier(一元;6 个方法中的第 3 个)
Coordinator objectxla::megascale::runtime::BarrierCoordinator,vptr 0x21c9bb700xf8 = 248 bytes
Base classxla::megascale::runtime::Coordinator<BarrierRequest, BarrierResponse, AnyInvocable<…>>(base vtable off_21C33918
Coordinator mapflat_hash_map<string, unique_ptr<BarrierCoordinator>> @ CommunicationBackend +0x1b0
Arrival storeflat_hash_set<tuple<int,int>>slice_idhost_id)@ BarrierCoordinator +0xd8
Server entryGrpcAsyncCbServiceImpl::Barrier 0x1ce74280OnBarrierRequestReceived 0x1ccac5c0AddRequest 0x1ccb42a0
Client entryCommunicator::Barrier(id, opt<int>, opt<Duration>) 0x1cca8ee0GetBarrierResponse 0x1ce79cc0SendRPC 0x1ce79de0
Timeout flagFLAGS_tf_tpu_preexecution_barrier_timeout 0x22256500absl::Duration 默认 30 s
Source TUplatforms/xla/megascale/runtime/communication/{topology_coordinator,communication_backend,grpc_transport}.{h,cc}

注意 — 嵌入的源码字符串即使在 barrier 路径上也把 coordinator 逻辑命名为 topology_coordinator.h/.cc,因为 BarrierCoordinatorTopologyCoordinator 共享同一个模板。下文引用的 topology_coordinator.cc:323 这样的行号是位于该共享 TU 中的 barrier 代码,不是 topology 代码。


1. Barrier RPC

目的

MegaScaleTransport.Barrier 是跨 host barrier 的单一线路操作。它是一个阻塞的一元 gRPC 调用:host 发起它,coordinator 保持回复打开(不调用其 finish callback),直到 barrier 完成,然后结束它。从调用方视角看,RPC 只是阻塞到 rendezvous 释放。

线路格式

请求通过 BarrierRequest::Clear 0x1cf7f220 构建和解析(has-bits 位于 C++ +0x10);响应通过 BarrierResponse::Clear 0x1cf7f760 / MergeImpl 0x1cf7f660

字段 #名称类型C++ 偏移含义
1barrier_idstring+0x18rendezvous key;ArenaStringPtr(低位带 tag,mask & ~3
2slice_idint32+0x20(slice, host) 到达 tuple 的低半部分
3host_idint32+0x24到达 tuple 的高半部分
4num_participantsint32+0x28预期到达数,会与 coordinator 存储的 count 校验

响应只携带 barrier_id(字段 1,+0x18),由 CreateResponse 回显。C++ 对象在 +0x20… 有 int 字段(has-bit 位于 +0x10),镜像请求形状,但 coordinator 从不写入它们 — 因此响应的字段 2-4 线路编号是根据请求对称性推断的,而不是观察到被设置(LOW)。

注意 — 字段 4 是 num_participants,不是 timeout。ProcessRequest 读取 *((int*)req + 10)+0x28 处的 proto 字段),并将其与存储的 num_participants_ 比较;不匹配会以 INVALID_ARGUMENT 拒绝。没有 timeout proto 字段 — barrier timeout 完全通过带外的 gRPC client deadline 携带(见 §5)。

Server Callback Chain

text
GrpcAsyncCbServiceImpl::Barrier(ctx, req, resp)            0x1ce74280
  │  VLog(3) "calling barrier_callback_ with request: <req>"  (grpc_transport.cc:1325)
  │  wrap the gRPC reactor-finish closure as
  │    AnyInvocable<void(StatusOr<BarrierResponse> const&)>   (writes resp, Finish()es)
  └─ barrier_callback_(req, cb)   [transport +80/+104]
       └─ CommunicationBackend::OnBarrierRequestReceived     0x1ccac5c0
            └─ BarrierCoordinator::AddRequest(req, cb)        0x1ccb42a0  [vtable +0x10]
```text

server 侧在 `MegaScaleTransport` callback-service chain 中使用 `WithCallbackMethod_Barrier`;client 侧通过 pooled channel 派发 `MegaScaleTransport::Stub::Barrier` `0x1ce9a7c0`。

---

## 2. BarrierCoordinator 对象

### 目的

coordinator 进程上的每个 live `barrier_id` 都对应一个 `BarrierCoordinator`。它累计到达者,并在最后一个预期到达者到达时释放所有等待中的调用方。它是 topology coordinator 的 sibling — 相同的 `Coordinator<>` 基类,但使用 `(slice, host)`-tuple counter,而不是每个 slice 的 host map。

### 对象布局(`0xf8` = 248 bytes)

在 `OnBarrierRequestReceived`(`0x1ccac5c0`)中通过 `operator new(0xf8)` 分配。偏移由 ctor `0x1ccb3fa0` 加上 `ProcessRequest` / `IsComplete` / dtor 中的成员访问确认。

| 偏移 | 大小 | 字段 |
|---|---|---|
| `+0x00` | 8 | vptr(`0x21c9bb70`) |
| `+0x08`–`+0x57` | 0x50 | 嵌入的 `Coordinator<>` 基类:`TracedMutex(kind=9)` |
| `+0x58` | 1 | `state_`(0 init / 1 ready / 2 completed / 3 error) |
| `+0x60`–`+0x87` | 0x28 | `StatusOr<BarrierResponse>`(init = `UNAVAILABLE` "IN_PROGRESS") |
| `+0x88` | 8 | `response_setters_.data` — `vector<AnyInvocable<void(StatusOr<BarrierResponse> const&)>>` |
| `+0x90` / `+0x98` | 8 / 8 | `response_setters_.size` / `.capacity` |
| `+0xa0`–`+0xbf` | 0x20 | `absl::Notification` |
| `+0xb0` | 8 | status-report cancellable alarm handle |
| `+0xb8`–`+0xcf` | 0x18 | `std::string barrier_id`(SSO;cap byte 位于 `+0xcf`) |
| `+0xd0` | 4 | `num_participants_`(`topology_coordinator.h:299` 处 CHECK `> 0`) |
| `+0xd8`–`+0xf7` | 0x20 | `flat_hash_set<tuple<int,int>> seen_workers`(size = `*(this+0xe0) >> 17`) |

基类偏移(`+0x58` `state_`、`+0x60` `StatusOr`、`+0x88` callbacks、`+0xa0` `Notification`、`+0xb0` alarm)与 `TopologyCoordinator` 完全共享;只有派生类尾部(`+0xb8` 之后)不同。

### 算法 — 构造

```c
// BarrierCoordinator::BarrierCoordinator(string_view id, int num_participants)   0x1ccb3fa0
function ctor(this, id, num_participants):
    this.vptr        = &off_21C33918                       // base vtable first
    TracedMutex_ctor(this + 0x08, /*kind*/ 9)              // embedded mutex
    this.state_      = 0                                   // +0x58
    this.StatusOr_   = MakeErrorImpl<14>("Coordinator in IN_PROGRESS")  // +0x60, cat 14 = UNAVAILABLE
    zero(this + 0x88, 0x20)                                // callbacks vector + Notification head
    this.alarm_      = 0                                   // +0xb0 (within zeroed range)
    this.vptr        = &off_21C9BB70                       // overwrite with derived vtable
    store_sso_string(this + 0xb8, id)                      // barrier_id (heap if len > 0x16)
    this.num_participants_ = num_participants               // +0xd0
    this.seen_workers_ = empty flat_hash_set               // +0xd8 (+0xd8 = 1, growth-info word @ +0xe0 = 0)
    CHECK(num_participants > 0) @ topology_coordinator.h:299  // FATAL otherwise

两次 vtable 写入(先 base 后 derived)是构造期间的标准 C++ vtable 转换;反编译显示先写入 off_21C33918,然后在基类成员初始化后写入 off_21C9BB70

Vtable(vptr 0x21c9bb70,9 槽)

.data.rel.roR_X86_64_RELATIVE relocation 解析得出。

VA方法
+0x000x1cf55760~BarrierCoordinator(D2/D1)
+0x080x1cf55960~BarrierCoordinator(D0,deleting)
+0x100x1ccb42a0Coordinator<Barrier>::AddRequest(req, cb)(base)
+0x180x1ccb4a80Coordinator<Barrier>::GetState() const(base)
+0x200x1cf54e60ProcessRequest(req) — 到达记账
+0x280x1cf559a0IsComplete() const
+0x300x213b7e20CreateResponse()
+0x380x213b7ce0ReportStatus() const
+0x400x22048600base accessor(GetNumWorkers-style;不在 barrier hot path 上)

注意 — AddRequest+0x10)和 GetState+0x18)是与 TopologyCoordinator 共享的 base-class entry;ProcessRequest/IsComplete/CreateResponse/ReportStatus+0x20+0x38)是赋予基类 barrier-specific 行为的 derived override。基类通过 vtable 调用它们 — 这是 template-method pattern。


3. barrier_id Keying

目的

每个 barrier_id 都是一个独立的 rendezvous。coordinator 进程拥有一个 live barrier map,第一次看到某个 id 时惰性创建一个 BarrierCoordinator,并将该 id 的所有后续到达路由到同一个对象。

算法 — Lazy Insert

c
// CommunicationBackend::OnBarrierRequestReceived(req, reply_cb)   0x1ccac5c0
function OnBarrierRequestReceived(backend, req, reply_cb):
    VLog(3) "Received barrier request from (SliceId, HostId, barrier_id) <s>,<h>,<id>"  // :954
    lock(backend.mutex_)                                  // +0xe0
    slot = backend.barrier_map_[req.barrier_id]           // flat_hash_map @ +0x1b0
    if slot == null:                                      // first sight of this id
        slot = new(0xf8) BarrierCoordinator(req.barrier_id, req.num_participants)
    cb = move(reply_cb)
    slot->AddRequest(req, cb)                             // vtable +0x10
```text

*ctor* 的 participant count 取自 **第一个** 请求的字段 4;每个后续请求的字段 4 都会在 `ProcessRequest` 中校验为相等([§4](#4-arrival-accounting-and-release))。

> **陷阱 —** 这里没有 **coordinator-only** guard。如果命中非 coordinator 进程,topology discovery 会以 "TopologyCoordinator not initialized." 拒绝;barrier 路径没有这种检查 — *任何* 持有 barrier map 的进程都可以托管 `BarrierCoordinator`。假设只有选出的 coordinator 会分配 `BarrierCoordinator` 的重新实现会发生偏离;门控纯粹是调用方发送到 coordinator 的端点,而不是 server-side identity check。

在 `CommunicationBackend` 中,barrier map 位于 `+0x1b0`(`operator[](backend+432, id)`,通过 `operator new(0xf8)` = 248 bytes 分配每个 coordinator);相邻的 `TopologyCoordinator*` 位于 `+0x1a0`,`ErrorReporter*` 位于 `+0x1a8`,auto-barrier counter 位于 `+0x1d0`。

### 两种风格,一个机制

两种风格都通过相同的 3 参数 `Communicator::Barrier`(`0x1cca8ee0`)和相同的 server-side `BarrierCoordinator`。只有 id 生成和 replay 语义不同。

| 方面 | Pre-execution barrier | Collective-rendezvous barrier |
|---|---|---|
| 调用方 | `Communicator::Barrier(id, n, timeout)` | `Communicator::Barrier()`(无参数)`0x1cca8de0` |
| `barrier_id` | 显式,由 executor 提供 | 自动 `"__global-auto-<N>"`(counter @ backend `+0x1d0`) |
| Replay protection | 每进程 once-per-process used-id set(`ALREADY_EXISTS`) | 从不碰撞 — 每次调用 fresh id |
| `num_participants` | 调用方提供或默认 `NumHosts()` | 默认 `NumHosts()` |
| 驱动方 | `tpu_execute.cc`,由 `FLAGS_tf_tpu_enable_preexecution_barrier` 门控 | cross-host collective 开始处的 collective layer |

无参数形式在 backend mutex 下读取并递增 backend `+0x1d0` 处的单调 counter,构建 `StrCat("__global-auto-", N)`,然后以未设置的 `num_participants`/`timeout` 委托给 3 参数形式。由于每个 collective 都生成 fresh id,collective 从不会触发 replay protection。

命名形式首先将 `barrier_id` 插入位于 `Communicator +0xa8` 的每进程 used-id set;重复使用会在发送任何 RPC 之前返回 `MakeErrorImpl<6>`(`ALREADY_EXISTS`)"Barrier ID: $0 has already been used."(`communication_backend.cc:379`)。

> **特性 —** 默认 participant count 是 **整个作业**。当调用方省略 `num_participants` 时,它默认取 `MultiSliceTopologyAndLocation::NumHosts()` — 在 bootstrap topology exchange 期间解析出的总 host 数([Bootstrap 收敛](bootstrap/convergence.md))。因此未参数化的 barrier 只有在 multi-slice 作业中的 *每个* host 都到达时才会完成。机制支持任意 count(例如 sub-group barrier),但在此二进制中未定位到传入非默认 count 的调用方(LOW 表示 sub-group barrier 在实践中被使用)。

---

## 4. 到达记账与释放 {#4-arrival-accounting-and-release}

### 目的

coordinator 必须对每个不同 host 精确计数一次,拒绝错误声明的 count 和重复到达,在最后一个预期 host 到达的瞬间触发,并向所有等待者广播一个响应。这四件事都发生在 `ProcessRequest` 和基类 `AddRequest` 内。

### 算法 — ProcessRequest(验证 + 计数)

```c
// BarrierCoordinator::ProcessRequest(req)   0x1cf54e60   [vtable +0x20]
function ProcessRequest(this, req):
    if req.num_participants (+0x28) != this.num_participants_ (+0xd0):
        return INVALID_ARGUMENT,
               "Mismatched number of barrier participants: Expected: $0 Msg: $1"  // :323
    key = tuple<int,int>(req.slice_id (+0x20), req.host_id (+0x24))
    if this.seen_workers_.find(key):                      // flat_hash_set @ +0xd8
        return INVALID_ARGUMENT,
               "Extra barrier participant. Expected: $0 Message $1"               // :331
    this.seen_workers_.insert(key)                        // find_or_prepare_insert_large
    return OK

该 set 是 flat_hash_set<tuple<int,int>>不是 "slice:host" 字符串 set。每个 unique host 只计数一次,因此由 10 秒重试循环(§5)重新发出的 host RPC 不会重复计数 — 它的第二次到达会命中 find 并被作为 duplicate 拒绝,随后基类路径会将其折叠进缓存响应。

算法 — IsComplete(提前触发)

c
// BarrierCoordinator::IsComplete() const   0x1cf559a0   [vtable +0x28]
function IsComplete(this):
    return (*(uint64*)(this + 0xe0) >> 17) == this.num_participants_   // +0xd0
```text

`>> 17` 从 `+0xe0` 处的 control-block growth-info word 提取 SwissTable element count。完成条件在 `seen.size() == num_participants_` 的瞬间触发 — 即最后一个预期 host 到达时,与 topology coordinator 的 “all slots seen” early-fire 相同。

### 算法 — AddRequest(状态机 + 释放)

```c
// Coordinator<Barrier>::AddRequest(req, cb)   0x1ccb42a0   [vtable +0x10, base]
function AddRequest(this, req, cb):
    VLog(5) "AddRequest: <req>"                           // topology_coordinator.h:75
    lock(this.mutex_)                                     // +0x08, TracedReleasableMutexLock
    if this.state_ == 3:                                  // poisoned (sticky error)
        cb(this.StatusOr_); return                        // +0x60
    rsp = this.vtable[+0x20](req)                         // ProcessRequest -> OK or INVALID_ARGUMENT
    if this.state_ == 2:                                  // already completed
        cb(per-request response/error); return           // serve cached, fast path
    push cb onto this.response_setters_ (+0x88)
    if rsp is error:
        this.state_ = 3; this.StatusOr_ = rsp; serve rsp  // poison the id
    if this.vtable[+0x28]():                              // IsComplete()
        this.state_ = 2
        this.StatusOr_ = this.vtable[+0x30]()             // CreateResponse()
        this.Notification_.Notify()                       // +0xa0
        VLog(5) "Num responses to send: <n>"              // h:131
        for cb_i in response_setters_: cb_i(this.StatusOr_); VLog(5) "Response sent <i>"  // h:135
        clear(response_setters_)
    else if this.state_ == 0:
        this.state_ = 1; ScheduleStatusReport()           // arm 1-second alarm @ +0xb0
    VLog(5) "Done processing Request received at: <t> Duration: <d>"  // h:141
    if duration > ~5 s: LOG "Long running topology coordinator AddRequest: Duration: <d>"  // h:144

释放机制

完成时(在 mutex 下):state_ = 2StatusOr_ := CreateResponse()(带有从 +0xb8 回显的 barrier_idBarrierResponse,并在 topology_coordinator.cc:364 记录 "MegaScale Barrier completed for id <id>");Notification.Notify();然后迭代 response_setters_,用缓存响应调用每个排队的 AnyInvocable<void(StatusOr<BarrierResponse> const&)>。每次调用都会结束对应的 gRPC 调用并解除远端 host 的 SendRPC 阻塞。gRPC framework 在其 callback 触发前不会向 client 发信号 — 因此 “release” 精确地就是这一轮单次 fan-out pass,之后 vector 被销毁。

+0xa0 处的 Notification 还会唤醒绕过 gRPC 的 进程内调用方(coordinator 自身的 host),并被析构函数的 settle 路径使用;对于远端 host,只有 callback fan 重要。这与 Bootstrap 收敛 中描述的 dual signalling 相同。


5. Timeout

目的

barrier 必须限制 host 等待其他 host 的时长。该限制完全位于 client 侧:每 RPC gRPC deadline 加上重试循环。coordinator 自身不施加 timeout。

Flags

Flag (VA)类型默认值影响
FLAGS_tf_tpu_enable_preexecution_barrier 0x222564a0bool(gate)executor 中 pre-execution barrier 的 master switch
FLAGS_tf_tpu_preexecution_barrier_timeout 0x22256500absl::Duration30 s应用于 Barrier RPC 的 client gRPC deadline
FLAGS_xla_tpu_enable_megascale_barrier 0x223b4d08bool(gate)megascale barrier 路径的更高层 enable

30 秒默认值由 AbslFlagDefaultGenFortf_tpu_preexecution_barrier_timeout::Gen 0xe6fd5c0 写入为 absl::Duration {sec=30, ns=0}*this = 30; *(this+2) = 0)。timeout 和 enable flag 都在 learning/45eac/tfrt/tf_tpu/tpu_execute.cc(TFRT TPU executor)中注册,确认 pre-execution barrier 由每次 launch 的 execute 路径驱动。

算法 — Client Deadline + Retry Loop

c
// GrpcTransport::SendRPC<BarrierRequest, BarrierResponse>(...)   0x1ce79de0
function SendRPC(method, peer, req, opt_timeout):
    deadline = opt_timeout ? Now() + opt_timeout : +inf (0x7fff..ff)
    VLog(3) "Calling GetBarrierResponse with deadline: <t>"       // grpc_transport.cc:2197
    while Now() < deadline:
        ctx = ClientContext(); ctx.set_deadline(Timepoint2Timespec(deadline))
        stub = GetOrCreateClient(peer)                            // channel-pooled, round-robin
        status, resp = IssueSyncRPC(stub, req)                    // Stub::Barrier (blocking unary)  0x1ce739c0
        if status.ok():
            VLog(3) "<method> succeeded."                         // :2221
            return resp
        LOG "<method> to <peer> returned with status: <s>. Sleeping for 10 seconds."  // :2216
        AbslInternalSleepFor(10 s)                                // retry
    return last sticky error status                              // typically DEADLINE_EXCEEDED
```text

`IssueSyncRPC`(`0x1ce739c0`)在一组预打开的 stub 之间 round-robin(80-byte entry,`index = call_count % pool_size`,在 client mutex 下),并通过 `GrpcStatusToAbslStatus` 转换 gRPC status。使用 30 s budget 和 10 s retry sleep 时,调用方在 deadline 到期前大约会尝试三次。

> **陷阱 —** coordinator 的 progress path 上没有 `WaitForNotificationWithTimeout`。coordinator 永远不会按自己的时钟中止 barrier;未完成的 `BarrierCoordinator` 会保持 callback pending,并每秒重新记录进度([§6](#6-failure-handling))。*唯一*边界是每个调用方的 gRPC deadline。添加 server-side timeout 的重新实现不会匹配观察到的行为,后者是 coordinator 只是无限等待并记录日志,直到被拆除。

### Status Report Cadence

当 `AddRequest` 将 coordinator 从状态 01 时,它通过 `ScheduleStatusReport` lambda `0x1ccb4ea0` 在 `+0xb0` 处启动周期性 alarm:在 mutex 下调用 `ReportStatus`(vtable `+0x38`),如果仍未完成,则通过 `DefaultFiberExecutor` 上的 `thread::AddCancellableAt` 在 `Now() + 1 s` 重新 arm。

> **注意 —** re-arm 无条件是 `Now() + absl::Seconds(1)`,没有 backoff multiplier,因此节奏固定为 **1**。虽然 [Bootstrap 收敛](bootstrap/convergence.md) 将通用 alarm 描述为 "seconds to a minute",但 barrier 的具体 re-arm 始终是 1 s。

`ReportStatus`(`0x213b7ce0`)在完成时记录 "MegaScale Barrier completed."(`:353`),否则记录 "MegaScale Barrier in progress. Seen &lt;K&gt; of &lt;N&gt; expected participants. Seen hosts: &lt;list&gt;"(`:356`)。host list 来自 `GetSeenHosts`(`0x1cf55280`),它将 `(slice, host)` set 压缩为每个 slice 的 `gtl::IntervalSet<int>` range — 例如 `slice0.hosts[0-3,5], slice1.hosts[0-7]`。

---

## 6. 失败处理 {#6-failure-handling}

### 算法 — 失败模式

| 失败 | 检测位置 | 结果 |
|---|---|---|
| 某个 host 永不到达 | client gRPC deadline(30 s) | 每个等待者的 RPC 返回 `DEADLINE_EXCEEDED`,其 callback 被取消;coordinator 保持 `state_=1`,每 1 s 重新记录 "in progress" |
| 未完成的 coordinator 被拆除 | derived dtor `~BarrierCoordinator` `0x1cf55760` | 记录 "BarrierCoordinator: Unable to wait for all slices to connect. Saw &lt;K&gt; of &lt;N&gt; expected participants. Seen hosts: &lt;intervals&gt;"(`:371`) |
| Participant-count 不匹配 | `ProcessRequest` `0x1cf54e60` | `INVALID_ARGUMENT`;`AddRequest` 设置 `state_=3`,poison 该 id,并把错误返回给此 id 的当前和所有未来调用方 |
| 重复到达(distinct host) | `ProcessRequest` | `INVALID_ARGUMENT` "Extra barrier participant";同样 poisoning |
| 命名 id 被重复使用 | `Communicator::Barrier` `0x1cca8ee0` | client-side `ALREADY_EXISTS`,在任何 RPC 之前 |
| 未设置 coordinator 端点 | `Communicator::Barrier` | `INTERNAL` "Barriers not available without coordinator set."(`:384`) |
| Transport 未初始化 | `Communicator::Barrier` | `INTERNAL` "Transport not initialized."(`:1473`,source-location stamped at `:929`) |

### “Unable to wait” 析构路径

derived destructor 检查 `seen.size() >= num_participants_`;如果不满足,它会发出 canonical "barrier failed" 日志 "BarrierCoordinator: Unable to wait for all slices to connect. Saw &lt;K&gt; of &lt;N&gt; expected participants. Seen hosts: &lt;intervals&gt;"(`topology_coordinator.cc:371`),取消 status-report alarm(对 `+0xb0` 调用 `thread::Cancel`),然后链接到 base destructor — 如果 `state_ == 2`,base destructor 会通过 `WaitForNotificationWithTimeout` settle 任意 in-flight notification。

### 传播与 Poisoning

失败的 barrier 向 executor 返回非 OK `absl::Status`,并通过 PJRT 暴露给 JAX。在 coordinator 进程上,周边 runtime 还可能通过 `MegaScaleTransport.ReportError → ErrorReporter → RapidEye`([ErrorAggregator](error-aggregator.md))路由失败,其中 barrier hang 通常分类为 `HANG_DETECTED` / `PROGRAM_NOT_QUEUED`。poisoned barrier(count/duplicate 不匹配后 `state_=3`)在该 `BarrierCoordinator` 的生命周期内保持 poisoned;作业重启会构造 fresh map 和 fresh coordinator。

> **特性 —** `BarrierRequest` ****携带 `incarnation_id`(不同于有字段 5 的 `GetMultiSliceTopologyRequest`)。staleness 以结构方式处理:collective 每次调用都会生成 fresh `__global-auto-<N>` id,因此上一轮 launch 的 barrier 永远不会与当前轮混淆;命名 id 依赖 client-side once-per-process used-id set。barrier 自身没有跨进程 generation counter。

---

## 7. 与其他 Barrier 的关系

Megascale 跨 host barrier 是 libtpu 中三个不同 barrier 层级之一,每个层级位于不同 fabric 范围,并构建于不同原语之上。它们彼此独立 — 没有哪个叠加在另一个之上。

| 方面 | **本页 — DCN cross-host** | ICI cross-core tree | tpunetd in-slice |
|---|---|---|---|
| 范围 | cross-**host**(整个 multi-slice 作业,通过 DCN) | chip/slice 内 cross-**core**(通过 ICI) | in-**slice**(一个 slice 的 peer) |
| Transport | gRPC / protobuf | TensorCore sequencer Vsync ops on SFLAGs | gRPC(`TpuNetworkSessionBarrier`) |
| 拓扑 | 集中式星形(coordinator 上的 counter) | up-sweep/down-sweep routing-table tree | 分布式(master Notifies all,每个 peer WaitForReady) |
| 等待原语 | `absl::Notification` + gRPC callback fan-out | `VWaitGeOp` on an SFLAG | `CancellableCondVar` / `Mutex::AwaitCommon` |
| Keying | `(slice_id, host_id)` tuple set,count to N | reserved GLOBAL SFLAG `base+count+4` | 单个共享 `barrier_id` 字符串 |
| Timeout | gRPC deadline(`FLAGS_tf_tpu_preexecution_barrier_timeout`,30 s) | 无(hardware rendezvous) | `absl::Duration` arg |
| 实现 | `xla::megascale::runtime::BarrierCoordinator` | `net_util::BarrierCoresTree` `0x1c6a75c0` | `superpod::tpunetd_client::BroadcastBarrier` |

tpunetd `BroadcastBarrier::SyncWithTimeout`(`0x1ff9bce0`)确认 in-slice barrier 是通过 `CancellableCondVar` 发信号的 master-driven Notify/Wait pattern。Megascale barrier 从不调用它;依赖关系纯粹是时间上的 — tpunetd 的 in-slice rendezvous 必须在 Megascale runtime 构造 `CommunicationBackend` 之前完成(bootstrap [ICI handoff](bootstrap/convergence.md))。

---

## 相关组件

| 名称 | 关系 |
|---|---|
| `TopologyCoordinator` | sibling `Coordinator<>` specialisation;共享基类、状态机、`Notification` 和 alarm |
| `CommunicationBackend` | 拥有 barrier map(`+0x1b0`)、auto-id counter(`+0x1d0`),并派发 `OnBarrierRequestReceived` |
| `MegaScaleTransport` | 承载 `Barrier` RPC 的 gRPC service(6 个一元方法中的第 3 个) |
| `ErrorReporter` / RapidEye | barrier hang 的 downstream sink(`HANG_DETECTED` / `PROGRAM_NOT_QUEUED`) |

---

## 交叉引用

- [Megascale 概览](overview.md) — DCN vs ICI,以及 cross-host barrier 在作业启动和每次 launch 执行中的位置
- [Bootstrap 收敛](bootstrap/convergence.md) — 此 barrier 继承的通用 `Coordinator<>` 基类(状态机、callback fan、Notification、alarm);初始 topology barrier
- [ErrorAggregator](error-aggregator.md) — barrier failure 传播进入的 `ReportError → ErrorReporter → RapidEye` 路径
- [tpunetd 协议](tpunetd-protocol.md) — 其 `TpuNetworkSessionBarrier` 在此 barrier *之前*运行、且范围不同的 in-slice daemon protocol
- [Barriers 概览](../barrier/overview.md) — 片上 SFLAG barrier 模型;cross-host barrier 是一个从不触及 SFLAG 的独立层级
- [Tree-Barrier Vsync](../barrier/tree-barrier-vsync.md) — ICI cross-core up-sweep/down-sweep tree barrier;此 host-network barrier 的 on-pod analogue
- [Global-Barrier SFLAG Window](../barrier/global-barrier-window.md) — ICI tree barrier rendezvous 所用的 reserved GLOBAL SFLAG slot,与此 barrier 的 `Notification` 形成对比