Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
schema: 2

base:
name: minimaxm31flash-fp4-gb200-dynamo-sglang-agentx-disagg
identity:
model: {}
frameworks:
dynamo: "1.7.0.dev20261030"
sglang: "0.0.0.dev1+ge3718813e"
dynamo:
install: false
request_plane: tcp
event_plane: zmq
environment:
HF_HUB_CACHE: /hf_hub_cache
# Tachometer's per-node exporters slow decode steps and add host memory;
# InferenceX does not read its output.
observability:
tachometer:
enabled: false
slurm:
time_limit: "6:00:00"
health_check:
max_attempts: 1440
interval_seconds: 10
resources:
gpu_type: gb200
gpus_per_node: 4
services:
- name: etcd
type: etcd
placement:
node: infra
# Disables Dynamo's per-request lifecycle span export; InferenceX does not read it.
- name: otel-collector
type: otel-collector
enabled: false
# Keeps tokenize, route and stream CPU work off the engine trays.
frontend:
type: dynamo
enable_multiple_frontends: false
placement:
node: dedicated
env:
DYN_ROUTER_TEMPERATURE: "0"
DYN_ROUTER_QUEUE_THRESHOLD: None
DYN_ROUTER_ACTIVE_REQUEST_EXPIRY_SECS: "3600"
DYN_TCP_CONNECT_TIMEOUT: "120"
# The default frontend tokenizer disables its prefix cache for this model,
# so every turn would re-tokenize the full prompt.
DYN_TOKENIZER: "fastokens"
DYN_TOKENIZER_CACHE: "1"
DYN_TOKENIZER_CACHE_BYTES: "8000000000"
args:
router-mode: kv
router-session-affinity-ttl-secs: "14400"
active-decode-blocks-threshold: "None"
active-prefill-tokens-threshold: "None"
active-prefill-tokens-threshold-frac: "None"
engine: sglang
roles:
prefill:
nodes: 2
workers: 2
gpus: 4
env:
PYTHONUNBUFFERED: "1"
PYTHONNOUSERSITE: "1"
FMHA_SM100_ALLOW_JIT: "1"
SGLANG_TIMEOUT_KEEP_ALIVE: "1800"
SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT: "3600"
SGLANG_DISAGGREGATION_WAITING_TIMEOUT: "3600"
SGLANG_MOONCAKE_CUSTOM_MEM_POOL: "True"
SGLANG_OPT_DEEPGEMM_MEGA_MOE_NUM_MAX_TOKENS_PER_RANK: "32768"
NCCL_MNNVL_ENABLE: "1"
NCCL_CUMEM_ENABLE: "1"
MC_FORCE_MNNVL: "1"
MC_ENABLE_DEST_DEVICE_AFFINITY: "1"
# Some nodes list a BMC interface with the same address on every node first.
MC_TCP_BIND_ADDRESS: "{node}"
WITH_NVIDIA_PEERMEM: "0"
# Dynamo 1.7 backend admission rejects turns with 529 once a DP rank is full;
# the SGLang scheduler queues them instead.
DYN_BACKEND_ADMISSION_ENGINE_REQUEST_LIMIT: "10000"
DYN_BACKEND_ADMISSION_ENGINE_REQUEST_WAITING_LIMIT: "10000"
DYN_BACKEND_ADMISSION_REQUEST_QUEUE_LIMIT: "10000"
args:
served-model-name: MiniMaxAI/MiniMax-M3.1-Flash
trust-remote-code: true
reasoning-parser: minimax-m3
tool-call-parser: minimax-m3
tensor-parallel-size: 4
data-parallel-size: 4
expert-parallel-size: 4
enable-dp-attention: true
enable-dp-lm-head: true
# flashinfer_trtllm_routed needs attention TP to match EP, which attention DP breaks.
moe-a2a-backend: megamoe
disaggregation-transfer-backend: mooncake
chunked-prefill-size: 8192
# Shortest uncached prefill first: short cached turns stop queueing
# behind long uncached prompts, which cuts the TTFT tail.
schedule-policy: shortest-prefill-first
# 64 per DP rank.
max-running-requests: 256
mem-fraction-static: 0.85
enable-hierarchical-cache: true
# 180 GB per rank: 720 of the node's ~900 GB host allowance, leaving
# headroom for the engine, Mooncake and the OS.
hicache-size: 180
hicache-write-policy: write_back
speculative-algorithm: DSPARK
speculative-dspark-block-size: 7
speculative-use-block-verification: true
speculative-draft-kv-cache-dtype: fp8_e4m3
# A session's turns stay on one prefill worker.
router-mode: kv
router-session-affinity-ttl-secs: "14400"
watchdog-timeout: 3600
enable-metrics: true
enable-cache-report: true
kv_events: true
decode:
nodes: 2
workers: 1
gpus: 8
env:
PYTHONUNBUFFERED: "1"
PYTHONNOUSERSITE: "1"
FMHA_SM100_ALLOW_JIT: "1"
SGLANG_TIMEOUT_KEEP_ALIVE: "1800"
DYN_SGL_GATEWAY_WORKERS: "8"
SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT: "3600"
SGLANG_DISAGGREGATION_WAITING_TIMEOUT: "3600"
SGLANG_MOONCAKE_CUSTOM_MEM_POOL: "True"
SGLANG_OPT_DEEPGEMM_MEGA_MOE_NUM_MAX_TOKENS_PER_RANK: "16384"
NCCL_MNNVL_ENABLE: "1"
NCCL_CUMEM_ENABLE: "1"
MC_FORCE_MNNVL: "1"
MC_ENABLE_DEST_DEVICE_AFFINITY: "1"
MC_TCP_BIND_ADDRESS: "{node}"
WITH_NVIDIA_PEERMEM: "0"
DYN_BACKEND_ADMISSION_ENGINE_REQUEST_LIMIT: "10000"
DYN_BACKEND_ADMISSION_ENGINE_REQUEST_WAITING_LIMIT: "10000"
DYN_BACKEND_ADMISSION_REQUEST_QUEUE_LIMIT: "10000"
args:
served-model-name: MiniMaxAI/MiniMax-M3.1-Flash
trust-remote-code: true
reasoning-parser: minimax-m3
tool-call-parser: minimax-m3
tensor-parallel-size: 8
data-parallel-size: 8
expert-parallel-size: 8
enable-dp-attention: true
enable-dp-lm-head: true
moe-a2a-backend: megamoe
disaggregation-transfer-backend: mooncake
# The frontend picks the decode DP rank; least-loaded sends each request to
# the rank with the fewest in flight, where round-robin left the busiest rank
# at 1.45x the mean and every DP rank waits for it each step.
router-mode: least-loaded
load-balance-method: total_tokens
# 48 per DP rank.
max-running-requests: 384
cuda-graph-max-bs-decode: 48
mem-fraction-static: 0.85
speculative-algorithm: DSPARK
speculative-dspark-block-size: 7
speculative-use-block-verification: true
speculative-draft-kv-cache-dtype: fp8_e4m3
watchdog-timeout: 3600
enable-metrics: true
kv_events: false
sbatch_directives:
mem: "0"
exclusive: ""
srun_options:
container-remap-root: ""
mem: "0"
benchmark:
placement:
node: dedicated
env:
AIPERF_HTTP_X_DYNAMO_SESSION_ID_FROM_CORRELATION_ID: "true"
AIPERF_USE_DYNAMO_CONV_AWARE_ROUTING: "0"
AIPERF_REQUIRED_SERVER_METRIC_PREFIX: "sglang:"

override_2p_dep4_dep8:
name: minimaxm31flash-fp4-gb200-dynamo-sglang-agentx-disagg-2p-dep4-dep8

override_3p_dep4_dep16:
name: minimaxm31flash-fp4-gb200-dynamo-sglang-agentx-disagg-3p-dep4-dep16
roles:
prefill:
nodes: 3
workers: 3
decode:
nodes: 4
gpus: 16
args:
tensor-parallel-size: 16
data-parallel-size: 16
expert-parallel-size: 16
max-running-requests: 768
31 changes: 31 additions & 0 deletions inferencex-e2e/configs/nvidia-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5332,6 +5332,37 @@ minimaxm31flash-fp4-gb200-sglang-agentic-dspark:
- { tp: 4, spec-decoding: mtp, kv-offloading: dram, kv-offload-backend: { name: hicache }, conc-list: [32, 40, 48, 56, 64], srt-recipe: agentic.yaml }
- { tp: 4, ep: 4, spec-decoding: mtp, kv-offloading: dram, kv-offload-backend: { name: hicache }, conc-list: [72, 80], srt-recipe: agentic.yaml }

minimaxm31flash-fp4-gb200-dynamo-sglang-agentic-dspark-disagg:
image: lmsysorg/sglang:nightly-cu134-20261030-e371881@sha256:a82fff791d7dc1e5cfdfde9022487c60c079286fd54684950d55b787eb2e673a
model: MiniMaxAI/MiniMax-M3.1-Flash
model-prefix: minimaxm31flash
runner: cluster:gb200-nv
precision: fp4
framework: dynamo-sglang
router: { name: dynamo-router, version: "1.7.0.dev20261030" }
kv-p2p-transfer: mooncake
multinode: true
disagg: true
srt-recipe-dir: minimaxm31flash/sglang/gb200-fp4/agentx
scenarios:

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.

🟡 (optional) Published results for this config will claim 901 GB of host KV per node, while the recipe only pins 720 GB. dram-utilization: 1.0 makes matrix generation record the whole gb200-nv node share (860_160 MiB, about 901 GB) as total-cpu-dram-gb. The prefill recipe pins hicache-size: 180 on 4 ranks, which is 720 GB. Fix: set dram-utilization: 0.80, which resolves to 721 GB. The single-node sibling minimaxm31flash-fp4-gb200-sglang-agentic-dspark uses that value for the same 180 GB-per-rank pool.

Why this was flagged

