Skip to content

[TRTLLM-14093][feat] Eagle3 support for MiniMax-M3 on the MSA backend (consolidated, staging for #16021) - #2

Draft
zheyuf wants to merge 33 commits into
mainfrom
zheyu/feat/m3-eagle3-consolidated-main
Draft

[TRTLLM-14093][feat] Eagle3 support for MiniMax-M3 on the MSA backend (consolidated, staging for #16021)#2
zheyuf wants to merge 33 commits into
mainfrom
zheyu/feat/m3-eagle3-consolidated-main

Conversation

@zheyuf

@zheyuf zheyuf commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Staging PR for self-review. This is the consolidated MiniMax-M3 Eagle3 port rebased on main (NVIDIA/TensorRT-LLM@a67ede16f, 2026-09-07). Once it is reviewed here, this branch will be force-pushed to feat/minimax-m3-eagle3 (NVIDIA#16021); no CI runs on this fork, /bot run happens there. The two commits are meant to be reviewed in order: (1) Eagle3 on the MSA backend, (2) the shared draft KV cache (virtual attention-op pools) + tests.

Overview

One-model Eagle3 speculative decoding for MiniMax-M3 on the MSA sparse-attention backend, with CUDA graphs, the overlap scheduler, aggregated and disaggregated serving. This consolidates the Eagle3 work validated on the feat/m3_with_msa side branch — NVIDIA#16021 (this PR's original content), NVIDIA#17341, NVIDIA#17457, NVIDIA#17656 and NVIDIA#18066 — into the design those follow-ups converged on, rebased on current main.

What this enables

  • Eagle3 on the MSA backend. Spec-metadata capture hooks in the decoder layers, SpecDecOneEngineForCausalLM as the model base, multi-token (1 + draft_len) decode/verify in the MSA metadata: per-token cache slots, valid-block counts and plan rows, proxy scratch sized by the worst-case decode token count.
  • Overlap scheduler + CUDA graphs. on_update_kv_lens re-derives cache slots, valid-block counts and the fmha_sm100 plans' per-row length mirrors on device after the scheduler corrects kv_lens, clamped to the staged lengths: sync-free, capture-safe, idempotent. The clamp also covers the draft loop advancing kv_lens_cuda between CUDA-graph warmup runs. The staging and the patch only run when speculative decoding is active, so non-speculative MiniMax-M3 steps are unchanged.
  • Unified draft KV cache. MiniMax-M3 keeps its Eagle3 draft layer in the target KV cache manager in every supported configuration, so block reuse, eviction and disaggregated KV transfer cover the drafter's KV natively. The draft layer runs the generic TRTLLM attention op, which cannot address M3's non-uniform mega-slot through the regular pool mapping (KVCacheManagerV2 groups sub-pages by size, and at M3's production geometry the index-K page coalesces into the K/V pool). The M3 manager therefore presents each shared draft layer to the attention op as its own virtual pool rooted at the layer's K page, the same pattern DeepseekV4CacheManager and the SWA scratch-reuse path use. The draft loop runs on the shared manager like every other unified-KV model: no draft-side manager, no metadata swap, no change to the speculative-decoding code. trtllm-gen accepts the P128 draft shapes via an opt-in consulted only after its allowlist rejects the page size.
  • Dense reference path. The Triton/SDPA metadata gains the causal-ladder verify mask and device-side slot derivation.

Differences from the side-branch commits

Test Coverage

  • TestMiniMaxM3::test_nvfp4_eagle3 (GQA Eagle3 head, MMLU + GSM8K + chat-GSM8K acceptance probe), aggregated arms with/without attention DP and a disaggregated (context TP2 -> generation TP2, NIXL) arm; scheduled in l0_dgx_b200 and the QA list.
  • Unit tests (CPU): multi-token valid-block counts and proxy scratch sizing, on_update_kv_lens slot/count/plan-mirror re-derivation (incl. mixed plans, the staged-length clamp and the speculative-decoding gate), the virtual attention-op pool tables and the block-offset copy into them, shared-draft layout derivation.

Validation on main (this branch, GB300 TP4/EP4, MSA, FP8 KV, CUDA graphs, overlap scheduler)

  • Unit tests: 36 passed (tests/unittest/_torch/attention/sparse/test_minimax_m3_*.py).
  • Eagle3 draft_len=3, GQA head, 200 chat-GSM8K prompts, greedy: acceptance rate 0.832, mean acceptance length 3.50 (test floors 0.80 / 3.4; drafter card 0.839 / 3.518). GSM8K exact match 0.860 with Eagle3 vs 0.850 for the plain target on the same prompts.

Validation (side branch, same design)

4xB200, TP4/EP4, Eagle3 draft_len=3, GQA head: chat-GSM8K acceptance 0.832-0.835 / mean acceptance length 3.50 aggregated (ADP off/on), 0.827-0.828 / 3.48 disaggregated (NVIDIA#18066). Reference: 0.839 / 3.518 on vLLM (Inferact/MiniMax-M3-EAGLE3 card).

PR Checklist

  • PR title follows the [JIRA/NVBUG/None][type] format
  • Commits are signed off (DCO)
  • ruff (new-style files) / yapf + isort (legacy files) clean
  • CI (/bot run)

@zheyuf
zheyuf force-pushed the zheyu/feat/m3-eagle3-consolidated-main branch from 876fdb4 to 6b168cf Compare September 4, 2026 00:28
@zheyuf
zheyuf force-pushed the zheyu/feat/m3-eagle3-consolidated-main branch 18 times, most recently from 1f7ac50 to 08dbbe6 Compare September 8, 2026 22:36
Wanli-Jiang and others added 9 commits September 8, 2026 21:43
…reason guard (NVIDIA#18894)

Signed-off-by: Wanli-Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… checkpoint (NVIDIA#18823)

Signed-off-by: Wanli-Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…A#18916)

Signed-off-by: trtllm-agent <296075020+trtllm-agent@users.noreply.github.com>
Signed-off-by: trtllm-agent <296075020+trtllm-agent@users.noreply.github.com>
Signed-off-by: longcheng-nv <243710427+longcheng-nv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…st MXFP4 (NVIDIA#18709)

Signed-off-by: Xin Guan <294044352+xguannv@users.noreply.github.com>
Signed-off-by: TensorRT LLM <90828364+tensorrt-cicd@users.noreply.github.com>
…itional model path (NVIDIA#18901)

Signed-off-by: ADou <ikun3.1415927@gmail.com>
Signed-off-by: nv-guomingz <137257613+nv-guomingz@users.noreply.github.com>
…he V2 (NVIDIA#17643)

Signed-off-by: BoyueZ <301205962+BoyueZ@users.noreply.github.com>
Co-authored-by: BoyueZ <301205962+BoyueZ@users.noreply.github.com>
yuxianq and others added 22 commits September 9, 2026 14:24
…checks (NVIDIA#18930)

Signed-off-by: Yuxian Qiu <142763828+yuxianq@users.noreply.github.com>
…ise (NVIDIA#18477)

Signed-off-by: Zhenhua Wang <zhenhuaw@nvidia.com>
…a dead-end grammar state (NVIDIA#18896)

Signed-off-by: ZhaoyangWang <zhaoyangw@nvidia.com>
…`; cache a per-(layer,module) rank… (NVIDIA#18527)

Signed-off-by: trtllm-agent <296075020+trtllm-agent@users.noreply.github.com>
Signed-off-by: Lori Ren <lorir@nvidia.com>
Co-authored-by: Lori Ren <lorir@nvidia.com>
…IA#18804)

Signed-off-by: Yueh-Ting Chen <yueh.ting.chen@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Jiagan Cheng <jiaganc@nvidia.com>
NVIDIA#18557)

* Why?

Including the live generation batch size in FlashInfer plan keys created
a separate eager wrapper and large block-table allocation for every
observed batch size, exhausting device memory on long runs.

* What?

Key decode plans only by their required query width and static attention
configuration. CUDA-graph metadata keeps private wrapper caches per
captured batch size, while eager execution safely replans shared
wrappers for each iteration.

Signed-off-by: William Zhang <133824995+2ez4bz@users.noreply.github.com>
…)` gated on get_sm_version() in (120… (NVIDIA#18678)

Signed-off-by: trtllm-agent <296075020+trtllm-agent@users.noreply.github.com>
…A#18958)

Signed-off-by: trtllm-agent <296075020+trtllm-agent@users.noreply.github.com>
Signed-off-by: Ivy Zhang <25222398+crazydemo@users.noreply.github.com>
… preprocessing (NVIDIA#18925)

Signed-off-by: Yuxian Qiu <142763828+yuxianq@users.noreply.github.com>
…re-enable seven cases (NVIDIA#18949)

Signed-off-by: Yi Zhang <187001205+yizhang-nv@users.noreply.github.com>
Signed-off-by: Robin Kobus <19427718+Funatiq@users.noreply.github.com>
…ework (NVIDIA#17069)

Signed-off-by: Tyler Burt <195370667+tburt-nv@users.noreply.github.com>
…Cache families (NVIDIA#18784)

Signed-off-by: Lori Ren <lorir@nvidia.com>
Signed-off-by: Guiju Zhang <7135567+cascade812@users.noreply.github.com>
…x-M3 on the MSA backend

Add one-model Eagle3 support to the MiniMax-M3 MSA sparse attention path:
spec-metadata capture hooks in the decoder layers, SpecDecOneEngineForCausalLM
as the model base, multi-token (1 + draft_len) decode/verify in the MSA
metadata (per-token cache slots, valid-block counts and plan rows, proxy
scratch sized by the worst-case decode token count), and a sync-free
on_update_kv_lens that re-derives slots, counts and the plans' length mirrors
on device after the overlap scheduler corrects kv_lens, clamped to the staged
lengths (which also covers the draft loop advancing kv_lens_cuda between
CUDA-graph warmup runs). The staging and the patch only run when speculative
decoding is active, so non-speculative steps are unchanged. The dense SDPA
reference path gains the causal-ladder verify mask.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the target manager

MiniMax-M3 keeps its one-model Eagle3 draft layer in the target KV cache
manager (unified draft KV cache) in every supported configuration. The base
manager appends the draft layer after the target's; the M3 manager derives
that layout from the same speculative config and layer mask the base uses.

The draft layer runs the generic TRTLLM attention op, which addresses K/V
through pool pointers, index scales and block offsets and assumes a uniform
per-layer stride within a pool. KVCacheManagerV2 groups sub-pages by size
alone, and at M3's production geometry the per-sparse-layer index-K page is
the same size as a K or V page, so K, V and index-K coalesce into one pool
whose slot is non-uniform (three sub-pages per sparse layer, two per dense or
draft layer). M3's own kernels address their layers through per-layer views
and never notice; the draft layer would be addressed wrongly. The M3 manager
therefore presents each shared draft layer to the attention op as its own
virtual pool rooted at the layer's K page, with the slot's sub-page count as
the index scale and V one page after K, the same pattern DeepseekV4CacheManager
and the SWA scratch-reuse path use. The draft loop then runs on the shared
manager exactly like every other unified-KV model: no draft-side manager, no
metadata swap, no change to the speculative-decoding code. trtllm-gen accepts
the manager's P128 draft shapes through an opt-in it consults only once its
allowlist has rejected the page size.

Adds the GQA Eagle3 head accuracy test with aggregated and disaggregated
(NIXL) arms plus a chat-GSM8K acceptance probe, and unit tests for the virtual
pool tables, the block-offset copy and the layout derivation.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…port

- Mirror the fmha_sm100 plan's seqused_k in the CUDA-graph-stable plan
  buffers; the planner allocates it per step and the kernel reads it at
  launch, so the captured address must not move.
- Force the shared draft KV cache only for MiniMax-M3 one-model Eagle3, and
  reject the triton reference backend with CUDA graphs: its multi-token
  verify goes through the prefill builder, which cannot be captured. Drop the
  unreachable multi-token dense decode branch and the decode_qo_len field.
- Reject NVFP4 pool pointers in the virtual attention-op pool builder
  instead of writing a null block-scale pointer.
- Size the MSA proxy scratch from the KV cache manager's draft length, so
  runs without speculative decoding size by max_num_sequences.
- Document why per-token seqused_k mirrors the planner (0 for an empty row)
  while the valid-block count is clamped to 1.
- Drop the pinned cuda_graph/use_msa axes of test_nvfp4_eagle3 and list the
  disagg/overlap combinations explicitly; update the test lists.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@zheyuf
zheyuf force-pushed the zheyu/feat/m3-eagle3-consolidated-main branch from 4e7ac75 to 9f73051 Compare September 9, 2026 21:33
Parametrize disagg and overlap_scheduler independently instead of listing
combinations; the disaggregated arm no longer skips any of them. Test list
ids follow the new axis order.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
…mp decode valid blocks

Review follow-ups on the consolidated MiniMax-M3 Eagle3 PR:

- Remove the disaggregated arm of test_nvfp4_eagle3 (disagg does not take
  new end-to-end accuracy tests); test_disaggregated_serving.py is back to
  main. The grid is now overlap_scheduler x attention_dp.
- CI runs one combination (attention_dp=False, overlap_scheduler=True,
  the production shape) and inherits the stage timeout; the explicit
  TIMEOUT (180) annotations are gone from both lists.
- Clamp the decode-path valid-block counts to at least one block, matching
  the eager path and on_update_kv_lens.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.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.