Skip to content

[Distributed] Make --disable-custom-all-reduce fall back to NCCL - #60011

Open
roy6n23 wants to merge 1 commit into
vllm-project:mainfrom
roy6n23:disable-custom-all-reduce-backends
Open

roy6n23 wants to merge 1 commit into
vllm-project:mainfrom
roy6n23:disable-custom-all-reduce-backends

Conversation

@roy6n23

@roy6n23 roy6n23 commented Oct 5, 2026 •

Copy link
Copy Markdown

Overview

Fixes #59987. --disable-custom-all-reduce is documented as "Disable the custom all-reduce kernel and fall back to NCCL", but on Hopper and Blackwell it only removes the CUSTOM backend. The TP group keeps the FlashInfer and symmetric-memory all-reduce, and at the default -O2 the FlashInfer all-reduce + RMSNorm fusion stays on. This PR makes the flag turn those off too, so all-reduce falls back to NCCL.

Claims

  • With --disable-custom-all-reduce, the TP group's all-reduce backends are ['PYNCCL'] and the all-reduce + RMSNorm fusion is off (an explicit pass_config.fuse_allreduce_rms=True still turns it on).
  • Without the flag nothing changes.
  • GSM8K accuracy is the same with and without the change.

Validation

2x H100 SXM (NV18), vllm/vllm-openai:nightly-18f8f96025b556071eb627076f94df560fbd3a22 with this PR's diff applied to the installed package (18f8f9602 is 15 commits behind this PR's base and none of them touch the changed files), Qwen/Qwen2.5-1.5B-Instruct, TP=2, default -O2:

All-reduce backends (startup log) allreduce_rms fusion All-reduce kernels in one 32-token request, per rank (torch profiler) GSM8K, 1319 questions, 5-shot
main + --disable-custom-all-reduce ['FLASHINFER', 'PYNCCL'] on 1824 FlashInfer allreduce_fusion_kernel_oneshot_lamport, 0 NCCL all-reduce 0.540
this PR + --disable-custom-all-reduce ['PYNCCL'] off 1824 ncclDevKernel_AllReduce_Sum_bf16_RING_LL 0.542
this PR, no flag ['FLASHINFER', 'CUSTOM', 'PYNCCL'] on 1824 FlashInfer allreduce_fusion_kernel_oneshot_lamport 0.540
this PR + flag + -cc.pass_config.fuse_allreduce_rms=True ['PYNCCL'] on 1824 FlashInfer allreduce_fusion_kernel_oneshot_lamport -

1824 is 57 all-reduces per forward pass (the embedding plus two per layer, 28 layers) times 32 forward passes, so on main with the flag every all-reduce in the model ran in FlashInfer and none in NCCL. The greedy completion of the profiled request was the same in all four runs.

SYMM_MEM is missing from these lists because multicast does not work on this host: SymmMemCommunicator logs "symmetric memory multicast operations are not supported" after the CUDA driver returns error 401, the same error that made NCCL's NVLS setup fail in ncclCommInitRank, so all four runs used NCCL_NVLS_ENABLE=0. On the host in #59987 (2x H100, vLLM 0.30.0) the default list was ['FLASHINFER', 'CUSTOM', 'SYMM_MEM', 'PYNCCL'] and the flag left ['FLASHINFER', 'SYMM_MEM', 'PYNCCL']. The unit test below covers the symmetric-memory gate.

Reproduction commands

All four runs were on the same pod. The first row used the image as is; for the other three the vllm/ part of this PR's diff was applied to the installed package with patch -p1.

export NCCL_NVLS_ENABLE=0            # this host only, see above
export VLLM_DISABLE_COMPILE_CACHE=1  # no compiled graph reused across runs

# EXTRA_ARGS per row: "--disable-custom-all-reduce" (rows 1 and 2), "" (row 3),
# "--disable-custom-all-reduce -cc.pass_config.fuse_allreduce_rms=True" (row 4)
vllm serve Qwen/Qwen2.5-1.5B-Instruct --tensor-parallel-size 2 --port 8000 --max-model-len 4096 \
  --profiler-config '{"profiler": "torch", "torch_profiler_dir": "./trace", "torch_profiler_with_stack": false, "ignore_frontend": true}' \
  $EXTRA_ARGS > serve.log 2>&1 &

# Backends and fusion columns
grep "all-reduce backends" serve.log
grep "Enabled custom fusions" serve.log

# One profiled 32-token request
curl -X POST localhost:8000/start_profile
curl localhost:8000/v1/completions -H 'Content-Type: application/json' \
  -d '{"model": "Qwen/Qwen2.5-1.5B-Instruct", "prompt": "The capital of France is", "max_tokens": 32, "temperature": 0}'
curl -X POST localhost:8000/stop_profile

# GSM8K (rows 1-3)
python tests/evals/gsm8k/gsm8k_eval.py --port 8000 --num-questions 1319

# Unit tests, after applying this PR on the same host
pytest -v tests/distributed/test_comm_ops.py tests/test_config.py \
  -k "disable_custom_all_reduce or precedes_nccl or allreduce_rms_fusion_default or (multi_process_tensor_parallel and not pipeline)"

Counting the all-reduce kernels in each rank's trace:

import collections, glob, gzip, json

for f in sorted(glob.glob("trace/**/*.pt.trace.json.gz", recursive=True)):
    events = json.load(gzip.open(f, "rt"))["traceEvents"]
    counts = collections.Counter(
        e["name"].split("(")[0] for e in events
        if e.get("cat") == "kernel" and any(s in e["name"].lower() for s in ("nccl", "allreduce"))
    )
    print(f, dict(counts))

It also prints 32 ncclDevKernel_AllGather_RING_LL launches in every run: the logits processor's all-gather across vocab shards, one per forward pass, not all-reduces.

Tests:

  • New test_disable_custom_all_reduce_falls_back_to_nccl (tests/distributed/test_comm_ops.py, runs on CPU with stand-in backends): builds a TP CudaCommunicator with custom all-reduce disabled and checks that an all-reduce goes to pynccl, not to FlashInfer, FlashInfer PCIe IPC or symmetric memory. It fails on main and passes with the fix.
  • New test_allreduce_rms_fusion_default_follows_disable_custom_all_reduce (tests/test_config.py): on a platform patched to look like SM90 with FlashInfer, the fusion default is on without the flag and off with it. The flag case fails on main.
  • On the 2x H100 host with the fix: the two new tests, test_flashinfer_all_reduce_precedes_nccl and the three test_multi_process_tensor_parallel[*-2] cases, 7 passed.
  • In a CPU-only container, tests/distributed/test_comm_ops.py and tests/test_config.py: 435 passed, 17 skipped, 19 failed. The same 19 fail on main in that container (gated HF repos and CPU-platform defaults).
  • pre-commit run --files <changed files>: all hooks pass.

Duplicate check: no open PR references #59987. Open PRs that match disable_custom_all_reduce or VLLM_ALLREDUCE_USE_FLASHINFER touch other things (#55835 cross-node MNNVL groups, #59730 IPC all-gather, #47751 custom all-reduce on sm_12x).

Details

The flag only reaches _ENABLE_CUSTOM_ALL_REDUCE, which gates CustomAllreduce, and on ROCm also AITER and QuickReduce all-reduce. FlashInfer all-reduce (on by default since #52998) and symmetric-memory all-reduce were added later with their own env vars and never tied to the flag. The fusion default, enable_allreduce_rms_fusion, doesn't look at it either. So on SM 9.0 / 10.x the flag leaves most all-reduces on FlashInfer: at -O2 the ones followed by RMSNorm run inside the fused kernel, and the rest go through ['FLASHINFER', 'SYMM_MEM', 'PYNCCL'].

The change:

  • CudaCommunicator: FlashInfer, FlashInfer PCIe IPC and symmetric-memory all-reduce also require _ENABLE_CUSTOM_ALL_REDUCE, the way AITER and QuickReduce already do.
  • enable_allreduce_rms_fusion returns False when the flag is set. This only changes the default; an explicit fuse_allreduce_rms still wins.
  • The flag's docstring (also the --help text) and docs/design/fusions.md now say what it turns off.

Things to be aware of:

  • Anyone who sets the flag today and is getting FlashInfer or symmetric-memory all-reduce will get NCCL instead, which is what the flag says it does. There is no longer a way to turn off only vLLM's custom kernel and keep FlashInfer; if that combination is needed, an env var for the custom kernel (like the existing VLLM_ALLREDUCE_USE_* ones) would be the natural counterpart.
  • Not covered: some models call FlashInfer's fused all-reduce directly in their eager paths through _can_use_flashinfer in fused_allreduce_gemma_rms_norm.py (DeepSeek V3.2, Kimi K3, MiniMax M3). I left those out to keep this PR small and can gate them in a follow-up if you want.
  • Tests that pass the flag (the tensorizer tests, Whisper) now run on NCCL. The fusion e2e and full-graph test helpers also set it by default, but their only TP=2 tests, in test_tp2_ar_rms.py, set it to False.
  • A correction to the issue: it said the flag plus VLLM_ALLREDUCE_USE_FLASHINFER=0 VLLM_ALLREDUCE_USE_SYMM_MEM=0 gives NCCL only. At -O2 the fusion also has to be off (-cc.pass_config.fuse_allreduce_rms=False).

AI assistance: Claude Code (Claude Opus 5.5) drafted the patch and the tests and ran the validation above in a local CPU container and on a rented 2x H100 pod. I reviewed every changed line and the results.


Pull Request Checklist
  • I used vLLM's /pr-checklist skill. (Mandatory for agents, optional for humans).

  • AI assistance was used during the creation of this PR.

  • Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.

  • Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.

  • Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.

  • Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.

--disable-custom-all-reduce only removed the custom all-reduce kernel from
the TP group. On Hopper and Blackwell the FlashInfer and symmetric-memory
all-reduce stayed on, and at -O2 so did the FlashInfer all-reduce + RMSNorm
fusion, so all-reduce did not fall back to NCCL as documented. Gate them on
the flag too, as QuickReduce and AITER all-reduce already are on ROCm, and
turn the fusion off by default when the flag is set.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Roy Zheng <39311511+roy6n23@users.noreply.github.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@mergify

mergify Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Documentation preview: https://vllm--60011.org.readthedocs.build/en/60011/

@mergify mergify Bot added documentation Improvements or additions to documentation nvidia labels Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to the vLLM project.

💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in #pr-reviews, coordinate on features in #feat- channels, or join special interest groups in #sig- channels.

PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment /ci run for upstream CI or /amd-ci run for AMD CI only whenever CI signals are needed.

Once the PR is approved or has the ready label, the PR author can also use the corresponding /ci run, /ci retry, and /ci cancel commands, or their /amd-ci variants. New commits do not start upstream CI automatically.

If you have any questions, please reach out to us on Slack at https://slack.vllm.ai.

Agent Guidelines

IMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban.

🚀

@roy6n23

roy6n23 commented Oct 12, 2026

Copy link
Copy Markdown
Author

A user-side data point: in #60660 (a FlashInfer MNNVL all-reduce crash on 4x H20 with vLLM 0.30.0) the reporter kept --disable-custom-all-reduce set while ruling out causes, and the startup log still shows Initialized FlashInfer Allreduce norm fusion workspace with backend=mnnvl; the report points to #59987 for this. The crash itself went away after upgrading vLLM and FlashInfer, so this PR has nothing to do with its cause. It is only an example of the flag being used to rule out vLLM's own all-reduce while FlashInfer all-reduce stayed on.

AI assistance: Claude Code found the issue and drafted this comment; I checked it against the issue.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation nvidia

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[Bug]: --disable-custom-all-reduce says it falls back to NCCL, but FlashInfer and symm-mem all-reduce stay enabled

1 participant