agentic_dram_offload_gb (infx/matrix/generate.py:475-518) computes the prefill share as available-cpu-dram-mib 860_160 (runners.yaml:572) × utilization × 4/4 GPUs. With 1.0 that comes to 901 GB. The value reaches TOTAL_CPU_DRAM_GB through infx/srt_slurm/generate.py:59. It is published as allocated_cpu_dram_gb (infx/results/agentic/init.py:205). The decode side also gets 901 GB as decode_allocated_cpu_dram_gb, even though decode runs no HiCache. The recipe really allocates 180 GB × 4 ranks = 720 GB per prefill node; its own comment says "720 of the node's ~900 GB host allowance". The same-cluster, same-pool sibling uses dram-utilization 0.80. Its recipe records TOTAL_CPU_DRAM_GB '721' (benchmarks/single_node/.../minimaxm31flash/sglang/gb200-fp4-mtp/agentic.yaml:148). So results with identical host pools would report different DRAM budgets, and this one overstates its pool by about 25%. Nothing checks the recorded value against hicache-size, because the recipe never reads TOTAL_CPU_DRAM_GB.

Verification: nit. This happens on every DRAM-offload point of the new config. In agentic_dram_offload_gb, share_gb returns 860160 MiB × 1.0 × 4/4, which is about 901 GB. infx/results/agentic/__init__.py:205 publishes this as allocated_cpu_dram_gb. The recipe really pins hicache-size: 180 on 4 ranks per prefill node, which is 720 GB. Nothing fails at runtime.

agentic-coding:
- dram-utilization: 1.0
search-space:
- spec-decoding: mtp
kv-offloading: dram
kv-offload-backend: { name: hicache }
conc-list: [224, 256]
srt-recipe: disagg-variants.yaml:override_2p_dep4_dep8
prefill: { num-worker: 2, tp: 4, ep: 4, dp-attn: true }
decode: { num-worker: 1, tp: 8, ep: 8, dp-attn: true }
- spec-decoding: mtp
kv-offloading: dram
kv-offload-backend: { name: hicache }
conc-list: [320, 360]
srt-recipe: disagg-variants.yaml:override_3p_dep4_dep16
prefill: { num-worker: 3, tp: 4, ep: 4, dp-attn: true }
decode: { num-worker: 1, tp: 16, ep: 16, dp-attn: true }

# Day-0 Kimi K3 AgentX coverage on GB200. The three aggregate srt-slurm
# profiles mirror the serving strategies synthesized by the official recipe:
# latency: multi-node TP16 (4 GB200 nodes / 16 GPUs)
Expand Down
9 changes: 9 additions & 0 deletions inferencex-e2e/perf-changelog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11739,3 +11739,12 @@
pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/4676
scenario-type: [agentic-coding]
append-only: true

- config-keys:
- minimaxm31flash-fp4-gb200-dynamo-sglang-agentic-dspark-disagg
scenario-type: [agentic-coding]
description:
- "Add disaggregated SGLang behind Dynamo for MiniMax-M3.1-Flash AgentX on GB200 with lmsysorg/sglang:nightly-cu134-20261030-e371881 (Dynamo 1.7.0.dev20261030, Mooncake transfer, minimax-msa kernels)."
- "2 DEP4 prefill workers with a DEP8 decode at conc 224 and 256, or 3 DEP4 prefill workers with a DEP16 decode at conc 320 and 360; MegaMoE, DSpark block 7 with fp8 draft KV, Dynamo KV router with fastokens for prefill and least-loaded routing across decode DP ranks."
- "Prefill: shortest-prefill-first, chunk 8192, mem-fraction-static 0.85, HiCache 180 GB per rank write_back."
pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/XXXX

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.

🔴 The changelog check will fail on this PR, so the new config never gets scheduled. Its pr-link ends in pull/XXXX, with four X's. The validator only accepts XXX, https://github.com/SemiAnalysisAI/InferenceX/pull/XXX, or the PR's real URL (validate_perf_changelog.py:21-24). Fix: set pr-link to this PR's real URL, or to the exact .../pull/XXX placeholder.

Why this was flagged

The new entry at inferencex-e2e/perf-changelog.yaml:11750 sets pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/XXXX. On PR runs, validate_added_pr_link (inferencex-e2e/infx/workflows/validate_perf_changelog.py:105-116) accepts only a link in PR_LINK_PLACEHOLDERS ("XXX" or "https://github.com/SemiAnalysisAI/InferenceX/pull/XXX") or the PR's own URL. Four X's matches none of these, so it raises "new PR entry must use ... or an XXX placeholder". On main, CANONICAL_PR_LINK needs pull/\d+ and rejects it too. The changelog validation fails, so the sweep for minimaxm31flash-fp4-gb200-dynamo-sglang-agentic-dspark-disagg is never scheduled and the PR cannot get the /use <run_id> acceptance it needs.

Verification: Trigger: the PR goes through merge_with_reuse. The entry at inferencex-e2e/perf-changelog.yaml:11750 uses pull/XXXX, which matches neither placeholder (validate_perf_changelog.py:21-24). merge_with_reuse.py:688 calls canonicalize_changelog(pr, repo) and does not catch the exception, so the merge aborts. The PR-run changelog check does not call this validator.

Loading