Uh oh!
There was an error while loading. Please reload this page.
Expert Parallelism: common C API + NCCL EP backend - #3034
Conversation
Greptile SummaryThis PR lands the Expert Parallelism (EP) common C API and NCCL EP backend for TransformerEngine, providing the foundation for upcoming PyTorch and JAX framework bindings. It adds the
Confidence Score: 5/5New foundational EP backend with no blocking correctness issues in the current code; the previously identified races, dangling pointers, and stub-signature mismatches appear addressed. All previously raised issues (initialized_ TOCTOU, ep_group_ mutex races, desc.sizes lifetime, stub signature mismatch, comm_window.h NCCL header dependency, max_token_bytes hardcoding, empty arch_list guard) appear resolved in the current revision. The new findings are limited to an LRU-eviction latency concern and a missing first-call guard for mismatched layer_cfg — both non-blocking robustness issues that don't affect correct usage of the API. transformer_engine/common/ep/ep_backend.cpp — LRU eviction path and prepare_handle_locked deserve a second look before the framework bindings land on top of this. Important Files Changed
Sequence DiagramsequenceDiagram
participant FW as Framework (PyTorch/JAX)
participant API as nvte_ep_* (ep_api.cpp)
participant BE as EPBackend singleton
participant Cache as LRU Handle Cache
participant NCCL as NCCL EP (ncclEp*)
FW->>API: nvte_ep_initialize(ep_comm, group_config)
API->>BE: EPBackend::initialize()
BE->>NCCL: ncclGetVersion() [version gate]
BE->>NCCL: ncclEpCreateGroup(ep_group_)
FW->>API: nvte_ep_handle_mem_size(layer_cfg)
API->>BE: handle_mem_size() [acquires mutex]
BE->>NCCL: ncclEpHandleMemSize()
BE-->>FW: hm_size bytes
Note over FW: allocate handle_mem[hm_size]
FW->>API: nvte_ep_prepare(handle_mem, topk_idx, ...)
API->>BE: prepare() [acquires mutex]
BE->>Cache: prepare_handle_locked(handle_mem, layer_cfg)
Cache->>NCCL: ncclEpInitHandle() [on cache miss]
BE->>NCCL: ncclEpUpdateHandle() [routing AllGather, async stream]
FW->>API: nvte_ep_dispatch(handle_mem, tokens, ...)
API->>BE: dispatch() [acquires mutex]
BE->>Cache: lookup_handle_locked(handle_mem)
BE->>NCCL: ncclEpDispatch() [async stream]
FW->>API: nvte_ep_combine(handle_mem, expert_out, ...)
API->>BE: combine() [acquires mutex]
BE->>Cache: lookup_handle_locked(handle_mem)
BE->>NCCL: ncclEpCombine() [async stream]
FW->>API: nvte_ep_shutdown()
API->>BE: EPBackend::shutdown() [acquires mutex]
BE->>NCCL: ncclEpHandleDestroy() [each LRU entry]
BE->>NCCL: ncclEpGroupDestroy(ep_group_)
Reviews (21): Last reviewed commit: "make core to be RTLD_LAZY" | Re-trigger Greptile |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
099857f to
17e5126CompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
1e74f99 to
319f9d5CompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
…irun in run_test_ep.sh Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
for more information, see https://pre-commit.ci
Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
… NCCL EP build Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
…de dir from its prefix Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
…routing to global counter Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
…ader version log Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
…ticast Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
…CL EP Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
for more information, see https://pre-commit.ci
Signed-off-by: Phuong Nguyen <phuonguyen@nvidia.com>
1abf478 to
3459461Comparephu0ngng
commented
Jun 12, 2026
/te-ci L1 |
phu0ngng
commented
Jun 12, 2026
Pipeline 54600556 |
There was a problem hiding this comment.
Nit: expert_parallel.h or expert_parallelism.h would be a less ambiguous file name, especially in a public-facing header.
Asking a few AIs "What does EP mean in deep learning?":
- Claude: "Expectation Propagation", "Energy Propagation", or "Episode"
- Gemini: "Epoch", various non-MoE models (EP-DNN, EP-PINN, EP-RNN)
- ChatGPT: "Expert Parallelism", "Epoch", "Embedded Projection"
Uh oh!
There was an error while loading. Please reload this page.
| return [remove_dups(reqs) for reqs in [install_reqs, test_reqs]] | ||
| def _discover_nccl_home() -> str: |
There was a problem hiding this comment.
This could be a standalone utility funciton in build_utils/utils.py. It's actually quite general and not specific to NCCL EP.
| print(f"[NCCL EP] No arch >= 90 in NVTE_CUDA_ARCHS ('{archs}'); skipping build.") | ||
| build_with_nccl_ep = False | ||
| if build_with_nccl_ep: | ||
| nccl_home = build_nccl_ep_submodule() |
There was a problem hiding this comment.
Flagging that we compile libnccl_ep.a at a different time than when we compile libtransformer_engine.so.
libnccl_ep.a: Compiled during the Setuptools configuration stage, while processingsetup.py.libtransformer_engine.so: Compiled during the Setuptools build stage, configured via a customsetuptools.Extension.
It's not obviously wrong, but it does seem messy. I suppose there are also some edge case problems (if NCCL is not installed but is listed as a dependency, compiling NCCL EP in the configuration stage will fail but building during the build stage can succeed).
It seems the "proper" approach would be to treat libnccl_ep.a compilation as basically a part of compiling libtransformer_engine.so. However, CMakeExtension is a very general class for CMake projects and I'm not sure how messy it would be to make add the NCCL EP compilation logic.
| ) | ||
| gencode = " ".join(f"-gencode=arch=compute_{a},code=sm_{a}" for a in arch_list) | ||
| nproc = os.cpu_count() or 8 |
There was a problem hiding this comment.
This seems likely to break users with wimpy nodes. We can reuse an existing API to control build parallelism:
| nproc=os.cpu_count() or8 | |
| nproc=get_max_jobs_for_parallel_build() |
phu0ngng
commented
Jun 13, 2026
Pipeline 54600556 - all tests passed. |
timmoon10
left a comment
There was a problem hiding this comment.
This still has some minor issues, but deadlines are what they are and the changes are well-contained. We should incorporate suggestions into future PRs.
Uh oh!
There was an error while loading. Please reload this page.
This reverts commit c3396ee. Signed-off-by: Tim Moon <tmoon@nvidia.com>
Summary
First PR in the TE Expert Parallelism (EP) series. Lands the common C API and NCCL EP backend that later framework PRs (PyTorch, JAX) build on. No Python bindings yet — common-lib foundation plus build wiring only. Build/load works on any arch; SM and NCCL version gates fire at runtime.
Every network-bound payload tensor takes an optional
NVTECommWindow. When the window is provided, the backend uses NCCL EP's symmetric-memory zero-copy path, which skips the D2D Memcpy from the user buffers to the Symmetric Staging Buffers.Implementation
Public C API (
transformer_engine/common/include/transformer_engine/{ep.h,comm_window.h})Types:
NVTEEpGroupConfig,NVTEEpLayerConfig,NVTEEpHandle,NVTECommWindow(side-band{ncclWindow_t window, size_t offset}; NCCL peer handles are not carried onNVTETensor).Lifecycle (host-only, eager):
nvte_ep_initialize— borrow an externalncclComm_tfor the EP sub-group and init the singleton backend.nvte_ep_shutdown— tear down the backend; idempotent; does not destroyep_comm.nvte_ep_register_layer— reserve ahandle_idfor a layer config and report thehandle_membuffer size the caller must allocate. The pair{id, mem}becomes the per-stepNVTEEpHandle.Per-step (allocation-free, CUDA-graph capturable)
nvte_ep_prepare— all-gather the routing map and write routing maps tohandle.mem.nvte_ep_dispatch— scatter tokens and routing weights from source ranks to expert ranks.tokens,topk_weights,recv_tokens,recv_topk_weightseach accept an optional symm-mem window for zero-copy.nvte_ep_combine— scatter-sum expert outputs back to source ranks (unweighted; caller pre-multiplies byrecv_topk_weights).expert_outaccepts a window.nvte_ep_dispatch_bwd— backward of dispatch; routes token and weight grads back to source.gradandg_recv_topk_weightsaccept windows; the gathered outputs (grad_tokens,grad_topk_weights).nvte_ep_combine_bwd— backward of combine;gradandgrad_expert_outaccept windows. Padded slots ingrad_expert_outare zeroed.Backend + build
transformer_engine/common/ep/):EPBackendsingleton, HT-mode dispatch/combine over NCCL EP (libnccl_ep.so), group/layer registration. Internal helpermake_payload_tensor()builds the per-callncclEpTensor_t: when the caller'sNVTECommWindow.window != nullptrit setswin_hdl+win_offset(zero-copy); otherwise it setsdatafromnvte_tensor_data(t)(HBM fallback).EPBackend::initialize): SM>=90 (viacudaDeviceGetAttribute), NCCL>=2.30.4 (viancclGetVersion), CUDA multicast/NVLS support.NVTE_WITH_NCCL_EP=OFF,ep/ep_api_stub.cppprovides throwingnvte_ep_*stubs so framework bindings link unconditionally; failure surfaces at firstnvte_ep_initialize.setup.pybuildslibnccl_ep.sofrom3rdparty/ncclby default; auto-disables NCCL EP when no requested CUDA arch >= 90. ExplicitNVTE_BUILD_WITH_NCCL_EP=1with all archs < 90 is treated as user errorNVTE_BUILD_WITH_NCCL_EP=0to opt out.NCCL_HOMEresolved dynamically: explicit env →/opt/nvidia/nccl,/usr/local/nccl,/usr→ldconfig -pfallback.Testing
tests/cpp_distributed/.Type of change
Checklist: