[Bugfix][SM70] Read the quantization SM70 gate from the worker's own device - #576
Open
Peuqui wants to merge 2 commits into
Open
[Bugfix][SM70] Read the quantization SM70 gate from the worker's own device#576Peuqui wants to merge 2 commits into
Peuqui wants to merge 2 commits into
Conversation
is_exact_sm70_cuda_platform() gates the native SM70 routes -- the TurboMind NVFP4/MXFP4 MoE selectors, the compressed-tensors W8A16-FP8 scheme and four modelopt gates. It probed device 0 of the visibility list instead of the device the worker builds its layers on, so on a node that mixes card generations every rank got the same, wrong answer: with a Turing card first the Volta workers lose the SM70 kernels, with a Volta card first the Turing workers claim them. Both failures are silent. Same bug class as 1CatAI#514, which fixed the SM70 config defaults; the quantization gate was not part of that change. Homogeneous nodes are unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
test_mxfp4_sm70_platform_gate_is_exact replaces current_platform.is_device_capability with a lambda that only accepts `capability`. Now that is_exact_sm70_cuda_platform passes the worker's device through, that stub raises TypeError. Widen it the way tests/config/test_sm70_gates_any_visible_device.py already does; the test's intent is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
is_exact_sm70_cuda_platform()decides whether a worker takes the native SM70routes. It is read by nine call sites: the TurboMind NVFP4 and MXFP4 MoE
selectors, the compressed-tensors W8A16-FP8 scheme,
mxfp4.py, and four gatesin
modelopt.py.It asked device 0:
is_device_capabilitydefaults todevice_id=0, i.e. the first entry of thevisibility list — not the device this worker builds its layers on. On a node
that mixes card generations, every rank therefore gets the same answer, and it
is the wrong one for all but one card generation.
Measured on 2x Quadro RTX 8000 (sm75) + 3x Tesla V100 (sm70),
CUDA_DEVICE_ORDER=PCI_BUS_ID, calling the real function once per device aftertorch.cuda.set_device(i):CUDA_VISIBLE_DEVICES=0,2,1,3(Turing first — our serving layout):CUDA_VISIBLE_DEVICES=1,3,0,2(Volta first):Both directions are harmful and both are silent. With a Turing card first the
Volta workers lose the SM70 kernels they are the only ones that can run. With a
Volta card first the Turing workers claim them.
The fix reads the capability of the device the worker is on:
torch.accelerator.current_device_index()is the idiom already used across thetree (
distributed/weight_transfer/,eplb_state.py,logits_processor.py).This is the same bug class as #514, which fixed the SM70 config defaults; the
quantization gate was not part of that change.
Homogeneous nodes are unaffected: there every device has the same capability,
so device 0 and the worker's device always agreed.
Results
Same probe, same hardware, with the fix — all eight rows correct:
Test Plan
Environment: checkout at
origin/main4f19ef7 with the compiled extensions of a1Cat-vLLM 1.5.0 wheel linked in (see Limitations).
Test Result
New file: 5 passed.
Quantization unit subset, with this change: 643 passed, 29 failed,
8 skipped. The same 35 files on unmodified
origin/mainwith the new testskept: 640 passed, 32 failed, 8 skipped. Diffing the two failure lists:
The 29 failures are identical on both trees and environmental: 23 are
ValueError("type fp8e4nv not supported in this architecture")— Triton has noFP8 on Volta/Turing — and six are CPU/CUDA device mismatches in test fixtures
(
test_per_token_kv_cache.py,test_sm70_modelopt_nvfp4_kernel_oracle.py,test_sm70_modelopt_nvfp4.py,test_sm70_mxfp4_moe.py).Widening the call signature does break exactly one existing stub, which this PR
therefore updates.
test_mxfp4_sm70_platform_gate_is_exactreplacedcurrent_platform.is_device_capabilitywith a lambda taking onlycapability,so passing
device_idraisedTypeError. The two lambdas now takedevice_id=0, matching whattests/config/test_sm70_gates_any_visible_device.pyalready does since #514. The test's intent is unchanged, and that file goes from
31 to 32 passed.
Every other test in the tree that stubs
is_device_capabilitywith a narrowlambda: 217 passed, 44 failed, 1 skipped both with and without the change,
with an empty diff between the two failure lists. None of those failures mention
device_id; they are CUDA/kernel failures on this bench.Counter-check with
vllm/model_executor/layers/quantization/sm70_turbomind.pyreverted to
origin/main, the new tests kept: 3 failed, 2 passed —test_gate_is_true_on_the_volta_worker,test_gate_does_not_answer_for_device_zeroandtest_moe_route_selection_follows_the_gate. The two that still pass are theTuring case (which device 0 happens to answer correctly in that fixture) and
the non-CUDA case.
pre-commit over both files: ruff check, ruff format, typos, mypy-local, SPDX
headers, root lazy imports, forbidden imports, the "Prevent new 'torch.cuda'
APIs call" check, config-docstring check, attention-backend docs and the
boolean-ops check all Passed.
pre-commit run mypy-3.10 --hook-stage manual:Passed.
Not a duplicate
Checked on 2026-09-08 against every open PR. One open PR touches
vllm/model_executor/layers/quantization/sm70_turbomind.py: #561("[Kernel] Reduce DFlash2 weight and scale memory on SM70"). Its only hunk in
that file is at line 447, in
apply_prepared_linear; this change is at line 68.is_exact_sm70_cuda_platformandis_device_capabilitydo not occur in #561.No open issue mentions the quantization capability gate.
Limitations
The device ordering matters for this fix, and it is worth stating explicitly:
is_device_capabilityresolves itsdevice_idthrough the visibility list toan NVML index, which is PCI ordered, while torch's device index follows
CUDA_DEVICE_ORDER. The two agree underCUDA_DEVICE_ORDER=PCI_BUS_ID, whichvLLM already warns to set when it detects different devices in the system, and
which this bench sets. Without it the two orderings can disagree on a
heterogeneous box — but that is a pre-existing property of
is_device_capabilitythroughout the tree, not something this change introduces. I measured both with
and without it and kept the tree's own idiom rather than reaching past the
platform API.
The directory run above is the unit-test subset. Sixteen files in
tests/quantization/boot a full engine or pull a checkpoint —test_cpu_offload.pyalone downloads 7.8 GB — and two more (
test_quark.py,test_mixed_precision.py)need
lm_eval, which is not installed here. Those are excluded, and the runs arepinned with
HF_HUB_OFFLINE=1so nothing downloads silently. None of them touchsm70_turbomind.py.The measurements above call the real function on real hardware but do not boot a
model; the routes it gates are exercised by the unit tests. I have not built
current main from source on this hardware — that is a multi-hour CUDA build.
AI assistance: this change was developed with Claude (Anthropic) as a coding
assistant. Every changed line was reviewed by me and the test runs above were
executed on my hardware; I can defend the change end to end.
🤖 Generated with Claude Code