Skip to content

perf(ep/v2): sync main + port #613 InterNodeV1LL combine opt to the cco kernel - #631

Merged
jhchouuu merged 8 commits into
dev/adpat_v1ops_to_cco_apifrom
dev/pr625-sync-main-port613
Sep 7, 2026
Merged

jhchouuu merged 8 commits into
dev/adpat_v1ops_to_cco_apifrom
dev/pr625-sync-main-port613

Conversation

@jhchouuu

@jhchouuu jhchouuu commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Targets the #625 branch (dev/adpat_v1ops_to_cco_api), not main.

What

  1. Merge main into the CCO-internode branch. Brings in perf(ep): optimize InterNodeV1LL small-token latency on EP16 #613 (InterNodeV1LL small-token opt), feat(shmem): add a CPU host-proxy RDMA transport alongside IBGDA #558 (host-proxy RDMA transport), bugfix: mlx5 ci hung #622, etc. Clean merge, no conflicts.

  2. Port perf(ep): optimize InterNodeV1LL small-token latency on EP16 #613's combine-gather optimization to the cco kernel. ep_internode_kernel.hpp is a deliberate second copy of the v1 kernel, so perf(ep): optimize InterNodeV1LL small-token latency on EP16 #613 landing in internode_v1.cpp via the merge does not reach it. Mirrored here in the two LL combine paths (CombineIntraNodeLLTyped, CombineInterNodeLLTyped):

    • 16B load-first gather (CombineGather / kCombineVecBytes=16) with a per-launch CombineVecAligned() fallback to the 4B path, replacing WarpAccum<TokT,4>.
    • Size the warp slice by the vector step: MultiWarpIter gets CombineVecStep granularity in the intra-LL path; the inter-LL path sets warpsPerToken = hiddenDim / vecStep (was a fixed 4 → 6 for hidden 6144 bf16) and snaps hiddenDimPerWarp to a whole number of steps, keeping every warp on the vector path.

    Helpers are duplicated rather than shared, matching the PR's two-copy split of the v1 kernel.

Validation (2-node MI308X + bnxt, ROCm 7.14, EP16)

  • v1_ll test 128-tok, 500 rounds → 1000/1000 Dispatch+Combine Pass, 0 fail. The 16B gather is correct (bf16 hidden 6144 is 16B-aligned; unaligned topk/dtype fall back to 4B).

  • v1_ll bench 128-tok, clean idle before/after (2-rep median):

    dispatch avg (µs) combine avg (µs)
    before (pre-port) 147.8 166.2
    after (ported) 148.5 163.7

Note on the perf delta

The port is correct and non-regressing but latency-neutral on this MI308X CCO path (combine ~-1.5%, within noise). #613's larger win on MI308X came substantially from its re-tuned InterNodeV1LL launch table (combine block/rdma/warp = 32/21/6), whereas the cco path uses the hardcoded _KERNELS geometry (256/128/8) — only warpsPerToken (4→6) tracks the tuned split. Small-token combine on MI308X is also XGMI-bandwidth-bound, so vectorizing the gather is neutral there. Realizing #613's latency win on the cco path needs a separate re-tune of the cco v1_ll launch geometry; this PR keeps the two kernel copies in sync and should help on the arch/geometry combos where the shmem path saw the gain.

🤖 Generated with Claude Code

itej89 and others added 8 commits September 1, 2026 20:41
- Opt-in via MORI_ENABLE_HOST_PROXY. Unset, every existing path is
   unchanged: no removed lines in shmem init, the native branch of
   symmetric memory registration is identical, and GpuStates only grows
   by appended fields.
- GPU warps publish 128 B descriptors into a host-pinned ring; per-NIC
   CPU threads drain them into ibv_post_send, chaining by QP so a batch
   costs one post per QP.
- Built on IBVerbsDeviceContext rather than the mlx5/bnxt/ionic DV
   providers -- proxy mode needs no vendor direct-verbs library, and
   inherits its QP setup, error handling and endpoint teardown.
- One ring and one proxy thread per NIC; QPs are picked by the agreed-rail
   formula and symmetric memory carries per-NIC lkey/rkey.
- Atomics: native IBV_WR_ATOMIC_FETCH_AND_ADD on mlx5; SEND_WITH_IMM
   emulation elsewhere, where the responder performs the add and replies
   for the fetch variants. Targets are validated against the heap range.
- Signals paired with data use RDMA_WRITE on the same QP as the payload
   so PCIe ordering is preserved.
- MORI_PROXY_ENABLED goes through _tunable_defines(), so it is part of the
   JIT cache key and reaches both the genco and bitcode compiles.
- Validated on 2-node EP16 across Mellanox CX7 / MI300X, AMD Pensando
   AINIC (DigitalOcean and Crusoe) and Broadcom Thor2. Steady-state
   throughput matches main; proxy mode shows tighter worst-case latency.
- Known limitation: the async_ll kernel type is not supported under the
   proxy.
* migrate mlx ci to 19-05 & 19-14

* fix mlx poll cq bug:  clamp doneIdx against dbTouchIdx, not postIdx — the old
 window exceeded 65536, so a stale wqe_counter wrapped into a bogus advance and
 the recycle gate overwrote live SQ slots.
…rnel

The cco internode kernel (ep_internode_kernel.hpp) is a separate copy of the
shmem v1 kernel, so the #613 combine optimization landing in
internode_v1.cpp via the main merge did not reach it. Mirror it here:

  - 16B load-first gather (CombineVecBytes=16 / CombineGather) with a per-launch
    CombineVecAligned() fallback to the 4B path, replacing WarpAccum<TokT,4> in
    CombineIntraNodeLLTyped and CombineInterNodeLLTyped.
  - Size the warp slice by the vector step instead of a fixed warpsPerToken=4:
    MultiWarpIter gets CombineVecStep granularity in the intra-LL path, and the
    inter-LL path sets warpsPerToken = hiddenDim / vecStep and snaps
    hiddenDimPerWarp to a whole number of steps, so every warp stays on the
    vector path instead of a scalar tail.

Helpers are duplicated (not shared with internode_v1.cpp) to match the PR's
deliberate two-copy split of the v1 kernel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1_ll

The cco internode path takes its grid from dispatch_combine.py (the shmem
resolve) via the launch redirect, which is not CU-aware: on MI308X (80 CU) it
lands on 96/64/8 (MANUAL) or the InterNodeV1LL AUTO default 256/128/8 -- 1.2x
and 3.2x the CU count, so the grid tail runs a second wave and small-token
latency suffers.

Add internode_tuning_configs.py: a per-device (PCI DID / CU count), per-shape,
per-token table with an explicit rdma_block_num per phase, mirroring
tuning_configs.py but looked up host-side with the live num_tokens (the redirect
has no runtime schedule). lookup() clamps block_num <= CU count. The redirect's
dispatch/combine wrapper pins the result when the caller left geometry unset;
an explicit block_num still wins.

MI308X EP16 h6144 (fp8 dispatch / bf16 combine), tuned 2-node on skyriver07+04,
vs shmem-main (pr627) v1_ll, us disp/comb:
  tok4   shmem 47.4/58.4  ->  cco 46.1/62.8   (disp -3%, comb structural gap)
  tok8   shmem 47.1/59.1  ->  cco 47.3/61.6
  tok16  shmem 49.3/62.5  ->  cco 46.4/55.3   (disp -6%, comb -12%)
  tok32  shmem 56.1/78.9  ->  cco 51.0/66.0   (disp -9%, comb -16%)
dispatch beats shmem at every count; combine wins big at 16/32. The tok4/8
combine gap is the 4-kernel combine launch overhead, not geometry -- tracked
separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oupling

The tok4/8 dispatch geometry (32/16/6, 64/16/4) was tuned for dispatch latency
in isolation, but dispatch and combine are coupled: they share the CUDA-graph
replay and the QPs, and a dispatch with rdma_block_num=16 leaves the combine
that follows it ~18us slower at 4/8 tokens than rdma=32 does (combine ~77us vs
~56us, measured 2-node clean on skyriver07+04). The isolated dispatch win (~46
vs ~50us) is dwarfed by that combine loss.

Hold small-token dispatch at 64/32/8. tok8 then measures d~50/c~56 (combine now
beats shmem-main's ~59; dispatch ~ties), where 64/16/4 gave d~46/c~76.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clean fp8-dispatch/bf16-combine sweep on skyriver07+04: tok8 combine at
32/21/6 measures Best 47 / Avg 58.7 vs 64/32/4's Best 53 / Avg 63.5 -- the
earlier 64/32/4 was a contention-contaminated pick. Small blocks win at small
token counts for combine, same as tok4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jhchouuu
jhchouuu merged commit 562d5b4 into dev/adpat_v1ops_to_cco_api Sep 7, 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.

4 participants