Skip to content

[#10345][perf] Enable multi-stream MOE for super. Also adds multi-stream MLA attn - #11520

Merged
suyoggupta merged 11 commits into
NVIDIA:mainfrom
nv-auto-deploy:sg/multi-stream-fixes
Feb 15, 2026
Merged

[#10345][perf] Enable multi-stream MOE for super. Also adds multi-stream MLA attn#11520
suyoggupta merged 11 commits into
NVIDIA:mainfrom
nv-auto-deploy:sg/multi-stream-fixes

Conversation

@suyoggupta

@suyoggupta suyoggupta commented Feb 14, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Release Notes

  • New Features

    • Added SwiGLU MLP optimization with automatic pattern matching and fusion.
    • Introduced NVFP4-quantized SwiGLU support for efficient inference.
    • Enabled multi-stream execution for MOE and MLA attention layers to improve throughput.
    • Added MOE export capability with configurable expert reduction during tracing.
  • Tests

    • Added comprehensive test coverage for SwiGLU, NVFP4 SwiGLU, and multi-stream features.

Speed up torch.export for MOE models by temporarily reducing the number
of experts during tracing, then programmatically expanding the FX graph
to include all expert weights afterward.

Expert nn.ModuleLists are discovered via a TorchDispatchMode probe that
intercepts torch_moe-family custom ops during a lightweight forward pass,
so the optimization does NOT rely on any particular attribute name.

Changes:
- export.py: Add _MoeExpertProbe / _find_moe_module_lists for name-
  independent expert discovery.  Add _reduce_moe_experts /
  _restore_moe_experts / _expand_moe_experts_in_graph helpers and
  wire them into torch_export_to_gm via num_moe_experts_for_export.
- export_to_gm.py: Thread num_moe_experts_for_export through the
  ExportToGMConfig and transform pipeline.
- test_export.py: Add SimpleMoEForExport unit tests (parametrized over
  expert_attr_name='experts' and 'mlp_bank' to prove name independence)
  and optional Glm4MoeLiteForCausalLM real-model tests.

Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR introduces SwiGLU MLP fusion, multi-stream execution for MoE and MLA attention, reduced MOE expert tracing for efficient export, and refactored Add+RMSNorm fusion. Configuration updates enable these new transform stages across multiple deployment profiles.

Changes

Cohort / File(s) Summary
Configuration Updates
examples/auto_deploy/model_registry/configs/glm-4.7-flash.yaml, examples/auto_deploy/super_v3.yaml, tensorrt_llm/_torch/auto_deploy/config/default.yaml, tests/integration/defs/accuracy/test_llm_api_autodeploy.py
Enable new transforms (multi_stream_moe, multi_stream_mla_attn, match_swiglu_pattern, fuse_swiglu, match_nvfp4_swiglu_pattern, fuse_nvfp4_swiglu) in compile and pattern_matcher stages; add shape-propagation requirements to existing patterns.
SwiGLU Custom Operations
tensorrt_llm/_torch/auto_deploy/custom_ops/linear/__init__.py, tensorrt_llm/_torch/auto_deploy/custom_ops/linear/swiglu.py
Implement four SwiGLU MLP variants: torch_swiglu_mlp, fused_swiglu_mlp, torch_nvfp4_swiglu_mlp, and fused_nvfp4_swiglu_mlp with FlashInfer kernel support and PyTorch fallbacks; include fake tracing implementations.
SwiGLU Fusion Transform
tensorrt_llm/_torch/auto_deploy/transform/library/fuse_swiglu.py
Add pattern matching (MatchSwiGLUPattern, MatchNVFP4SwiGLUPattern) and fusion (FuseSwiGLU, FuseNVFP4SwiGLU) transforms using ADPatternMatcherPass for graph transformation; handle weight concatenation and bias management for both standard and NVFP4-quantized variants.
Multi-Stream MOE Orchestration
tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_moe.py
Replace generic event recording with passthrough-based approach; introduce begin/end/wait stream markers and graph-level shared-expert relocation; detect merge add nodes, distinguish routed/shared inputs, and rewrite graph to execute shared experts on auxiliary CUDA stream with proper synchronization.
Multi-Stream MLA Attention
tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_attn.py
Detect KV-projection fork points in MLA attention, create auxiliary-stream variants of KV linears, and rewrite graph to route KV projections through aux stream while recording synchronization events before Q-chain; includes device-specific event and stream management.
MOE Export with Reduced Experts
tensorrt_llm/_torch/auto_deploy/export/export.py, tensorrt_llm/_torch/auto_deploy/transform/library/export_to_gm.py
Introduce expert probe to detect MOE parameter lists, reduce expert counts before tracing for efficiency, restore original expert lists after capture, and expand MOE weights back into GraphModule with new get_attr nodes and parameter registration; add num_moe_experts_for_export configuration field.
Graph Utilities
tensorrt_llm/_torch/auto_deploy/utils/_graph.py
Add create_derived_custom_op infrastructure for dynamically creating derived custom operators with same schema but different names; maintain per-namespace FRAGMENT libraries and caches for meta/fake implementations.
Add+RMSNorm Fusion Refactoring
tensorrt_llm/_torch/auto_deploy/transform/library/fused_add_rms_norm.py
Replace pattern-matcher-based approach with direct FX graph traversal; identify (add, optional cast, norm) triples via graph walking and replace with flashinfer_fused_add_rms_norm; support two patterns (with/without cast) using getitem for output extraction.
Minor Model Fix
tensorrt_llm/_torch/auto_deploy/models/custom/modeling_glm4_moe_lite.py
Remove dtype cast in Glm4MoeLiteMoE.forward final_hidden_states return; directly return tensor instead of casting to input dtype.
Test Coverage
tests/unittest/_torch/auto_deploy/unit/singlegpu/custom_ops/test_multi_stream.py, test_multi_stream_attn.py, transformations/library/test_fuse_swiglu.py, test_nvfp4_swiglu.py, test_fused_add_rms_norm.py, transformations/test_export.py, utils/test_create_derived_custom_op.py
Add comprehensive test suites for multi-stream operations, SwiGLU fusion, NVFP4 fusion, Add+RMSNorm fusion, MOE export with expert reduction, and derived custom op infrastructure; include CUDA graph validation, numerical correctness checks, and pattern matching verification.

Sequence Diagram(s)

sequenceDiagram
    participant Model as Source Model
    participant Probe as MOE Expert Probe
    participant Tracer as Torch Exporter
    participant GraphMod as GraphModule
    participant Expander as MOE Expander

    Model->>Probe: Scan for MOE parameters
    Probe->>Probe: Identify expert ModuleLists
    Probe-->>Model: Return expert targets
    Model->>Model: Reduce expert counts (num_moe_experts_for_export)
    Model->>Tracer: Forward with reduced experts
    Tracer->>GraphMod: Capture reduced graph
    GraphMod-->>Tracer: Return captured module
    Tracer->>Model: Restore original expert lists
    Tracer->>Expander: Expand MOE weights in graph
    Expander->>GraphMod: Create get_attr nodes
    Expander->>GraphMod: Register new parameters
    Expander-->>Tracer: Return expanded GraphModule
    Tracer-->>Model: Final optimized graph
Loading
sequenceDiagram
    participant GraphMod as FX GraphModule
    participant Analyzer as MOE Analyzer
    participant StreamMgr as CUDA Stream Manager
    participant GraphRewriter as Graph Rewriter

    GraphMod->>Analyzer: Locate MOE fusion nodes
    Analyzer->>Analyzer: Find merge add node downstream
    Analyzer->>Analyzer: Identify routed vs shared inputs
    Analyzer->>Analyzer: Traverse shared-expert subgraph
    Analyzer-->>GraphRewriter: Return fork point and shared ops
    GraphRewriter->>StreamMgr: Allocate auxiliary stream
    GraphRewriter->>GraphMod: Insert begin_aux_stream_passthrough
    GraphRewriter->>GraphMod: Mark shared expert operations
    GraphRewriter->>GraphMod: Insert end_aux_stream_passthrough
    GraphRewriter->>StreamMgr: Record synchronization event
    GraphRewriter->>GraphMod: Insert wait_aux_stream_passthrough on routed path
    GraphRewriter->>GraphMod: Rewire merge add dependencies
    GraphRewriter-->>GraphMod: Return transformed module with multi-stream ops
Loading
sequenceDiagram
    participant GraphMod as GraphModule
    participant PatternMatch as Pattern Matcher
    participant GraphTransform as Graph Transformer
    participant FusionEngine as Fusion Engine

    GraphMod->>PatternMatch: Scan for SwiGLU patterns
    PatternMatch->>PatternMatch: Detect silu(x @ gate.T) * (x @ up.T) @ down.T
    PatternMatch->>GraphTransform: Register pattern matches
    GraphTransform->>GraphTransform: Replace with torch_swiglu_mlp ops
    GraphTransform-->>GraphMod: Update graph with matched ops
    GraphMod->>FusionEngine: Fuse matched SwiGLU ops
    FusionEngine->>FusionEngine: Concatenate gate + up weights
    FusionEngine->>FusionEngine: Optionally concatenate biases
    FusionEngine->>GraphMod: Create fused_swiglu_mlp nodes
    FusionEngine->>GraphMod: Rewire dependencies
    FusionEngine->>GraphMod: Eliminate dead code
    FusionEngine-->>GraphMod: Return fused GraphModule
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 3
❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (38 files):

⚔️ .github/workflows/blossom-ci.yml (content)
⚔️ README.md (content)
⚔️ examples/auto_deploy/model_registry/configs/glm-4.7-flash.yaml (content)
⚔️ examples/auto_deploy/super_v3.yaml (content)
⚔️ requirements.txt (content)
⚔️ tensorrt_llm/_torch/auto_deploy/config/default.yaml (content)
⚔️ tensorrt_llm/_torch/auto_deploy/custom_ops/linear/__init__.py (content)
⚔️ tensorrt_llm/_torch/auto_deploy/export/export.py (content)
⚔️ tensorrt_llm/_torch/auto_deploy/models/custom/modeling_glm4_moe_lite.py (content)
⚔️ tensorrt_llm/_torch/auto_deploy/transform/library/export_to_gm.py (content)
⚔️ tensorrt_llm/_torch/auto_deploy/transform/library/fused_add_rms_norm.py (content)
⚔️ tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_moe.py (content)
⚔️ tensorrt_llm/_torch/auto_deploy/transform/library/ssm_cache.py (content)
⚔️ tensorrt_llm/_torch/auto_deploy/utils/_graph.py (content)
⚔️ tensorrt_llm/_torch/distributed/__init__.py (content)
⚔️ tensorrt_llm/_torch/distributed/ops.py (content)
⚔️ tensorrt_llm/_torch/models/checkpoints/hf/nemotron_h_weight_mapper.py (content)
⚔️ tensorrt_llm/_torch/modules/fused_moe/quantization.py (content)
⚔️ tensorrt_llm/_torch/modules/linear.py (content)
⚔️ tensorrt_llm/_torch/pyexecutor/sampling_utils.py (content)
⚔️ tensorrt_llm/commands/serve.py (content)
⚔️ tensorrt_llm/executor/executor.py (content)
⚔️ tensorrt_llm/executor/ipc.py (content)
⚔️ tensorrt_llm/inputs/data.py (content)
⚔️ tensorrt_llm/llmapi/__init__.py (content)
⚔️ tensorrt_llm/llmapi/disagg_utils.py (content)
⚔️ tensorrt_llm/llmapi/utils.py (content)
⚔️ tensorrt_llm/ray_stub.py (content)
⚔️ tensorrt_llm/serve/openai_protocol.py (content)
⚔️ tensorrt_llm/serve/openai_server.py (content)
⚔️ tests/integration/defs/accuracy/test_disaggregated_serving.py (content)
⚔️ tests/integration/defs/accuracy/test_llm_api_autodeploy.py (content)
⚔️ tests/integration/test_lists/test-db/l0_b200.yml (content)
⚔️ tests/integration/test_lists/test-db/l0_dgx_b200.yml (content)
⚔️ tests/integration/test_lists/waives.txt (content)
⚔️ tests/unittest/_torch/auto_deploy/unit/singlegpu/custom_ops/test_multi_stream.py (content)
⚔️ tests/unittest/_torch/auto_deploy/unit/singlegpu/transformations/library/test_fused_add_rms_norm.py (content)
⚔️ tests/unittest/_torch/auto_deploy/unit/singlegpu/transformations/test_export.py (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
Description check ⚠️ Warning Pull request has no description provided by the author; template sections are not filled in. Add a comprehensive description explaining what changes are made, why they're needed, which tests validate them, and confirm the checklist items have been reviewed.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly references issue #10345 and accurately summarizes the main changes: enabling multi-stream MOE for 'super' and adding multi-stream MLA attention.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch sg/multi-stream-fixes
  • Post resolved changes as copyable diffs in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@tensorrt_llm/_torch/auto_deploy/transform/library/fused_add_rms_norm.py`:
- Around line 129-140: The rare-branch handling of cast_node currently builds a
list from cast_node.users and inserts new_cast before an arbitrary user, which
wastes allocation and can violate topological order; change the insertion to use
the add_out node as the anchor (use graph.inserting_after(add_out)) so new_cast
is placed after its input and before all users, and avoid list(...) by using
next(iter(cast_node.users)) if you still need to reference a user; keep the
replace_all_uses_with(new_cast) and graph.erase_node(cast_node) logic and add
id(cast_node) to erased as before.

In `@tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_attn.py`:
- Around line 166-171: The graph currently hard-codes the device by passing
torch.cuda.current_device() into record_event_passthrough inside the
graph.inserting_before(earliest_q) block, which bakes a transform-time device
into the FX graph; remove the device kwarg so record_event_passthrough uses its
default (runtime resolution, -1) and resolves torch.cuda.current_device() at
call time—update the call that creates rec_node (the graph.call_function
invocation of record_event_passthrough) to omit the device argument.
- Around line 1-12: Add the required NVIDIA Apache-2.0 copyright header (with
the year of latest meaningful modification) at the very top of the file before
the existing module docstring in multi_stream_attn.py; ensure the header uses
the standard NVIDIA header text and license notice so it precedes the docstring
and applies to the entire module.
- Around line 217-218: Remove the unconditional file dump that writes gm.graph
to /tmp (the with open(... "/tmp/after_multi_stream_mla_attn.txt") block) — this
is debug-only code; delete that block from multi_stream_attn.py and replace it
with a debug log call using the existing logger (import ad_logger from
...utils.logger if not already present) e.g. call ad_logger.debug with a
descriptive message and gm.graph (e.g., "After multi_stream_mla_attn
transform:\n%s", gm.graph) so the information is only emitted to logs and not
written to disk.

In `@tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_moe.py`:
- Around line 435-436: Remove the unconditional debug dump that writes gm.graph
to /tmp — delete the with open("/tmp/after_multi_stream_moe.txt", "w") ...
f.write(str(gm.graph)) block (or gate it behind proper debug logging) inside the
multi-stream MoE transform where the local variable gm is available; if you need
to keep the dump for local debugging, wrap it with a runtime debug check (e.g.,
if logger.isEnabledFor(logging.DEBUG) or an explicit DEBUG_TRANSFORMS flag) and
surround the file write with try/except to avoid raising on read-only
filesystems, and avoid writing to /tmp or any world-readable location.

In `@tensorrt_llm/_torch/auto_deploy/utils/_graph.py`:
- Around line 74-75: Replace the private attribute access base_overload._schema
with the public torch.library API: call
torch.library.infer_schema(base_overload) (or infer_schema(base_op) if you need
the original callable) to obtain the operator schema, and assign that result to
schema; keep the base_overload selection logic (base_overload = base_op.default
if hasattr(base_op, "default") else base_op) but replace the direct _schema
access with torch.library.infer_schema(...) so you rely on the stable
torch.library schema inference API.
🧹 Nitpick comments (14)
tests/unittest/_torch/auto_deploy/unit/singlegpu/transformations/library/test_fused_add_rms_norm.py (2)

6-8: Remove unused noqa directive (static analysis).

Ruff reports the blanket noqa on line 6 is unused. If the import itself is used (it is — in _count_fused_ops), just drop the # noqa comment.

Also, the import style pulls in a symbol directly rather than using from package.subpackage import module. The same applies to lines 11–12 (TransformConfig, FuseAddRMSNorm). Per coding guidelines, prefer from package.subpackage import module and then reference module.Symbol.

Example for lines 6-8 and 11-12
-from tensorrt_llm._torch.auto_deploy.custom_ops.normalization.flashinfer_fused_add_rms_norm import (  # noqa
-    flashinfer_fused_add_rms_norm,
-)
+from tensorrt_llm._torch.auto_deploy.custom_ops.normalization import flashinfer_fused_add_rms_norm as fused_add_rms_norm_mod

However, since flashinfer_fused_add_rms_norm is used as a node-target identity check, importing the function directly may be more pragmatic here. At minimum, remove the stale # noqa.

-from tensorrt_llm._torch.auto_deploy.custom_ops.normalization.flashinfer_fused_add_rms_norm import (  # noqa
-    flashinfer_fused_add_rms_norm,
-)
+from tensorrt_llm._torch.auto_deploy.custom_ops.normalization.flashinfer_fused_add_rms_norm import (
+    flashinfer_fused_add_rms_norm,
+)

124-130: _count_fused_ops checks Python function identity, not a registered op.

_count_rms_norm_ops and _count_add_ops both use is_op(n, torch.ops.…) to match registered ops, but _count_fused_ops compares n.target against the raw Python function flashinfer_fused_add_rms_norm. This will only work if the fused op is inserted into the graph as a plain call_function targeting that Python callable (not as a torch.ops dispatch key). If the transform implementation changes to register a proper torch.ops entry, this check will silently stop matching.

This is fine if the current transform indeed inserts a plain Python callable, but worth keeping in mind.

tensorrt_llm/_torch/auto_deploy/utils/_graph.py (1)

105-110: Default fake implementation assumes output shape equals first arg's shape.

The _default_fake returns torch.empty_like(args[0]), which is only correct for ops whose output shape matches the first input. For ops like linear (where output shape differs), callers must always provide make_fake. The docstring documents this, but consider adding a brief inline comment here as well since this is a common footgun.

tensorrt_llm/_torch/auto_deploy/transform/library/fuse_swiglu.py (3)

32-32: Import style: import the module, not the function directly.

Per coding guidelines, use from ...custom_ops.linear import swiglu and reference swiglu.torch_swiglu_mlp. Same applies to line 289 for torch_nvfp4_swiglu_mlp.

Proposed fix
-from ...custom_ops.linear.swiglu import torch_swiglu_mlp
+from ...custom_ops.linear import swiglu

Then update references:

-    return torch_swiglu_mlp(x, gate_weight, up_weight, down_weight, None, None, None)
+    return swiglu.torch_swiglu_mlp(x, gate_weight, up_weight, down_weight, None, None, None)

And for line 289:

-from ...custom_ops.linear.swiglu import torch_nvfp4_swiglu_mlp  # noqa: E402
+# (move to top-of-file imports)
+# from ...custom_ops.linear import swiglu  # already imported above

Then use swiglu.torch_nvfp4_swiglu_mlp in the replacement function.

As per coding guidelines, "Python imports must use from package.subpackage import module style; never use from module import Class."


287-289: Move this import to the top of the file.

The mid-file import with # noqa: E402 is unnecessary — there's no circular dependency issue since both symbols come from the same module. Moving it to line 32 alongside the other swiglu import would be cleaner.


548-563: No validation that gate and up input scales match before fusing.

The docstring says "gate+up input_scale and alpha must match (shared input)" but there's no assertion. If they differ (e.g., from a misconfigured quantization pipeline), this would silently use only gate's scales, producing incorrect results.

Proposed assertion
+            # Validate that gate and up share the same input scale and alpha
+            # (required because the fused op uses a single scale for both).
+            gate_input_scale = get_attr_by_name(gm, gate_input_scale_node.target)
+            up_input_scale = get_attr_by_name(gm, up_input_scale_node.target)
+            gate_alpha = get_attr_by_name(gm, gate_alpha_node.target)
+            up_alpha = get_attr_by_name(gm, up_alpha_node.target)
+            assert torch.equal(gate_input_scale, up_input_scale), (
+                "Gate and up input scales must match for NVFP4 SwiGLU fusion"
+            )
+            assert torch.equal(gate_alpha, up_alpha), (
+                "Gate and up alpha must match for NVFP4 SwiGLU fusion"
+            )
+
             # Create the fused_nvfp4_swiglu_mlp node
tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_moe.py (1)

238-240: BFS uses list.pop(0) — O(n) per pop.

queue.pop(0) on a list is O(n). Use collections.deque with popleft() for O(1) BFS. Same issue at line 323.

Proposed fix
+from collections import deque
+
 def _find_merge_add(moe_node: Node) -> Optional[Node]:
     visited: Set[Node] = set()
-    queue = list(moe_node.users.keys())
+    queue = deque(moe_node.users.keys())
     while queue:
-        n = queue.pop(0)
+        n = queue.popleft()
         if n in visited:
             continue
         visited.add(n)
         if is_op(n, torch.ops.aten.add.Tensor):
             return n
         queue.extend(n.users.keys())

Similarly for line 320-323:

-        queue = [shared_output]
+        queue = deque([shared_output])
         while queue:
-            n = queue.pop(0)
+            n = queue.popleft()
tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_attn.py (2)

27-32: Import ModelFactory directly from its source module.

ModelFactory is imported transitively through multi_stream_moe, but it originates from ...models.factory. Import it directly to avoid a hidden dependency chain and make the dependency explicit.

Proposed fix
 from .multi_stream_moe import (
-    ModelFactory,
     _make_aux_stream_impl,
     cuda_stream_manager,
     record_event_passthrough,
 )
+from ...models.factory import ModelFactory

48-110: KV projection detection heuristic is reasonable but fragile.

The "has downstream linear within 3 hops = Q-like, otherwise KV-like" heuristic works well for DeepSeek-style MLA but could misfire on architectures where the KV chain includes a learned transformation (linear). A brief inline comment noting which architecture(s) this targets would help future maintainers.

tests/unittest/_torch/auto_deploy/unit/singlegpu/custom_ops/test_multi_stream_attn.py (1)

19-23: Import style: importing private functions directly rather than the module.

The coding guidelines specify from package.subpackage import module style. Here, individual underscore-prefixed functions are imported directly. Since these are internal test helpers being tested, this is a common pattern in unit tests, but flagging for awareness.

tensorrt_llm/_torch/auto_deploy/export/export.py (1)

236-329: _expand_moe_experts_in_graph: hardcoded arg index 3 assumes a fixed MOE op signature.

Line 272 starts scanning list arguments from range(3, len(node.args)). This assumes all torch_moe-family ops have the same argument layout with per-expert weight lists starting at position 3. If any of the three MOE ops (torch_moe, torch_quant_fp8_moe, torch_quant_nvfp4_moe) has a different signature, this would silently skip or mis-identify weight lists. A defensive check or a per-op signature map would be more robust, though the current code works correctly given the existing op signatures.

tests/unittest/_torch/auto_deploy/unit/singlegpu/transformations/test_export.py (2)

331-335: Duplicate helper: _count_moe_experts and _count_moe_experts_in_graph are identical.

Both functions iterate the graph looking for torch_moe nodes and return len(node.args[3]). Consider extracting a single shared helper.

Proposed consolidation

Move _count_moe_experts_in_graph to module level (outside the if _HAS_GLM4: block) and reuse it in test_moe_export_with_reduced_experts:

+def _count_moe_experts_in_graph(gm: GraphModule) -> int:
+    """Return the number of experts in the first ``torch_moe`` call in *gm*."""
+    for node in gm.graph.nodes:
+        if node.op == "call_function" and "torch_moe" in str(node.target):
+            return len(node.args[3])  # w1_weight list length
+    return 0
+
+
 `@pytest.mark.parametrize`("expert_attr_name", ["experts", "mlp_bank"])
 ...
 def test_moe_export_with_reduced_experts(...):
     ...
-    def _count_moe_experts(gm):
-        for node in gm.graph.nodes:
-            if node.op == "call_function" and "torch_moe" in str(node.target):
-                return len(node.args[3])
-        return 0
-
-    assert _count_moe_experts(gm_full) == num_experts
+    assert _count_moe_experts_in_graph(gm_full) == num_experts

Also applies to: 400-405


249-249: Unused noqa directive per static analysis.

Ruff reports RUF100: Unused noqa directive (non-enabled: F401, E402). If F401 and E402 are not enabled in the project's Ruff config, the noqa comment is unnecessary.

tests/unittest/_torch/auto_deploy/unit/singlegpu/transformations/library/test_nvfp4_swiglu.py (1)

14-14: Remove unused noqa directive.

Static analysis (Ruff RUF100) flags # noqa: F401 as unnecessary here. The side-effect import is valid, but the suppression comment isn't needed.

Proposed fix
-import tensorrt_llm._torch.auto_deploy.custom_ops  # noqa: F401
+import tensorrt_llm._torch.auto_deploy.custom_ops

Comment thread tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_attn.py Outdated
Comment thread tensorrt_llm/_torch/auto_deploy/transform/library/multi_stream_moe.py Outdated
Comment thread tensorrt_llm/_torch/auto_deploy/utils/_graph.py

@taylor-yb-lee taylor-yb-lee left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like need rebase to remove the commit for export

Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
- Replace hardcoded magic number 3 with schema-driven introspection for
  finding List[Tensor] arguments in MOE ops
- Rename min_num_experts to num_moe_experts_for_export for consistency
- Remove unnecessary try/except guard around GLM4 MoE Lite import in tests

Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
@suyoggupta

Copy link
Copy Markdown
Collaborator Author

/bot run --extra-stage "DGX_B200-4_GPUs-AutoDeploy-1, DGX_H100-4_GPUs-AutoDeploy-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #35973 [ run ] triggered by Bot. Commit: 0f2940b

… multi_stream_attn

Remove the device kwarg from the graph.call_function invocation of
record_event_passthrough so that the default (-1) is used and
torch.cuda.current_device() is resolved at runtime rather than being
baked into the FX graph at transform time.

Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #35973 [ run ] completed with state FAILURE. Commit: 0f2940b
/LLM/main/L0_MergeRequest_PR pipeline #27784 completed with status: 'FAILURE'

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

@suyoggupta

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #35975 [ run ] triggered by Bot. Commit: 52198b1

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #35975 [ run ] completed with state SUCCESS. Commit: 52198b1
/LLM/main/L0_MergeRequest_PR pipeline #27786 completed with status: 'FAILURE'

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
@suyoggupta

Copy link
Copy Markdown
Collaborator Author

/bot run --extra-stage "DGX_B200-4_GPUs-AutoDeploy-1, DGX_H100-4_GPUs-AutoDeploy-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #35986 [ run ] triggered by Bot. Commit: 5997e15

Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
@suyoggupta

Copy link
Copy Markdown
Collaborator Author

/bot run --extra-stage "DGX_B200-4_GPUs-AutoDeploy-1, DGX_H100-4_GPUs-AutoDeploy-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #35988 [ run ] triggered by Bot. Commit: aa390ba

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #35988 [ run ] completed with state SUCCESS. Commit: aa390ba
/LLM/main/L0_MergeRequest_PR pipeline #27796 completed with status: 'FAILURE'

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
@suyoggupta

Copy link
Copy Markdown
Collaborator Author

/bot run --extra-stage "DGX_B200-4_GPUs-AutoDeploy-1, DGX_H100-4_GPUs-AutoDeploy-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #36004 [ run ] triggered by Bot. Commit: a06ad9d

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #36011 [ run ] triggered by Bot. Commit: a06ad9d

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #36011 [ run ] completed with state SUCCESS. Commit: a06ad9d
/LLM/main/L0_MergeRequest_PR pipeline #27821 completed with status: 'FAILURE'

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

@suyoggupta

Copy link
Copy Markdown
Collaborator Author

/bot run --extra-stage "DGX_B200-4_GPUs-AutoDeploy-1, DGX_H100-4_GPUs-AutoDeploy-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #36018 [ run ] triggered by Bot. Commit: a06ad9d

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #36018 [ run ] completed with state SUCCESS. Commit: a06ad9d
/LLM/main/L0_MergeRequest_PR pipeline #27826 completed with status: 'SUCCESS'

@suyoggupta
suyoggupta merged commit f3d784c into NVIDIA:main Feb 15, 2026
5 checks passed
return _derived_op_libs[namespace]


def create_derived_custom_op(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

given that this transform is at a later stage, where we are already outside the AutoDeploy IR, I'd prefer to just use regular call_function nodes calling into eager python rather than defining custom ops.

Might be something good to discuss

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The aux_stream_wrapper (now removed) was an attempt at doing precisely this. It ran into issues with transforms downstream of multi-stream

peihu-nv pushed a commit to peihu-nv/TensorRT-LLM that referenced this pull request Feb 19, 2026
…ti-stream MLA attn (NVIDIA#11520)

Signed-off-by: Suyog Gupta <41447211+suyoggupta@users.noreply.github.com>
Signed-off-by: peihu-nv <259410613+peihu-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.

4 participants