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 9 commits into
mainfrom
zheyu/feat/m3-eagle3-consolidated-main
Draft

zheyuf wants to merge 9 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
zheyuf and others added 3 commits September 9, 2026 14:33
…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>
Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Resolve the conflicts with NVIDIA#18611, which moved the MSA generation phase
off fmha_sm100 onto MiniMax-M3's dedicated decode kernels (CuTe DSL
indexer scorer, Triton sparse decode, trtllm-gen dense decode). Main's
structure is kept and the Eagle3 pieces are re-targeted at it:

- cache_manager.py: both sides had extracted _kv_slot_geometry; only the
  docstring wording differed.
- msa_backend.py: the decode span accepts the uniform 1 + draft_len query
  length and the CuTe DSL scorer is validated up front for it.
  on_update_kv_lens now patches msa_seq_lens_cuda, which all three decode
  kernels read, plus the write slots and the per-token valid-block
  counts; the fmha_sm100 plan patching is dropped since the plans cover
  context rows only. The write slots are re-derived from the staged
  msa_block_table, so the per-token msa_req_to_token buffer and its
  per-step H2D copy go away. The num_extra_kv_tokens correction moves
  into _stage_host_lengths so every staged length, msa_seq_lens_cuda
  included, is the attended one. The pure-decode valid-block staging is
  per query token, and the proxy scratch keeps its token-based sizing.
- test_msa_backend.py: keep both sides and rewrite the on_update_kv_lens
  tests against the new buffers. Fix the msa_utils import paths moved
  under kernels/ here and in test_llm_api_pytorch.py.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
@zheyuf
zheyuf force-pushed the zheyu/feat/m3-eagle3-consolidated-main branch from f9f7e97 to 7dec97c Compare September 14, 2026 04:03
… tables

A drafter with a different K/V page stride puts KVCacheManagerV2 into
per-layer page tables, where every layer already has its own attention-op
pool and pool ids are layer ids. Appending pools at num_pools + i there
aliased real layers' pools and indexed the host block-offset table with a
layer id.

Signed-off-by: Zheyu Fu <zheyuf@nvidia.com>
Only tree acceptance relocates accepted draft KV, and neither the MSA
decode kernels nor M3's coalesced pool layout support it. Reject tree
configs at startup and any relocation request in the manager.

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.

1 participant