From e3c2fd30a77ccbc370ce17077869c5292de44511 Mon Sep 17 00:00:00 2001 From: honglie <275632494+yhl-amd@users.noreply.github.com> Date: Wed, 23 Sep 2026 14:01:01 +0000 Subject: [PATCH 1/4] perf(atom): enable MiniMax-M3 FlyDSL decode and fix GPU visibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更新到 nightly_202609231248,启用 FlyDSL paged decode 和 dense work planner,修复 ROCR/HIP 重复筛选。保留 19 个吞吐点,按 #3189 仅单独调度一个 TP4 C48 offload eval。 --- .../agentic/minimaxm3_fp4_mi355x_atom_mtp.sh | 12 +++++++---- configs/amd-master.yaml | 2 +- docs/configuration-procedures.md | 21 +++++++++++++++++++ docs/configuration-procedures_zh.md | 20 ++++++++++++++++++ perf-changelog.yaml | 11 ++++++++++ 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_mi355x_atom_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_mi355x_atom_mtp.sh index 1d2fbb285f..0c9dbca167 100644 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_mi355x_atom_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_mi355x_atom_mtp.sh @@ -36,8 +36,10 @@ if [ "$TP" -ne 2 ] && [ "$TP" -ne 4 ] && [ "$TP" -ne 8 ]; then exit 1 fi -if [[ -n "${ROCR_VISIBLE_DEVICES+x}" ]]; then - export HIP_VISIBLE_DEVICES="$ROCR_VISIBLE_DEVICES" +# ROCR filters and renumbers GPUs before HIP sees them. Keep a single mask; +# applying the physical IDs again through HIP can hide the NUMA-spread ranks. +if [[ -n "${ROCR_VISIBLE_DEVICES:-}" ]]; then + unset HIP_VISIBLE_DEVICES fi if [[ "$MODEL_PATH" == "$MODEL" ]]; then @@ -126,7 +128,7 @@ case "$KV_OFFLOAD_BACKEND" in # GPUs 0-3 are on NUMA node 0, 4-7 on node 1. Ranks pinning host memory on # one node starve each other: 256 GB/rank takes 45 min (TP2) / 27 min (TP4) # all on node 0, and 21 s with TP2 split one per node. - if [[ -z "${ROCR_VISIBLE_DEVICES+x}" ]]; then + if [[ -z "${ROCR_VISIBLE_DEVICES+x}" && -z "${HIP_VISIBLE_DEVICES+x}" ]]; then case "$TP" in 2) NUMA_GPUS=0,4 ;; 4) NUMA_GPUS=0,1,4,5 ;; @@ -134,7 +136,6 @@ case "$KV_OFFLOAD_BACKEND" in esac if [[ -n "$NUMA_GPUS" ]]; then export ROCR_VISIBLE_DEVICES="$NUMA_GPUS" - export HIP_VISIBLE_DEVICES="$NUMA_GPUS" echo "NUMA-spread GPUs for offload: $NUMA_GPUS" fi fi @@ -183,6 +184,9 @@ export AITER_SITUV2_A4W4=1 export AITER_QUICK_REDUCE_QUANTIZATION=INT4 export AITER_FLYDSL_STAGE2_FP8=1 export ATOM_FORCE_ATTN_TRITON=1 +# ATOM #2366: opt into FlyDSL paged decode and its dense-decode work planner. +export ATOM_PA_FLYDSL=1 +export ATOM_PA_FLYDSL_PLAN=1 # golden_al_distribution/minimaxm3_eagle3_gqa.yaml: minimax-m3.thinking_on[3] -> AL 2.78. # Synthetic acceptance on throughput runs, real target verification on eval-only. diff --git a/configs/amd-master.yaml b/configs/amd-master.yaml index b26f8afda6..2ca0c6a913 100644 --- a/configs/amd-master.yaml +++ b/configs/amd-master.yaml @@ -632,7 +632,7 @@ kimik3-fp4-mi355x-atom-agentic-mtp: - { tp: 8, dcp-size: 8, kv-offloading: dram, kv-offload-backend: { name: lmcache, version: "0.4.5" }, conc-list: [56, 72], spec-decoding: mtp } minimaxm3-fp4-mi355x-atom-agentic-mtp: - image: rocm/atom-dev:nightly_202609171455 + image: rocm/atom-dev:nightly_202609231248 model: amd/MiniMax-M3-MXFP4 model-prefix: minimaxm3 runner: cluster:mi355x-amds diff --git a/docs/configuration-procedures.md b/docs/configuration-procedures.md index c6941009a7..160bf9e2fa 100644 --- a/docs/configuration-procedures.md +++ b/docs/configuration-procedures.md @@ -258,6 +258,27 @@ The pinned image is the official ATOM nightly The recipe does not patch AITER source at runtime; TP communication fusion, DSpark K6 and graph capture use the implementation shipped in the image. +### MiniMax-M3 ATOM FlyDSL paged decode + +`minimaxm3-fp4-mi355x-atom-agentic-mtp` uses +`rocm/atom-dev:nightly_202609231248` with `ATOM_PA_FLYDSL=1` and +`ATOM_PA_FLYDSL_PLAN=1`, following [ROCm/ATOM#2366](https://github.com/ROCm/ATOM/pull/2366) +and the [upstream recipe](https://github.com/ROCm/ATOM/blob/94cde4ba786f45b38c26ee8201444659e44f861f/recipes/MiniMax-M3-Agentic-InferenceX.md). +FlyDSL handles supported paged-decode shapes; its work planner balances dense +decode by actual context length. Unsupported shapes retain the Gluon fallback. +Verify the selected route and capture-time work-plan creation in `server.log`. + +When ROCR selects GPUs, the script clears HIP's second mask to avoid filtering +the renumbered devices again. Offload selects `0,4` for TP2 or `0,1,4,5` for TP4 +only when neither mask was supplied. Explicit ROCR and HIP-only allocations +remain authoritative. The 19 resident/offload points, EAGLE3 K3, golden AL 2.78, +indexer CP and DRAM budgets are preserved. + +Following #3189, this update uses `no-evals: true` for its PR sweep and one +separate TP4 C48 LMCache-offload eval at the same commit. Select it with +`test-config --config-files configs/amd-master.yaml --config-keys minimaxm3-fp4-mi355x-atom-agentic-mtp --conc 48 --evals-only`. +That emits one `minimax-vendor` / `minimax_m3_full` job using real acceptance. + ### DeepSeek-V4.1-Flash DSpark The GB200 DSpark recipe uses a minimum CUDA graph capture size of 64 tokens to cover concurrent AgentX subagents. This raises c1/c2/c4 from 8/16/32 to 64; c8 and above retain their existing sizes. The full trace, AL 3.51, and Engram UVA settings are preserved; low-concurrency tail latency improvements require CI confirmation. diff --git a/docs/configuration-procedures_zh.md b/docs/configuration-procedures_zh.md index 54986db75c..fa36141f1d 100644 --- a/docs/configuration-procedures_zh.md +++ b/docs/configuration-procedures_zh.md @@ -230,6 +230,26 @@ schedule 和 ragged verification 保持关闭。 配方不再在运行时修改 AITER 源码;TP 通信融合、DSpark K6 和 graph capture 直接使用镜像内实现。 +### MiniMax-M3 ATOM FlyDSL paged decode + +`minimaxm3-fp4-mi355x-atom-agentic-mtp` 按照 +[ROCm/ATOM#2366](https://github.com/ROCm/ATOM/pull/2366) 和 +[上游配方](https://github.com/ROCm/ATOM/blob/94cde4ba786f45b38c26ee8201444659e44f861f/recipes/MiniMax-M3-Agentic-InferenceX.md), +使用 `rocm/atom-dev:nightly_202609231248`,启用 `ATOM_PA_FLYDSL=1` 和 +`ATOM_PA_FLYDSL_PLAN=1`。FlyDSL 处理支持的 paged-decode shape,work planner +按实际上下文长度均衡 dense decode 工作量;不支持的 shape 仍回退至 Gluon。 +从 `server.log` 核对实际路由,以及 work plan 是否在图捕获时创建。 + +当 ROCR 已选择 GPU 时,脚本清除 HIP 的第二层 mask,避免再次筛选已重新编号的设备。 +仅在调用方未传入任何 mask 时,offload 才为 TP2 选择 `0,4`、为 TP4 选择 `0,1,4,5`。 +保留显式 ROCR 分配和仅 HIP 的分配。19 个 resident/offload 点、EAGLE3 K3、 +golden AL 2.78、indexer CP 和 DRAM 预算保持原值。 + +沿用 #3189 的方式,本次更新的 PR sweep 设置 `no-evals: true`,另在同一提交上 +单独运行一个 TP4 C48 LMCache-offload eval。使用 +`test-config --config-files configs/amd-master.yaml --config-keys minimaxm3-fp4-mi355x-atom-agentic-mtp --conc 48 --evals-only` +选择该点,只生成一个使用真实 acceptance 的 `minimax-vendor` / `minimax_m3_full` job。 + ### DeepSeek-V4.1-Flash DSpark GB200 的 DSpark 配方将 CUDA graph 最小捕获范围设为 64 tokens,以覆盖 AgentX 子代理并发。这会将 c1/c2/c4 的上限从 8/16/32 提升至 64;c8 及以上保持原有大小。完整轨迹、AL 3.51 和 Engram UVA 配置保持不变;需通过 CI 验证低并发尾延迟改善。 diff --git a/perf-changelog.yaml b/perf-changelog.yaml index bce3819e20..057bf73edb 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8758,3 +8758,14 @@ - "Replace the PD-buffers-in-DRAM route with tilert==0.1.6.post1 on both TileRT ranks (PyPI, 2026-09-22): the shipped wheel shards the mooncake receive buffer (decode, receive_server.py) and the connector staging buffer (prefill TP rank 0, prefill_connector.py) by layer across the eight devices (TILERT_PD_SHARDS, default 8, capped at device_count; layer lid on device lid % 8; the glm5_2 profile has 79 layers, so the heaviest shard holds 10 of them: 99.06 GiB x 10/79 = 12.54 GiB per card) instead of one dense 99.06 GiB buffer per role, and both fit on the GPU at the full 1048576-token context without host memory. Each shard is registered with mooncake on its own device, hello_layout carries per-shard bases and rdma_plan writes layer by layer into the matching remote shard, so the KV path is device-to-device again (81 GB in 751 ms = 108 GB/s on 2x8 MI350X per CrimsonDump/InferenceX@56a1e5a, against the 20.9 GiB/s measured for the host-to-host hop) and mla_nsa.convert() dequantises each layer on the shard that received it rather than on cuda:0. patches/tilert-0.1.6-pd-buffers-in-dram.patch, docs/waiver/3330.md and TILERT_PD_BUFFER_DEVICE (the AgentX recipe, server_tilert.sh, job.slurm, setup_deps.sh, including the 0.1.6 pin guard and the patch apt package) are removed; neither image is modified. Router metadata 0.1.6 -> 0.1.6.post1: pd_router.py is one of the six files post1 changes, its fixed 600 s request timeouts to vLLM and decode become TILERT_PD_HTTP_TIMEOUT_S (default 3600). GPU_MEM_UTIL stays 0.85; the 12.54 GiB staging shard sits outside vLLM's budget next to the ~6.3 GiB non-torch baseline. server_tilert.sh now honours EVAL_ONLY/RUN_EVAL on the AgentX path (GSM8K on the same router instead of an unconditional trace replay) and exports PORT for benchmark_lib's run_lm_eval; evals run with real MTP verification since simulated acceptance is already disabled under those flags. Measured by CrimsonDump on 2x8 MI350X at this context with bf16 KV, 3600 s AgentX at concurrency 1: submission_valid true, 239 successful requests, 0 errors, TTFT p50 5711.8 ms, ITL p50 2.18 ms, peak device memory 202.1 GiB per decode card and 269.2 GiB per prefill card of 287.69 GiB." - "在两侧 TileRT rank 上以 tilert==0.1.6.post1(PyPI,2026-09-22)取代 PD 缓冲进 DRAM 的方案:正式 wheel 把 mooncake 接收缓冲(decode,receive_server.py)与 connector 暂存缓冲(prefill TP rank 0,prefill_connector.py)按层分片到 8 张卡(TILERT_PD_SHARDS,默认 8,以 device_count 为上限;第 lid 层落在第 lid % 8 张卡;glm5_2 profile 共 79 层,最重分片含 10 层:99.06 GiB x 10/79 = 每卡 12.54 GiB),不再是每个角色一块致密的 99.06 GiB 缓冲,于是在完整 1048576 上下文下两者都能放进 GPU,无需主机内存。各分片在所在卡上向 mooncake 注册,hello_layout 携带各分片基址,rdma_plan 逐层写入对应的远端分片,KV 通路重回设备到设备(2x8 MI350X 上 81 GB / 751 ms = 108 GB/s,见 CrimsonDump/InferenceX@56a1e5a;对比主机到主机实测 20.9 GiB/s),mla_nsa.convert() 在收到该层的分片上反量化而非集中于 cuda:0。移除 patches/tilert-0.1.6-pd-buffers-in-dram.patch、docs/waiver/3330.md 与 TILERT_PD_BUFFER_DEVICE(AgentX 配方、server_tilert.sh、job.slurm、setup_deps.sh,含 0.1.6 版本锁定检查与 patch apt 包);两侧镜像均无改动。router 元数据 0.1.6 -> 0.1.6.post1:pd_router.py 是 post1 改动的六个文件之一,其对 vLLM 与 decode 固定的 600 秒请求超时改为 TILERT_PD_HTTP_TIMEOUT_S(默认 3600)。GPU_MEM_UTIL 保持 0.85;12.54 GiB 暂存分片与约 6.3 GiB 非 torch 基线同在 vLLM 预算之外。server_tilert.sh 现在在 AgentX 路径也遵循 EVAL_ONLY/RUN_EVAL(在同一 router 上跑 GSM8K,而非无条件回放轨迹),并为 benchmark_lib 的 run_lm_eval 导出 PORT;这些标志下模拟接受已关闭,评测使用真实 MTP 验证。CrimsonDump 在 2x8 MI350X、该上下文、bf16 KV 下实测 3600 秒 AgentX 并发 1:submission_valid true、239 条成功、0 错误、TTFT p50 5711.8 ms、ITL p50 2.18 ms,decode 每卡峰值 202.1 GiB、prefill 每卡 269.2 GiB(卡容量 287.69 GiB)。" pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3366 + +- config-keys: + - minimaxm3-fp4-mi355x-atom-agentic-mtp + scenario-type: + - agentic-coding + no-evals: true + description: + - "Update MiniMax-M3 ATOM AgentX from rocm/atom-dev:nightly_202609171455 to nightly_202609231248 (digest sha256:80f2c66579704aba933a9ff2a6e22e1dc61917c0fe6a2b0a0166816cd6d0100a), containing ROCm/ATOM#2366. Enable ATOM_PA_FLYDSL=1 and ATOM_PA_FLYDSL_PLAN=1 for FlyDSL paged decode and context-length-aware dense-decode work planning." + - "Use only ROCR_VISIBLE_DEVICES for automatically selected NUMA-spread GPUs and remove the inherited ROCR-to-HIP double mask. Preserve explicit ROCR allocations and HIP-only allocations; retain all 19 TP2/TP4 resident/offload points, EAGLE3 K3, golden AL 2.78, indexer CP and CPU memory budgets." + - "As in PR #3189, run a throughput-only PR sweep and dispatch exactly one representative TP4 C48 LMCache-offload eval separately against the same head, using the full MiniMax vendor suite and real draft acceptance." + pr-link: TBD From 08eabe44a35cf1219e17c2f54d9353924c9db06d Mon Sep 17 00:00:00 2001 From: honglie <275632494+yhl-amd@users.noreply.github.com> Date: Wed, 23 Sep 2026 14:02:02 +0000 Subject: [PATCH 2/4] docs: link MiniMax-M3 FlyDSL changelog to PR 3388 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 回填 MiniMax-M3 FlyDSL 更新的 upstream PR 链接。 --- perf-changelog.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 057bf73edb..e7adb50164 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8768,4 +8768,4 @@ - "Update MiniMax-M3 ATOM AgentX from rocm/atom-dev:nightly_202609171455 to nightly_202609231248 (digest sha256:80f2c66579704aba933a9ff2a6e22e1dc61917c0fe6a2b0a0166816cd6d0100a), containing ROCm/ATOM#2366. Enable ATOM_PA_FLYDSL=1 and ATOM_PA_FLYDSL_PLAN=1 for FlyDSL paged decode and context-length-aware dense-decode work planning." - "Use only ROCR_VISIBLE_DEVICES for automatically selected NUMA-spread GPUs and remove the inherited ROCR-to-HIP double mask. Preserve explicit ROCR allocations and HIP-only allocations; retain all 19 TP2/TP4 resident/offload points, EAGLE3 K3, golden AL 2.78, indexer CP and CPU memory budgets." - "As in PR #3189, run a throughput-only PR sweep and dispatch exactly one representative TP4 C48 LMCache-offload eval separately against the same head, using the full MiniMax vendor suite and real draft acceptance." - pr-link: TBD + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3388 From 7bbb0ec775dd86b8f6ebb3c4e345cdfe283b1c1a Mon Sep 17 00:00:00 2001 From: honglie <275632494+yhl-amd@users.noreply.github.com> Date: Wed, 23 Sep 2026 14:13:01 +0000 Subject: [PATCH 3/4] feat(ci): select eval concurrencies within the PR sweep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 MiniMax-M3 的 19 个吞吐点和唯一的 TP4 C48 eval 合并到同一次 PR sweep。新增 eval-concs 过滤,仅限制 eval,不裁剪吞吐点。旧运行已取消,暂不重新启动 GPU 测试。 --- docs/configuration-procedures.md | 8 +++---- docs/configuration-procedures_zh.md | 7 +++--- docs/eval-agentx-procedures.md | 10 ++++++++ docs/eval-agentx-procedures_zh.md | 7 ++++++ infx/matrix/plan.py | 27 +++++++++++++++++++++- infx/matrix/validation.py | 18 ++++++++++++--- perf-changelog.yaml | 4 ++-- utils/test_process_changelog.py | 36 ++++++++++++++++++++++++++++- 8 files changed, 102 insertions(+), 15 deletions(-) diff --git a/docs/configuration-procedures.md b/docs/configuration-procedures.md index 160bf9e2fa..2f82a3001f 100644 --- a/docs/configuration-procedures.md +++ b/docs/configuration-procedures.md @@ -274,10 +274,10 @@ only when neither mask was supplied. Explicit ROCR and HIP-only allocations remain authoritative. The 19 resident/offload points, EAGLE3 K3, golden AL 2.78, indexer CP and DRAM budgets are preserved. -Following #3189, this update uses `no-evals: true` for its PR sweep and one -separate TP4 C48 LMCache-offload eval at the same commit. Select it with -`test-config --config-files configs/amd-master.yaml --config-keys minimaxm3-fp4-mi355x-atom-agentic-mtp --conc 48 --evals-only`. -That emits one `minimax-vendor` / `minimax_m3_full` job using real acceptance. +The changelog uses `eval-concs: [48]` to include all 19 throughput points and +exactly one TP4 C48 LMCache-offload eval in the same PR sweep. The eval uses +`minimax-vendor` / `minimax_m3_full` with real acceptance. The concurrency filter +changes eval selection only; throughput retains every configured point. ### DeepSeek-V4.1-Flash DSpark diff --git a/docs/configuration-procedures_zh.md b/docs/configuration-procedures_zh.md index fa36141f1d..9c1dc5578d 100644 --- a/docs/configuration-procedures_zh.md +++ b/docs/configuration-procedures_zh.md @@ -245,10 +245,9 @@ schedule 和 ragged verification 保持关闭。 保留显式 ROCR 分配和仅 HIP 的分配。19 个 resident/offload 点、EAGLE3 K3、 golden AL 2.78、indexer CP 和 DRAM 预算保持原值。 -沿用 #3189 的方式,本次更新的 PR sweep 设置 `no-evals: true`,另在同一提交上 -单独运行一个 TP4 C48 LMCache-offload eval。使用 -`test-config --config-files configs/amd-master.yaml --config-keys minimaxm3-fp4-mi355x-atom-agentic-mtp --conc 48 --evals-only` -选择该点,只生成一个使用真实 acceptance 的 `minimax-vendor` / `minimax_m3_full` job。 +changelog 使用 `eval-concs: [48]`,使同一次 PR sweep 包含全部 19 个吞吐点和 +唯一一个 TP4 C48 LMCache-offload eval。eval 使用 `minimax-vendor` / +`minimax_m3_full` 和真实 acceptance。并发过滤仅影响 eval 选择,吞吐保留所有配置点。 ### DeepSeek-V4.1-Flash DSpark diff --git a/docs/eval-agentx-procedures.md b/docs/eval-agentx-procedures.md index 06c9ef6cf9..c81f971453 100644 --- a/docs/eval-agentx-procedures.md +++ b/docs/eval-agentx-procedures.md @@ -21,6 +21,16 @@ Combining `no-evals` with `all-evals`, `evals-only`, or `eval-min-prefill-ep` on the entry, or with either eval PR modifier, is rejected. Such a run provides throughput evidence, not model-evaluation evidence. +To keep throughput and a limited eval selection in one PR sweep, set +`eval-concs: [48]` on the changelog entry instead of `no-evals`. This filters +the eval points already selected by the normal policy and leaves every throughput +point intact. All matching deployments at the selected concurrency remain; +it does not impose a job-count limit or add unselected points. An empty match +fails validation. Multi-node `all-evals` rows are narrowed to the matching +concurrencies; other multi-node rows must match their selected `eval-conc`. +The field requires a nonempty list of positive integers and cannot be combined +with `no-evals` or `append-only`. + There are two distinct layers: the matrix generator decides **which jobs exist**, while runtime variables decide **what a launched job does**. | Need | Generator/workflow mode | Runtime behavior | diff --git a/docs/eval-agentx-procedures_zh.md b/docs/eval-agentx-procedures_zh.md index 03c0580439..b40c49193b 100644 --- a/docs/eval-agentx-procedures_zh.md +++ b/docs/eval-agentx-procedures_zh.md @@ -19,6 +19,13 @@ `all-evals`、`evals-only` 或 `eval-min-prefill-ep`,PR 也不能同时使用两个 eval modifier 中的任意一个。这类运行提供吞吐量证据,不提供模型评估证据。 +若要在同一次 PR sweep 中保留吞吐量和少量 eval,请在 changelog 条目中设置 +`eval-concs: [48]`,而不是 `no-evals`。该字段只过滤常规策略已选中的 eval 点, +保留全部吞吐点。所选并发下的所有匹配部署都会保留;它不限制 job 总数,也不会 +增加原本未选中的点。无匹配结果会使校验失败。多节点 `all-evals` 行会缩减为 +匹配的并发列表;其他多节点行必须匹配其已选定的 `eval-conc`。字段必须是非空 +正整数列表,不能与 `no-evals` 或 `append-only` 同时使用。 + 这里有两个不同层次:矩阵生成器决定**存在哪些作业**,运行时变量决定**已启动作业执行什么操作**。 | 需求 | 生成器/工作流模式 | 运行时行为 | diff --git a/infx/matrix/plan.py b/infx/matrix/plan.py index a964e1984f..4b67454a0f 100644 --- a/infx/matrix/plan.py +++ b/infx/matrix/plan.py @@ -109,6 +109,23 @@ def get_config_keys_from_master(config_keys: list[str], master_config: dict) -> return list(resolved_keys) +def filter_eval_rows_by_concurrency(eval_rows: list[dict], concs: list[int] | None) -> list[dict]: + """Restrict selected eval points without expanding the default eval policy.""" + if concs is None: + return eval_rows + allowed = set(concs) + kept = [] + for row in eval_rows: + if isinstance(row["conc"], list): + selected = row["conc"] if row.get("eval-all-concs") else [row["eval-conc"]] + selected = [conc for conc in selected if conc in allowed] + if selected: + kept.append({**row, "conc": selected, "eval-conc": max(selected)}) + elif row["conc"] in allowed: + kept.append(row) + return kept + + @contextmanager def generation_inputs_at_ref(ref: str) -> Iterator[GenerationInputs]: """Materialize config and generator inputs from one repository revision.""" @@ -543,6 +560,7 @@ def generate_current( continue eval_groups = group_unseen_scenarios(all_configs, entry_scenarios, eval_scenarios_seen) + selected_eval_results = [] for scenarios, eval_configs in eval_groups.items(): entry_eval_results = generate_current( eval_configs, @@ -552,7 +570,14 @@ def generate_current( entry_eval_results = filter_eval_rows_by_prefill_ep( entry_eval_results, entry.eval_min_prefill_ep ) - all_eval_results.extend(entry_eval_results) + selected_eval_results.extend( + filter_eval_rows_by_concurrency(entry_eval_results, entry.eval_concs) + ) + if eval_groups and entry.eval_concs is not None and not selected_eval_results: + raise ValueError( + f"eval-concs {entry.eval_concs} matched no selected evals for {all_configs}" + ) + all_eval_results.extend(selected_eval_results) if trim: all_benchmark_results = trim_conc(all_benchmark_results) diff --git a/infx/matrix/validation.py b/infx/matrix/validation.py index d3503c7f2f..98bf2eefe8 100644 --- a/infx/matrix/validation.py +++ b/infx/matrix/validation.py @@ -1,6 +1,6 @@ import pprint from enum import Enum -from typing import Any, Literal, Self +from typing import Annotated, Any, Literal, Self import yaml from pydantic import ( @@ -1013,6 +1013,12 @@ class ChangelogEntry(BaseModel): evals_only: bool = Field(alias="evals-only", default=False) all_evals: bool = Field(alias="all-evals", default=False) no_evals: bool = Field(alias="no-evals", default=False) + eval_concs: list[Annotated[int, Field(gt=0, strict=True)]] | None = Field( + alias="eval-concs", + default=None, + min_length=1, + description="Keep only these already-selected eval concurrencies; preserve throughput.", + ) append_only: bool = Field( alias="append-only", default=False, @@ -1041,11 +1047,17 @@ class ChangelogEntry(BaseModel): def validate_append_only_mode(self) -> Self: """Append-only entries are throughput deltas, never eval-only requests.""" if self.no_evals and ( - self.evals_only or self.all_evals or self.eval_min_prefill_ep is not None + self.evals_only + or self.all_evals + or self.eval_min_prefill_ep is not None + or self.eval_concs is not None ): raise ValueError("no-evals cannot be combined with eval selection fields") if self.append_only and ( - self.evals_only or self.all_evals or self.eval_min_prefill_ep is not None + self.evals_only + or self.all_evals + or self.eval_min_prefill_ep is not None + or self.eval_concs is not None ): raise ValueError("append-only cannot be combined with eval selection fields") return self diff --git a/perf-changelog.yaml b/perf-changelog.yaml index e7adb50164..8f198a0a8e 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8763,9 +8763,9 @@ - minimaxm3-fp4-mi355x-atom-agentic-mtp scenario-type: - agentic-coding - no-evals: true + eval-concs: [48] description: - "Update MiniMax-M3 ATOM AgentX from rocm/atom-dev:nightly_202609171455 to nightly_202609231248 (digest sha256:80f2c66579704aba933a9ff2a6e22e1dc61917c0fe6a2b0a0166816cd6d0100a), containing ROCm/ATOM#2366. Enable ATOM_PA_FLYDSL=1 and ATOM_PA_FLYDSL_PLAN=1 for FlyDSL paged decode and context-length-aware dense-decode work planning." - "Use only ROCR_VISIBLE_DEVICES for automatically selected NUMA-spread GPUs and remove the inherited ROCR-to-HIP double mask. Preserve explicit ROCR allocations and HIP-only allocations; retain all 19 TP2/TP4 resident/offload points, EAGLE3 K3, golden AL 2.78, indexer CP and CPU memory budgets." - - "As in PR #3189, run a throughput-only PR sweep and dispatch exactly one representative TP4 C48 LMCache-offload eval separately against the same head, using the full MiniMax vendor suite and real draft acceptance." + - "Run all 19 throughput points and exactly one representative TP4 C48 LMCache-offload eval in the same PR sweep. Use eval-concs: [48] to restrict only eval selection, retaining the full MiniMax vendor suite and real draft acceptance." pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3388 diff --git a/utils/test_process_changelog.py b/utils/test_process_changelog.py index febb282ebd..a7c56f891b 100644 --- a/utils/test_process_changelog.py +++ b/utils/test_process_changelog.py @@ -653,7 +653,7 @@ def test_no_evals_preserves_throughput_and_other_entries(changelog_run, skip): assert output["changelog_metadata"]["entries"][0]["no-evals"] is skip -@pytest.mark.parametrize("flags", [{"evals-only": True}, {"all-evals": True}, {"eval-min-prefill-ep": 2}]) +@pytest.mark.parametrize("flags", [{"evals-only": True}, {"all-evals": True}, {"eval-min-prefill-ep": 2}, {"eval-concs": [32]}]) def test_no_evals_rejects_conflicting_entry_options(changelog_run, flags): with pytest.raises(ValueError, match="no-evals cannot be combined"): changelog_run([{"no-evals": True, **flags}]) @@ -675,6 +675,7 @@ def test_append_only_rejects_cli_eval_modifiers_before_generation(changelog_run, @pytest.mark.parametrize("entries", [ [{"append-only": True}, {}], [{"append-only": True, "all-evals": True}], [{"append-only": True, "evals-only": True}], [{"append-only": True, "eval-min-prefill-ep": 2}], + [{"append-only": True, "eval-concs": [32]}], ]) def test_append_only_rejects_mixed_or_entry_eval_modes(changelog_run, entries): with pytest.raises(ValueError, match="append-only"): @@ -738,6 +739,39 @@ def test_eval_prefill_ep_filter_preserves_single_node_and_order(threshold, expec assert [row["label"] for row in process_changelog.filter_eval_rows_by_prefill_ep(rows, threshold)] == expected +def test_eval_concs_keeps_one_vendor_eval_in_the_throughput_plan(planning_repo, changelog_run): + root, master, _ = planning_repo + master["single"]["model-prefix"] = "minimaxm3" + (root / "configs/nvidia-master.yaml").write_text(yaml.safe_dump(master)) + output = changelog_run([{"scenario-type": ["agentic-coding"], "eval-concs": [32]}]) + assert [r["conc"] for r in output["single_node"]["agentic"]] == [16, 32] + assert [(r["conc"], r["eval-framework"], r["eval-suite"]) for r in output["agentic_evals"]] == [ + (32, "minimax-vendor", "minimax_m3_full"), + ] + assert output["evals"] == [] + + +def test_eval_concs_filters_multinode_all_evals_without_changing_throughput(changelog_run): + output = changelog_run([ + {"config-keys": ["multi"], "scenario-type": ["fixed-seq-len"], "eval-concs": [32]}, + ], ["--all-evals"]) + assert [r["conc"] for r in output["multi_node"]["8k1k"]] == [[16, 32, 64]] + assert [(r["conc"], r["eval-conc"], r["eval-all-concs"]) for r in output["multinode_evals"]] == [ + ([32], 32, True), + ] + + +def test_eval_concs_does_not_retarget_a_selected_multinode_eval(changelog_run): + with pytest.raises(ValueError, match="matched no selected evals"): + changelog_run([{"config-keys": ["multi"], "scenario-type": ["fixed-seq-len"], "eval-concs": [16]}]) + + +@pytest.mark.parametrize("concs", [[], [0], [-1], [True], ["32"]]) +def test_eval_concs_rejects_invalid_selections(changelog_run, concs): + with pytest.raises(ValueError, match="eval-concs"): + changelog_run([{"eval-concs": concs}]) + + def test_current_plan_loads_inputs_once_and_uses_no_generator_process(planning_repo, monkeypatch): import builtins from collections import Counter From 25bce60ac571ac6db7df08ca68e5d9d3ea569840 Mon Sep 17 00:00:00 2001 From: seungrokj Date: Fri, 25 Sep 2026 10:41:49 -0700 Subject: [PATCH 4/4] perf(minimaxm3-atom): trim conc points and re-enable evals Drop the highest conc-list entries on TP4/TP2 offload arms and remove the no-evals modifier so the sweep carries model-eval evidence. Co-Authored-By: Claude Opus 4.6 --- configs/amd-master.yaml | 5 ++--- perf-changelog.yaml | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/configs/amd-master.yaml b/configs/amd-master.yaml index 45284ea0c3..d69fd6c453 100644 --- a/configs/amd-master.yaml +++ b/configs/amd-master.yaml @@ -721,10 +721,9 @@ minimaxm3-fp4-mi355x-atom-agentic-mtp: # = TOTAL_CPU_DRAM_GB / TP = node_DRAM * dram-utilization / 8 (TP-independent). - dram-utilization: 0.687 search-space: - - { tp: 4, kv-offloading: none, conc-list: [1, 2, 4, 5, 8, 10, 12, 15, 20, 24, 28, 32], spec-decoding: mtp } + - { tp: 4, kv-offloading: none, conc-list: [1, 2, 4, 5, 8, 10, 12, 15, 20, 24, 28], spec-decoding: mtp } - { tp: 2, kv-offloading: none, conc-list: [1, 2], spec-decoding: mtp } - - { tp: 2, kv-offloading: dram, kv-offload-backend: { name: lmcache, version: "0.5.5rc3+rocm7.2.4" }, conc-list: [20, 25, 30], spec-decoding: mtp } - - { tp: 4, kv-offloading: dram, kv-offload-backend: { name: lmcache, version: "0.5.5rc3+rocm7.2.4" }, conc-list: [40, 48], spec-decoding: mtp } + - { tp: 2, kv-offloading: dram, kv-offload-backend: { name: lmcache, version: "0.5.5rc3+rocm7.2.4" }, conc-list: [20, 25], spec-decoding: mtp } dsr1-fp4-mi355x-sglang-disagg: image: lmsysorg/sglang-rocm:v0.5.17-rocm720-mi35x-20260809 diff --git a/perf-changelog.yaml b/perf-changelog.yaml index eb67973232..066f6d1176 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8907,7 +8907,6 @@ - minimaxm3-fp4-mi355x-atom-agentic-mtp scenario-type: - agentic-coding - no-evals: true description: - "Update MiniMax-M3 ATOM AgentX from rocm/atom-dev:nightly_202609171455 to nightly_202609231248 (digest sha256:80f2c66579704aba933a9ff2a6e22e1dc61917c0fe6a2b0a0166816cd6d0100a), containing ROCm/ATOM#2366. Enable ATOM_PA_FLYDSL=1 and ATOM_PA_FLYDSL_PLAN=1 for FlyDSL paged decode and context-length-aware dense-decode work planning." - "Use only ROCR_VISIBLE_DEVICES for automatically selected NUMA-spread GPUs and remove the inherited ROCR-to-HIP double mask. Preserve explicit ROCR allocations and HIP-only allocations; retain all 19 TP2/TP4 resident/offload points, EAGLE3 K3, golden AL 2.78, indexer CP and CPU memory budgets."