CollectiveX is an experimental MoE expert-parallel communication benchmark. It measures dispatch, combine, and paired roundtrip latency across EP libraries and accelerator systems, then uploads neutral result artifacts.
A second suite, the vLLM swap_blocks benchmark
(中文), measures pinned CPU↔GPU and same-GPU block copies,
with its own correctness checks and latency/bandwidth JSON output. It runs through the same
sweep matrix and pool launchers (suites: swap-blocks).
CollectiveX schedules benchmarks, executes them on real allocations, and uploads the neutral artifacts each run emits. It does not validate those artifacts, promote, rank, recommend, select, or decide what a consumer displays. Any downstream display or comparison is the consumer's responsibility. The full measurement methodology is in docs/methodology.md.
The workload uses packed placement and one pinned fixed-profile resource configuration per
backend/topology. There is no tuning sweep. Combine is always BF16. Dispatch precision is a swept
dimension, with a BF16 control plus, on every backend whose FP8 dispatch is supported upstream
(DeepEP V2, MoRI, UCCL-EP, FlashInfer EP), an FP8 dispatch, caller-prequantized in normal mode (in
low-latency the DeepEP and UCCL-EP kernels quantize internally from BF16. MoRI stays
caller-prequantized, while FlashInfer has no low-latency path). That caller-side quantize is charged
inside the measured dispatch, because a production forward pass pays it on the critical path. NCCL EP
is BF16-only this release, so it emits the control alone. Coverage is uniform routing only. Cases run
in one of two modes:
normaluseslayout-and-dispatch-v1, rank-deduplicated token payloads, and activation-only, unweighted rank-sum combine. It runs the full decode and prefill ladders.low-latencyuses each backend's decode-optimized kernel family: on DeepEP the legacydeep_ep.BufferIBGDAlow_latency_dispatch/low_latency_combine(a per-expert padded receive and a source-side gate-weighted combine). On UCCL-EP the same legacyBufferlow-latency kernels, which at the scoped EP8 runcudaIpcover NVLink rather than its CPU-proxy transport. On MoRI theAsyncLLkernel driven split-phase (send+recv inside each timed component — the kernel SGLang deploys for low-latency; same compact layout and unweighted rank-sum combine asIntraNode). It is a decode-phase-only, per-SKU-capability-gated addition whose runnable set differs fromnormal's, so it is enabled from each SKU'sll_backendsregistry entry (currently DeepEP V2 at EP8 on H100/H200 and at EP8 and EP16 on B200 (the nscale bare-metal pool, whose gdrdrv-backed IBGDA over native IB is what a low-latency scale-out needs and no virtualized pool has) and on GB200/GB300, whose EP16 stays inside the MNNVL scale-up domain, plus MoRI EP8 on MI355X only (the MI300X/MI325X registries carry no low-latency rows) and UCCL-EP EP8 on H100/H200/B200 only (UCCL's low-latency host assertkNumMaxTopK + 1 <= num_warp_groups * num_warps_per_groupcannot hold on AMD, wherekNumMaxWarpGroupsis 16, since upstream raisedkNumMaxTopK9 -> 16 (uccl#1016, 2026-07-13) and our pin is six days later. The product is 16 for every CU count, so this is a dated regression rather than a hardware limit, and the AMD SKUs keep UCCL-EP normal mode without LL), and NCCL EP at EP8 on H100/H200/B300 and at EP8 and EP16 on B200/GB200/GB300, enabled with the v0.2 upgrade (thenccl-extensionswheel ships the combine-recv fence whose absence had held these rows — see the backend table below; the earlier NVIDIA/nccl#2303 signal aliasing was already fixed by the single-handle change). B300 carries thecandidateNCCL EP as its only low-latency row, so it has no production decode coverage. DeepEP V2 emits no LL row at all on B300 (the IBGDA address-handle wall in the backend table below), and_ll_runnableadds only runnable cells, so that wall is prose here rather than a classified matrix row). Scoped single-node EP8 runs over the intra-node NVLink/XGMI low-latency path (no/dev/gdrdrvneeded, as validated on H200 with it absent). NVSHMEM/IBGDA on the wire carries payload only on a multi-node scale-out (EP16) run. The legacy Buffer still self-enables IBGDA at EP8, which is why B300 fails there.
Cases use a fixed timing profile from configs/sweep.json: 256 trials x 8 timed iterations (2048
samples per component) with 32 synchronized full roundtrip warmups before each measured component at
every trial/point. Component measurement order rotates each trial so every timed component occupies
every position in the sequence, and each iteration takes the cross-rank maximum before nearest-rank
p50/p90/p95/p99. A keyed BLAKE2b counter produces
byte-identical routing and gate weights on every runtime. Graph-compatible backend/mode pairs (mostly decode; MoRI and prefill
stay eager) run these measurements under CUDA graph replay by default, where graphed fresh-entry
components publish only p50; COLLX_CUDA_GRAPH=0 restores eager (see the methodology's CUDA Graph
Replay section).
Those components all measure fresh entry (the GPU is drained around every timed window), the
latency of an idle pipeline, not what a decode loop pays. So every row also carries the chained
pair period: 4 trials x (128 dispatch→combine pairs issued back-to-back with no host sync, first
16 dropped as pipeline fill) = 448 observations, reduced across ranks by median. Each trial runs
two sibling chains (a floors chain carrying only per-op events, then a period chain carrying
only the outer pair events), because the first version's single six-events-per-pair chain charged
its four inner record() calls into the period wherever the device outran the host, publishing a
~flat 10–30µs host constant as transport (+20–38% at T=1, fleet-wide). components.pair_period is
the headline latency for every row that carries one (released 2026-08-06 after the b200/h200/gb200
hand references were confirmed against two-pass fleet artifacts), and summarize.py footnotes what
its starred columns hold either way. The floors chain publishes chain_floor_us, the
cross-rank minimum of each op's window, while the period chain also yields chain_health.pair_spread_us
(cross-rank cadence proof), interpair_gap_us (the per-pair cost outside the published window, which is the
regression guard for instrumentation creeping back in, and the discriminator that keeps a
sync-dominated period − Σfloors gap from being misread as that defect returning. See the
methodology's chain_floor_us bullet for what each sign of that residual means) and
settle_drift_us (late-half minus
early-half period, the convergence proof chain_drop otherwise merely assumes). Chained per-op
medians are never published: inter-rank wait parks in whichever op window a rank blocks in, stable
per rank, arbitrary across ranks, and conserved only in the pair total. Nothing existing was renamed
or re-meant and the sweep version stays 1, so consumers key on the presence of
components.pair_period.
The chained regime is checked twice over: each chain trial's own final combined output is compared
against a drained pair through the identical code path (correctness.chain_last_output_passed,
with the size of any difference in correctness.chain_last_output_error), and the full oracle runs
once per ladder point against the state the chain leaves behind
(correctness.post_chain_state_passed). The second always gates. The first gates only where the
chain stages per pair, and is null where staging is hoisted out of the chain. Under the hoist
neither regime combines an input matching its own dispatch, so the two are not comparable. That
boundary was measured rather than assumed: identical h100 cases differ by 1000×–2966× the combine
tolerance with the hoist and by exactly zero without it. See the methodology's Correctness section. The null is a deliberate, bounded gap. An FP8-only,
free-running-only, stateless corruption would red no gate, and the CX_FP8_CONSUME=dequant hatch
is the standing probe for it.
roundtrip means dispatch then combine (the transport) in every row. Expert-output staging sits
outside it and is reported separately as stage. Under FP8 that component is harness scaffolding
standing in for the expert GEMM, which in production consumes FP8 operands natively rather than
materialising a BF16 copy, so stage must not be summed into a total or compared between backends.
Rows measured before this change carried the staging copy inside the chain for MoRI BF16 and
FlashInfer BF16, and the sweep version stays 1 across it, so
implementation.stage_excluded_from_roundtrip and whether a stage component is present are the
only way to tell the two generations apart. See docs/methodology.md for the
full contract.
Correctness is checked against an implementation-independent oracle that reproduces the backend's
two-level reduction, with intra-scale-up-domain FP32, then a BF16 cast of each domain's partial for the
scale-out send. The combine gate is a tight max elementwise relative error below 8 * 2^-8
(denominator clamped at 0.02), which holds across scale-up and multi-node scale-out topologies
alike. Under FP8 dispatch the oracle applies the same per-token cast round-trip to its semantic
payload, so the dispatched-payload compare stays bit-exact and the combine gate is unchanged. The
quantization is modeled, not tolerated. Any failed rank or point makes the case ineligible in the
result it writes.
The matrix covers H100, H200, B200, B300, GB200, GB300, MI300X, MI325X, and MI355X. sweep_matrix.py materializes
the requested SKUs, backends, EP sizes, and token ladders, then extracts strict per-shard controls
and rejects missing, stale, malformed, or altered shard controls. --only-sku, --exclude-skus,
--ep-sizes, and --precisions select a subset. --suites picks the suites (ep by default;
swap-blocks adds one single-GPU shard per pool from configs/swap_sweep.json). Every suite's
shards take the same path: the pool launcher allocates, runtime/config.py case-args encodes each
case as its entrypoint's argv, and the rank wrapper execs that entrypoint. The matrix is generated
per dispatch, with no frozen digest or locked case count.
| Systems | EP8 | EP16 |
|---|---|---|
| H100/H200/B200/B300 | 1x8 NVLink, scale-up | 2x8 NVLink + RDMA, scale-out |
| MI300X/MI325X/MI355X | 1x8 XGMI, scale-up | 2x8 XGMI + RDMA, scale-out |
| GB200/GB300 | 2x4 MNNVL, scale-up | 4x4 MNNVL, scale-up |
Physical host count does not determine scope: both GB topologies stay inside one 72-GPU MNNVL scale-up domain.
| Backend | Engine availability | Current scope |
|---|---|---|
| DeepEP V2 | production, with vLLM --all2all-backend deepep_v2, SGLang --moe-a2a-backend deepep |
normal mode is PR #605 ElasticBuffer plus exact upstream #630 and #640 fixes: LSA for scale-up and GIN for x86 EP16 scale-out. FP8 dispatch via use_fp8_dispatch (blockwise e4m3fn) alongside BF16. low-latency mode is the legacy deep_ep.Buffer IBGDA decode kernels (per-expert padded layout, weighted combine, use_fp8 e4m3fn), decode only, with EP8 wherever enabled, plus EP16 on GB200/GB300 (inside the MNNVL domain) and on B200's nscale bare-metal pool (IBGDA over native IB rails with /dev/gdrdrv, although the prior virtualized b200 pool could never run it). B300 is an unsupported coverage row in low-latency: the legacy Buffer self-enables NVSHMEM IBGDA even for a single-node EP8 run, and on B300 address-handle creation fails (ibgda.cpp:2234 Unable to create ah), rc255 on all eight ranks. NVSHMEM_DISABLE_IB=1 does not help. The Buffer re-enables IBGDA regardless, and the run fails identically with it set and unset (measured on b300-002 and b300-011) |
| MoRI | production, with vLLM --all2all-backend mori_*, SGLang --moe-a2a-backend mori |
normal mode uses the direct IntraNode kernel for scale-up EP8 on every CDNA SKU and the InterNodeV1 kernel for scale-out EP16 on mi355x (2x8 over Pollara RoCE, MoRI's default STATIC_HEAP). EP16 stays an unsupported row on the tw pairs, which have no cross-node GPU fabric. Two caller-side defects kept the mi355x row red before: this harness passed dispatch's returned recv-slot indices to combine() instead of the rank's own routing (part of ROCm/mori#475, guarded upstream by ROCm/mori#546), and it forced MORI_SHMEM_MODE=VMM_HEAP for scale-out, which on ROCm 7.2 leaves the heap in the cached pool and corrupts cross-node combine partials from T~64 up and at every prefill size (ROCm/mori#610; same-branch CI A/B: STATIC_HEAP green on every rung in run 34939333022, VMM_HEAP red in run 34941185534). The adapter now fails closed on any heap mode other than STATIC_HEAP. uccl-ep EP16 stays off mi355x: its CPU-proxy RDMA is functional on Pollara but ~13x under its documented bandwidth (~6 GB/s vs 82; unchanged by registration mode or traffic class — ionic-driver suspect). low-latency mode selects the AsyncLL decode kernel driven split-phase (dispatch send+recv, combine send+recv — the kernel SGLang deploys; same compact layout and unweighted combine as IntraNode; earlier rows measured IntraNodeLL, discriminated by kernel_generation), decode/EP8 only. FP8 dispatch is caller-prequantized (per-SKU e4m3fnuz on gfx942, e4m3fn on gfx950). Combine stays BF16 (quant_type=none) alongside BF16 dispatch |
| UCCL-EP | candidate (no engine exposes a UCCL-EP selector) |
UCCL EP: a drop-in, API-identical DeepEP replacement whose CPU proxies issue GPUDirect RDMA over plain libibverbs (no NVSHMEM/IBGDA), with software message ordering, atomics, and flow control. Scale-up is single-node cudaIpc over NVLink/XGMI (never MNNVL). normal mode is the legacy Buffer dispatch/combine (unweighted rank-sum). low-latency reuses the legacy low_latency_dispatch/low_latency_combine decode kernels (weighted combine), decode/EP8 only. FP8 dispatch is caller-prequantized in normal mode (blockwise e4m3fn, per-SKU e4m3fnuz on gfx942). In low-latency mode the caller sends BF16 and the decode kernel quantizes to e4m3 internally (use_fp8). Combine is BF16. Runs on NVIDIA and AMD (H100/H200/B200 + MI300X/MI325X/MI355X), EP8 scale-up. Cross-node EP16 is functional (the internode RDMA path connects and the light case passes correctness) but its CPU-proxy throughput overruns the standardized per-case wall-clock budget on heavy token counts, so EP16 is an unsupported coverage row for now |
| NCCL EP | candidate (NVIDIA's own library, but no engine exposes an NCCL-EP selector) |
NCCL EP v0.2: NVIDIA's native MoE dispatch/combine on the NCCL Device API, using LSA (NVLink load/store) intra-node and GIN (GPU-Initiated Networking) inter-node. Since v0.2 it ships as the nccl-extensions PyPI wheel (which owns nccl.ep; nccl4py — pinned alongside — provides only nccl.core), replacing the contrib/nccl_ep tree in NVIDIA/nccl, which has not moved since 2026-06-11. normal mode selects the HIGH_THROUGHPUT algorithm (FLAT [N, hidden] receive, unweighted rank-sum combine). HT requires ZeroCopyMode.ON: its receive token plane is NCCL-allocated and collectively registered as a symmetric window, so dispatch and combine use it directly. LL uses the rank-major, pre-reduced contract used by inference frameworks; zero-copy is enabled within one LSA/MNNVL domain and disabled for scale-out. The LOW_LATENCY algorithm carries ll_backends rows at EP8 on H100/H200/B300 and EP8+EP16 on B200/GB200/GB300. Its decode ladder runs unclamped to the full 256-slot receive: v0.1's combine recv pipeline was a port of DeepEP's pre-#642 kernel, missing the shared-memory fence before mbarrier_arrive (bimodal T=256 corruption on GB300, 1 of 5 executions at 0.4704 relative error against healthy 0.0039), and the v0.2 wheel ships that fence (fence_view_async_shared before the emptyBarriers arrive in the shipped ll_ep.cuh), the documented restore condition for the T<=128 clamp it forced. BF16 only for now: v0.2 exposes FP8 dispatch (DS_FP8E3M4) and an experimental NVFP4 combine recipe, but wiring those into the fp8_consume model is separate bring-up, so no FP8 case is emitted yet. NVIDIA-only and CUDA 13 only. EP8 and EP16 on all six NVIDIA SKUs: EP16 stays inside the MNNVL scale-up domain on GB200/GB300 and is a 2x8 RDMA scale-out over the cross-node GIN path on H100/H200/B200/B300. Under v0.1 that GIN path faulted inside nccl_ep.cc identically on RoCE and IB on every x86 pool; v0.2 clears it, revalidated on-metal on B200, H100 and H200, with B300 enabled on the same fix pending its pool's revalidation |
| FlashInfer EP | production, with vLLM --all2all-backend flashinfer_nvlink_one_sided |
FlashInfer MoeAlltoAll: TensorRT-LLM's one-sided MNNVL all-to-all, where each rank writes tokens straight into its peers' workspace windows and combine reads them back, with no send/recv pairing and no NVSHMEM. normal mode only (there is one kernel family and no separate decode path), and GB200/GB300 only, since the transport is MNNVL. FP8 dispatch is caller-prequantized blockwise e4m3fn, carried as a fourth dispatch payload alongside its per-128-block FP32 scales, with the combine plane forced to BF16. The C++ toNvDataType accepts only fp16/bf16/fp32 for combine, so an FP8 combine buffer would raise rather than corrupt. EP8 and EP16, both inside the scale-up domain. Unlike every other backend here, its combine accumulates in the PAYLOAD dtype rather than FP32: wheels before 0.6.16 reduce the top-k contributions with a pairwise BF16 tree that rounds at every level, so the oracle models that reduction directly (combine_reduction = "topk-slot-tree") instead of widening the tolerance. 0.6.16 moved the accumulator to FP32, and the adapter switches models on the installed version |
DeepEP V2 means the ElasticBuffer implementation introduced by
DeepEP PR #605, not a newer legacy Buffer build.
The pinned source is upstream main, which contains #605 along with
PR #630 (fixes pure scale-up initialization when
GIN is unavailable), PR #640 (stops NCCL
shared-memory mappings being misclassified as duplicate NCCL libraries), and
PR #642 (the low-latency combine fence that fixes
the Blackwell top-rung corruption of
issue #700), which the previous pin, the #630
head on the pre-merge #605 branch, predated. Scale-up cases request NCCL Device API LSA and fail closed
unless the realized LSA team covers the full EP world. x86 EP16 scale-out cases instead require the
hybrid path with GIN, two logical scale-out domains represented by two physical RDMA ranks, and eight
scale-up ranks per domain. GB EP16 remains MNNVL scale-up and therefore uses LSA. Whether a given
SKU/backend/EP cell is attempted is a capability fact. Whether it succeeded is decided by the
benchmark's return code.
.github/workflows/collectivex-sweep.yml has two jobs. setup generates a public-SKU matrix
(backend, only_sku, exclude_skus, ep_sizes inputs) and uploads the matrix.
sweep extracts a strict ignored .shards/<id>.json control per matrix entry, executes one
allocation per shard, fetches pinned DeepEP source before allocation when required, and uploads the
result artifacts with always() so a red or partial run still uploads.
Each shard emits per-case result JSON and a small mechanical summary. A case counts as successful on the benchmark's own return code. There is no completeness or privacy validation step, and failed or unsupported cells produce no synthetic record. No step promotes a run, builds a dataset, or advances a channel. The neutral artifacts are the output. A consumer downloads them and decides what to display.
No operator credentials are passed to the workflow or uploaded. Runner-local overrides and any selectors stay on the runner. Per-step runner logs are kept on the runner for postmortem, and result artifacts carry only the fields listed in the methodology.
Each SKU's Slurm and storage values come from its tracked baseline in the registry. An optional
runner-local JSON document at $XDG_CONFIG_HOME/inferencex/collectivex.json or
COLLECTIVEX_OPERATOR_CONFIG overlays that baseline per field. A runner with no registry entry, an
unknown field, and non-JSON input all fail closed, and configuration is never evaluated as shell.
Duplicate JSON keys are NOT rejected. json.load keeps the last silently, and runner keys other
than the one being resolved are not validated, so a typo'd SKU name is ignored rather than
reported. GHA passes no operator secret, so a SKU runs entirely from its tracked baseline unless a
runner-local document is present.
All public per-SKU platform data lives in the tracked configs/platform_config.json registry:
architecture/product, container image and platform, fixed placement, launcher, runnable backend/EP
pairs, the scale-out fabric identity (NIC and switch, so same-GPU clusters on different fabrics
are distinct entries, e.g. a second b200 cluster), tracked operator defaults, and scale-out RDMA
selectors. Operator documents can override the defaults. Launchers
declare and check the fields they actually require. sweep_matrix.py derives EP topology from the
placement fields. The sweep includes every registered SKU by default.
Every selected non-MNNVL EP16 placement additionally requires rdma_devices for its
operator-approved fabric. socket_ifname pins the cross-node socket interface; without it the
allocated node's default-route interface is used (h200-dgxc, b300). Optional ib_gid_index,
rdma_service_level, rdma_traffic_class, rail_isolated and rdma_fabric are also allowlisted.
Service level and traffic class are mapped into MoRI's RDMA/IO QoS environment.
CollectiveX does not heuristically select a management route or HCA. After allocation, every
non-MNNVL scale-out node must prove that all configured interfaces and active HCA ports exist before
backend setup. Scale-up and MNNVL jobs clear these overrides. Scale-out NCCL/RCCL is pinned to IB
with exact-match HCA selectors so a socket fallback fails instead of being mislabeled as RDMA.
Scale-out also disables NCCL dual-port NIC fusion (NCCL_IB_MERGE_NICS=0): a fused device disables
NCCL GIN, which the DeepEP V2 EP16 hybrid path requires, and a rail-isolated fabric
(rail_isolated=1, per-port rail subnets with no cross-rail routing) additionally sets
NCCL_CROSS_NIC=0.
ib_gid_index is applied only when every selected HCA port reports an Ethernet link layer, where it
selects the operator-approved RoCE GID. Native InfiniBand profiles retain explicit HCA and service
level pinning but leave the RoCE-only GID override unset so NVSHMEM/NCCL can use the native LID path.
Mixed Ethernet and InfiniBand HCA lists are rejected.
rdma_fabric: "efa" declares an AWS Elastic Fabric Adapter cluster (b300 is a p6-b300.48xlarge
pool with 16 EFA devices per node). EFA is not a verbs HCA: its ports report no link layer, it has
no GID table, service level or traffic class, and NCCL reaches it only through the aws-ofi-nccl
libfabric plugin that the cluster's enroot hook mounts into every container. On such a fabric the
probe accepts the unspecified link layer for the listed rdma_devices (which must still be ACTIVE
on every node), the IB selector family (NCCL_IB_*, NVSHMEM_HCA_LIST/IBGDA, MoRI, UCCL) stays
unset, NCCL_NET_PLUGIN=ofi and FI_PROVIDER=efa select the plugin, NVSHMEM is pointed at its
libfabric transport, and backend setup fails unless the plugin library is present in the container.
NCCL GIN then rides the plugin's own GIN implementation (OFI_NCCL_GIN_TYPE selects proxy or GDAKI),
which requires GDRCopy 2.5+ (gdrdrv loaded, libgdrapi present) on the node: without it the plugin's
GIN init fails, NCCL disables the Device API for the communicator, and ncclEpCreateGroup returns
ncclInvalidUsage (verified on b300-dsxe 2026-09-11; that pool ships no gdrcopy, so its EP16 legs are
withheld from the registry until it does). DeepEP V2 low-latency is also withheld there: its legacy
Buffer initialises NVSHMEM with an RDMA transport even single-node, and on that pool NVSHMEM aborts
with "nvshmem detect topo failed" (status 28) with and without NVSHMEM_REMOTE_TRANSPORT=none
(runs 34521825749, 34523594787); the HT ElasticBuffer path, which needs no NVSHMEM, passes.
stage_dir is a pre-existing, runner-owned, non-symlinked base outside the checkout and workflow
workspace. It is not group- or world-writable and is visible at the same path on the runner and every
allocated node. Jobs create only a marked mode-0700 execution child, prove cross-node read/write
visibility, and remove that exact child after allocation teardown. They never mount the runner
checkout or create a stage beneath image storage on AMD. When an AMD operator row omits stage_dir,
the runner derives a private base beside its standard _work directory on the shared runner
filesystem. The root-owned squash cache is never used as a repository stage.
H200, B200, and B300 runners may omit stage_dir. Their isolated execution child is created under a
runner-owned mode-0700 base in the validated operating-system account home, independent of the
workflow's temporary HOME. H100 may also omit stage_dir. Its private base is created beside, never
beneath, the configured shared container directory so it is compute-visible. Canonical B300 execution
ignores any legacy configured stage_dir and always uses the validated compute-visible account-home
base. An execution-ID suffix isolates parallel B300 workers. Canonical GB300 execution likewise
ignores its legacy group-writable stage_dir and derives an execution-specific private base beneath the
validated compute-visible account home. Backend preparation runs from that staged tree on every node.
Enroot imports the configured image tag into a per-run-scoped squash keyed by image tag and image
platform, so one run never reuses another run's imported filesystem. The image tag and platform are
per-SKU registry fields. The DeepEP V2 source pin lives in runtime/common.sh and its build is
fetched and verified at the pinned commit, checked for ElasticBuffer, and cached in a
cluster-local build cache keyed by architecture, image, and commit. Only the fixed /cx-cache mount
reaches the container.
python3 -m unittest discover collectivex/tests -p 'test_*.py'
python3 collectivex/sweep_matrix.py --backend all --out /tmp/cx-matrix.json >/dev/null
bash -n collectivex/runtime/*.sh collectivex/launchers/*.shCore paths are configs/, sweep_matrix.py, summarize.py, bench/, runtime/, launchers/,
and tests/.
NCCL-EP nightly installation and exact wheel provenance are documented in the NCCL-EP guide.