From 0f5faee251bc29f0bf8726c167241d7178e54b6d Mon Sep 17 00:00:00 2001 From: Wenyao Gao Date: Wed, 23 Sep 2026 01:07:46 -0700 Subject: [PATCH 1/5] feat: complete Qwen3.5 B300 PowerX coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补齐 Qwen3.5 B300 的 c1/c2 并要求有效功耗,保留既有覆盖。 --- configs/nvidia-master.yaml | 3 ++- perf-changelog.yaml | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/configs/nvidia-master.yaml b/configs/nvidia-master.yaml index 9988ca1dc3..cc7b447529 100644 --- a/configs/nvidia-master.yaml +++ b/configs/nvidia-master.yaml @@ -1166,8 +1166,9 @@ qwen3.5-fp8-b300-sglang: fixed-seq-len: - isl: 8192 osl: 1024 + require-power: true search-space: - - { tp: 4, ep: 1, conc-start: 4, conc-end: 256 } + - { tp: 4, ep: 1, conc-start: 1, conc-end: 256 } qwen3.5-fp4-b300-sglang: image: lmsysorg/sglang:v0.5.14-cu130 diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 80f83a2bc3..120a788b63 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8710,3 +8710,13 @@ - "删除显式的 direct/page_first_direct HiCache 覆盖,使 TP4/EP4 HiCache arm 运行 SGLang 默认的 kernel/page_first 路径;处于休眠状态的 DP-attention 与 Mooncake 分支同样删除这两个覆盖。该路径在 ROCm 上的正确性来自 sgl-project/sglang#35233——它把 registered host pool 的 device-accessible alias 交给 transfer kernel;上游在同一个 TP4/EP4 MXFP4 MI355X arm 上实测并发 14 时 kernel/page_first 为 338 tok/s,direct/page_first_direct 为 291 tok/s。" - "将 dram-utilization 从 0.80 提升到 0.85,并把 TP4/EP4 arm 的 ratio-1.0 host KV pool(实测约 115.19 GB/rank)改为固定 180 GB/rank;DSA indexer 同比扩展到约 41.25 GB/rank,在 SA 的 1,274 GB 预算内保留约 125 GB 启动余量。该 arm 的并发 sweep 为 4、8、10、12、14、16,TP8/EP1 GPU-resident arm 仅保留 1、2、4。" pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3329 + +- config-keys: + - qwen3.5-fp8-b300-sglang + scenario-type: + - fixed-seq-len + description: + - Preserve Qwen3.5 FP8 b300 coverage and require validated power; include the article + ladder where missing. + - 保留现有覆盖并要求通过验证的功耗,补齐缺失的文章并发梯度。 + pr-link: XXX From 81aeba8a7e52847328f6582656bf34ea441289a0 Mon Sep 17 00:00:00 2001 From: Wenyao Gao Date: Wed, 23 Sep 2026 01:12:54 -0700 Subject: [PATCH 2/5] chore: link Qwen3.5 B300 qualification PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 记录 Qwen3.5 B300 的真实 PR 链接,完成交付溯源。 --- perf-changelog.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 120a788b63..7e56d75c00 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8719,4 +8719,4 @@ - Preserve Qwen3.5 FP8 b300 coverage and require validated power; include the article ladder where missing. - 保留现有覆盖并要求通过验证的功耗,补齐缺失的文章并发梯度。 - pr-link: XXX + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3379 From 390eb5acc40945c62ce41c7124e78f8e12888d86 Mon Sep 17 00:00:00 2001 From: Wenyao Gao Date: Wed, 23 Sep 2026 10:40:35 -0700 Subject: [PATCH 3/5] fix: route Qwen3.5 B300 sweeps through batch allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 Qwen3.5 FP8 STP 接入现有 B300 batch 分配路径,显式校验路由输入并添加行为回归测试;保留服务参数、测量和功耗验证。 --- perf-changelog.yaml | 10 +++ runners/launch_b300-dsxe.sh | 16 +++- utils/test_b300_qwen_batch.py | 140 ++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 utils/test_b300_qwen_batch.py diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 7e56d75c00..a831032c8a 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8720,3 +8720,13 @@ ladder where missing. - 保留现有覆盖并要求通过验证的功耗,补齐缺失的文章并发梯度。 pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3379 + +- config-keys: + - qwen3.5-fp8-b300-sglang + scenario-type: + - fixed-seq-len + description: + - Route Qwen3.5 FP8 STP through the existing B300 batch allocation path, retaining + its serving settings and measurements; the batch container step uses PMIx. + - 将 Qwen3.5 FP8 STP 接入现有 B300 batch 分配路径,保留服务参数和测量设置;batch 容器步骤使用 PMIx。 + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3379 diff --git a/runners/launch_b300-dsxe.sh b/runners/launch_b300-dsxe.sh index a9c21d65f9..adaa44c317 100755 --- a/runners/launch_b300-dsxe.sh +++ b/runners/launch_b300-dsxe.sh @@ -15,10 +15,18 @@ SLURM_ACCOUNT="benchmark" # This lane's interactive allocation notifications fail on login-02, while # batch submission and steps launched from the allocated node work. Keep the -# workaround scoped to this recipe and use normal Slurm resource accounting. -if [[ "$IS_MULTINODE" != true && "${MODEL_PREFIX:-}" == dsv41flash && - "${FRAMEWORK:-}" == sglang && "${IS_AGENTIC:-}" == 1 && +# workaround scoped to the recipes below and use normal Slurm resource accounting. +# Qwen3.5 FP8 fixed-sequence STP reuses the same batch allocation path. +if [[ "$IS_MULTINODE" != true && "${MODEL_PREFIX:-}" == qwen3.5 && + "${FRAMEWORK:-}" == sglang && "$IS_AGENTIC" == 0 && "${B300_AGENTX_BATCH:-}" != 1 ]]; then + check_env_vars PRECISION SPEC_DECODING +fi +if [[ "$IS_MULTINODE" != true && "${FRAMEWORK:-}" == sglang && + "${B300_AGENTX_BATCH:-}" != 1 ]] && + { [[ "${MODEL_PREFIX:-}" == dsv41flash && "$IS_AGENTIC" == 1 ]] || + [[ "${MODEL_PREFIX:-}" == qwen3.5 && "$IS_AGENTIC" == 0 && + "$PRECISION" == fp8 && "$SPEC_DECODING" == none ]]; }; then check_env_vars GITHUB_WORKSPACE GPU_COUNT RUNNER_NAME BATCH_SCRIPT=$(mktemp "${RUNNER_TEMP:-$GITHUB_WORKSPACE}/b300-agentx.XXXXXX.sh") || exit 1 BATCH_LOG="${BATCH_SCRIPT%.sh}.log" @@ -39,7 +47,7 @@ if [[ "$IS_MULTINODE" != true && "${MODEL_PREFIX:-}" == dsv41flash && trap 'rc=$?; scancel "$JOB_ID" 2>/dev/null || true; rm -f "$BATCH_SCRIPT"; exit "$rc"' EXIT trap 'exit 130' INT trap 'exit 143' TERM - echo "B300 AgentX batch job $JOB_ID; log: $BATCH_LOG" + echo "B300 batch job $JOB_ID; log: $BATCH_LOG" stream_slurm_job_log "$JOB_ID" "$BATCH_LOG" || exit 1 verify_slurm_job_status "$JOB_ID" exit $? diff --git a/utils/test_b300_qwen_batch.py b/utils/test_b300_qwen_batch.py new file mode 100644 index 0000000000..0cf3f152f8 --- /dev/null +++ b/utils/test_b300_qwen_batch.py @@ -0,0 +1,140 @@ +"""Exercise B300 batch routing without submitting a Slurm job.""" + +import json +import os +import shutil +import subprocess +import sys +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[1] + + +@pytest.mark.parametrize( + ("overrides", "batch"), + [ + ({}, True), + ({"EVAL_ONLY": "true"}, True), + ({"MODEL_PREFIX": "dsv41flash", "IS_AGENTIC": "1", "SPEC_DECODING": "mtp"}, True), + ({"MODEL_PREFIX": "other"}, False), + ({"PRECISION": "fp4"}, False), + ({"SPEC_DECODING": "mtp"}, False), + ({"IS_AGENTIC": "1"}, False), + ({"IS_MULTINODE": "true"}, False), + ({"FRAMEWORK": "vllm"}, False), + ({"B300_AGENTX_BATCH": "1"}, False), + ({"PRECISION": None}, False), + ({"SPEC_DECODING": None}, False), + ({"PRECISION": ""}, False), + ({"SPEC_DECODING": ""}, False), + ], +) +def test_batch_allocation_routing( + tmp_path: Path, overrides: dict[str, str | None], batch: bool +) -> None: + workspace = tmp_path / "workspace" + for name in ( + "runners/launch_b300-dsxe.sh", + "runners/slurm_utils.sh", + "benchmarks/benchmark_lib.sh", + ): + target = workspace / name + target.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(ROOT / name, target) + commands = tmp_path / "commands" + commands.mkdir() + for name in ( + "sbatch", + "squeue", + "sacct", + "scancel", + "mkdir", + "tail", + "sleep", + "salloc", + "srun", + "enroot", + "unsquashfs", + ): + stub = commands / name + stub.write_text( + f"#!{sys.executable}\n" + "import json, os, sys\nfrom pathlib import Path\n" + "name = Path(sys.argv[0]).name\nargs = sys.argv[1:]\n" + "capture = Path(os.environ['CAPTURE'])\n" + "if name == 'sbatch':\n" + " capture.write_text(json.dumps(args))\n" + " log = next(a.removeprefix('--output=') for a in args if a.startswith('--output='))\n" + " Path(log).write_text('batch log fixture\\n')\n" + " print('12345;fixture')\n" + "elif name == 'sacct': print('COMPLETED|0:0')\n" + "elif name == 'scancel': capture.with_suffix('.cleanup').write_text(json.dumps(args))\n" + "elif name in ('salloc', 'srun', 'enroot', 'unsquashfs'): sys.exit(97)\n" + ) + stub.chmod(0o755) + capture = tmp_path / "submitted.json" + result = subprocess.run( + ["bash", str(workspace / "runners/launch_b300-dsxe.sh")], + cwd=workspace, + env={ + key: value + for key, value in { + "PATH": f"{commands}:/usr/bin:/bin", + "HOME": os.environ["HOME"], + "ENROOT_IMPORT_TIME_LIMIT": "120", + "SALLOC_TIME_LIMIT": "480", + "EVAL_ONLY": "false", + "RUN_EVAL": "false", + "IS_MULTINODE": "false", + "IS_AGENTIC": "0", + "MODEL_PREFIX": "qwen3.5", + "FRAMEWORK": "sglang", + "PRECISION": "fp8", + "SPEC_DECODING": "none", + "B300_AGENTX_BATCH": "0", + "GITHUB_WORKSPACE": str(workspace), + "GPU_COUNT": "4", + "RUNNER_NAME": "fixture_01", + "SALLOC_EXCLUDE": "excluded-node", + "CAPTURE": str(capture), + **overrides, + }.items() + if value is not None + }, + capture_output=True, + text=True, + timeout=8, + check=False, + ) + assert capture.exists() is batch, result.stdout + result.stderr + if batch: + assert result.returncode == 0, result.stderr + args = json.loads(capture.read_text()) + assert { + "--partition=batch_1", + "--account=benchmark", + "--nodes=1", + "--ntasks=1", + "--gres=gpu:4", + "--exclusive", + "--mem=0", + "--time=480", + "--export=ALL", + "--exclude=excluded-node", + f"--chdir={workspace}", + } <= set(args) + assert json.loads(capture.with_suffix(".cleanup").read_text()) == ["12345"] + assert not Path(args[-1]).exists() + else: + assert result.returncode == 1 + missing = [name for name, value in overrides.items() if value is None or value == ""] + if missing: + assert "required environment variables are not set" in result.stdout + assert all(name in result.stdout for name in missing) + else: + assert ( + "B300_HF_CACHE_HOST_DIR" in result.stdout + or "Unsupported framework" in result.stdout + ) From 8afe84dc28f97d7b64f4bf8fcbedfd61afcd6881 Mon Sep 17 00:00:00 2001 From: Wenyao Gao Date: Thu, 24 Sep 2026 02:10:23 -0700 Subject: [PATCH 4/5] chore: capture Qwen B300 c256 eval finish metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 仅为 Qwen B300 c256 eval 启用完整请求日志,记录结束原因和 token 数;保持模型、生成设置和准确率阈值不变。 --- benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh b/benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh index ce0ef07dcd..b67f264d6f 100644 --- a/benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh +++ b/benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh @@ -29,10 +29,15 @@ nvidia-smi SERVER_LOG=/workspace/server.log +REQUEST_LOG_ARGS=() CONTEXT_LENGTH=$((ISL + OSL + 20)) if [ "${EVAL_ONLY}" = "true" ]; then setup_eval_context CONTEXT_LENGTH="$EVAL_MAX_MODEL_LEN" + if [ "$CONC" = "256" ]; then + REQUEST_LOG_ARGS=(--log-requests --log-requests-level 3 --log-requests-format json) + export SGLANG_LOG_REQUEST_EXCEEDED_MS=0 + fi fi start_gpu_monitor @@ -58,7 +63,7 @@ PYTHONNOUSERSITE=1 python3 -m sglang.launch_server --model-path $MODEL_PATH --se --scheduler-recv-interval 10 \ --tokenizer-worker-num 6 \ --tokenizer-path $MODEL_PATH \ ---context-length $CONTEXT_LENGTH > $SERVER_LOG 2>&1 & +--context-length $CONTEXT_LENGTH "${REQUEST_LOG_ARGS[@]}" > $SERVER_LOG 2>&1 & SERVER_PID=$! From 1534ee2688abb1043434cc0199b10fd49c1a6b44 Mon Sep 17 00:00:00 2001 From: Wenyao Gao Date: Thu, 24 Sep 2026 12:17:29 -0700 Subject: [PATCH 5/5] fix: disable JIT DeepGEMM for Qwen B300 accuracy validation --- .../single_node/fixed_seq_len/qwen3.5_fp8_b300.sh | 2 +- perf-changelog.yaml | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh b/benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh index b67f264d6f..ab558167b1 100644 --- a/benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh +++ b/benchmarks/single_node/fixed_seq_len/qwen3.5_fp8_b300.sh @@ -43,7 +43,7 @@ fi start_gpu_monitor set -x -PYTHONNOUSERSITE=1 python3 -m sglang.launch_server --model-path $MODEL_PATH --served-model-name $MODEL --host 0.0.0.0 --port $PORT \ +PYTHONNOUSERSITE=1 SGLANG_ENABLE_JIT_DEEPGEMM=0 python3 -m sglang.launch_server --model-path $MODEL_PATH --served-model-name $MODEL --host 0.0.0.0 --port $PORT \ --trust-remote-code \ --tensor-parallel-size $TP --data-parallel-size 1 --expert-parallel-size $EP_SIZE \ --enable-symm-mem \ diff --git a/perf-changelog.yaml b/perf-changelog.yaml index ba1ff03f4e..feb6596898 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8803,3 +8803,14 @@ its serving settings and measurements; the batch container step uses PMIx. - 将 Qwen3.5 FP8 STP 接入现有 B300 batch 分配路径,保留服务参数和测量设置;batch 容器步骤使用 PMIx。 pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3379 + +- config-keys: + - qwen3.5-fp8-b300-sglang + scenario-type: + - fixed-seq-len + description: + - Disable JIT DeepGEMM for Qwen3.5 FP8 B300 to validate the native Blackwell + scale-format accuracy warning with the existing FlashInfer fallback. + - 在 Qwen3.5 FP8 B300 上关闭 JIT DeepGEMM,以现有 FlashInfer 回退路径验证 Blackwell + scale-format 精度警告;保留模型、评测输入与准确率门槛。 + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3379