Skip to content

[Perf] [NVIDIA] minimax-m3: Score EAGLE verify rows in one pass over the index K - #45451

Open
thanhhao98 wants to merge 17 commits into
sgl-project:mainfrom
thanhhao98:htphan/m3-verify-packed-score-pr
Open

thanhhao98 wants to merge 17 commits into
sgl-project:mainfrom
thanhhao98:htphan/m3-verify-packed-score-pr

Conversation

@thanhhao98

@thanhhao98 thanhhao98 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Depends on #43804; only commits after it are new.

Motivation

With 4 EAGLE3 draft tokens, MiniMax-M3's sparse layers score each verify token as its own decode row (#41497, #43804), reading a request's index K 4 times. At AgentX c16 on GB300, _decode_score_kernel is 15.0 ms of a 36.1 ms verify step (nsys, one rank).

Modifications

  • New _decode_score_packed_kernel: a request's packed_queries rows share one 16-row dot tile, so each K tile loads once; each row keeps its own length mask, and both kernels run the same 16-row MMA, so max scores equal the per-row kernel's.
  • flash_decode_with_topk_idx packs on CUDA for score-only layers, whole groups and packed_queries × gqa ≤ 16; minimax_sparse_decode forwards packed_queries (from [AMD] MiniMax-M3 indexer CP: packed scoring for EAGLE verify rows #42614). SM90 keeps its paged ([Perf] minimax-sparse: Speed up MiniMax-M3 sparse attention on Hopper #46135) and per-row kernels, ROCm the per-row kernel.
  • The packed kernel runs one fixed config (BLOCK_SIZE_N 128, 4 warps, 2 stages; within 13 % of a sweep's best): autotune would tune on the 1-token CUDA-graph warm-up rows and differ per rank.
  • A second kernel rather than a PACK option on _decode_score_kernel, so the per-row kernel keeps its CUDA autotune and ROCm heuristics; its chunk-count rule moves unchanged into _num_kv_chunks, which [Perf] minimax-sparse: Speed up MiniMax-M3 sparse attention on Hopper #46135's paged launch also calls with its cap of 1024.

Prior art: AMD draft #39466 (needs local_blocks > 0), merged #45251 (DeepSeek-V4.1 indexer).

Accuracy Tests

GSM8K (sgl-eval 0.1.3 cookbook + --max-tokens 32768), MiniMax-M3-NVFP4, 4× GB300 TP4, EAGLE3 at real acceptance, SGLANG_DISABLE_MSA=1:

GSM8K #43804 + this PR
1,319 q 96.74 % 97.12 %
100 q, one at a time 98 % 98 %
  • New test_minimax_sparse_decode_packed_score.py (22 passed, GB300; B200 CI, skipped on SM90): packed = per-row scores and selected-block scores (max; lse via the Triton top-k), incl. local_blocks 0, fp8 K and graph replay.
  • test_minimax_linear_verify.py now asserts one packed launch per score-only verify forward (none on SM90) and also runs on B200; it and the decode top-k (160), page-table top-k (38) and sparse kernel (54) tests pass on GB300 after merging main.

Speed Tests and Profiling

Index step (score + top-k), one layer, one TP4 rank, GB300, cold-L2 marker.do_bench; per-row → packed µs, same top-k:

index K / q 16 req × 131K 32 req × 524K
bf16 / bf16 293.1 → 119.1 (2.46×) 2,089.8 → 825.5 (2.53×)
fp8 / fp8 238.3 → 87.4 (2.73×) 1,779.6 → 595.1 (2.99×)

AgentX replay on 4× GB300, EAGLE3 at synthetic AL 2.78, same node; PR arm: earlier revision, same kernel math:

c16 tok/s/user (1000/p90 ITL) total tok/s/GPU p90 TTFT
#43804 31.9 12,931 6.85 s
+ this PR 79.2 14,733 3.89 s
Reproduce

Server (both arms; #43804 or #43804 + this PR on lmsysorg/sglang:nightly-dev-cu13-20261012-e6072935, 4× GB300):

SGLANG_DISABLE_MSA=1 python3 -m sglang.launch_server --model-path nvidia/MiniMax-M3-NVFP4 --trust-remote-code --tp 4 --context-length 1048576 --reasoning-parser minimax-m3 --tool-call-parser minimax-m3 --default-chat-template-kwargs '{"thinking_mode":"enabled"}' --enable-metrics --enable-cache-report --random-seed 42 --speculative-algorithm EAGLE3 --speculative-draft-model-path Inferact/MiniMax-M3-EAGLE3-GQA --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 --speculative-draft-model-quantization unquant

GSM8K (the 1,319 questions, then the first 100 one at a time):

sgl-eval run gsm8k --base-url http://127.0.0.1:30000/v1 --thinking --temperature 1.0 --top-p 0.95 --max-tokens 32768
sgl-eval run gsm8k --base-url http://127.0.0.1:30000/v1 --thinking --temperature 1.0 --top-p 0.95 --max-tokens 32768 --num-examples 100 --num-threads 1

Index step: python3 test/registered/kernels/benchmark/attention/bench_minimax_packed_verify_score.py (added here).

AgentX (both arms add --max-running-requests 128 --mem-fraction-static 0.90 --schedule-policy lpm --attention-backend trtllm_mha and the env SGLANG_OPT_USE_MINIMAX_DENSE_SPARSE_DECODE=1 SGLANG_SIMULATE_ACC_LEN=2.78 SGLANG_SIMULATE_ACC_METHOD=match-expected SGLANG_SIMULATE_ACC_TOKEN_MODE=real-draft-token, the InferenceX golden acceptance for EAGLE3-GQA thinking-on K=3), client agentx-harness==1.0.11:

AIPERF_EXPERIMENTAL_FAST=1 agentx profile --url http://127.0.0.1:30000 --model nvidia/MiniMax-M3-NVFP4 --tokenizer nvidia/MiniMax-M3-NVFP4 --tokenizer-trust-remote-code --concurrency 16 --benchmark-duration 1200 --warmup-requests-per-lane 1 --server-metrics http://127.0.0.1:30000/metrics --public-dataset semianalysis_cc_traces_weka_062126

User speed = 1000 / p90 ITL; tok/s/GPU = total (input + output) tok/s / 4.

Checklist

  • Format your code according to the Format code with pre-commit.
  • Add unit tests.
  • Update documentation (no user-facing change).
  • Provide accuracy and speed benchmark results.
  • Follow the SGLang code style guidance.

CI States

Latest PR Test (Base): ❌ Run #40295094791
Latest PR Test (Extra): ❌ Run #40295094653
Latest PR Test (AMD ROCm 10): ❌ Run #40295094531

Hao Phan and others added 2 commits October 12, 2026 15:16
TARGET_VERIFY reaches the sparse layers' forward_extend, which builds prefill
metadata from extend_seq_lens. Verify batches carry none, so EAGLE3 fails at the
FlashInfer autotune warm-up on CUDA. ROCm already runs a linear draft chain
through the sparse decode kernels, one causal row per draft token; run that path
on every non-NPU GPU, for EAGLE chains only (draft_is_chain_layout).

The CUDA verify graph also took its score-buffer bound from the 1-token capture
dummies, so replay at a real context would write past the buffer. Bound verify
capture by the context length on every platform and count the draft rows in the
eager bound. Rows past the context length are never committed; clamp them so the
bound, and with it the decode top-k register bucket, stays at the context length.
Verify rows skip MSA decode, whose plan covers decode batches only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the index K

With linear EAGLE verify each draft token of a request is its own decode row, so
the score-only indexer read the request's whole index K once per draft token.
_decode_score_packed_kernel scores a request's rows in one 16-row dot tile: each
K tile is loaded once, and each row keeps its own length mask, so max scores and
the selected blocks equal the per-row kernel's. flash_decode_with_topk_idx takes
it on CUDA for score-only layers when the batch is whole groups of at most 16
tile rows, and minimax_sparse_decode forwards the backend's packed_queries.

@nvpohanh nvpohanh 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.

[by Claude Code] This review is done by agents. Please feel free to disagree if they do not make sense.

[by Claude Code] Severity: style | Confidence: High

Issue

The Accuracy Tests and Speed Tests sections give the model, GPUs, TP, and results, but no commands. Others cannot rerun the GSM8K, index-step, or AgentX numbers.

Fix

Add the server launch command (EAGLE3 draft model and --speculative-* flags) and the full sgl-eval command for GSM8K, the script behind the index-step table, and the server and AgentX replay commands for both arms, including how acceptance was fixed at AL 2.78.

Why it matters

nsys puts the score kernel at 15.0 of 36.1 ms per verify step, so a 2.5x faster kernel saves about 9 ms. The AgentX table shows 2.5x tok/s/user, so the commands would help others check where the rest of the gain comes from.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants