Repository navigation
feat(sglang): v0.5.22 image, GLM-5.2-MXFP4 mixed and PD (TP1xPP4 prefill) examples, router decode request balancing - #210
Merged
Conversation
llying-001
added a commit
that referenced
this pull request
Oct 21, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
llying-001
added a commit
that referenced
this pull request
Oct 21, 2026
…K 0.9704, accept 4.60), PR #210 updated; PP4 single-request latency note; C88 PP4 queued Co-authored-by: Cursor <cursoragent@cursor.com>
llying-001
marked this pull request as ready for review
October 22, 2026 02:30
llying-001
requested review from
jiejingzhangamd,
limou102 and
xiaobochen-amd
as code owners
October 22, 2026 02:30
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Responses prompt normalization can diverge from workers, and saved deployment overrides leave stale router URLs in two client scripts.
2 open issues
What changed in this PR
Upgrades infera’s MI355X SGLang image to v0.5.22 and adds GLM-5.2-MXFP4 deployment kits for aggregated and disaggregated serving.
Changes:
- Updates the image, version-specific patches and Mooncake build dependencies.
- Adapts SGLang argument parsing and Responses normalization, with compatibility tests.
- Adds deployment, smoke-test, GSM8K and AgentX scripts; formats the MoE profiler without changing behavior.
| File | Description |
|---|---|
tests/engine/sglang/test_decode_radix_cache_guard.py |
Updates expectations for v0.5.22 argument resolution. |
tests/engine/sglang/test_cuda_graph_max_bs_args.py |
Tests legacy and split CUDA graph flags. |
infera/router/kv_event/responses_input.py |
Initializes the Responses shim’s system-message capability. |
infera/projection/core/projection/module_profilers/moe_mlp.py |
Applies formatting-only changes. |
infera/engine/sglang/args.py |
Adds flag translation and model-config compatibility. |
examples/sglang_mix_glm5.2/README.md |
Documents the aggregated recipe and validation. |
examples/sglang_mix_glm5.2/env.sh |
Defines aggregated deployment settings. |
examples/sglang_mix_glm5.2/engine/worker.sh |
Launches the TP4/DP4 worker. |
examples/sglang_mix_glm5.2/engine/up.sh |
Starts etcd, worker and router. |
examples/sglang_mix_glm5.2/engine/smoke.sh |
Runs aggregated smoke checks. |
examples/sglang_mix_glm5.2/engine/smoke.py |
Checks registration and inference responses. |
examples/sglang_mix_glm5.2/engine/eval.sh |
Runs InferenceX GSM8K evaluation. |
examples/sglang_mix_glm5.2/engine/down.sh |
Saves logs and removes containers. |
examples/sglang_mix_glm5.2/engine/common.sh |
Provides shared deployment helpers. |
examples/sglang_mix_glm5.2/engine/agentx/constraints.txt |
Pins AgentX client dependencies. |
examples/sglang_mix_glm5.2/engine/agentx/agentx.sh |
Runs aggregated AgentX benchmarks. |
examples/sglang_2p1d_glm5.2/README.md |
Documents topology, results and operational caveats. |
examples/sglang_2p1d_glm5.2/env.sh |
Defines two-node deployment settings. |
examples/sglang_2p1d_glm5.2/engine/worker.sh |
Launches prefill or decode workers with EAGLE. |
examples/sglang_2p1d_glm5.2/engine/up.sh |
Coordinates local and remote worker startup. |
examples/sglang_2p1d_glm5.2/engine/smoke.sh |
Runs smoke checks using saved deployment settings. |
examples/sglang_2p1d_glm5.2/engine/smoke.py |
Checks disaggregated registration and inference. |
examples/sglang_2p1d_glm5.2/engine/eval.sh |
Runs GSM8K through the disaggregated router. |
examples/sglang_2p1d_glm5.2/engine/down.sh |
Collects logs and tears down both nodes. |
examples/sglang_2p1d_glm5.2/engine/common.sh |
Provides SSH, configuration and health helpers. |
examples/sglang_2p1d_glm5.2/engine/agentx/constraints.txt |
Pins AgentX client dependencies. |
examples/sglang_2p1d_glm5.2/engine/agentx/agentx.sh |
Runs AgentX with multi-worker metrics. |
deploy/docker/scripts/build_mooncake_sglang.sh |
Installs yalantinglibs from the pinned submodule. |
deploy/docker/patches/sglang_rocm/v0522/patch_mla_absorb_bmm_default_config.py |
Delegates absorb-BMM configuration to AITER. |
deploy/docker/patches/sglang_rocm/patch_hicache_rocm_staged_write_back.py |
Supports the relocated DSA host pool. |
deploy/docker/patches/sglang_responses/v0522/patch_responses_unstreamed_tool_args.py |
Adapts tool-argument reconciliation to the new layout. |
deploy/docker/patches/sglang_kv_events/patch_kv_metrics_send_noblock.py |
Makes auxiliary KV-metrics sends nonblocking. |
deploy/docker/patches/sglang_dsa/v0522/dsa_page_table_rows.diff |
Reanchors the page-table row patch. |
deploy/docker/patches/sglang_dsa/v0522/apply_sglang_dsa_patches_v0522.sh |
Applies patches and verifies bytecode markers. |
deploy/docker/patches/sglang_dsa/patch_dsa_indexer_hip_dp_padded_rows.py |
Updates anchors for newer indexer layouts. |
deploy/docker/patches/sglang_disagg/v0522/patch_prefill_nonfinal_chunk_wait_event.py |
Adds completion events for non-final KV transfers. |
deploy/docker/patches/sglang_decode_radix_spec/patch_decode_radix_spec.py |
Skips patching when upstream permits speculation. |
deploy/docker/patch.upstream.status.md |
Records patch status on the new base. |
deploy/docker/Dockerfile.sglang |
Pins v0.5.22 and selects applicable patches. |
Review effort: Balanced
| source "$KIT/engine/common.sh" | ||
| RUN_DIR="$(run_dir)" | ||
| # shellcheck source=/dev/null | ||
| source "$RUN_DIR/engine-config.env" |
| # template, which is not available here; False is the answer for every | ||
| # Jinja template that cannot render them inline, and differs from the | ||
| # engine only for a body that interleaves system messages on such a model. | ||
| shim.supports_inline_system = False |
7 of 12 tasks
Pin lmsysorg/sglang-rocm:v0.5.22-rocm720-mi35x-20261018 and consume the patch directories by explicit file lists. Carried on this base: the DSA set (v0522 driver, page-table-rows re-cut), the non-final chunk wait event, the Responses unstreamed tool-args fix, the staged write-back gate; new: the MLA absorb-BMM default config and the non-blocking KV-metrics send, which the v0.5.21 deployments bind-mounted. Dropped as upstream: the early-send conn.py half, Responses PD bootstrap and custom-encoder prompt, the HiCache host allocator, the NextN fusion architecture. The decode-radix-spec patch becomes a no-op where SGLang no longer rejects it. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…rite-back scripts Both scripts as carried on dev/pd_opt/glm_5.2_agentx (43a78d5): the indexer anchors survive the v0.5.19 import change, and the write-back gate finds DSAIndexerPoolHost in pool_host/dsa.py as well as memory_pool_host.py. The main copies no longer find their anchors on the v0.5.22 base. Mooncake's yalantinglibs is installed from its submodule when the base lacks it. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
- engine: the Decode radix guard builds the ModelConfig with model_config_of() where ServerArgs.get_model_config() is gone; it fell into its warning path and answered 'supported' for every model. - router: give the borrowed OpenAIServingResponses the supports_inline_system attribute its _construct_input_messages now reads; every /v1/responses body failed to normalise and hashed to nothing. - test: v0.5.22 records the decode-leg disable_radix_cache as a resolution instead of overwriting the field; keep the argv-read assertion. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…ttention (WIP: validation pending) Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…958, c64 0.74); note 4 one kit per node; note 6 garbled outputs under sustained concurrency with DP attention (upstream, open) Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…GPU, interactivity p90 22.5; v0.5.21 image 31,605 / 20.8) Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
… graphs; upstream v0.5.19-v0.5.22 all affected Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…s-decode on SGLang builds that split it (v0.5.22 rejects the old spelling as ambiguous); test Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
… top-k kernel With DP attention and decode CUDA graphs, the AITER custom all-reduce garbled about 30% of GSM8K answers at concurrency 64 on every upstream image from v0.5.19 to v0.5.22; on RCCL the same recipe scores 0.980 with nothing garbled. SGLANG_OPT_USE_TOPK_V2=true adds 8.6% tokens/s/GPU and 18% interactivity p90 at AgentX C48 on the same node, with no change in GSM8K or long-context needle retrieval. README: validation, reference numbers (34,662 tok/s/GPU), note 6. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
… as InferenceX runs it sglang_2p1d_glm5.2: GLM-5.2-MXFP4 PD-disaggregated across two MI355X nodes, two TP4 + DP4-attention prefills with a 250 GB-per-rank write-back HiCache tier and shortest-prefill-first scheduling, one TP8 + DP8-attention EAGLE decode, KV over Mooncake on eight ionic rails, kv-aware router with prefill session affinity. Validation pending. Both kits' eval.sh now call InferenceX's run_eval at the pinned commit (its lm-eval revision and patches, utils/evals/gsm8k.yaml, full test set) instead of lm_eval 0.4.13 on 200 questions; the InferenceX checkout moves to common.sh. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…prefills (they register after the start-up PD probe) Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…0.9697) and the C176 reference point (35,637 tok/s/GPU) Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…not be removed yet Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…ot be removed yet Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
… every measured point and the known issues PREFILL_WORKERS (1 or 2, default 2) sets how many prefills up.sh starts and waits for; agentx.sh counts the GPUs from it and smoke.sh expects that many prefills, both read from the run's engine-config.env. README: reference table with the 2P1D C176 / C128 / C96 / C64 and 1P1D C64 / C32 points, why interactivity stays flat until the busiest decode rank drops below seven requests and why one prefill serves below C88; note 9, the prefill GPU memory access fault and the hung GPU it leaves; observed VRAM release times. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…t p90 42.8) Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…so the transfer includes draft-layer KV (note 10); validated 1P1D smoke 6/6, GSM8K 0.9704; note 3: VRAM delay comes from HiCache Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…tainer names common.sh derived ROUTER_URL from env.sh before smoke.sh and agentx.sh restored the run's engine-config.env, so after `ROUTER_PORT=29999 bash engine/up.sh` both still called port 28300. eval.sh and down.sh did not restore the run at all (eval.sh used the current ROUTER_PORT, down.sh the current CTR and DECODE_SSH). load_run restores the run's settings and derives ROUTER_URL and the container names again; smoke.sh, eval.sh, agentx.sh and down.sh use it. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
… on the template SGLang v0.5.22 keeps a Responses body's system messages (instructions, developer items) in place when the engine's chat template renders them inline -- GLM-5.3's, Kimi-K3's encoder -- and coalesces them into one leading system message otherwise. The shim hard-coded the coalescing answer, so on an inline-capable engine it hashed a prefix the engine never built. Render both ways and return None when they differ; the body then routes on load, as the module does for every body it cannot reproduce. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…oad (--pp-size > 2) DeepseekV2Model sizes its gemm-output allocator from self.embed_tokens.embedding_dim, but every middle pipeline stage holds a PPMissingLayer there, so PP rank 1 died with AttributeError at load time. The embedding width is config.hidden_size; the patch reads that instead. Stages that have an embedding, and PP1, are unchanged. Verified in a throwaway container of infera-sglang:v0522-fdbafb60: applies once, a second run skips; the same two-line change ran as a bind-mounted file through the TP1 x PP4 prefill validation (GSM8K 0.9674 / 0.9719, with and without HiCache) and every PP4 AgentX point since 10-21. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…r 4 GPUs Each prefill is now TP1 x PP4 (layers 20,20,20,18: the last stage also holds the LM head and the NextN draft layer), overlap scheduler off, 8k chunks. Against the TP4 + DP4-attention prefill it removes the DP attention barrier and the hot rank a long session pins, and the four stages share one KV pool. The decode keeps TP + DP attention over however many GPUs DECODE_GPUS lists, so a 4-GPU list gives the 4+4 shape; agentx.sh records the decode TP from it, and the prefill as TP1 / PP4 / no DP attention (the result JSON used to say TP4 / DP attention for every prefill). Same flags as the PP4 runs measured from a copy of this kit (v6-pp4, chunk 8192, HiCache on); the README is updated with the new numbers. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
… demand Under DP attention every decode step waits for the busiest rank, whose cost grows with its request count as well as its context. Decode input demand balances in-flight input tokens only, so one rank can hold many short requests. The new weight (tokens per held request, default 0 = unchanged) adds weight * requests to each candidate's projected tokens, the form Dynamo uses for router-decode-active-request-weight. Exposes the per-target request count as infera_router_decode_demand_requests. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…and the 2P1D kit README, with the 1P1D C88 A/B Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: liyingli <liyingli@amd.com>
…s by default up.sh passes --decode-request-weight $DECODE_REQUEST_WEIGHT (env.sh, default 1,000,000, recorded per run); 0 keeps token-only decode demand. The README section is no longer optional. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
llying-001
force-pushed
the
feat/sglang-mix-glm5.2-tp4-v0522
branch
from
October 23, 2026 09:05
d395c3b to
f491b56
Compare
The default shape (2P1D) has only been measured with token-only decode demand; the 1P points with an 8-GPU decode set 1000000 explicitly. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…rst Pareto baseline Topology, recipe and validation for the PP4 prefills (smoke 6/6, GSM8K 0.9666 / 0.9674 and tests/unit + tests/engine/sglang on an image built from this branch); the reference numbers are the baseline per shape with the decode request weight each ran with and the command that starts it: 2P1D and the 4-GPU decode at weight 0, 1P1D at 1000000 (C88 31,088 at p90 71.7, C64 28,981 at 86.0, C48 22,331 at 103.9, C32 16,309 at 111.7). Note 11 says why the prefills are PP4 and what that costs; note 9 dates the memory access fault to the TP4 prefills; the port table drops the DP-rank KV event ports. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
llying-001
added a commit
that referenced
this pull request
Oct 23, 2026
…ight, first Pareto baseline) Co-authored-by: Cursor <cursoragent@cursor.com>
… recipe's A/B The table came from AUS runs of the previous recipe (TP4 + DP4-attention prefills, 1800 s windows) without saying so. It now shows 1P1D C88 and C64 with this recipe at weight 0 and 1000000 (3600 s), and keeps the AUS A/B as a dated footnote with its recipe and window. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
llying-001
added a commit
that referenced
this pull request
Oct 23, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
xiaobochen-amd
approved these changes
Oct 26, 2026
llying-001
added a commit
that referenced
this pull request
Oct 27, 2026
…X Pareto Gap analysis, work items, risks and timeline for getting the PR #210 Pareto onto InferenceX; the PR's points recomputed under the dashboard's E2E normalized interactivity P90, and the 10-27 InferenceX API snapshot. Signed-off-by: liyingli <liyingli@amd.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Description
Moves
Dockerfile.sglangfrom the SGLang v0.5.18 base tolmsysorg/sglang-rocm:v0.5.22-rocm720-mi35x-20261018and keeps infera's SGLang integration working on it. Adds two runnable GLM-5.2-MXFP4 kits for MI355X, tuned for the InferenceX AgentX replay, and a router option the PD kit uses:examples/sglang_mix_glm5.2: aggregated TP4 + DP4 attention on one node.examples/sglang_2p1d_glm5.2: PD across two nodes, TP1 × PP4 prefills (one or two) and a TP + DP-attention decode on 8 or 4 GPUs. One recipe;env.shpicks the shape for each stretch of the Pareto line, and the README gives the first MI355X baseline for it.--decode-request-weight(folded in from router: --decode-request-weight balances decode DP ranks by held requests #213): decode input demand also charges the requests a target already holds, so DP ranks are balanced by request count as well as by tokens.Rebased onto main
adbb9dc5(10-23); every commit is signed off.Type of change
Changes
Image
Dockerfile.sglang:deploy/docker/patch.upstream.status.mdrecords, for every patch, whether it is baked, already upstream, or not needed on this base (each re-verified in a throwaway container of the base).sglang_dsa/v0522/(page-table rows re-cut, apply script);sglang_disagg/v0522/patch_prefill_nonfinal_chunk_wait_event.py;sglang_responses/v0522/patch_responses_unstreamed_tool_args.py;sglang_rocm/v0522/patch_mla_absorb_bmm_default_config.py;sglang_kv_events/patch_kv_metrics_send_noblock.py;sglang_pp/v0522/patch_deepseek_v2_pp_embed_dim.py:DeepseekV2Modelsizes its gemm-output allocator fromembed_tokens, aPPMissingLayeron middle pipeline stages, so--pp-size> 2 failed to load; it now readsconfig.hidden_size.patch_decode_radix_spec.pyis a no-op on this base.build_mooncake_sglang.sh: installs yalantinglibs from Mooncake's pinned submodule, which the v0.5.22 base no longer ships.infera
infera/engine/sglang/args.py:--cuda-graph-max-bsinto--cuda-graph-max-bs-decode/-prefill, and argparse then rejects the old spelling as an ambiguous prefix (e2e-mixed failed on it). When the running SGLang has no exact--cuda-graph-max-bs, it is mapped onto--cuda-graph-max-bs-decode; older images are unchanged.model_config_ofwhereServerArgs.get_model_configis gone.infera/router/kv_event/responses_input.py: the Responses shim setssupports_inline_system = False, which v0.5.22 reads in_construct_input_messages; when a body's system messages render differently with and without inline system support, it returns None and the body routes on load.tests/engine/sglang/test_cuda_graph_max_bs_args.py(new),tests/engine/sglang/test_decode_radix_cache_guard.py,tests/unit/router/test_responses_input.py.Router (
--decode-request-weight W,INFERA_DECODE_REQUEST_WEIGHT)booked input tokens + this request's tokens + W × requests it holds(booked at dispatch, released when the decode stream ends), the shape of Dynamo'srouter-decode-active-request-weight. Under DP attention a step waits for the busiest rank, whose cost grows with its request count, so token-only demand can leave one rank with many short requests.W = 0(default) is today's token-only demand;W > 0requires--decode-input-demand onorshadow.infera_router_decode_demand_requests{target}; Python launcher flag;manual/reference/cli.md,manual/features/kv_aware_routing.md.Examples (same layout as the ATOM kits)
env.sh;engine/up.sh,smoke.sh,eval.sh,down.sh; no automatic gates. The clients anddown.shread the run's own settings (router URL, container names) back.918524ffwith its client constraints; GSM8K through InferenceX'srun_evalon the full 1,319 questions.--disable-custom-all-reduce(with the AITER custom all-reduce on, about 30% of GSM8K answers at concurrency 64 come out garbled under DP attention plus decode CUDA graphs; mixed README, note 6);SGLANG_OPT_USE_TOPK_V2=true.examples/sglang_2p1d_glm5.2):DECODE_GPUS(8, or 4 for the 4+4 shape), EAGLE MTP 5/1/6;MC_MAX_MR_SIZE=1 GiB;DECODE_REQUEST_WEIGHT(default 0) sets the request weight;agentx.shrecords the prefill as TP1 / PP4 and the decode TP fromDECODE_GPUS.First Pareto baseline (MI355X, AgentX, InferenceX
918524ff)Each point on a freshly started deployment, 3,600 s measured, 10 warm-up requests per lane, forced MTP acceptance 3.61; throughput per GPU over all of the deployment's GPUs. Full table and the command for each shape in the README.
Validation
3ad7527c): dco, lint, unit, unit-torch-cpu, rust, agent_sys pass; engine and e2e were still queued.pre-commit run --all-files(cargo-fmt / gofmt need toolchains the container lacks;cargo fmt --checkpasses separately), unit 2,864 passed,cargo clippy -D warningsclean,cargo test369 + 46 + 4 + 14 passed.3ad7527c(the head minus README and the weight default):tests/unit2,656 passed / 91 skipped,tests/engine/sglangevery file passes.Known issues (documented in the READMEs):
--disable-custom-all-reduce.MC_MAX_MR_SIZE=1 GiBavoids it.Checklist: