[AMD] Add MiniMax-M2.7 accuracy and performance nightly tests (#22722)

Co-authored-by: HaiShaw <hixiao@gmail.com>
This commit is contained in:
Michael
2026-04-14 00:30:11 -07:00
committed by GitHub
co-authored by HaiShaw
parent d7ecab5113
commit eab045b2b7
7 changed files with 805 additions and 113 deletions
+9 -56
View File
@@ -45,7 +45,7 @@ on:
- nightly-8-gpu-qwen35-rocm720 - nightly-8-gpu-qwen35-rocm720
- nightly-8-gpu-glm5-rocm720 - nightly-8-gpu-glm5-rocm720
- nightly-8-gpu-glm51-rocm720 - nightly-8-gpu-glm51-rocm720
- nightly-8-gpu-minimax-m25-rocm720 - nightly-8-gpu-minimax-m27-rocm720
- nightly-1-gpu-zimage-turbo-rocm720 - nightly-1-gpu-zimage-turbo-rocm720
- nightly-test-1-gpu-mi35x-rocm720 - nightly-test-1-gpu-mi35x-rocm720
- nightly-accuracy-8-gpu-mi35x-rocm720 - nightly-accuracy-8-gpu-mi35x-rocm720
@@ -63,7 +63,6 @@ on:
- nightly-8-gpu-mi35x-qwen35-rocm720 - nightly-8-gpu-mi35x-qwen35-rocm720
- nightly-8-gpu-mi35x-glm5-rocm720 - nightly-8-gpu-mi35x-glm5-rocm720
- nightly-8-gpu-mi35x-glm51-rocm720 - nightly-8-gpu-mi35x-glm51-rocm720
- nightly-8-gpu-mi35x-minimax-m25-rocm720
job_filter: job_filter:
description: 'Or type comma-separated job names (overrides dropdown if non-empty)' description: 'Or type comma-separated job names (overrides dropdown if non-empty)'
required: false required: false
@@ -754,9 +753,9 @@ jobs:
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0} exit ${TEST_EXIT_CODE:-0}
# 8-GPU MiniMax-M2.5 (Accuracy + Performance combined) ROCm 7.2 # 8-GPU MiniMax-M2.7 (Accuracy + Performance combined, replaces M2.5) ROCm 7.2
nightly-8-gpu-minimax-m25-rocm720: nightly-8-gpu-minimax-m27-rocm720:
if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-minimax-m25-rocm720,')) if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-minimax-m27-rocm720,'))
runs-on: linux-mi325-8gpu-sglang runs-on: linux-mi325-8gpu-sglang
steps: steps:
- name: Checkout code - name: Checkout code
@@ -774,18 +773,18 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps
- name: Accuracy Test ROCm 7.2 (8-GPU MiniMax-M2.5) - name: Accuracy Test ROCm 7.2 (8-GPU MiniMax-M2.7)
timeout-minutes: 120 timeout-minutes: 120
run: | run: |
> github_summary.md # Clear summary file > github_summary.md # Clear summary file
bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \
-e SGLANG_USE_AITER=1 \ -e SGLANG_USE_AITER=1 \
-e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \
python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-minimax-m25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-minimax-m27 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$?
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0} exit ${TEST_EXIT_CODE:-0}
- name: Performance Test ROCm 7.2 (8-GPU MiniMax-M2.5) - name: Performance Test ROCm 7.2 (8-GPU MiniMax-M2.7)
timeout-minutes: 120 timeout-minutes: 120
continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed
run: | run: |
@@ -793,7 +792,7 @@ jobs:
bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \
-e SGLANG_USE_AITER=1 \ -e SGLANG_USE_AITER=1 \
-e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \
python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-minimax-m25 --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-minimax-m27 --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$?
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0} exit ${TEST_EXIT_CODE:-0}
@@ -1411,51 +1410,6 @@ jobs:
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0} exit ${TEST_EXIT_CODE:-0}
# MI35x 8-GPU MiniMax-M2.5 (Accuracy + Performance combined) ROCm 7.2
nightly-8-gpu-mi35x-minimax-m25-rocm720:
if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-minimax-m25-rocm720,'))
runs-on: linux-mi35x-gpu-8
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup docker (ROCm 7.2)
run: |
touch github_summary.md
bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
- name: Install dependencies
run: |
bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps
bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate
- name: Accuracy Test MI35x ROCm 7.2 (8-GPU MiniMax-M2.5)
timeout-minutes: 120
run: |
> github_summary.md # Clear summary file
bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \
-e SGLANG_USE_AITER=1 \
-e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \
python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-minimax-m25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$?
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0}
- name: Performance Test MI35x ROCm 7.2 (8-GPU MiniMax-M2.5)
timeout-minutes: 120
continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed
run: |
> github_summary.md # Clear summary file
bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \
-e SGLANG_USE_AITER=1 \
-e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \
python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-minimax-m25 --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$?
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0}
# MI35x 8-GPU DeepSeek-V3.2 Performance Test (MTP) ROCm 7.2 # MI35x 8-GPU DeepSeek-V3.2 Performance Test (MTP) ROCm 7.2
nightly-perf-8-gpu-mi35x-deepseek-v32-mtp-rocm720: nightly-perf-8-gpu-mi35x-deepseek-v32-mtp-rocm720:
if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-8-gpu-mi35x-deepseek-v32-mtp-rocm720,')) if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-8-gpu-mi35x-deepseek-v32-mtp-rocm720,'))
@@ -1515,7 +1469,7 @@ jobs:
- nightly-8-gpu-qwen35-rocm720 - nightly-8-gpu-qwen35-rocm720
- nightly-8-gpu-glm5-rocm720 - nightly-8-gpu-glm5-rocm720
- nightly-8-gpu-glm51-rocm720 - nightly-8-gpu-glm51-rocm720
- nightly-8-gpu-minimax-m25-rocm720 - nightly-8-gpu-minimax-m27-rocm720
# MI30x ROCm 7.2 Diffusion Tests # MI30x ROCm 7.2 Diffusion Tests
- nightly-1-gpu-zimage-turbo-rocm720 - nightly-1-gpu-zimage-turbo-rocm720
# MI35x ROCm 7.2 jobs # MI35x ROCm 7.2 jobs
@@ -1535,7 +1489,6 @@ jobs:
- nightly-8-gpu-mi35x-qwen35-rocm720 - nightly-8-gpu-mi35x-qwen35-rocm720
- nightly-8-gpu-mi35x-glm5-rocm720 - nightly-8-gpu-mi35x-glm5-rocm720
- nightly-8-gpu-mi35x-glm51-rocm720 - nightly-8-gpu-mi35x-glm51-rocm720
- nightly-8-gpu-mi35x-minimax-m25-rocm720
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check if any job failed - name: Check if any job failed
+9 -56
View File
@@ -46,7 +46,7 @@ on:
- nightly-8-gpu-glm5 - nightly-8-gpu-glm5
- nightly-8-gpu-glm51 - nightly-8-gpu-glm51
- nightly-8-gpu-glm51-mxfp4 - nightly-8-gpu-glm51-mxfp4
- nightly-8-gpu-minimax-m25 - nightly-8-gpu-minimax-m27
- nightly-1-gpu-zimage-turbo - nightly-1-gpu-zimage-turbo
- nightly-test-1-gpu-mi35x - nightly-test-1-gpu-mi35x
- nightly-accuracy-8-gpu-mi35x - nightly-accuracy-8-gpu-mi35x
@@ -65,7 +65,6 @@ on:
- nightly-8-gpu-mi35x-glm5 - nightly-8-gpu-mi35x-glm5
- nightly-8-gpu-mi35x-glm51 - nightly-8-gpu-mi35x-glm51
- nightly-8-gpu-mi35x-glm51-mxfp4 - nightly-8-gpu-mi35x-glm51-mxfp4
- nightly-8-gpu-mi35x-minimax-m25
job_filter: job_filter:
description: 'Or type comma-separated job names (overrides dropdown if non-empty)' description: 'Or type comma-separated job names (overrides dropdown if non-empty)'
required: false required: false
@@ -760,9 +759,9 @@ jobs:
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0} exit ${TEST_EXIT_CODE:-0}
# 8-GPU MiniMax-M2.5 (Accuracy + Performance combined) # 8-GPU MiniMax-M2.7 (Accuracy + Performance combined, replaces M2.5)
nightly-8-gpu-minimax-m25: nightly-8-gpu-minimax-m27:
if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-minimax-m25,')) if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-minimax-m27,'))
runs-on: linux-mi325-8gpu-sglang runs-on: linux-mi325-8gpu-sglang
steps: steps:
- name: Checkout code - name: Checkout code
@@ -780,18 +779,18 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: bash scripts/ci/amd/amd_ci_install_dependency.sh run: bash scripts/ci/amd/amd_ci_install_dependency.sh
- name: Accuracy Test (8-GPU MiniMax-M2.5) - name: Accuracy Test (8-GPU MiniMax-M2.7)
timeout-minutes: 120 timeout-minutes: 120
run: | run: |
> github_summary.md # Clear summary file > github_summary.md # Clear summary file
bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \
-e SGLANG_USE_AITER=1 \ -e SGLANG_USE_AITER=1 \
-e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \
python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-minimax-m25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-minimax-m27 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$?
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0} exit ${TEST_EXIT_CODE:-0}
- name: Performance Test (8-GPU MiniMax-M2.5) - name: Performance Test (8-GPU MiniMax-M2.7)
timeout-minutes: 120 timeout-minutes: 120
continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed
run: | run: |
@@ -799,7 +798,7 @@ jobs:
bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \
-e SGLANG_USE_AITER=1 \ -e SGLANG_USE_AITER=1 \
-e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \
python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-minimax-m25 --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-minimax-m27 --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$?
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0} exit ${TEST_EXIT_CODE:-0}
@@ -1420,51 +1419,6 @@ jobs:
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0} exit ${TEST_EXIT_CODE:-0}
# MI35x 8-GPU MiniMax-M2.5 (Accuracy + Performance combined)
nightly-8-gpu-mi35x-minimax-m25:
if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-minimax-m25,'))
runs-on: linux-mi35x-gpu-8
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup docker
run: |
touch github_summary.md
bash scripts/ci/amd/amd_ci_start_container.sh
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
- name: Install dependencies
run: |
bash scripts/ci/amd/amd_ci_install_dependency.sh
bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate
- name: Accuracy Test MI35x (8-GPU MiniMax-M2.5)
timeout-minutes: 120
run: |
> github_summary.md # Clear summary file
bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \
-e SGLANG_USE_AITER=1 \
-e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \
python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-minimax-m25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$?
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0}
- name: Performance Test MI35x (8-GPU MiniMax-M2.5)
timeout-minutes: 120
continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed
run: |
> github_summary.md # Clear summary file
bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \
-e SGLANG_USE_AITER=1 \
-e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \
python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-minimax-m25 --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$?
echo "$(<github_summary.md )" >> $GITHUB_STEP_SUMMARY || true
exit ${TEST_EXIT_CODE:-0}
# MI35x 8-GPU DeepSeek-V3.2 Performance Test (MTP) # MI35x 8-GPU DeepSeek-V3.2 Performance Test (MTP)
nightly-perf-8-gpu-mi35x-deepseek-v32-mtp: nightly-perf-8-gpu-mi35x-deepseek-v32-mtp:
if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-8-gpu-mi35x-deepseek-v32-mtp,')) if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-8-gpu-mi35x-deepseek-v32-mtp,'))
@@ -1524,7 +1478,7 @@ jobs:
- nightly-8-gpu-qwen35 - nightly-8-gpu-qwen35
- nightly-8-gpu-glm5 - nightly-8-gpu-glm5
- nightly-8-gpu-glm51 - nightly-8-gpu-glm51
- nightly-8-gpu-minimax-m25 - nightly-8-gpu-minimax-m27
# MI30x Diffusion Tests # MI30x Diffusion Tests
- nightly-1-gpu-zimage-turbo - nightly-1-gpu-zimage-turbo
# MI35x jobs # MI35x jobs
@@ -1542,7 +1496,6 @@ jobs:
- nightly-8-gpu-mi35x-qwen35 - nightly-8-gpu-mi35x-qwen35
- nightly-8-gpu-mi35x-glm5 - nightly-8-gpu-mi35x-glm5
- nightly-8-gpu-mi35x-glm51 - nightly-8-gpu-mi35x-glm51
- nightly-8-gpu-mi35x-minimax-m25
# MI35x perf jobs excluded from check - perf failures don't block CI # MI35x perf jobs excluded from check - perf failures don't block CI
# - nightly-perf-8-gpu-mi35x-deepseek-v32-basic # - nightly-perf-8-gpu-mi35x-deepseek-v32-basic
# - nightly-perf-8-gpu-mi35x-deepseek-v32-mtp # - nightly-perf-8-gpu-mi35x-deepseek-v32-mtp
+7 -1
View File
@@ -33,7 +33,6 @@ from sglang.jit_kernel.all_reduce import (
from sglang.kernel_api_logging import debug_kernel_api from sglang.kernel_api_logging import debug_kernel_api
from sglang.srt.batch_overlap.two_batch_overlap import model_forward_maybe_tbo from sglang.srt.batch_overlap.two_batch_overlap import model_forward_maybe_tbo
from sglang.srt.distributed import ( from sglang.srt.distributed import (
get_bool_env_var,
get_moe_expert_parallel_world_size, get_moe_expert_parallel_world_size,
get_pp_group, get_pp_group,
get_tensor_model_parallel_world_size, get_tensor_model_parallel_world_size,
@@ -81,9 +80,16 @@ from sglang.srt.model_loader.weight_utils import (
maybe_remap_kv_scale_name, maybe_remap_kv_scale_name,
) )
from sglang.srt.server_args import get_global_server_args from sglang.srt.server_args import get_global_server_args
# get_bool_env_var is defined in sglang.srt.utils.common, not sglang.srt.distributed.
# Importing from the wrong module causes this file to fail import, which prevents the
# native MiniMaxM2ForCausalLM from registering in ModelRegistry. The fallback to the
# transformers wrapper then crashes on config.rope_parameters (transformers v5 issue).
# Other files (custom_all_reduce.py, hf_transformers_utils.py) also use sglang.srt.utils.
from sglang.srt.utils import ( from sglang.srt.utils import (
BumpAllocator, BumpAllocator,
add_prefix, add_prefix,
get_bool_env_var,
get_compiler_backend, get_compiler_backend,
is_cuda, is_cuda,
is_non_idle_and_non_empty, is_non_idle_and_non_empty,
@@ -0,0 +1,245 @@
"""AMD MiniMax-M2.7 GSM8K Completion Evaluation Test (8-GPU)
Tests MiniMax-M2.7 with TP=8 + EP=8 configuration using few-shot completion
benchmark on MI325/MI300X.
Registry: nightly-amd-accuracy-8-gpu-minimax-m27 suite
"""
import ast
import os
import re
import time
import unittest
from dataclasses import dataclass
from typing import List, Optional, Tuple
import numpy as np
from sglang.srt.utils import kill_process_tree
from sglang.test.ci.ci_register import register_amd_ci
from sglang.test.test_utils import (
DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
DEFAULT_URL_FOR_TEST,
is_in_ci,
popen_launch_server,
write_github_step_summary,
)
from sglang.utils import download_and_cache_file, read_jsonl
register_amd_ci(
est_time=3600,
suite="nightly-amd-accuracy-8-gpu-minimax-m27",
nightly=True,
)
INVALID = -9999999
@dataclass
class ModelConfig:
"""Configuration for a model to test."""
model_path: str
tp_size: int = 8
accuracy_threshold: float = 0.50
other_args: Optional[List[str]] = None
env_vars: Optional[dict] = None
timeout: Optional[int] = None
variant: Optional[str] = None
def __post_init__(self):
if self.other_args is None:
self.other_args = []
if self.env_vars is None:
self.env_vars = {}
def get_display_name(self) -> str:
if self.variant:
return f"{self.model_path} ({self.variant})"
return self.model_path
MINIMAX_M27_MODELS = [
ModelConfig(
model_path="MiniMaxAI/MiniMax-M2.7",
tp_size=8,
accuracy_threshold=0.93,
timeout=3600,
variant="TP8+EP8",
other_args=[
"--ep-size",
"8",
"--trust-remote-code",
"--attention-backend",
"aiter",
"--mem-fraction-static",
"0.85",
"--model-loader-extra-config",
'{"enable_multithread_load": true}',
"--watchdog-timeout",
"1200",
],
env_vars={"SGLANG_USE_AITER": "1"},
),
]
def get_one_example(lines, i, include_answer):
"""Format a single GSM8K example."""
ret = "Question: " + lines[i]["question"] + "\nAnswer:"
if include_answer:
ret += " " + lines[i]["answer"]
return ret
def get_few_shot_examples(lines, k):
"""Get k few-shot examples for prompting."""
ret = ""
for i in range(k):
ret += get_one_example(lines, i, True) + "\n\n"
return ret
def get_answer_value(answer_str):
"""Extract numerical answer from response."""
answer_str = answer_str.replace(",", "")
numbers = re.findall(r"\d+", answer_str)
if len(numbers) < 1:
return INVALID
try:
return ast.literal_eval(numbers[-1])
except SyntaxError:
return INVALID
def run_gsm8k_benchmark(
base_url: str,
num_questions: int = 200,
num_shots: int = 5,
parallel: int = 64,
) -> Tuple[float, float, float]:
"""Run GSM8K few-shot completion benchmark."""
import sglang as sgl
from sglang.lang.backend.runtime_endpoint import RuntimeEndpoint
url = "https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl"
data_path = download_and_cache_file(url)
lines = list(read_jsonl(data_path))
few_shot_examples = get_few_shot_examples(lines, num_shots)
questions = []
labels = []
for i in range(len(lines[:num_questions])):
questions.append(get_one_example(lines, i, False))
labels.append(get_answer_value(lines[i]["answer"]))
assert all(l != INVALID for l in labels)
arguments = [{"question": q} for q in questions]
@sgl.function
def few_shot_gsm8k(s, question):
s += few_shot_examples + question
s += sgl.gen(
"answer", max_tokens=512, stop=["Question", "Assistant:", "<|separator|>"]
)
backend = RuntimeEndpoint(base_url)
sgl.set_default_backend(backend)
tic = time.perf_counter()
states = few_shot_gsm8k.run_batch(
arguments, temperature=0, num_threads=parallel, progress_bar=True
)
latency = time.perf_counter() - tic
preds = [get_answer_value(states[i]["answer"]) for i in range(len(states))]
acc = np.mean(np.array(preds) == np.array(labels))
invalid = np.mean(np.array(preds) == INVALID)
return float(acc), float(invalid), float(latency)
class TestMiniMaxM27EvalAMD(unittest.TestCase):
"""MiniMax-M2.7 GSM8K Completion Evaluation Test for AMD MI325/MI300X."""
@classmethod
def setUpClass(cls):
cls.models = MINIMAX_M27_MODELS
cls.base_url = DEFAULT_URL_FOR_TEST
cls.num_questions = int(os.environ.get("GSM8K_NUM_QUESTIONS", "200"))
def test_minimax_m27_accuracy(self):
"""Test MiniMax-M2.7 with GSM8K completion benchmark."""
all_results = []
summary = "### MiniMax-M2.7 Models (MI325)\n\n"
summary += "| Model | Variant | TP | Accuracy | Threshold | Status |\n"
summary += "| ----- | ------- | -- | -------- | --------- | ------ |\n"
for config in self.models:
display_name = config.get_display_name()
with self.subTest(model=display_name):
print(f"\n{'='*60}")
print(f"Testing: {display_name}")
print(f"{'='*60}")
env = os.environ.copy()
for key, value in config.env_vars.items():
env[key] = value
other_args = list(config.other_args)
other_args.extend(["--tp", str(config.tp_size)])
timeout = config.timeout or DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH
try:
process = popen_launch_server(
model=config.model_path,
base_url=self.base_url,
timeout=timeout,
other_args=other_args,
env=env,
)
try:
acc, invalid, latency = run_gsm8k_benchmark(
self.base_url, num_questions=self.num_questions
)
passed = acc >= config.accuracy_threshold
status = "PASS" if passed else "FAIL"
print(
f" accuracy={acc:.3f} threshold={config.accuracy_threshold} {status}"
)
all_results.append(
{
"model": display_name,
"accuracy": acc,
"passed": passed,
}
)
summary += f"| {config.model_path} | {config.variant or 'N/A'} | {config.tp_size} | {acc:.3f} | {config.accuracy_threshold} | {status} |\n"
finally:
kill_process_tree(process.pid)
except Exception as e:
summary += f"| {config.model_path} | {config.variant or 'N/A'} | {config.tp_size} | N/A | {config.accuracy_threshold} | ERROR |\n"
all_results.append(
{
"model": display_name,
"accuracy": None,
"passed": False,
"error": str(e),
}
)
if is_in_ci():
write_github_step_summary(summary)
failed = [r for r in all_results if not r["passed"]]
if failed:
raise AssertionError(f"Failed models: {[r['model'] for r in failed]}")
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,249 @@
"""MI35x MiniMax-M2.7 GSM8K Completion Evaluation Test (8-GPU)
Tests MiniMax-M2.7 with TP=8 + EP=8 configuration using few-shot completion
benchmark on MI35x.
Registry: nightly-amd-8-gpu-mi35x-minimax-m27 suite
"""
import ast
import os
os.environ.setdefault("HF_HOME", "/data2/models/huggingface")
os.environ.setdefault("HF_HUB_CACHE", "/data2/models/huggingface/hub")
import re
import time
import unittest
from dataclasses import dataclass
from typing import List, Optional, Tuple
import numpy as np
from sglang.srt.utils import kill_process_tree
from sglang.test.ci.ci_register import register_amd_ci
from sglang.test.test_utils import (
DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
DEFAULT_URL_FOR_TEST,
is_in_ci,
popen_launch_server,
write_github_step_summary,
)
from sglang.utils import download_and_cache_file, read_jsonl
register_amd_ci(
est_time=5400,
suite="nightly-amd-8-gpu-mi35x-minimax-m27",
nightly=True,
)
INVALID = -9999999
@dataclass
class ModelConfig:
"""Configuration for a model to test."""
model_path: str
tp_size: int = 8
accuracy_threshold: float = 0.50
other_args: Optional[List[str]] = None
env_vars: Optional[dict] = None
timeout: Optional[int] = None
variant: Optional[str] = None
def __post_init__(self):
if self.other_args is None:
self.other_args = []
if self.env_vars is None:
self.env_vars = {}
def get_display_name(self) -> str:
if self.variant:
return f"{self.model_path} ({self.variant})"
return self.model_path
MI35X_MINIMAX_M27_MODELS = [
ModelConfig(
model_path="MiniMaxAI/MiniMax-M2.7",
tp_size=8,
accuracy_threshold=0.93,
timeout=5400,
variant="TP8+EP8",
other_args=[
"--ep-size",
"8",
"--trust-remote-code",
"--attention-backend",
"aiter",
"--mem-fraction-static",
"0.85",
"--model-loader-extra-config",
'{"enable_multithread_load": true}',
"--watchdog-timeout",
"1200",
],
env_vars={"SGLANG_USE_AITER": "1"},
),
]
def get_one_example(lines, i, include_answer):
"""Format a single GSM8K example."""
ret = "Question: " + lines[i]["question"] + "\nAnswer:"
if include_answer:
ret += " " + lines[i]["answer"]
return ret
def get_few_shot_examples(lines, k):
"""Get k few-shot examples for prompting."""
ret = ""
for i in range(k):
ret += get_one_example(lines, i, True) + "\n\n"
return ret
def get_answer_value(answer_str):
"""Extract numerical answer from response."""
answer_str = answer_str.replace(",", "")
numbers = re.findall(r"\d+", answer_str)
if len(numbers) < 1:
return INVALID
try:
return ast.literal_eval(numbers[-1])
except SyntaxError:
return INVALID
def run_gsm8k_benchmark(
base_url: str,
num_questions: int = 200,
num_shots: int = 5,
parallel: int = 64,
) -> Tuple[float, float, float]:
"""Run GSM8K few-shot completion benchmark."""
import sglang as sgl
from sglang.lang.backend.runtime_endpoint import RuntimeEndpoint
url = "https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl"
data_path = download_and_cache_file(url)
lines = list(read_jsonl(data_path))
few_shot_examples = get_few_shot_examples(lines, num_shots)
questions = []
labels = []
for i in range(len(lines[:num_questions])):
questions.append(get_one_example(lines, i, False))
labels.append(get_answer_value(lines[i]["answer"]))
assert all(l != INVALID for l in labels)
arguments = [{"question": q} for q in questions]
@sgl.function
def few_shot_gsm8k(s, question):
s += few_shot_examples + question
s += sgl.gen(
"answer", max_tokens=512, stop=["Question", "Assistant:", "<|separator|>"]
)
backend = RuntimeEndpoint(base_url)
sgl.set_default_backend(backend)
tic = time.perf_counter()
states = few_shot_gsm8k.run_batch(
arguments, temperature=0, num_threads=parallel, progress_bar=True
)
latency = time.perf_counter() - tic
preds = [get_answer_value(states[i]["answer"]) for i in range(len(states))]
acc = np.mean(np.array(preds) == np.array(labels))
invalid = np.mean(np.array(preds) == INVALID)
return float(acc), float(invalid), float(latency)
class TestMiniMaxM27EvalMI35x(unittest.TestCase):
"""MiniMax-M2.7 GSM8K Completion Evaluation Test for AMD MI35x."""
@classmethod
def setUpClass(cls):
cls.models = MI35X_MINIMAX_M27_MODELS
cls.base_url = DEFAULT_URL_FOR_TEST
cls.num_questions = int(os.environ.get("GSM8K_NUM_QUESTIONS", "200"))
def test_minimax_m27_accuracy(self):
"""Test MiniMax-M2.7 with GSM8K completion benchmark."""
all_results = []
summary = "### MiniMax-M2.7 Models (MI35x)\n\n"
summary += "| Model | Variant | TP | Accuracy | Threshold | Status |\n"
summary += "| ----- | ------- | -- | -------- | --------- | ------ |\n"
for config in self.models:
display_name = config.get_display_name()
with self.subTest(model=display_name):
print(f"\n{'='*60}")
print(f"Testing: {display_name}")
print(f"{'='*60}")
env = os.environ.copy()
for key, value in config.env_vars.items():
env[key] = value
other_args = list(config.other_args)
other_args.extend(["--tp", str(config.tp_size)])
timeout = config.timeout or DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH
try:
process = popen_launch_server(
model=config.model_path,
base_url=self.base_url,
timeout=timeout,
other_args=other_args,
env=env,
)
try:
acc, invalid, latency = run_gsm8k_benchmark(
self.base_url, num_questions=self.num_questions
)
passed = acc >= config.accuracy_threshold
status = "PASS" if passed else "FAIL"
print(
f" accuracy={acc:.3f} threshold={config.accuracy_threshold} {status}"
)
all_results.append(
{
"model": display_name,
"accuracy": acc,
"passed": passed,
}
)
summary += f"| {config.model_path} | {config.variant or 'N/A'} | {config.tp_size} | {acc:.3f} | {config.accuracy_threshold} | {status} |\n"
finally:
kill_process_tree(process.pid)
except Exception as e:
summary += f"| {config.model_path} | {config.variant or 'N/A'} | {config.tp_size} | N/A | {config.accuracy_threshold} | ERROR |\n"
all_results.append(
{
"model": display_name,
"accuracy": None,
"passed": False,
"error": str(e),
}
)
if is_in_ci():
write_github_step_summary(summary)
failed = [r for r in all_results if not r["passed"]]
if failed:
raise AssertionError(f"Failed models: {[r['model'] for r in failed]}")
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,140 @@
"""Nightly performance benchmark for MiniMax-M2.7 on MI325/MI300X (8-GPU).
This test benchmarks MiniMax-M2.7 with TP=8 + EP=8 configuration.
The model path can be configured via MINIMAX_M27_MODEL_PATH environment variable.
Registry: nightly-perf-8-gpu-minimax-m27 suite
Example usage:
python -m pytest test_minimax_m27_perf_amd.py -v
"""
import os
import unittest
from typing import List
from sglang.test.ci.ci_register import register_amd_ci
from sglang.test.nightly_bench_utils import BenchmarkResult
from sglang.test.nightly_utils import NightlyBenchmarkRunner
from sglang.test.test_utils import DEFAULT_URL_FOR_TEST, _parse_int_list_env
register_amd_ci(est_time=5400, suite="nightly-perf-8-gpu-minimax-m27", nightly=True)
def generate_simple_markdown_report(results: List[BenchmarkResult]) -> str:
"""Generate a simplified markdown report without traces and cost columns.
Skips the first result if it's a warmup run (duplicate batch_size).
"""
model_header = results[0].model_path
if results[0].run_name and results[0].run_name != "default":
model_header += f" ({results[0].run_name})"
gpu_config = os.getenv("GPU_CONFIG", "MI325")
if gpu_config:
model_header += f" [{gpu_config}]"
summary = f"### {model_header}\n"
summary += "| batch size | input len | latency (s) | input throughput (tok/s) | output throughput (tok/s) | ITL (ms) |\n"
summary += "| ---------- | --------- | ----------- | ------------------------ | ------------------------- | -------- |\n"
report_results = (
results[1:]
if len(results) > 1 and results[0].batch_size == results[1].batch_size
else results
)
for result in report_results:
itl = 1 / (result.output_throughput / result.batch_size) * 1000
summary += f"| {result.batch_size} | {result.input_len} | {result.latency:.2f} | {result.input_throughput:.2f} | {result.output_throughput:.2f} | {itl:.2f} |\n"
return summary
MINIMAX_M27_MODEL_PATH = os.environ.get(
"MINIMAX_M27_MODEL_PATH", "MiniMaxAI/MiniMax-M2.7"
)
PROFILE_DIR = "performance_profiles_minimax_m27"
class TestNightlyMiniMaxM27Performance(unittest.TestCase):
"""Nightly performance benchmark for MiniMax-M2.7 on MI325/MI300X.
Tests MiniMax-M2.7 with TP=8 + EP=8 configuration.
"""
@classmethod
def setUpClass(cls):
cls.base_url = DEFAULT_URL_FOR_TEST
cls.batch_sizes = [1, 8, 16, 64]
cls.input_lens = tuple(_parse_int_list_env("NIGHTLY_INPUT_LENS", "4096"))
cls.output_lens = tuple(_parse_int_list_env("NIGHTLY_OUTPUT_LENS", "512"))
cls.model_config = {
"name": "minimax-m27-tp8-ep8",
"model_path": MINIMAX_M27_MODEL_PATH,
"other_args": [
"--trust-remote-code",
"--tp",
"8",
"--ep-size",
"8",
"--attention-backend",
"aiter",
"--mem-fraction-static",
"0.85",
"--model-loader-extra-config",
'{"enable_multithread_load": true}',
"--watchdog-timeout",
"1200",
],
"env_vars": {
"SGLANG_USE_AITER": "1",
},
}
cls.runner = NightlyBenchmarkRunner(PROFILE_DIR, cls.__name__, cls.base_url)
cls.runner.setup_profile_directory()
cls.runner.full_report = f"## {cls.__name__}\n"
def test_bench_minimax_m27(self):
"""Run benchmark for MiniMax-M2.7."""
old_env = {}
for key, value in self.model_config.get("env_vars", {}).items():
old_env[key] = os.environ.get(key)
os.environ[key] = value
print(f"Setting env: {key}={value}")
try:
result_tuple = self.runner.run_benchmark_for_model(
model_path=self.model_config["model_path"],
batch_sizes=self.batch_sizes,
input_lens=self.input_lens,
output_lens=self.output_lens,
other_args=self.model_config["other_args"],
variant=self.model_config["name"],
extra_bench_args=["--trust-remote-code"],
enable_profile=False,
timeout=5400,
)
results = result_tuple[0]
success = result_tuple[1]
if results:
self.runner.full_report += (
generate_simple_markdown_report(results) + "\n"
)
self.assertTrue(success, "Benchmark failed for MiniMax-M2.7")
finally:
for key, value in old_env.items():
if value is None:
os.environ.pop(key, None)
else:
os.environ[key] = value
self.runner.write_final_report()
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,146 @@
"""MI35x Nightly performance benchmark for MiniMax-M2.7 (8-GPU).
This test benchmarks MiniMax-M2.7 with TP=8 + EP=8 configuration on MI35x.
The model path can be configured via MINIMAX_M27_MODEL_PATH environment variable.
Registry: nightly-perf-8-gpu-mi35x-minimax-m27 suite
Example usage:
python -m pytest test_minimax_m27_perf_mi35x.py -v
"""
import os
os.environ.setdefault("HF_HOME", "/data2/models/huggingface")
os.environ.setdefault("HF_HUB_CACHE", "/data2/models/huggingface/hub")
import unittest
from typing import List
from sglang.test.ci.ci_register import register_amd_ci
from sglang.test.nightly_bench_utils import BenchmarkResult
from sglang.test.nightly_utils import NightlyBenchmarkRunner
from sglang.test.test_utils import DEFAULT_URL_FOR_TEST, _parse_int_list_env
register_amd_ci(
est_time=5400, suite="nightly-perf-8-gpu-mi35x-minimax-m27", nightly=True
)
def generate_simple_markdown_report(results: List[BenchmarkResult]) -> str:
"""Generate a simplified markdown report without traces and cost columns.
Skips the first result if it's a warmup run (duplicate batch_size).
"""
model_header = results[0].model_path
if results[0].run_name and results[0].run_name != "default":
model_header += f" ({results[0].run_name})"
gpu_config = os.getenv("GPU_CONFIG", "MI35x")
if gpu_config:
model_header += f" [{gpu_config}]"
summary = f"### {model_header}\n"
summary += "| batch size | input len | latency (s) | input throughput (tok/s) | output throughput (tok/s) | ITL (ms) |\n"
summary += "| ---------- | --------- | ----------- | ------------------------ | ------------------------- | -------- |\n"
report_results = (
results[1:]
if len(results) > 1 and results[0].batch_size == results[1].batch_size
else results
)
for result in report_results:
itl = 1 / (result.output_throughput / result.batch_size) * 1000
summary += f"| {result.batch_size} | {result.input_len} | {result.latency:.2f} | {result.input_throughput:.2f} | {result.output_throughput:.2f} | {itl:.2f} |\n"
return summary
MINIMAX_M27_MODEL_PATH = os.environ.get(
"MINIMAX_M27_MODEL_PATH", "MiniMaxAI/MiniMax-M2.7"
)
PROFILE_DIR = "performance_profiles_minimax_m27_mi35x"
class TestNightlyMiniMaxM27PerformanceMI35x(unittest.TestCase):
"""MI35x Nightly performance benchmark for MiniMax-M2.7.
Tests MiniMax-M2.7 with TP=8 + EP=8 configuration.
"""
@classmethod
def setUpClass(cls):
cls.base_url = DEFAULT_URL_FOR_TEST
cls.batch_sizes = [1, 8, 16, 64]
cls.input_lens = tuple(_parse_int_list_env("NIGHTLY_INPUT_LENS", "4096"))
cls.output_lens = tuple(_parse_int_list_env("NIGHTLY_OUTPUT_LENS", "512"))
cls.model_config = {
"name": "minimax-m27-tp8-ep8",
"model_path": MINIMAX_M27_MODEL_PATH,
"other_args": [
"--trust-remote-code",
"--tp",
"8",
"--ep-size",
"8",
"--attention-backend",
"aiter",
"--mem-fraction-static",
"0.85",
"--model-loader-extra-config",
'{"enable_multithread_load": true}',
"--watchdog-timeout",
"1200",
],
"env_vars": {
"SGLANG_USE_AITER": "1",
},
}
cls.runner = NightlyBenchmarkRunner(PROFILE_DIR, cls.__name__, cls.base_url)
cls.runner.setup_profile_directory()
cls.runner.full_report = f"## {cls.__name__}\n"
def test_bench_minimax_m27(self):
"""Run benchmark for MiniMax-M2.7."""
old_env = {}
for key, value in self.model_config.get("env_vars", {}).items():
old_env[key] = os.environ.get(key)
os.environ[key] = value
print(f"Setting env: {key}={value}")
try:
result_tuple = self.runner.run_benchmark_for_model(
model_path=self.model_config["model_path"],
batch_sizes=self.batch_sizes,
input_lens=self.input_lens,
output_lens=self.output_lens,
other_args=self.model_config["other_args"],
variant=self.model_config["name"],
extra_bench_args=["--trust-remote-code"],
enable_profile=False,
timeout=5400,
)
results = result_tuple[0]
success = result_tuple[1]
if results:
self.runner.full_report += (
generate_simple_markdown_report(results) + "\n"
)
self.assertTrue(success, "Benchmark failed for MiniMax-M2.7 on MI35x")
finally:
for key, value in old_env.items():
if value is None:
os.environ.pop(key, None)
else:
os.environ[key] = value
self.runner.write_final_report()
if __name__ == "__main__":
unittest.main()