Skip to content

Refresh DeepSeek-V4 B200 SGLang AgentX MTP - #2578

Open
cquil11 wants to merge 4 commits into
mainfrom
agent/refresh-dsv4-b200-sglang-agentx
Open

Refresh DeepSeek-V4 B200 SGLang AgentX MTP#2578
cquil11 wants to merge 4 commits into
mainfrom
agent/refresh-dsv4-b200-sglang-agentx

Conversation

@cquil11

@cquil11 cquil11 commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Restore the purged B200 DeepSeek-V4-Pro SGLang AgentX resident, DP-attention, and HiCache grid.
  • Use stable SGLang v0.5.17 with native EAGLE MTP (3 steps, top-k 1, 4 draft tokens).
  • Pin throughput to the committed golden synthetic acceptance length 2.49 while keeping real MTP verification for eval.
  • Follow the official SGLang DeepSeek-V4 Blackwell recipe and require nonempty sglang: server metrics.

This supersedes the B200 portion of #2145.

Production data audit

The current production database has no aggregate B200 DeepSeek-V4 SGLang AgentX MTP results, so this refresh does not duplicate an up-to-date submission.

Validation

  • bash syntax
  • perf changelog validation and generation
  • 231 matrix tests
  • 28 MTP throughput points plus one real-verification evaluation point generated

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the contribution! Please reach out to respective companies' CODEOWNER to fill in the latest PR_REVIEW_CHECKLIST.md before pinging core maintainer on Slack for review. In order for the signoff PR check bot to trigger, you must follow the PR_REVIEW_CHECKLIST.md template correctly, including the phrase As a PR reviewer and CODEOWNER, I have reviewed this and have.

For PR verification, add the full-sweep-fail-fast label (strongly recommended) to this PR — the benchmark sweep only runs on labeled PRs. Use full-sweep-enabled only if you need matrix jobs to keep running past a failure.

PR authors are responsible for ensuring that after merging, all GitHub Action jobs fully pass. A lot of the time, failures are just flakes and simply re-running the failed jobs will fix it. See GitHub's docs on re-running failed jobs


感谢你的贡献!请联系相应公司的 CODEOWNER 填写最新的 PR_REVIEW_CHECKLIST.md,然后再在 Slack 上联系核心维护者进行审阅。为了触发 signoff PR 检查机器人,你必须正确遵循 PR_REVIEW_CHECKLIST.md 模板,包括保留英文语句 As a PR reviewer and CODEOWNER, I have reviewed this and have

如需进行 PR 验证,请为此 PR 添加 full-sweep-fail-fast 标签(强烈推荐)— 基准测试 sweep 仅在带有标签的 PR 上运行。仅当需要矩阵任务在失败后继续运行时才使用 full-sweep-enabled

PR 作者有责任确保合并后所有 GitHub Action 任务完全通过。 很多时候失败只是偶发抖动(flake),重新运行失败的任务即可解决。参见 GitHub 关于重新运行失败任务的文档

@cquil11
cquil11 force-pushed the agent/refresh-dsv4-b200-sglang-agentx branch from 7c7a5b4 to 721ec8d Compare August 12, 2026 17:12
@cquil11 cquil11 changed the title Refresh DeepSeek-V4 B200 SGLang AgentX Refresh DeepSeek-V4 B200 SGLang AgentX MTP Aug 12, 2026
@cquil11
cquil11 marked this pull request as ready for review August 12, 2026 17:12
@cquil11
cquil11 requested a review from a team August 12, 2026 17:12
@cquil11
cquil11 requested a review from Ankur-singh as a code owner August 12, 2026 17:12
@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @cquil11's task in 8m 25s —— View job


PR Review

  • Gather context (diff, changed files, repo guidelines)
  • Review benchmark script dsv4_fp4_b200_sglang_mtp.sh
  • Review configs/nvidia-master.yaml changes (image accessibility, model prefix, EP flags)
  • Review perf-changelog.yaml entry position
  • Post review feedback

Summary

