Skip to content

[None][perf] NVFP4 linear-SF AllReduce epilogue - #17452

Draft
brb-nv wants to merge 3 commits into
NVIDIA:feat/m3_with_msafrom
brb-nv:user/brb/m3-perf-allreduce-nvfp4-linear-sf
Draft

[None][perf] NVFP4 linear-SF AllReduce epilogue#17452
brb-nv wants to merge 3 commits into
NVIDIA:feat/m3_with_msafrom
brb-nv:user/brb/m3-perf-allreduce-nvfp4-linear-sf

Conversation

@brb-nv

@brb-nv brb-nv commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

@coderabbitai summary

Description

Test Coverage

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

brb-nv added 3 commits August 9, 2026 13:20
…ar SF layout

The fused epilogue already emits NVFP4, but only with scale factors in the
SWIZZLED 128x4 layout the CUTLASS FP4 GEMMs want. The trtllm-gen MoE wants
LINEAR row-major and asserts on a swizzled Fp4QuantizedTensor, so no producer
could hand it a pre-quantized activation.

Less was missing than it looked. The AR fusion kernel already takes a layout
field, and cvt_quant_get_sf_out_offset already has a LINEAR branch which, with
the arguments that kernel passes, reduces to rowIdx * numColVecs + kIdx. Only
the host side hardcoded swizzled: the layout was never set and scale_out was
always sized with computeSwizzledLayoutSFSize.

Exposed as a new fusion op rather than a layout flag. A flag would have had to
cross four op schemas -- allreduce, allreduce_pg, tunable_allreduce and their
fakes -- and every Python caller; an op is additive, changes no existing
caller, and the UB and MNNVL paths reject it for free because they allow-list
the ops they support.

Two things fell out. selectStrategyLookUpTable dereferenced
mapFusionOpToIndex.find(op) without checking it, so any op missing from that
table was undefined behavior under AUTO; the new op is now in the table and the
lookup falls back to NCCL on a miss. And TRTLLMGenFusedMoE.forward_impl opened
with an assert on x.dtype despite typing x as Union[Tensor, Fp4QuantizedTensor],
which has no dtype -- the accepted type had never been exercised on that
backend.

Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
…ce epilogue

Between the attention o_proj AllReduce and the first routed-expert GEMM sits a
serial window on the main stream, every sparse layer, and one of the kernels in
it is the standalone NVFP4 quantize of the MoE input. The AllReduce that opens
the window already computes the bf16 RMSNorm result that quantize reads, so it
can emit the quantized activation from the same pass.

Uses the OUT_ variant because the router gate and the shared expert both still
need the bf16 norm. The fold is bitwise-identical: the epilogue quantizes from
the same bf16 values it writes to norm_out, through the same conversion the
standalone kernel uses. It stands down when the experts are not NVFP4, when
NVFP4_AWQ needs a per-channel pre-quant scale the epilogue cannot apply, and
when the MoE would pad the activation past the hidden size.

Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
Asserts what makes the fold safe to fold: that
fp4_quantize(norm_out, scale, 16, False, False) reproduces the epilogue's own
fp4 and scale-factor outputs with atol=rtol=0, so the quantized activation is
the same one the standalone kernel would have produced from the norm the
epilogue writes.

One trap is worth recording. This module is registered with
cloudpickle.register_pickle_by_value, and cloudpickle then pulls in any
sys.modules entry under a referenced module whose name components all appear in
the worker's own co_names. Reading torch.ops directly in a worker body drags in
sys.modules["torch.ops"], whose type subclasses ModuleType instead of being it,
so it misses cloudpickle's module reducer and fails to pickle in the parent --
surfacing as "cannot pickle '_Ops' object" with no rank ever starting. Every
worker here reads torch.ops from a nested helper, which keeps the name off the
outer code object.

Signed-off-by: Balaram Buddharaju <169953907+brb-nv@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant