Prhub

#50926 [CI][Bugfix] Fix flaky `test_store_orders_after_compute_write`

原始 PR 作者 njhill 合并时间 2026-08-04 08:54 文件变更 1 提交数 1 评论 0 代码增减 +7 / -0

执行摘要

修复 simple_kv_offload 测试的跨阶段流竞争导致的偶发失败。

该测试是一个自校验的竞态测试:无 barrier 的控制组必须实际发生竞态(control > 0),而带 barrier 的修复组必须完全干净(fixed == 0)。但在 CI 上出现了 store raced compute even with the barrier: 1 corrupt 的失败,说明 barrier 实验组被上一阶段(无 barrier 控制组)遗留的 in-flight 内核污染,导致测试结果不稳定,需要让每个阶段自包含。

这是一个小而精准的 CI 稳定性修复,值得快速合入。它展示了一个有价值的调试思路:当自校验竞态测试出现“修复组反而失败”的反直觉现象时,要考虑前一阶段遗留的异步内核造成的跨阶段污染,而不是急着怀疑 barrier 逻辑本身。

讨论亮点

没有实质性的评审讨论。两个 review 分别来自 claude[bot](指出 fork 仓库自动评审被禁用,需维护者手动触发)和 tlrmchlsmth(直接 APPROVED)。PR 作者 njhill 在 commit message 中详细解释了失败机制。

实现拆解

  1. 定位根因_drive_store 的无 barrier 控制阶段中,store 只等待 store-copy 事件,而 compute stream 上的 sleep+fill 内核不受约束,host 循环会继续推进,留下约 800ms 的内核积压。
  2. 修复方式:在 _drive_store 返回前(循环结束后)对 compute_stream 调用 synchronize(),确保该阶段所有计算内核执行完毕后再进入下一个阶段。
  3. 不影响测试语义:该同步仅发生在每个阶段内部,不影响阶段内的竞态探测逻辑,且不改变两个断言的含义。
文件 模块 状态 重要度
tests/v1/simple_kv_offload/test_worker.py 测试 modified 3.99

关键符号

_drive_store test_store_orders_after_compute_write

关键源码片段

tests/v1/simple_kv_offload/test_worker.py test-coverage

这是本 PR 唯一修改的文件,在 `_drive_store` 返回前增加 compute stream 排空,消除跨阶段竞态导致的 flaky 失败。

# tests/v1/simple_kv_offload/test_worker.py
def _drive_store(backend, gpu, cpu, with_barrier: bool) -> int:
    compute_stream = torch.cuda.Stream()
    corrupt = 0
    for it in range(ITERS):
        val = (it % 126) + 1 # 1..126; distinct from the zero-initialized pool
        with torch.cuda.stream(compute_stream):
            torch.cuda._sleep(SLEEP_CYCLES)
            gpu.fill_(val)
​
        wait_event = None
        if with_barrier:
            wait_event = torch.Event()
            wait_event.record(compute_stream)
​
        store_events: list[tuple[int, torch.Event]] = []
        backend.launch_copy(
            block_ids,
            block_ids,
            is_store=True,
            event_idx=it,
            events_list=store_events,
            wait_event=wait_event,
        )
​
        deadline = time.time() + 10.0
        while not store_events and time.time() < deadline:
            time.sleep(0.0005)
        assert store_events, "background copy was never enqueued"
        store_events[0][1].synchronize()
​
        if int((cpu[:, 0].to(torch.int32) != val).sum().item()):
            corrupt += 1
​
    # 排空 compute stream 后再返回:无 barrier 控制阶段中 store 从不等待
    # compute,host 循环会领先很远,留下大量 sleep+fill 内核在飞。若不排空,
    # 上一阶段遗留的 fill 会与 barrier 阶段的 fill->copy 窗口在共享的 gpu
    # tensor 上竞争,偶发破坏一个迭代,导致 'store raced compute even with
    # the barrier' 断言误报。
    compute_stream.synchronize()
    return corrupt

评论区精华

fork 仓库自动 review 被禁用 other

claude[bot] 指出该 PR 来自 fork,自动 review 被禁用,需要维护者手动触发。

结论:tlrmchlsmth 直接批准了该 PR,说明人工 review 完成。 · 已解决

风险与影响

  1. 该改动只影响测试代码,不影响任何生产逻辑,回归面极低。
  2. compute_stream.synchronize() 会让 _drive_store 阶段之间多一次主机端等待,可能略微增加测试耗时,但能稳定消除跨阶段竞态。
  3. 一个潜在风险是:如果未来该测试里的“无 barrier 必须竞态”的语义需要调整,新加的同步点可能会掩盖真正的问题,但这是测试代码自身的权衡,风险很小。

影响范围限定于 tests/v1/simple_kv_offload/test_worker.py 这一个测试文件,面向 CI 稳定性,消除一个偶发失败点。对用户无影响,对团队而言减少了 CI 红盘与重试成本。

仅测试代码变更 跨阶段异步竞态 CI 稳定性

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论