One 🔴 BLOCKING issue (inline comment posted): the new perf-changelog.yaml entry is inserted mid-file (line ~5441, right after the PR #2508 entry) instead of appended to the end of the file — utils/validate_perf_changelog.py enforces append-only byte-for-byte history and will reject this against current main. Please move the entry to the bottom of the file.

Everything else checks out:

  • benchmarks/single_node/agentic/dsv4_fp4_b200_sglang_mtp.sh follows the established glm5.2/qwen3.5 B200 SGLang AgentX patterns (router via consistent hashing + correlation-ID keys, wait_for_ready/write_command/run_eval lib signatures all correct, multi-line server command, sglang: metrics gate).
  • Golden synthetic acceptance length 2.49 matches the committed DSv4 3-step golden (benchmarks/multi_node/amd_utils/server_sglang.sh DSV4_GOLDEN_AL=2.49) and the existing DSv4 vLLM recipes; the simulation env vars are correctly skipped for EVAL_ONLY, so eval keeps real MTP verification.
  • The agentic replay legitimately omits --use-chat-template (documented convention — AIPerf drives /v1/chat/completions, prompts are already chat-formatted).
  • lmsysorg/sglang:v0.5.17-cu130 is a public Docker Hub image already used elsewhere in nvidia-master.yaml; launcher routing (launch_b200-dgxc.sh) resolves the new config key to the new script and exports PORT.
  • Parser names (deepseekv4 / deepseek-v4), --swa-full-tokens-ratio, and flashinfer_mxfp4 MoE backend all match the existing DSv4 SGLang srt-slurm recipes; the chat template file exists.

@cquil11
cquil11 force-pushed the agent/refresh-dsv4-b200-sglang-agentx branch from 721ec8d to 8b73f94 Compare August 12, 2026 17:16
@github-actions

Copy link
Copy Markdown
Contributor

Comment thread perf-changelog.yaml Outdated
Comment on lines +5441 to +5449
- config-keys:
- dsv4-fp4-b200-sglang-agentic-hicache-mtp
scenario-type:
- agentic-coding
description:
- "Refresh the purged B200 DeepSeek-V4-Pro SGLang AgentX resident, DP-attention, and HiCache grid on SGLang v0.5.17."
- "Use native EAGLE MTP (3 steps, top-k 1, 4 draft tokens) and golden synthetic acceptance length 2.49 for throughput; eval retains real verification."
- "Follow the official SGLang DeepSeek-V4 Blackwell recipe and require nonempty SGLang server metrics."
pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2578

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.

🔴 BLOCKING: New perf-changelog.yaml entry is inserted mid-file instead of appended to the end.

Why it matters: The file is read chronologically (oldest at top, newest at bottom — it starts at PR #95 and ends at PR #2562's entry on line 5906). This entry was inserted at line 5441, right after the PR #2508 entry, with ~450 lines of existing history below it. Beyond breaking the ordering convention, utils/validate_perf_changelog.py enforces append-only byte-for-byte history (head_raw.startswith(base_raw) in validate_raw_change), so CI changelog validation will fail with "appended entries changed historical perf-changelog.yaml bytes; restore the base file byte-for-byte and append at the end".

Fix: Delete this entry from here and append it verbatim after the last entry in the file (currently the qwen3.5-fp4-mi355x-sglang-agentic-mtp entry for PR #2562, ending at line 5906), separated by exactly one empty line.

Fix this →

Comment on lines +259 to +262
if [ "${#METRICS_ARGS[@]}" -gt 0 ]; then
capture_cache_metrics
trap capture_cache_metrics EXIT
fi

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 EXIT trap guard if [ "${#METRICS_ARGS[@]}" -gt 0 ] at line 259 is always true, since METRICS_ARGS is set unconditionally at line 103 to a fixed 2-element array and is never emptied or reassigned on any path. It reads as though metrics capture is optional (mirroring the genuinely-conditional CACHE_ARGS pattern above it), but it isn't — either drop the guard or make METRICS_ARGS actually conditional.

Extended reasoning...

The bug: METRICS_ARGS is declared once, unconditionally, at line 103:

METRICS_ARGS=(--enable-metrics --enable-cache-report)

It is never reassigned, appended to, or emptied anywhere else in the script — a grep for METRICS_ARGS across the file turns up exactly three hits: the assignment at line 103, its expansion into SGLANG_CMD at line ~204, and the guard at line 259:

if [ "${#METRICS_ARGS[@]}" -gt 0 ]; then
    capture_cache_metrics
    trap capture_cache_metrics EXIT
fi

Since the array always has exactly 2 elements, ${#METRICS_ARGS[@]} is always 2, and the condition is always true. The if block is dead weight — capture_cache_metrics and the EXIT trap install unconditionally regardless of what this guard says.

Why it's misleading rather than merely redundant: the script has one real precedent for this shape a few lines earlier — CACHE_ARGS. That array starts empty (CACHE_ARGS=()) and is populated only inside the require_agentic_kv_offload_backend hicache branch, so a length check on it is a legitimate runtime conditional. METRICS_ARGS copies that visual pattern (an array-length guard right before use) without the underlying conditionality that makes the pattern meaningful. A reader skimming the script would reasonably assume metrics/cache-report capture is optional in some configuration, when in fact it is always on.

Step-by-step proof:

  1. Line 103 executes unconditionally on every invocation of the script: METRICS_ARGS=(--enable-metrics --enable-cache-report).
  2. No branch (HiCache on/off, DP-attention on/off, eval-only or not) touches METRICS_ARGS again before line 259.
  3. At line 259, ${#METRICS_ARGS[@]} evaluates to 2 in every possible run.
  4. [ 2 -gt 0 ] is always true, so capture_cache_metrics is always invoked immediately and the trap capture_cache_metrics EXIT is always installed.
  5. Therefore no execution path skips this block — the guard has no observable effect on behavior.

Impact: none functionally — this doesn't change program behavior since the branch is always taken anyway. It's purely a readability/maintainability nit: a future editor could plausibly try to make metrics capture conditional by clearing METRICS_ARGS somewhere, not realizing the guard already silently assumed that possibility without it ever occurring.

Fix: either (a) drop the if and call capture_cache_metrics/install the trap unconditionally, since metrics are always enabled, or (b) if optional metrics capture was actually intended, make METRICS_ARGS conditionally empty (e.g., only set it under a flag) so the guard reflects real behavior.

Comment on lines +50 to +57
# processing use the isolated environment when InferenceX is mounted at /ix.
SGLANG_PYTHON="$(command -v python3)"
if [[ "$INFMAX_CONTAINER_WORKSPACE" != /workspace ]]; then
AGENTIC_VENV="${AGENTIC_VENV:-/tmp/inferencex-agentic-venv}"
"$SGLANG_PYTHON" -m venv "$AGENTIC_VENV"
export PATH="$AGENTIC_VENV/bin:$PATH"
fi
install_agentic_deps

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.

🟡 In eval-only mode, the empty AGENTIC_VENV created at dsv4_fp4_b200_sglang_mtp.sh:52-56 shadows python3 before transformers is installed into it, so get_native_max_context_length's bare-python3 probe (benchmark_lib.sh:908) fails silently and falls back to a hardcoded 16384 instead of DeepSeek-V4-Pro's real native context. For this specific recipe the fallback is harmless in practice (the single-node agentic eval runs GSM8K, whose prompts/outputs fit well inside 16384), but the detection is still silently wrong and worth fixing, e.g. by creating the venv with --system-site-packages so the native-context probe still sees the system transformers.

Extended reasoning...

The mechanism is real. When INFMAX_CONTAINER_WORKSPACE != /workspace (the documented normal case for this B200 image, since it mounts InferenceX at /ix), the script runs "$SGLANG_PYTHON" -m venv "$AGENTIC_VENV" with no --system-site-packages, then prepends $AGENTIC_VENV/bin to PATH. This venv starts completely empty. install_agentic_deps (benchmark_lib.sh:1826) builds a separate AIPERF_VENV via uv --python "$AIPERF_PYTHON" and never touches AGENTIC_VENV, so the new venv stays empty until _install_lm_eval_deps eventually runs python3 -m pip install ... lm-eval[api] into it.

In EVAL_ONLY=true mode, run_eval (benchmark_lib.sh:1689-1690) calls compute_eval_context_length before _install_lm_eval_deps runs (that install happens later, inside run_lm_eval, at line 1008). compute_eval_context_length calls get_native_max_context_length (line 908), which shells out to a bare python3 -c '... from transformers import AutoConfig ...'. Since AGENTIC_VENV/bin is first on PATH and empty at this point, the import raises, the except swallows it, and the probe prints 0. Because MAX_MODEL_LEN is unconditionally unset for agentic callers (benchmark_lib.sh:77) and this recipe never calls setup_eval_context, compute_eval_context_length sees benchmark_ctx=0 and native_max=0 and falls through to eval_ctx=${MAX_MODEL_LEN:-16384}=16384 (line 946), emitting a WARN to stderr along the way.

Step-by-step proof:

  1. INFMAX_CONTAINER_WORKSPACE resolves to /ix (not /workspace) for this image, so the script hits the if branch and creates AGENTIC_VENV empty, then export PATH="$AGENTIC_VENV/bin:$PATH".
  2. EVAL_ONLY=true → the script calls run_eval --port "$PORT".
  3. run_eval sees EVAL_MAX_MODEL_LEN unset → calls compute_eval_context_length "$MODEL" "${MAX_MODEL_LEN:-0}" with MAX_MODEL_LEN unset (→ 0).
  4. compute_eval_context_length calls get_native_max_context_length, which runs bare python3 -c '...AutoConfig...'. python3 now resolves inside the empty AGENTIC_VENV, transformers isn't installed there yet, import fails, function prints 0.
  5. Both benchmark_ctx and native_max are 0 → fallback branch: eval_ctx=16384, EVAL_MAX_MODEL_LEN=16384.
  6. Later, run_lm_eval passes max_length=16384 and computes max_output_tokens=16384-4096=12288 for lm_eval --model_args/--gen_kwargs.
  7. Without the venv (the /workspace case), bare python3 resolves to the image's system Python, which already has transformers installed, so the probe would have returned DeepSeek-V4-Pro's real (larger) native context instead of 0.

Where the original framing overreaches (addressing the refutation). One verifier objection is correct and should be acknowledged: AGENTIC_VENV is not simply redundant dead weight. _install_lm_eval_deps (benchmark_lib.sh:870-887) and the lm_eval invocation itself (line 1029) use bare python3 -m pip install --break-system-packages ... / python3 -m lm_eval. Without something ahead of the system Python on PATH, those bare-python3 calls would install/upgrade lm-eval[api] (and transitively transformers) directly into the SGLang server's system interpreter — exactly the corruption the script's own comment says it's trying to avoid. So the venv does serve a real isolation purpose for the eval path; it isn't redundant with AIPERF_VENV.

The refutation's second point is also correct and matters for grading severity: this config has multinode: false, and per utils/matrix_logic/generate_sweep_configs.py:289-291/405-406, single-node agentic entries run their eval through the GSM8K lm-eval path, not SWE-bench. GSM8K prompts and chain-of-thought generations are far shorter than 16384 tokens, and max_output_tokens still comes out to 12288 either way, so for this recipe's actual eval point there is no truncation or observable score impact — the fallback happens to be harmless here.

Why it's still worth flagging. The detection is genuinely broken (a documented-intent violation per benchmark_lib.sh:70-71, "agentic replays must use the model's native context limit"), it fails silently (only a stderr WARN, no exit), and it's not obviously scoped to "harmless for GSM8K" from the call site — the same pattern will silently misconfigure any future agentic recipe/eval-task combination where the actual context matters, and it's easy to overlook since nothing crashes. A simple, low-risk fix: create AGENTIC_VENV with --system-site-packages (so the bare-python3 native-context probe still resolves transformers from the image's system install while pip installs continue to prefer the venv's own site-packages), or resolve the native-context probe via $SGLANG_PYTHON explicitly instead of a bare python3.

@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

…00-sglang-agentx

# Conflicts:
#	perf-changelog.yaml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant