Skip to content

fix(npu): order SHM H2D with graph replay#2035

Draft
pjgao wants to merge 2 commits into
xLLM-AI:mainfrom
pjgao:bugfix/order-shm-h2d-for-npu-graph
Draft

fix(npu): order SHM H2D with graph replay#2035
pjgao wants to merge 2 commits into
xLLM-AI:mainfrom
pjgao:bugfix/order-shm-h2d-for-npu-graph

Conversation

@pjgao

@pjgao pjgao commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

背景

PR1964 为减少 Qwen3.5 CausalConv1d 前的 Host-to-Device(H2D)空泡,把 SHM 输入的 device materialization 提前到了 ForwardSharedMemoryManager::input_read()。在 NPU Graph、schedule overlap、SHM 同时开启时,input_read() 运行在后台 polling thread,因此整包 payload 以及 linear_state_indices 的异步 H2D 都从 polling stream 下发。

这条快速路径在普通解码下可以隐藏搬运开销,但 MTP5 会增加 draft、validate 和 Graph replay 轮次,放大 polling stream 与计算线程并发下发的窗口。TP2 两个 rank 的推进顺序一旦不同,一个 rank 可能停在 Graph task update/H2D,另一个 rank 已进入 HCCL 等待,最终表现为不对称等待、卡住或 TPOT 波动。

根因

问题不是 SHM 容量太小,而是 SHM 内存属性和异步执行顺序不成立:

  1. POSIX SHM 是普通共享内存,torch::from_blob(..., pinned_memory=true) 只修改 Tensor 描述,不能把底层页面变成真正的 pinned memory。
  2. polling thread 在该内存上发起 non-blocking H2D 后,producer 可以很快复用或覆盖 SHM;原 Tensor 也没有独立 ownership 保证异步搬运完成前 payload 一直有效。
  3. polling stream 的 H2D 与计算线程的 Graph task update/replay 没有统一的 stream/event 顺序。MTP5 + TP2 下,这个竞态更容易放大为 rank 间不对称等待。
  4. 仅延迟 linear_state_indices.to(NPU) 仍保留了整包 payload 的 polling-stream H2D,虽然能避免卡死,但没有消除共享内存生命周期和跨 stream 排序问题,性能只能到约 2.994 ms TPOT。

修改

本 PR 保留 SHM transport、schedule overlap 和 Graph replay,只调整 NPU Graph + overlap 组合下的输入 materialization 位置:

  • WorkerServiceenable_graph && enable_schedule_overlap 时调用 input_read(..., false),明确禁止 polling thread 发起 NPU H2D。
  • ForwardSharedMemoryManager 把本轮 SHM payload 复制到真正的、由 ForwardInput 持有的 pinned CPU snapshot。这样 producer 可以继续写下一轮 SHM,而当前轮 snapshot 的生命周期覆盖后续异步 H2D。
  • linear_state_indices 与整包 payload 一起延迟,不再从 polling stream 单独下发。
  • 后续继续走现有 WorkerImpl prepare path,由 ordered prepare stream 执行 ForwardInput::to(NPU),再按已有 capture mutex / ready event 顺序进入 Graph task update 和 replay。

改动范围为 3 个文件,PR 相对 main 为 41 行新增、13 行删除;没有修改 WorkerImpl 的执行逻辑,只复用其已有有序 H2D 路径。

跨平台影响被限制在 NPU:

  • NPU 非 Graph 或未开启 schedule overlap 时继续使用原有提前 H2D 快速路径;
  • CUDA、MLU 的 device materialization 分支保持不变;
  • CPU 默认路径不会新增 pinned-memory 分配;
  • SHM wire format、producer 写入逻辑和 Graph replay 逻辑均未改变。

时序图

PR2035 ordered SHM H2D 泳道图

图中关键术语:

  • POSIX SHM:scheduler 与 worker 之间传递序列化输入的普通共享内存,不等同于 pinned memory。
  • polling thread / polling stream:后台轮询 SHM version、反序列化输入的线程及其曾经使用的 NPU stream;修复后只做 CPU staging,不再 enqueue NPU 工作。
  • owned pinned CPU snapshot:从 SHM 拷贝出的本轮私有锁页副本,由 ForwardInput 持有,避免 producer 复用 SHM 时破坏尚未完成的 H2D。
  • prepare stream:worker 现有的有序输入准备 stream;payload 和 indices 的 H2D 在这里统一下发。
  • Graph task update / replay:更新已捕获 NPU Graph 的动态输入和任务参数,然后重放 Graph。
  • ready event:prepare stream 与 compute stream 之间的完成信号,保证 Graph update/replay 只消费已就绪输入。
  • rank / HCCL:TP2 的两个进程通过 HCCL 集合通信同步;一侧执行顺序异常时,另一侧通常表现为 HCCL 等待。
  • MTP5:推测解码深度为 5,更多 draft/validate/replay 轮次会扩大竞态窗口。

验证

构建与测试:

  • NPU xllm 目标重新编译、链接成功;
  • BatchTest.SharedMemoryRoundTripPreservesLinearStateIds:PASS;
  • BatchTest.SharedMemoryRoundTripPreservesEmptyRankTensors:PASS;
  • git diff --check:PASS。

端到端配置:

  • Qwen3.5-2B,Target TP2,Draft Body TP1,MTP5;
  • HCCL AIV、Graph、schedule overlap、graph decode no-padding、SHM 开启;
  • graph double buffer、prefix cache 关闭;
  • rank 绑核 480–519 / 520–559;
  • log_request 数据集,warmup 8,正式 3 × 20,每请求输出 25 tokens;
  • 当前 PR 提交 6e2d9a2b 对应二进制,正式请求前 ready、真实生成 smoke 均 PASS。

最终 60 条结果:

指标 结果
成功请求 60 / 60
Client E2E 145.645 ms
Client TTFT 74.868 ms
Client TPOT 2.949 ms
Server TPOT 2.975 ms
MTP acceptance rate 59.322%

全程无 timeout、无 rank hang;停止后的 PID、端口和 NPU cleanup 为 PASS。作为对照,之前仅延迟 linear_state_indices 的窄修复 Client TPOT 为 2.994 ms;本方案恢复到历史 2.9 ms 区间,同时从根因上修复 SHM ownership 与跨 stream 排序问题。

本机端到端 binary 同时包含机器所需的权重加载 patch 和 greedy sampling broadcast bypass patch;这两部分不在本 PR 中。

@pjgao
pjgao force-pushed the bugfix/order-shm-h2d-for-npu-graph branch from 8ac687c to 85e3507 Compare July 25, 2026 22:59
@pjgao
pjgao force-pushed the bugfix/order-shm-h2d-for-npu-graph branch from 85e3507 to 4ea2d5c Compare July 25, 2026 23:35
@pjgao pjgao changed the title bugfix: order shm h2d on npu prepare stream. bugfix: defer linear state h2d during graph overlap. Jul 25, 2026
@pjgao pjgao changed the title bugfix: defer linear state h2d during graph overlap. fix(npu): order SHM H2D with graph replay Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant