DeepEP on EFA

§8 · DeepEP V1 — the NVSHMEM backend on EFA measured

The rest of this guide covers DeepEP-V2 (the NCCL-GIN / ElasticBuffer path). This section covers the other DeepEP backend — V1, the legacy NVSHMEM backend (deep_ep.Buffer, low_latency_dispatch), built on source-compiled NVSHMEM linked against EFA's libfabric. It is what vLLM drives via --all2all-backend deepep_high_throughput / deepep_low_latency. We ran a fresh head-to-head on p5en / H200 / 16 EFA NICs: our NVSHMEM 3.6.5 fork vs the AWS 3.7.0 build.

V1 vs V2 — two different DeepEP backends

V1 — NVSHMEM backend (this section)V2 — NCCL-GIN backend (rest of site)
Python objectdeep_ep.Buffer / low_latency_dispatchdeep_ep.ElasticBuffer
TransportNVSHMEM → CPU proxy → libfabric/EFANCCL-GIN type-2 CPU proxy → EFA
vLLM flag--all2all-backend deepep_high_throughput | deepep_low_latency--all2all-backend deepep_v2
Needs on EFAsource-built NVSHMEM vs EFA libfabric + the EFA shim (no IBGDA)aws-ofi-nccl GIN plugin + ElasticBuffer
DeepEP commit class567632d (pre-EPv2)EPv2 (restructured kernels)

Both are CPU-proxy paths on EFA. Neither uses GPU-initiated RDMA — EFA exposes no IBGDA. The "proxy tax" §2 describes applies to V1 too.

The V1 campaign scoreboard — four frameworks, one transport

All four capstones are complete. The same NVSHMEM/EFA transport validated across serving (vLLM + SGLang), training (Megatron), and full RL (NeMo-RL GRPO):

All measured 2026-06-25 → 2026-07-08 · 2× p5en.48xlarge / H200 / 16 EFA NICs · Qwen3-30B-A3B(-FP8) · evidence: dmvevents/deepep-efa-ab-h200 capstone/
capstoneframeworkworkloadheadline result
C1vLLM v0.11.1 (source)EP16 serving, both backendseager verdict revised: graphed LL wins decode (61.6-65.0 ms, 1.06-1.08× dense), HT unchanged
C2SGLang 0.5.5.post3 (stock)EP16 serving, 3 deepep-modesINVERTS C1: LL wins everywhere, 60–66 ms TPOT, decode c32 497.6 tok/s (+50%)
C3Megatron-LM 23dd639c (stock, 0 patches)2-node MoE trainingloss 26.41→24.59; grad-norms match V2 digit-for-digit; EFA TX 1.083 GB
C4NeMo-RL 46be4e8full GRPO e2e (rollout→reward→train→refit)3/3 steps, internode EP4, EFA TX 537 GB/node
V1-vs-V2: valid comparisons
  • Megatron numerics: same seeds/driver/base commit → digit-for-digit grad-norm equivalence across NVSHMEM-proxy vs NCCL-GIN — the only controlled cross-transport A/B in either campaign.
  • Integration cost: V1 needed FEWER patches everywhere (SGLang stock vs V2 seam patch; Megatron 0 commits vs 3; NeMo-RL 1-hunk guard) — frameworks natively speak the V1 Buffer API.
  • Validation depth: V1 ran the actual GRPO loop; V2's gate was an import-chain wrapper.
  • Mode choice is a framework property: cuda-graph coverage of the dispatch path decides HT-vs-LL, not the wire.
NOT valid to compare
  • Raw serving tok/s across campaigns (different harnesses: AIPerf vs vllm bench/sglang.bench_serving; different framework versions: vLLM 0.24 vs 0.11.1, SGLang 0.5.11 vs 0.5.5) — single-harness A/B not yet run.
  • Training step-times (H200 vs H100, different warmup).
  • Any claim that the verdict flipped: the CPU-proxy ceiling stands; V1 moved the floor (75→60-66 ms via cuda-graphed LL), not the direction. The vLLM dense/allgather A/B is now complete (HT 0.89-0.93× dense = V1 mirror of V2's verdict); SGLang dense arm remains open.

The headline: ours vs AWS on H200 (same nodes, same DeepEP tuner)

1.9×
AWS faster — prefill BF16 dispatch (71.6 vs our 37.0 GB/s RDMA)
2.1×
AWS faster — prefill combine (63.5 vs 30.6 GB/s)
≈ tie
intranode NVLink (320/330/321 GB/s both) — transport-agnostic
0.67 ms
our decode LL dispatch on H200 (after the env fix below)
Internode prefill 4096-tok, BF16, per-bottleneck RDMA GB/s · 2 reps each · p5en/H200/16-NIC
metricA — ours (NVSHMEM 3.6.5 + SWAP)B — AWS (NVSHMEM 3.7.0 + patch)winner
dispatch37.0 / 37.071.6 / 71.7B 1.94×
combine30.6 / 30.763.1 / 63.5B 2.08×
FP8 dispatch29.062.6B 2.13×
correctness24/2464/64tie

Why AWS V1 is ~2× faster (same architecture, NOT IBGDA)

Both stacks are CPU-proxy + libfabric. AWS pulls ahead purely on host-transport efficiency it gets from NVSHMEM 3.7.0:

Our SWAP-004/007/009/017/018 patches are partial hand-ports of work NVSHMEM 3.7.0 ships natively and more completely. The fix is to rebase off 3.6.5 onto 3.7.0 + adopt the AWS deepep_aws_efa.patch, not to keep patching 3.6.5.

Decode / low-latency on H200 — the handle-cache bug + the fix

vLLM's deepep_low_latency backend calls Buffer.low_latency_dispatch/combine. On our NVSHMEM 3.6.5 build this segfaulted on H200 (signal 11 @ 0x28). Root cause (verified at source + runtime, not an SRD-ordering or NIC-count issue — reproduced at NIC_PER_PE=1):

NVSHMEM 3.6.5 symmetric-heap handle-cache bug. For the large (1.88 GB) LL buffer, the proxy's get_transport_mem_handle returns a NULL/garbage remote handle at high offset → NULL flows into fi_write (nvshmemt_libfabric_rma_impl); the NDEBUG build compiled out the guarding assert. Size-gated, not H200-gated.
path3.6.5 fix attemptresult
LL dispatchNVSHMEM_ENABLE_RAIL_OPT=1WORKS — 0.66/0.67/0.72 ms, PASS (first ever our-LL on H200)
LL combineRAIL_OPT + CUMEM_GRANULARITY=2GBstill segv (offset ~939 MB) — needs the real fix
bothrebase to NVSHMEM 3.7.0fixed upstream — see below

The real fix is NVSHMEM 3.7.0: its changelog explicitly closes this — "Fixed a bug in remote transports during memory registration … memory handle management cache" + a NVSHMEM_CUMEM_GRANULARITY static-heap override. The AWS V1 build already runs full LL D+C on H200 (~0.82 ms) because its patch deletes the device-side rkey cache, so all handle resolution happens CPU-side in 3.7.0's fixed transport — the device never executes the buggy offset >> log2_granularity.

The capstone: does V1 actually serve faster? (vLLM EP16, H200, measured)

The microbench above says AWS V1 moves dispatch bytes ~2× faster. The real question is whether that converts to serving throughput. We built a single NGC-from-scratch image (NVSHMEM 3.7.0 + DeepEP 567632d + the EFA shim + vLLM from source) and served Qwen3-30B-A3B-FP8 with Expert Parallelism (EP16, DP16×TP1) across 2× p5en/H200, driving both DeepEP-V1 backends. Repro = one Dockerfile + one serve.yaml + one run_test.sh: github.com/dmvevents/deepep-efa-ab-h200/tree/master/capstone.

~75 ms
HT per-user TPOT — PINNED across all 4 regimes (prefill/decode × conc4/conc32)
+29–75%
deepep_low_latency is WORSE TPOT than high_throughput — in every regime
✓ runs
decode LL completes on 3.7.0 (segfaulted on our 3.6.5)
7.7×
decode tok/s scales w/ concurrency (55→425) — but TPOT stays flat
vLLM v0.11.0, enforce-eager, EP16, n=64 (conc4) / 256 (conc32) per cell · median TPOT (ms) / output tok/s
regimeHT TPOTLL TPOTLL vs HTHT tok/sLL tok/s
prefill conc473.598.4+34% worse53.037.0
prefill conc3277.0134.8+75% worse386.8190.8
decode conc472.793.8+29% worse55.042.6
decode conc3275.298.2+31% worse424.9324.9

REVISED: the eager confound, resolved (2026-07-08) measured

The original matrix above ran both backends --enforce-eager because NGC triton lacks triton_key. We retested with -O.level=0 -O.cudagraph_mode=FULL (level-0 compilation never touches inductor, so no triton_key; CUDA graphs capture fully). LL improves 21-38% TPOT; HT is unchanged (within 1.4% — it was never eager-limited).

-13/-14%
LL TPOT decode (61.6/65.0 ms) — beats HT (71.8/74.9 ms) when graphed
+7/8%
LL TPOT prefill (77.9/83.4 ms) — loses to HT (72.5/77.6 ms)
1.06-1.08×
graphed LL decode vs dense (eager) throughput — first measured DeepEP-beats-dense serving
~60-65 ms
vLLM LL vs SGLang LL floor — frameworks converge when dispatch is cuda-graphed
vLLM v0.11.1, CUDA graphs (level-0/FULL), same 4 regimes + dense allgather_reducescatter baseline (eager, matching the V2 campaign's dense-arm methodology) · n=64/256
regimedense (eager) TPOT / toksHT graphedLL graphedLL/dense toks
prefill c465.3 / 58.872.5 / 53.577.9 / 45.60.78×
decode c466.5 / 59.671.8 / 55.461.6 / 64.61.08×
prefill c3270.2 / 420.977.6 / 373.683.4 / 188.80.45×
decode c3268.5 / 462.774.9 / 425.165.0 / 488.71.06×

Evidence: dmvevents/deepep-efa-ab-h200 commit 55c322a, capstone/results/{cudagraph-retest,dense-ab}/. Retest 2026-07-08. Dense arm run under eager (no cudagraph, matching the V2 campaign's dense-arm methodology).

LL-worse-on-vLLM was an eager artifact. Cuda-graphed LL beats HT in decode (-13/-14%), loses prefill (+7/8%): mode-per-phase, as the SGLang lane predicted. Frameworks CONVERGE once dispatch is cuda-graphed: vLLM LL decode c32 65.0 ms / 488.7 tok/s vs SGLang LL 64.3 / 497.6 — the ~60-65 ms floor is the transport, not the framework.

First measured DeepEP-beats-dense serving cells on EFA in either campaign (graphed LL 1.06-1.08× decode throughput) — but dense wins prefill decisively and remains the safe single-mode default. The site's capacity-not-speedup verdict STANDS overall; this adds a measured decode-heavy exception, not a reversal.

The 2× microbench win does NOT convert to serving. HT per-user TPOT is pinned at ~73–77 ms across every regime (p99 within 1 ms of p50 in decode). Aggregate throughput scales with concurrency, but per-token latency is a hard floor — the fixed CPU-proxy all-to-all round-trip (§2's proxy tax). A faster dispatch microbench moves bytes faster; it does not remove the per-token host hop.

"Low-latency" is not low-latency on EFA. deepep_low_latency is 29–75% worse TPOT than deepep_high_throughput in every regime, including its design home (small-batch decode: 93.8 vs 72.7 ms). On EFA's CPU-proxy path its smaller-message / put+signal optimizations are swamped by — and add overhead to — the per-token host round-trip. Use deepep_high_throughput. This reproduces the V2 capstone's verdict (0.65–0.97× dense): a serving speedup needs GPU-initiated transport (GDAKI/IBGDA), which no shipping EFA stack exposes. Update 2026-07-17: a native kernel-posted path (CQ-poll, no hardware counters) is now measured in §10 — it beats the proxy on dispatch/combine latency but remains a research path, not a serving recipe; this section's verdict is unchanged.

Capstone-2: the same stack under SGLang — and the verdict INVERTS measured

Same image lineage, same NVSHMEM 3.7.0 + EFA shim, same model and nodes — but served by SGLang 0.5.5.post3 (--moe-a2a-backend deepep, TP16 + DP-attention 16). We swept all three --deepep-mode values across the same 4 regimes. On vLLM, "low-latency" was 29–75% worse. On SGLang, low_latency wins every regime:

-33%
LL TPOT vs normal mode — every regime (60-66 vs 91-100 ms)
+50%
LL decode conc32 throughput (497.6 vs 330.9 tok/s)
64.3 ms
SGLang LL decode TPOT — beats vLLM HT (75.2 ms) on the same hw/model
3 fixes
tokens-per-rank=512, QP_DEPTH=2048, watchdog 100s→1800s — all in the recipe
SGLang 0.5.5.post3, EP16 (TP16 + DP-attn 16), 2× p5en/H200, n=64 (conc4) / 256 (conc32) per cell · median TPOT (ms) / output tok/s
regimenormallow_latencyLL vs normal
prefill conc492.1 / 41.561.2 / 62.6-34% TPOT
prefill conc3299.2 / 306.866.3 / 445.8-33% TPOT, +45% tok/s
decode conc491.1 / 43.860.4 / 65.8-34% TPOT
decode conc3296.4 / 330.964.3 / 497.6-33% TPOT, +50% tok/s

auto mode == normal within noise (auto routes prefill chunks through the normal path). Raw JSONL + logs: capstone/sglang/results/ in the repro repo.

Why the inversion? SGLang's LL mode captures cuda graphs around low_latency_dispatch and keeps the CPU proxy hot; its normal mode force-disables cuda-graph, so per-token Python/launch overhead dominates. vLLM v0.11.0 ran --enforce-eager in both backends, so its LL path only added per-message overhead on the proxy (this was subsequently confirmed and resolved — see the REVISED eager-confound block in the Capstone-1 section above). Which DeepEP mode to use is a framework-integration property (cuda-graph coverage of the dispatch path), not a transport property.

Does this change the site's verdict? It moves the floor, not the direction. The ~75 ms "proxy floor" from the vLLM lane is not a transport constant — cuda-graphed LL pushes it to ~60–66 ms. But per-token latency still plateaus far above IB-class DeepEP deployments, and no dense-vs-DeepEP A/B was run on SGLang here: this is a better operating point within the same capacity/fit verdict, not evidence of a serving speedup over dense. GPU-initiated transport (GDAKI/IBGDA) remains the lever that would change the direction.

Capstone-3: training (Megatron-LM) measured

Does V1 train? The vLLM/SGLang capstones validated serving; this validates training. Stock Megatron-LM @23dd639c is a native DeepEP-V1 consumer: megatron/core/transformer/moe/fused_a2a.py imports deep_ep.Buffer directly with zero patches (the V2 campaign's Megatron PR #4632 exists to steer this file away from V1 — so for V1, upstream-as-is is the recipe). We ran the V2 lane's Gate-5 "Shape Y" driver (Qwen3-30B-A3B-style MoE: 128 experts, top-8, hidden 2048) on 2× p5en/H200 with the same seeds and base commit → direct A/B of Buffer/NVSHMEM-proxy vs ElasticBuffer/NCCL-GIN as a training transport.

0 patches
stock upstream Megatron is a native V1 consumer
digit-for-digit
grad_norms match V2/ElasticBuffer/GIN across all 3 steps
1.083 GB
EFA hardware TX delta (≥1 GB gate)
✓ PASS
loss decreasing (26.4→24.6), grad_norm finite, 3/3 gates
V1 Buffer/NVSHMEM vs V2 ElasticBuffer/GIN · same seeds, same Megatron commit, same model · 2× p5en.48xlarge/H200/16-NIC
stepV1 loss (this section)V2 loss (Gate-5)V1 grad_normV2 grad_norm
126.406226.407530.643030.6430
225.110625.102628.197928.1979
324.594424.609727.090927.0909

Losses agree to ~3 decimals (bf16 reduction-order noise); grad-norms match digit-for-digit. NVSHMEM v3.7.0 banner, NVSHMEM_REMOTE_TRANSPORT=libfabric, provider efa. Evidence: github.com/dmvevents/deepep-efa-ab-h200/tree/master/capstone/megatron.

The verdict: numerical equivalence across transports. Grad-norms match V2 digit-for-digit and losses agree to ~3 decimal places — the same tokens move through two entirely different transports (NVSHMEM host-proxy vs NCCL-GIN) with interchangeable training math. This is the strongest correctness statement either lane has produced.

Caveats: Only NORMAL-mode dispatch/combine is on Megatron's path (never low_latency_*). Step-time comparison vs V2 is not valid (different GPUs H200 vs H100, different warmup) — this validates correctness and fit, not a training-throughput claim. It does not change this site's capacity-not-speedup verdict; it confirms V1 trains with the same math as V2.

Capstone-4: the full RL loop (NeMo-RL GRPO) measured

Does V1 train with reinforcement learning? The vLLM/SGLang capstones validated inference serving; Capstone-3 validated supervised training. This validates the complete GRPO loop (rollout generation → reward → training → weight refit) — the stack V2's Gate-6 explicitly skipped as "too heavyweight". Stock NeMo-RL @46be4e8 drove 3 complete GRPO steps on Qwen3-30B-A3B across 2× p5en/H200, using vLLM colocated rollout generation (32 MATH completions per step, mean ~927 tokens), reward calculation, GRPO policy training through stock Megatron fused_a2a.py (deep_ep.Buffer → NVSHMEM 3.7.0 → EFA), and ZMQ weight refit back into vLLM (3.4 s per step).

3/3 steps
full RL loop: rollout→reward→train→refit
537 GB/node
EFA hardware TX delta (internode EP4, NIC counters verified)
3.4 s
Megatron→vLLM weight refit via ZMQ
0 forks
stock NeMo-RL + stock Megatron (1-hunk torch-2.8 guard only)
TP4/PP1/EP4, Qwen3-30B-A3B, 2× p5en.48xlarge/H200/16-NIC · 3 steps × 8 prompts × 4 generations on MATH
stepLossAvg Rewardstep time (s)
1/30.00030.187563.1
2/30.04590.062585.4
3/30.02320.531298.1

Timing split (step 3): generation 62%, policy training 8%, refit 4%. Rollouts are real — 32 completions/step, logged with rewards/advantages/logprobs. Source: github.com/dmvevents/deepep-efa-ab-h200/tree/master/capstone/nemo-rl (commit bc930e7).

The verdict: every stage of the RL loop executes coherently over V1. The expert-parallel a2a genuinely crossed nodes (TP4/PP1/EP4 topology, verified with EFA hardware TX counters at 537 GB/node). Megatron policy training routed through stock fused_a2a.py (deep_ep.Buffer), and weight streaming back to vLLM's generation engine completed in 3.4 s per step.

Honest caveats: 3 steps × 8 prompts is a transport-validation shape, not a convergence claim — reward numbers at n=32 samples/step are high-variance noise (0.19 → 0.06 → 0.53 is sampling variance, not learning progress). GRPO loss is near zero by construction at this scale. What this run does prove: the full loop (rollout + reward + training + refit) works end-to-end on V1.

The PP2 gotcha: an earlier PP2/EP2 run "passed" identically, but its PP boundary aligned with the node boundary → EP groups landed intranode, so DeepEP never touched EFA (TX counters were near zero). PP1/EP4 forces expert groups to span both nodes. NIC counters, not exit codes, are the gate.

How vLLM consumes V1 (the inference mapping)

vLLM all2all backendDeepEP V1 callregimeEFA status
deepep_high_throughputBuffer.dispatch / combineprefill & decodeworks on 3.6.5 & 3.7.0 — BEST TPOT on EFA, use this
deepep_low_latencyBuffer.low_latency_dispatch / combinedecode3.7.0 only; 29–75% worse TPOT than HT on EFA under vLLM (SGLang inverts this — see Capstone-2)

Verified in vLLM distributed/device_communicators/all2all.py: DeepEPHTAll2AllManager → deep_ep.Buffer(...); DeepEPLLAll2AllManager → Buffer.get_low_latency_rdma_size_hint + low_latency_dispatch.

The verdict for V1

V1 on EFA — what's true
  • Runs on EFA via source-built NVSHMEM + the EFA shim (no IBGDA).
  • Use NVSHMEM ≥ 3.7.0 + the AWS patch — it's ~2× our 3.6.5 fork on prefill and is the only V1 build that completes decode LL on H200.
  • vLLM/SGLang drive it directly via deepep_high_throughput / deepep_low_latency.
V1 on EFA — caveats
  • Same CPU-proxy "proxy tax" as V2 (§2) — the serving-throughput conclusions of this guide still apply.
  • Our hand-patched 3.6.5 fork is superseded; don't build new work on it.
  • A serving speedup over dense still needs GPU-initiated transport (GDAKI/IBGDA), absent on EFA.
V1 A/B from the nvshmem-efa campaign (2026-06-24/25). Hardware: 2× p5en.48xlarge, H200, 16 EFA NICs. Stacks: ours NVSHMEM 3.6.5-0 + SWAP + direct-signal-v1 vs AWS NVSHMEM 3.7.0 + deepep_aws_efa.patch (DeepEP 567632d). Capstone serving = vLLM v0.11.0 EP16 (enforce-eager) + Capstone-2 SGLang 0.5.5.post3 EP16 (2026-07-07), both Qwen3-30B-A3B-FP8. Capstone-3 Megatron training (2026-07-08): stock Megatron-LM @23dd639c trains over V1 with zero patches, numerics match V2 digit-for-digit. Capstone-4 NeMo-RL GRPO (2026-07-08): stock NeMo-RL @46be4e8 drives full GRPO loop (rollout→reward→train→refit) through V1, 3/3 steps PASS, 537 GB/node EFA TX. Gap-closure retest (2026-07-08): vLLM eager-confound resolved via CUDA graphs (level-0/FULL); LL beats HT in decode (-13/-14%), dense A/B complete (LL 1.06-1.08× dense decode, HT 0.89-0.93× dense). Evidence: commit 55c322a, capstone/results/{cudagraph-retest,dense-ab}/. Reproducible repo + raw logs + the 3-file serving recipe (Dockerfile / serve.yaml / run_test.sh): github.com/dmvevents/deepep-efa-ab-h200 (see capstone/). Campaign rollup + V1-vs-V2 comparison gist (private): available on request; all numbers trace to capstone/ in the evidence repo. Sanitized — no internal IPs, registry IDs, or hostnames.