Skip to content

GLM-5.3 series: engine image, example kits, and parked e2e cases - #151

Open
dorado269 wants to merge 27 commits into
mainfrom
yihou.dev.glm53.expr
Open

GLM-5.3 series: engine image, example kits, and parked e2e cases#151
dorado269 wants to merge 27 commits into
mainfrom
yihou.dev.glm53.expr

Conversation

@dorado269

@dorado269 dorado269 commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Adds GLM-5.3-series support: engine image, patches, aggregated and
disaggregated example kits, and e2e cases parked off by default.

The fact that shapes the whole change: these are two unrelated architectures

They share a product name and almost nothing else, verified from the
checkpoints' own config.json:

GLM-5.3, GLM-5.3-MXFP4 GLM-5.3-Flash, -Flash-MXFP4
model_type glm_moe_dsa glm5_next
hidden / layers 6144 / 78 4096 / 45
attention uniform MLA + DSA hybrid KDA linear + sparse
memory pools paged KV paged KV + a KDA state pool

The big models need no engine change — their config.json is identical to
GLM-5.2's field for field except transformers_version, so they reuse the
GLM-5.2 recipe. The Flash family exists in no released sglang, so it needs a
source overlay, which is why there are two Dockerfiles rather than one.

What is here

  • deploy/docker/Dockerfile.sglang — base moved to v0.5.18-rocm720-mi35x,
    with the one DSA patch hunk that drifted re-anchored (upstream renamed
    tp0_infotp0_info_cpu). Losing that hunk does not degrade gracefully: it
    is the only place the gathered column is min()-reduced, so without it every
    rank reads its own answer and the DP vote silently never happens.
  • deploy/docker/Dockerfile.sglang.glm53 — same base plus the sglang #36607
    overlay pinned at c821c425, for the Flash family. Kept separate so an
    unreleased-source fetch does not enter the default build path for Kimi-K3 and
    GLM-5.2.
  • examples/sglang_mix_glm5.3/ — aggregated kit covering all four checkpoints.
  • examples/sglang_1p1d_glm5.3/ — PD wrappers that drive the GLM-5.2 kit
    rather than forking it, so there is one source of truth for the engine recipe.
  • tests/e2e/ — four GLM-5.3 cases, all enable=False; verified the existing
    parameter expansion is unchanged.
  • deploy/docker/patches/sglang_carried/ — a MoE gate-bias fp32 fix, carried
    and deliberately not wired into any image
    . The directory is unglobbed so
    "carried, not applied" is structural rather than a comment someone can miss.

Measured on 8×MI355X / gfx950

Fixed-length, matched configuration both sides, benched through the router.

Alignment against the GLM-5.2 MIX baseline — the mission's bar:
0.89–1.11× across 8 matched points, TTFT better at 7 of 8, TPOT within ±10 % at
6 of 8. Conservative if anything: engine-side counters show our p50 arm did
11 points more prefill work than the baseline.

The p50 rows carry a measured quality statement, not an assumed one: scoring
490 generations at osl 320 gives 0 looping, worst 10-gram ×4 — throughput of
coherent text. The p90 rows are different: 54.7 % of 490 generations loop at
osl 3300, so those are a valid throughput measurement of the engine generating
repetitive text and must not be read as a quality result. The p90 ratio may
still be fair; the baseline's long-output arms cannot be checked the same way,
because its packup saved no generations.

MXFP4 vs FP8 on Flash, identical shape and topology: MXFP4 is 1.11× at
concurrency 1 and 1.23× at 8. First direct comparison on this architecture.

PD single-node 1P1D, feature-matched against aggregated on the same eight
GPUs: 1.10 / 1.26 / 0.87 / 0.87 at concurrency 1/8/16/24. PD is 10-26 %
ahead at low concurrency and ~13 % behind above it
— at concurrency 1 its
TTFT p50 is 199 ms against the aggregated arm's 407 ms.

Getting to a number that could be attributed took three arms, and the first
two were each individually plausible: an unmatched comparison said 1.15× ahead,
a feature-matched one at concurrency 24 alone said 0.86× behind, and only the
arm that isolated decode-side DP-attention showed the crossover belonged to DPA
— worth 1.33× on its own — rather than to disaggregation. A single concurrency
point does not characterise a topology.

Turning the HIP transport off makes single-node PD faster: 1.23× throughput
and 3.4× better TTFT p50 at concurrency 8, read against a measured ~5 % noise
floor. That inverts the kit's own premise, which described HIP-over-XGMI as the
fast path and loopback RDMA as the degraded fallback.

Two engine-script fixes, and why they are here

The GLM-5.3 PD wrappers used single-knob names (MTP, DPA, GPUS,
EXTRA_ENGINE_ARGS) against a strictly per-leg interface, so six knobs silently
did nothing and each degraded to a plausible default. MTP=0 launched decode at
mtp=1; GPUS put both legs on the same four cards. None errored.

Fixing that required two changes in sglang_1p1d_glm5.2/ — forwarding GPUS
and the KV-event ports per leg. Both use ${VAR:+...} so an unset variable
injects nothing, and two-node resolution was verified byte-identical before and
after.

Known and stated

Documented in the kits rather than left for rediscovery:

  • Long outputs degenerate into repetition loops — 0–1 % of requests at
    osl 320, 40–65 % at 3300, on GLM-5.3 and GLM-5.2. Throughput arithmetic is
    unaffected (loopers decode within 1 % of clean requests). Cause not
    established, but two candidates are now eliminated by a single arm: run
    with the chat template applied and MTP off — so no ROCm argmax branch — it
    still looped at 60 %, and scoring the TP4 control arm — 490 generations, MTP
    off throughout
    — puts that at 54.7 % against 54 % on the MTP-on
    arms. The template was never missing (the flag is parsed and never consumed;
    sglang-oai-chat applies it server-side regardless), and turning MTP off
    does not change the rate at all
    , so eagle_utils.py:726 is eliminated rather
    than merely unnecessary — the three open upstream ROCm PRs are not on this
    project's critical path for it. The surviving candidate, INFERRED, is that the
    prompts are repetitive by construction: benchmark/datasets/random.py:130-134
    reaches a long ISL by repeating one ShareGPT conversation and truncating, so an
    isl-15500 prompt is roughly a 50× repetition of a few hundred tokens.
  • Acceptance length does not detect that — an aggregate of 2.96 with 1.25 %
    at the 4.00 ceiling was measured while 54 % of the same requests were looping.
  • --dataset-name random does not build independent prompts. It draws
    seeded ShareGPT, so each arm's list is a strict prefix of the next and higher
    concurrency mechanically buys a higher cache-hit rate. Source predicts
    12.5/50.0/66.7 %; four independent datasets measured 12.38/49.51/66.05 %.
  • hip is single-node-only by design, and its knob gates selection rather
    than installation — so the natural discriminator reads 4/4 in both states.
  • Every figure is a floor: the FP4 MoE kernel is untuned.

Not included

GLM-5.3-Flash PD is out of scope. The kit records that the KDA state is
transferred (ten links with file:line) so the shape is feasible, and equally
that nobody has run it.

…t moved

GLM-5.3 and GLM-5.3-MXFP4 are glm_moe_dsa / GlmMoeDsaForCausalLM, field for
field identical to GLM-5.2 except transformers_version, so the released engine
already serves them through glm4_moe.py and this image needs no new model
source. Only the bump was needed. It cost two anchor repairs, both verified
in-image against lmsysorg/sglang:v0.5.18-rocm720-mi35x rather than assumed.

draft_cuda_graph_dp_vote.diff applies 6 of its 7 dp_attn.py hunks on v0.5.18.
Hunk 4 -- the min()-reduce -- rejects because upstream collapsed the per-field
device reads into one D2H copy and renamed the tensor with it
(tp0_info[:, N].min().item() -> tp0_info_cpu[:, N].min()).

Losing that one hunk does not degrade gracefully, which is why it gets a port
script rather than a shrug. It is the only place the gathered column is reduced
back onto self.can_run_draft_cuda_graph; without it that attribute keeps the
value the constructor put there, i.e. THIS RANK's answer. The vote silently
never happens and the DP group splits across graph-replay and eager exactly as
it did unpatched. The apply script's own header warns about this shape of
failure: an inert 04 looks exactly like a working one until load. It is also
why the existing dp_attn.py:can_run_draft_cuda_graph marker cannot gate it --
that identifier is present after six hunks, so the marker passes on an inert
patch. patch_draft_cuda_graph_dp_vote_v0518.py re-asserts all six sibling edits
before writing, and exits non-zero if any is missing.

The second anchor is in the sglang_disagg set, which had no skip gate and so
failed the build outright: mooncake/conn.py's typing import grew `Set` while
disaggregation/common/utils.py's did not, and serving_responses.py's
`background=` argument gained `and not request.stream`. Both fixes are still
absent upstream, so the patches are still needed; only their anchors are stale.
reanchor_sglang_disagg_glm53.sh already retargets exactly these two into a copy
-- verified that both read identically on stock v0.5.18 and on the GLM-5.3
branch -- so it is reused here rather than duplicated. Its name still says
glm53 because that is where it was first needed; its header now records that it
is not GLM-5.3-specific.

Verified in the built image: all four DSA bytecode markers present, including
the hunk-4 min-reduce, and the two disagg patches applied.

Signed-off-by: yihou <yihou@amd.com>
…s first commit

GLM-5.3-Flash and -Flash-MXFP4 are model_type glm5_next -- a different
architecture from the big pair, not a smaller version of it: hybrid KDA-linear
plus DSA attention, mHC, no-RoPE MLA, a compressed indexer k-pool and a vision
encoder. It exists in NO released sglang. Verified absent from
lmsysorg/sglang:v0.5.18-rocm720-mi35x AND from the vendor-validated
lmsysorg/sglang-rocm:v0.5.18-rocm724-mi35x-20260822, both checked inside the
images. So this image fetches the model source at build time, which no other
Dockerfile here does -- and that is exactly why it is a separate file rather
than build args on Dockerfile.sglang: folding it in would put a fetch of
unreleased source into the default build path for Kimi-K3 and GLM-5.2.

These three files are adopted from the in-flight Infera PR #143, copied rather
than branched from, since that PR is open, is someone else's, and its author
records that the image has never been built. This one has been built and has
served.

THE PIN IS CHANGED from #143's 9e692c92 to c821c425, and the difference is not
cosmetic. 9e692c92 is #36607's FIRST commit; five of the nine after it are the
ones this image exists for, including "[AMD] Support mixed Quark MXFP4 and
block-FP8 loading" and "[AMD] Enable AITER mHC for GLM on gfx95". Content, same
commands across both refs: glm5_next.py 1834 -> 1942 lines, aiter references
3 -> 12, quantization/quark/quark.py 1103 -> 1172. Building on the earlier pin
silently takes the pre-mHC path -- which upstream measured at 4.3-5.4x slower
and which no log calls out -- and cannot load a Quark MXFP4 checkpoint at all.

c821c425 is also the safest pin available rather than merely the newest:
#36607 MERGED into #36507's branch on 2026-08-28, so its head is frozen.
pull/36507/head is NOT a substitute -- it carried the AMD work between 08-28 and
08-30 and then LOST it in its 08-31 rebase; as of 09-01 it is back to aiter 3 /
quark.py 1103. Known-good fallback: 7fa1924c.

The header carries its own delete criterion -- a copy-pasteable probe and what
to do once glm5_next appears in a release -- so this does not quietly become
permanent.

Signed-off-by: yihou <yihou@amd.com>
One row per checkpoint in the sglang PD-mixed grid, all four enable=False, plus
the four model-id constants. The enable flag is what "disabled by default in
CI" means here: expand_cases skips the row, so nothing new is collected --
verified, the grid still expands to the same 3 params and none of them is a
GLM-5.3 id.

They are parked for a resource reason, not a confidence one. Each recipe was
brought up and smoke-checked on 8xMI355X; each needs 300-700 GB of weights
pre-staged and four GPUs for ten-plus minutes of cold start, which no runner
here has. Flipping the first field is the whole activation step, and the point
of the row is that the recipe -- which took real debugging to establish -- is in
the tree rather than in someone's shell history.

Each row records what would otherwise have to be rediscovered:

- Which IMAGE it needs. The two Flash rows require Dockerfile.sglang.glm53; the
  two big rows run on the stock image. Crossing them fails at CONFIG LOAD with
  "model type `glm5_next` but Transformers does not recognize this
  architecture" -- a message that names transformers and invites the wrong fix.
- Why flash-mxfp4 passes --disable-shared-experts-fusion: sglang PR #36607
  opened the gfx950 fusion gate without deepseek_v2's
  quant_blocks_shared_experts_fusion guard, so the checkpoint's BF16 shared
  expert lands in routed slot 288 of an MXFP4-packed FusedMoE and weight load
  dies on a 256-vs-512 mismatch. Upstream #37268 is the same bug on NVFP4.
- Why the same flag on big-mxfp4 is insurance rather than a fix, and why it is
  still defaulted on: that checkpoint's shared experts are themselves MXFP4 so
  the precondition is absent, but upstream #25261 shows this class failing
  SILENTLY with wrong output when the shapes happen to line up.
- That the DSA-on-ROCm env block is mandatory for the big pair: without it the
  model serves, returns 200s, and returns garbage.
- That the vendor card's --cuda-graph-max-bs 2 --max-running-requests 2 is a
  concurrency-2 accuracy config and must not be copied into a benchmark arm.

flash-fp8's row is honest about being the one recipe not yet validated in this
tree: whether it also needs the fusion flag is marked unverified, with the
specific index-count check that settles it.

Signed-off-by: yihou <yihou@amd.com>
One kit with a VARIANT switch rather than four near-duplicate directories: the
recipes differ in about six flags, and merging them makes the load-bearing fact
impossible to miss -- GLM-5.3 is two unrelated architectures sharing a product
name, and which one you serve decides which engine image you need.

env.sh is the only file a site edits. worker.sh carries the tuned recipe and
contains no addresses or paths; up.sh does container -> etcd -> worker ->
router, waiting on health at each step; smoke.sh is six blocks each chosen
because it goes red when a specific feature is SILENTLY absent, which is the
failure mode this model family specialises in:

- two AITER mHC lines per rank. Without them the server starts, answers
  correctly, and is 4.3-5.4x slower with nothing in any log saying so.
- "Shared experts fusion optimization enabled." must be ABSENT -- a health
  check that is the absence of a line.
- decode lines carrying BOTH "full token usage" and "mamba usage", because the
  Flash family keeps a KDA state pool as well as the paged KV pool.
- a fault scan that excludes torch._dynamo/metrics_context telemetry, which
  appears in every healthy run, so a real traceback stays visible.

The README states validation per variant rather than implying it: flash-mxfp4
and both big variants validated end to end, flash-fp8 recipe-carried but not
yet validated in this kit, PD not covered at all. No PD kit ships here on
purpose -- that shape has not been run for GLM-5.3, and for the big pair
sglang_1p1d_glm5.2 is the validated reference.

Three traps are baked into the scripts rather than left to the README: up.sh
binds `realpath` output, because where the weights path crosses an NFS mount
boundary binding the symlink's parent gives the container an empty directory
whose failure surfaces minutes later as an unrelated-looking processor error;
teardown names containers explicitly and never by pattern, and the GPU check is
advisory rather than a kill, because this runs on shared nodes; and bench.sh
uses sglang's own bench_serving rather than a shell fan-out, after a bash loop
of 32 concurrent curls measured 350 output tok/s against an engine reporting
2398 with an empty queue.

Signed-off-by: yihou <yihou@amd.com>
Two operators hit this independently, on different nodes and different ports:
overriding only --listen-peer-urls leaves --initial-cluster at its default
default=http://localhost:2380 while --initial-advertise-peer-urls is derived
from the detected host, and etcd exits 1. A script that hardcodes 2380 never
sees it, which is exactly why it bites the first time you land somewhere 2380
is taken. The three peer flags already moved together here; this records why.

Signed-off-by: yihou <yihou@amd.com>
…forking it

GLM-5.3 (big) is glm_moe_dsa and its config.json is identical to GLM-5.2's field
for field except transformers_version, so the engine recipe is not similar to
the GLM-5.2 one -- it IS the GLM-5.2 one. sglang_1p1d_glm5.2/engine/leg.sh
already carries it, validated on two clusters and both fabric types. Copying
those ~600 lines here to change a model path would create a second source of
truth that drifts the first time either is fixed, so this ships wrappers only
and points KIT_DIR at that kit, exactly as its own cluster/*.sh do.

Two shapes. cluster.2node.sh is the validated topology with GLM-5.3 weights
substituted. cluster.singlenode.sh splits one 8-GPU box into TP4 prefill on
cards 0-3 and TP4 decode on 4-7 -- worth having because it makes PD testable
without a second node, and because the mission explicitly allows it.

Neither has been run yet, and the README says so per shape rather than implying
readiness. The single-node one carries a real unknown that is called out rather
than glossed: both legs share a host, so the KV handoff is a loopback RDMA
transfer, and whether mooncake does that -- and at what speed -- is not
established. That matters because the failure mode here is silent: mooncake
falls back to a transport that works and is merely 5-20x slower, and nothing
raises. smoke checks MC_FORCE_TCP and "GID is NULL" in both leg logs for exactly
that reason.

Fabric preconditions ARE verified first-hand on the reference node: 8 ionic
devices all PORT_ACTIVE, ib_peer_mem loaded (so registration mode A, the best of
the three), libionic 54.0-187-1 = ABI 4 in the image, and ibv_devinfo reporting
8 HCAs from inside the container. The README records the trap found while
checking that: without --device=/dev/infiniband a container on that host reports
ZERO HCAs, which is indistinguishable from an ABI mismatch and is the same
reading that means RDMA has silently degraded to TCP.

GLM-5.3-Flash is deliberately out of scope -- different architecture, separate
question, no claim made.

Signed-off-by: yihou <yihou@amd.com>
All three were measured on this stack today, and each is the kind of thing that
is invisible until it costs you a run.

CACHE_REPORT, default off, must be on for any cache-sensitive workload.
Without --enable-cache-report the server answers normally and simply reports
nothing: usage.prompt_tokens_details comes back null through the router and the
engine logs "#cached-token: 0". That is indistinguishable from a genuine 0%
hit rate, so an agentic replay reads as "the cache never worked" when what
failed was the counter. Verified by sending the same prompt twice through a
live router and watching both come back uncached.

The KDA-pool clamp is real and it fires. On every rank at TP4:
  max_running_requests is capped to 200 by the mamba state cache
  (max_mamba_cache_size=1000, 5 state slots per request)
The note now says to read the RESOLVED value out of the worker log rather than
out of server_args -- server_args records what was REQUESTED, and reading it
instead is exactly how one bring-up concluded the clamp had not fired when it
had. smoke.sh surfaces the resolved cap as its own line so the next operator
sees it without knowing to look for it.

Decode CUDA-graph capture costs 15.4-17.4 GB per rank at TP4, against ~1.4 GB
measured at TP8 on the same model -- fewer ranks means each one's graphs cover a
larger shard. Anyone budgeting VRAM from a TP8 figure at TP4 will be surprised
by an order of magnitude, so the comment says not to carry it across.

Also: big-* now passes --max-running-requests explicitly rather than leaving it
to the engine's memory-derived default, which varies with whatever VRAM happens
to be free -- so two runs of the same recipe on differently-loaded nodes get
different admission limits, and the benchmark then measures the limit.

Signed-off-by: yihou <yihou@amd.com>
Under DP-attention the engine prints PER-RANK values at startup while
/get_server_info reports the global ones: ask for --max-running-requests 256
and --chunked-prefill-size 65536 at dp8 and the startup line says 32 and 8192.
That is 256/8 and 65536/8 -- a division, not a clamp -- but the line reads
exactly like a clamp, and it already sent one reader looking for a cap that was
not there. It also explains an apparent internal inconsistency in a reference
packup, where the prose said 65536 and the server dump said 8192: both correct.

Separately, --cuda-graph-max-bs is deprecated on v0.5.18 in favour of
--cuda-graph-max-bs-decode. It still resolves, so nothing breaks today, but the
vendor recipes and our earlier scripts emit the old spelling and will break on
the next base bump. This kit already uses the current flags.

Signed-off-by: yihou <yihou@amd.com>
MoEGate.__init__ allocates e_score_correction_bias as bf16 whenever a
quant_config is present and _use_aiter, and biased_grouped_topk_gpu casts
it down again at the aiter call. GLM's bias is a narrow band at a large
offset, so bf16 cannot hold it. Measured on the checkpoints themselves:
GLM-5.3 and GLM-5.3-MXFP4 collapse 238 distinct fp32 values to 8, and
GLM-5.3-Flash-MXFP4 collapses 282 to 11. noaux_tc selects experts by
sigmoid(logits) + bias, so this reorders top-k routing.

Both edits are applied together or not at all. aiter's launcher dispatches
on gating_output.dtype() and then reinterpret_casts the bias pointer to
that same scalar_t without checking the bias tensor's own dtype, so an
fp32 bias under a bf16 gating tensor is read as fp32 bytes reinterpreted
as bf16 -- applying the deepseek_v2.py half alone is worse than the defect.

The gate is not upstream sglang#37133's. That PR tests the architecture
strings, which is False for the whole Flash family:
Glm5NextForConditionalGeneration passes config.text_config down, and
Flash's text_config has architectures: None. This predicate is a union of
moe_router_dtype == "float32" (declared by all four GLM-5.3 configs and
ignored entirely by sglang), model_type, and upstream's arch test kept as
a superset. Checked against all 38 checkpoints on this host: 8/8 GLM keep
fp32, 30/30 non-GLM byte-identical.

Carried, not applied. No Dockerfile copies or runs patches/sglang_carried/,
which is why the script is not in patches/sglang_rocm/ beside its siblings:
those directories are consumed by an unconditional *.py loop, so a file
placed there is wired into every image that copies it.

VERIFIED AS TEXT AND AS PREDICATE LOGIC ONLY. It applies to copies of
v0.5.18, c821c425 and the live source from infera/engine-sglang:v0518-glm53
(byte-identical result to the patched v0.5.18 tree), is idempotent, and
both drift cases exit 1 having written neither file. It has never been
executed on a GPU, and no accuracy or throughput delta has been measured.
Wiring it mid-campaign would make our arm the only one running the fixed
router and destroy the like-for-like property the alignment ratios rest on.

Signed-off-by: yihou <yihou@amd.com>
Three updates, all from runs on 8xMI355X/gfx950 today.

1. big-mxfp4 carries numbers rather than a green tick: the TP8+DPA+MTP
   fixed-length sweep lands at 0.92 / 1.06 / 0.89 / 1.10 x the GLM-5.2 MIX
   baseline at concurrency 1/8/16/24.

2. flash-fp8 loads and serves. More usefully, the open question of whether it
   needs --disable-shared-experts-fusion is answered: it does not. It was brought
   up with fusion ENABLED and loaded all 62 shards cleanly, and the reason was
   predicted beforehand from the checkpoint index (129 .weight / 129
   .weight_scale_inv, uniformly block-FP8, so the mixed-precision precondition is
   absent). That makes it the control arm proving the gfx950 fusion path itself
   works -- what #36607 shipped unguarded is the decision to use it.

3. bench.sh documents a limitation of its own shape. At the default OSL 320 the
   output is clean; at 3300 it is 40-65 % repetition loops and at 17000 it is
   96-100 %, measured with a 10-gram check on both GLM-5.3 and GLM-5.2. The tok/s
   arithmetic is unaffected -- loopers were measured to decode at the same speed
   as clean requests -- so what is wrong is what the tokens are, not how many per
   second. The cause is NOT established: the leading candidate is this script's
   own --dataset-name random with no --apply-chat-template, and a second is the
   ROCm silent greedy fallback in EAGLE verify. Both were present in every arm
   measured and they are not mutually exclusive.

Recorded because acceptance length does not detect this -- an aggregate of 2.96
with 1.25 % at the 4.00 ceiling was measured while 54 % of the same requests were
looping -- so a user of this kit has no signal unless told.

Signed-off-by: yihou <yihou@amd.com>
The README said the same-host KV handoff is a loopback RDMA transfer and that
the risk is silent slowness. Both are wrong, and the correction changes what a
first bring-up should check.

Read from the mooncake tree and build cache in the shipped image: the pinned
commit 01d1eb2a IS the single-node disaggregation commit (rdma+hip
multi-protocol segments, validated by its author on MI355X). The image builds
USE_HIP=ON with ENABLE_MULTI_PROTOCOL=ON, auto_discover composes hip on top of
rdma so the segment advertises "rdma,hip", registration fans out to both, and
selectTransport routes per request by priority hip 4 > rdma 2. KV therefore
moves over HIP IPC across XGMI with no NIC in the path. Note MOONCAKE_PROTOCOL
defaults to "rdma" and does NOT select the transport on this build.

The real risk is different and is now stated: the kit gives the two legs
disjoint HIP_VISIBLE_DEVICES, so neither can see the other's GPUs. Whether
hipIpcOpenMemHandle imports across that boundary is UNKNOWN and deliberately not
predicted. If it fails it fails loudly at transfer time ("Failed to get kvcache
from prefill instance"), so single-node PD breaks rather than silently
degrading -- provided hip is installed. A probe that settles it in seconds
without loading weights is included.

Also documents two properties of the logging that the existing smoke check
missed: the TCP fallback has no success log at all (detect it by requiring the
positive rdma line), and no log line anywhere reports which transport a transfer
actually used. MC_FORCE_TCP and 'GID is NULL' are cross-host signals and do not
cover the single-node path; the missing check is requiring 'HIP transport
installed for intra-node GPU P2P' in both leg logs.

Signed-off-by: yihou <yihou@amd.com>
…IPC unknown

Both negative, recorded so the next person does not repeat them.

The ROCm 7.2 header says hipIpcOpenMemHandle can attempt to enable peer access
and points at hipDeviceCanAccessPeer to test it -- but that call takes visible
ordinals, and under disjoint HIP_VISIBLE_DEVICES the importer cannot name the
exporter's device at all. The doc is silent on that case.

Mooncake's own three HIP harnesses are all single-process and single-device, and
grep -rn HIP_VISIBLE_DEVICES across that repo returns nothing -- so the pinned
commit's 'prefill GPU0 / decode GPU1' validation is not reproducible from the
tree, and its test suite does not exercise the configuration this kit ships.

Together these are the argument for running the two-process probe rather than
reasoning further about it.

Signed-off-by: yihou <yihou@amd.com>
Two measurements close two open questions in the kits.

flash-fp8 now carries numbers: 99.70 tok/s at conc 1 and 456.68 at conc 8
(isl 7400 / osl 320, TP4, engine port). Against the flash-mxfp4 arm's 111.0 and
561.0 on the identical shape and harness, MXFP4 is 1.11x and 1.23x faster. That
is the first direct FP8-vs-MXFP4 comparison on this architecture at fixed
topology, and it says the quantization is not paying for itself in memory alone.

The 1P1D single-node IPC unknown is answered by measurement rather than left
open. Two processes in one container with disjoint HIP_VISIBLE_DEVICES: the
exporter wrote a byte pattern to its cuda:0, the importer -- which cannot see
that physical GPU -- imported the handle and read the pattern back correctly.
So the kit's disjoint-GPU topology is fine and the --base-gpu-id fallback is not
needed.

Worth recording how that was nearly a false positive: the first attempt returned
IMPORT OK and was not believed, because the handle records device index 0 while
the importer's own ordinal 0 is a different physical GPU -- a purely local
mapping would also return OK. Only the byte pattern distinguishes them. Anyone
repeating this should check the data, not the return code. Also noted:
torch.cuda.cudart() does not expose cudaIpcGetMemHandle in this build; the
storage IPC path is what carries HIP IPC handles here.

Both README validation tables now state what was measured rather than what was
expected.

Signed-off-by: yihou <yihou@amd.com>
Three defects found by source read, before any hardware. As shipped,
`bash cluster.singlenode.sh up` could not work, and one of the three put
the deployment in the silent-slow case the README promises is loud.

1. Both GLM-5.3 wrappers exported IMAGE, but engine/up.sh and common.sh
   require INFERA_IMAGE (the GLM-5.2 wrappers export that name; IMAGE is
   preflight_rdma.sh's). `up` died at its first require_env, before a
   container was started. Export both, and add INFERA_IMAGE to the
   placeholder guard.

2. leg.sh's KV_PUB_PORT/KV_SNAP_PORT were never forwarded by up.sh, and
   nothing a wrapper exports reaches leg.sh otherwise -- on() runs a
   fresh remote shell. Two legs on one host therefore both bound
   5557/8801 and the second died at bind, the same "port_base at N is
   not available" common.sh's reap() warns about across restarts.
   Forward them per leg, defaulting to leg.sh's own values, and give the
   two legs distinct values in the single-node wrapper only.

3. leg.sh hardcoded MC_DISABLE_HIP_TRANSPORT=1 with no override, which
   disables the transport the single-node shape depends on. With hip
   absent the local segment advertises "rdma" only and KV between two
   legs on ONE host takes loopback RDMA -- silently, since there is no
   log line for that fallback and a same-host transfer never touches a
   GID, so neither the MC_FORCE_TCP nor the GID-is-NULL check covers it.
   Make it overridable and set it to 0 in the single-node wrapper.

   THE REASON FOR THE ORIGINAL DISABLE IS UNKNOWN. It was deliberate and
   we could not establish why, so the default stays 1 and the two-node
   path does not move by a byte. If you disabled it for a reason we have
   missed, say so -- this change is scoped to the single-node wrapper
   precisely so it can be objected to cheaply.

   Supporting measurement, on this hardware: HIP IPC works across
   disjoint HIP_VISIBLE_DEVICES. An importer that could not see the
   exporter's physical GPU mapped its memory and read back the correct
   byte pattern, so the disjoint-GPU topology is not an obstacle and the
   --base-gpu-id fallback is not needed. A bare "IMPORT OK" would not
   have shown this -- the handle records device index 0 and the
   importer's own ordinal 0 is a different physical GPU, so a local
   mapping also returns OK. The data pattern is what rules that out.

Verified without hardware, against a stub engine/up.sh: the single-node
wrapper resolves to KV 5557/8801 + 5558/8802 and
MC_DISABLE_HIP_TRANSPORT=0, while the two-node wrapper still resolves to
5557/8801 on both legs and MC_DISABLE_HIP_TRANSPORT=1. All four scripts
pass bash -n.

Required check once this runs: `HIP transport installed for intra-node
GPU P2P` must appear in BOTH leg logs, and `hipIpcOpenMemHandle failed`
in neither.

Signed-off-by: yihou <yihou@amd.com>
Measured on smci355-ccs-aus-n01-33 with preflight_rdma.sh mode, which
returns registration mode A (peer-mem present, 8 x ionic 400 Gb/s, KV
pool full, nothing pinned, MC_GID_INDEX=1 on a routable GID).

Two values that preflight asks for and the wrappers were not supplying:

RDMAV_FORK_SAFE. Recommended in all three of preflight's modes, and
engine/leg.sh honours it only when it is passed in
([ "${RDMAV_FORK_SAFE:-0}" = "1" ]) -- so with the wrapper silent it
never reached the engine. Defaulted to 1 in the SINGLE-NODE wrapper
only. Deliberately not defaulted on for two-node: that shape was
validated end to end without it, and a validated path should not move on
the strength of a recommendation rather than a measurement. Left there
as a commented line with that reasoning.

RDMA_IB_DEVICES. The single-node placeholder read <ionic_0,ionic_1,...>,
which is the cross-node recipe. preflight states the rule for this shape
directly, under mode A: "all active rails (cross-node; mooncake pairs by
GID subnet). Single-node loopback: pin ONE device on both legs instead."
Placeholder and comment now say one device.

That second one interacts with the hip transport enabled in the previous
commit, and the combination is deliberate. preflight emits
MC_DISABLE_HIP_TRANSPORT=1 in all three of its modes and models
single-node PD as loopback RDMA, which contradicts this kit's README --
so there are now two independent sources disagreeing about the intended
single-node transport, and that disagreement may be the unestablished
reason behind leg.sh's original hardcode. Running hip ON with a
correctly pinned single rail covers both readings: if hip installs, KV
goes over XGMI and the rails do not matter; if it does not, the fallback
is the loopback RDMA preflight recommends rather than a misconfigured
eight-rail one. `HIP transport installed for intra-node GPU P2P` in the
leg logs distinguishes the two, and either outcome is a result about the
single-node shape.

Verified against a stub engine/up.sh, no hardware: two-node resolves
RDMAV_FORK_SAFE unset and MC_DISABLE_HIP_TRANSPORT=1 with KV 5557/8801
on both legs -- unchanged from before either commit. Single-node
resolves RDMAV_FORK_SAFE=1, MC_DISABLE_HIP_TRANSPORT=0, KV 5557/8801 and
5558/8802. Both pass bash -n.

Also corrects a claim I made earlier from an inherited note rather than a
test: common.sh's `docker run <etcd-image> etcd --flags` form is fine on
this image -- `docker run --rm quay.io/coreos/etcd:v3.5.14 etcd
--version` prints "etcd Version: 3.5.14". etcd is on PATH. The separate
peer-port collision on 2380 was real when measured, but that port is
free on this node now; it returns only if the foreign etcd does.

Signed-off-by: yihou <yihou@amd.com>
The single-container probe left an untested variable: real PD legs are two
containers, not two processes in one. Repeated across two containers with the
importer on --ipc=host, same disjoint HIP_VISIBLE_DEVICES split, same byte
pattern -- CROSS-CONTAINER IMPORT OK, READ BACK matches.

So the disjoint-device topology is safe at both levels and the --base-gpu-id
fallback is not needed. Caught by flash-fp8-0529, which noticed the shape
mismatch in the original probe spec.

Limits unchanged and still stated: cards 4,5 vs 6,7 rather than the literal
0-3 / 4-7, 1 MiB buffer, one handle, and it exercises the raw HIP IPC call
rather than mooncake's registration path that wraps it. The probe says the door
is unlocked; only 'HIP transport installed for intra-node GPU P2P' in both leg
logs says anyone walked through it.

Signed-off-by: yihou <yihou@amd.com>
The kit said PD for GLM-5.3-Flash was a question it made no claim about. It now
has an answer, from a link-by-link read of the pinned ref c821c425.

The reason to expect it broken: glm5_next keeps two pools, paged KV and a KDA
recurrent-state pool, while PD hands off after prefill. A decode leg starting
its linear-attention layers from a zero state fails as subtly wrong output, not
as a crash.

That premise does not hold. sglang's PD path is not KV-only -- it carries a
generic state-component mechanism, StateType.MAMBA is one of its members, and
glm5_next resolves onto the pool that mechanism reads. Ten links recorded with
file:line, from hybrid_arch.py recognising the model type through
disaggregation/utils.py duck-typing on get_state_buf_infos() to
mooncake/conn.py iterating state_types. No guard refuses the combination, and
that absence was grepped rather than assumed.

So the worry relocates rather than disappearing: from 'not transferred' to
'transferred, but unverified'. Whether the KDA buffers survive the round-trip
bit-exact on gfx950 is untested, and that is still the failure mode that
produces wrong output with nothing logged. Two checks are recorded in order -- a
runtime confirmation that StateType.MAMBA lands in kv_args.state_types, then the
decisive one: same prompt to Flash MIX and Flash PD, greedy, diff the token
sequences. The MIX reference side is already validated.

Three open upstream items in the same area are cited, including #37276 on PD +
mamba + speculative decoding, which is why running Flash PD with MTP off
sidesteps a known bug.

Signed-off-by: yihou <yihou@amd.com>
The single-node section builds its load-bearing unknown on the two legs having
disjoint HIP_VISIBLE_DEVICES. As shipped they had identical ones: up.sh forwards
a fixed list of per-leg variables through on(), which runs a fresh remote shell,
and GPUS was not among them -- so both legs fell through to leg.sh's seq default
and landed on the same four cards. The IPC probe answered a real question; that
question was simply never reached.

Recorded here rather than only in the fix, because of how it failed. The prefill
leg died with 'Raise --mem-fraction-static above 0.773' -- arithmetically correct
and diagnostically wrong. Taking the engine's advice would have let two legs
coexist on four cards and produced a deployment that ran, with every subsequent
number meaningless. The README's existing OOM note covers the failure direction
but not this form.

So the check to run before trusting any memory error is now stated: base_gpu_id
must differ between the leg logs (0 and 4). Cheaper and less ambiguous than
reading VRAM, and it is what distinguishes a tuning problem from a topology one.

Also corrects the leg.sh line reference from :153 to :159.

Signed-off-by: yihou <yihou@amd.com>
…r-leg interface

One design error with six faces. The GLM-5.2 kit's interface is strictly
per-leg -- PREFILL_DPA/DECODE_DPA, PREFILL_MTP/DECODE_MTP,
PREFILL_KVD/DECODE_KVD -- and engine/up.sh forwards exactly the names it
knows, because on() runs a fresh remote shell and nothing else reaches
engine/leg.sh. The GLM-5.3 wrappers invented simplified single knobs
(MTP, DPA, GPUS, EXTRA_ENGINE_ARGS) that the kit reads under no name at
all. Each silently did nothing and fell back to a plausible default, so
none produced an error and two would have produced a believable
benchmark number against a configuration the wrapper file claims is
different.

What each actually did, measured on a live bring-up rather than inferred:

  MTP=0                -> decode leg launched with mtp=1 (up.sh default
                          DECODE_MTP:-1). Caught in flight from the
                          resolved-args line; the run was killed 3 min in.
  GPUS                 -> PREFILL_GPUS/DECODE_GPUS read by nobody, so
                          leg.sh:26 fell back to `seq 0..TP-1` on BOTH
                          legs. Both loaded onto GPUs 0-3: measured
                          263.8 GB per card on 0-3 with 4-7 at 0.3 GB.
                          The prefill leg then died on "Loaded weights
                          leave no GPU memory for the KV cache under
                          --mem-fraction-static=0.7", which reads as a
                          GMU tuning problem and is not one -- raising it
                          would have produced two legs sharing four cards.
                          The decode leg meanwhile came up healthy and
                          registered in etcd, so a router would have
                          found one worker and served: a "PD deployment"
                          that is quietly a single aggregated leg.
  EXTRA_ENGINE_ARGS    -> leg.sh hardcoded EXTRA_ARGS=(--enable-cache-report),
                          so --disable-shared-experts-fusion never reached
                          the engine.
  DPA=1                -> read by nobody, but up.sh's defaults are
                          PREFILL_DPA:-0 / DECODE_DPA:-1, which is the
                          intended configuration. Silently CORRECT by
                          luck. Worse than visibly broken: DPA=0 for a
                          single-variable round would have produced dp8
                          anyway with nothing said.
  INFERA_IMAGE, KV ports -> fixed in 4493e33.

Fixes, all preserving today's behaviour where a path is already validated:

  up.sh forwards GPUS per leg with ${PREFILL_GPUS:+GPUS=...}, injection
  only when set. NOT a :- default: that would push a literal GPU list
  into the two-node path, where leg.sh's `seq 0..TP-1` is correct and
  stays correct if TP changes.

  up.sh forwards EXTRA_ENGINE_ARGS through COMMON_ENV, quoted so several
  flags survive as one value. leg.sh appends it unquoted to EXTRA_ARGS so
  they word-split. Empty when unset, so the GLM-5.2 kit's own wrappers --
  which do not define it -- are unaffected.

  Both GLM-5.3 wrappers now export the per-leg names the kit reads, with
  the single knob kept only as a convenience seed (PREFILL_MTP:-$MTP).

  cluster.2node.sh's PREFILL_GPUS/DECODE_GPUS are now UNSET rather than a
  literal 0..7. Now that up.sh forwards them, pinning eight cards would
  silently contradict TP=4; unset keeps leg.sh's TP-derived default.

Verified by running the real engine/up.sh with SSH_CMD=echo, so every
per-leg command is printed instead of executed -- no node, no container,
no GPU:

  single-node  prefill GPUS=0,1,2,3  decode GPUS=4,5,6,7
               MTP 0/0, DPA 0/1, KV 5557/8801 + 5558/8802,
               MC_DISABLE_HIP_TRANSPORT=0, EXTRA_ENGINE_ARGS forwarded
  two-node     GPUS absent from both legs (leg.sh default applies),
               MTP 0/0, DPA 0/1, KV 5557/8801 both, hip disable 1

All four scripts pass bash -n.

For the record: this is the fifth and sixth defect of this class in a kit
that had never been run end to end in this shape, which is what "not yet
run" means rather than a criticism of the kit. The GLM-5.2 wrappers have
no dead exports -- all 28 are read -- so the validated two-node GLM-5.2
runs took their configuration and nothing here casts doubt on them. The
defect is ours. Static greps under-detect it: up.sh contains the literal
string "MTP=${PREFILL_MTP:-0}", so a word-boundary search for MTP matches
an occurrence that is being assigned to, not read. The reliable test is
to launch and read the resolved-args line.

Signed-off-by: yihou <yihou@amd.com>
Corrects a check this file recommended one commit ago (e4ab8fe). base_gpu_id is
an index into the VISIBLE device set, and HIP_VISIBLE_DEVICES=4,5,6,7 renumbers
the decode leg's devices to 0-3 -- so it reads 0 on both legs when the split is
broken and 0 on both legs when it is correct. It does not discriminate at all,
and following the previous advice would have produced a confident all-clear on a
broken topology.

The VRAM read is the check. It is more expensive, it is the only unambiguous one
here, and 'more expensive' was the wrong reason to look for a substitute.

Caught by the operator running the relaunch, who checked the proposed check
against a now-correct deployment rather than assuming it worked.

Signed-off-by: yihou <yihou@amd.com>
Note 3 taught two failure directions for --mem-fraction-static, both
under load: prefill activation OOM at low token usage means lower it,
decode retract at high token usage means raise it. The single-node
bring-up hit a third form that neither covers, and in which the engine's
own suggested fix is a trap.

A leg aborts during startup profiling, weights loaded, no request served:

  ValueError: Loaded weights leave no GPU memory for the KV cache under
  --mem-fraction-static=0.7. Raise --mem-fraction-static above 0.773

0.773 is arithmetically correct -- it is derived from the memory actually
free at that instant. It is diagnostically wrong, because the reason
there is none is that the other leg is on the same cards. Measured:
GPUs 0-3 at 263.8 GB each, 4-7 at 0.3 GB. Following the advice yields a
WORKING deployment on the wrong topology, with every subsequent number
meaningless and nothing logged to say so.

The note now says to check the cards before touching the knob, names the
two checks that do NOT work (--showmemuse VRAM%, which does not fall when
memory is released; and per-leg base_gpu_id, which is an index into the
visible set and reads 0 on both legs whether the split is broken or
correct -- see 635fc51), and gives the discriminator between all three
forms: this one aborts at startup profiling, the classic prefill form
aborts under load at low token usage, the decode form retracts under load
at high token usage.

Written from the bring-up that hit it. The underlying GPU-split cause is
fixed in 1b5ea46; this note is for the next person whose legs collide for
some other reason.

Signed-off-by: yihou <yihou@amd.com>
leg.sh:60 exports MC_DISABLE_HIP_TRANSPORT=1 and unsets
MC_ENABLE_HIP_TRANSPORT. Neither name exists in the shipped mooncake binary --
exact-match against mooncake/engine.*.so finds MC_DISABLE_HIP, MC_USE_HIP_IPC
and MC_FORCE_TCP, and zero matches for either _TRANSPORT spelling.

Confirmed behaviourally, which is the stronger half: a run launched with
MC_DISABLE_HIP_TRANSPORT=1, verified present in the process environment via
/proc, still logged 'HIP transport installed for intra-node GPU P2P' 4x per leg
-- identical to a run without it.

So the line has never had an effect in either path. It is not evidence that
anyone deliberately disabled hip, which is likely why no reason for it could be
established: there was no effect to reason about. INFERRED that the author
intended to disable hip and used a name that does not exist.

Practical consequence for anyone testing the transport: an A/B must set
MC_DISABLE_HIP. Using the _TRANSPORT spelling yields a guaranteed-zero
differential that reads as a null result rather than a broken experiment --
the same trap as base_gpu_id, one level up. The discriminator to check is
'HIP transport installed for intra-node GPU P2P' going 4/4 to 0/0.

Signed-off-by: yihou <yihou@amd.com>
…ISABLE_HIP

leg.sh has set MC_DISABLE_HIP_TRANSPORT=1 and unset
MC_ENABLE_HIP_TRANSPORT since it was written. Neither name exists in the
shipped mooncake build, so neither line has ever had an effect -- in the
two-node shape or the single-node one.

Exact-match against mooncake/engine.cpython-310-x86_64-linux-gnu.so in
infera/engine-sglang:v0518-glm53:

  MC_DISABLE_HIP             1     <- the real knob
  MC_DISABLE_HIP_TRANSPORT   0
  MC_ENABLE_HIP_TRANSPORT    0
  MC_USE_HIP_IPC             1     <- a second gate, uninvestigated
  MC_FORCE_TCP               1

The behavioural evidence came first and is the stronger half. A
single-node pair launched with MC_DISABLE_HIP_TRANSPORT=1 -- confirmed
present in /proc/<pid>/environ for both engine processes -- still logged
"HIP transport installed for intra-node GPU P2P" 4 times per leg, with
zero install failures, exactly as the run with it set to 0. The strings
table only names the reason.

Consequences, including for a claim made earlier in this branch:

- The single-node shape was NEVER at risk of silently falling back to
  loopback RDMA through that knob. Any statement that "as shipped, KV
  would have moved over loopback RDMA" is WRONG and is retracted here.
  hip installs regardless.
- Making MC_DISABLE_HIP_TRANSPORT overridable (earlier on this branch)
  is therefore NOT a fix. It makes a dead knob configurable and changes
  nothing. It is kept only so it reads as the pair to the live name.
- INFERRED: whoever wrote the original hardcode probably intended to
  disable hip and used a name that does not exist. That would explain
  why no reason for the line could be established -- there was no effect
  to reason about. It also retires the apparent conflict with
  preflight_rdma.sh, which recommends the same dead name.

The fix is to forward the name that works. MC_DISABLE_HIP is passed
through COMMON_ENV in up.sh and into the leg's docker exec env in
leg.sh, both with ${VAR:+...} so an unset variable injects nothing and
the two-node path is byte-identical. cluster.singlenode.sh exports it
unset by default -- hip on is what that shape wants.

Verified by running the real engine/up.sh with SSH_CMD=echo, no node:
MC_DISABLE_HIP=1 appears exactly twice (once per leg); unset, it appears
zero times on both the single-node and two-node wrappers. All four
scripts pass bash -n.

Practical rule, recorded in both files: a hip-on/hip-off A/B MUST use
MC_DISABLE_HIP and MUST confirm the discriminator flipped -- "HIP
transport installed for intra-node GPU P2P" going from 4 per leg to 0 --
before benchmarking. With the dead name it produces a guaranteed-zero
differential that reads as a null result rather than a broken
experiment. That is the same shape as the base_gpu_id check retired in
635fc51: a control that returns the same value in both states.

Signed-off-by: yihou <yihou@amd.com>
… selection not installation

Three corrections to the transport section, all from a re-read at the commit that
actually built the shipped .so.

Two-node PD never uses hip regardless of configuration. selectTransport calls
isHipReachableTarget() and skips hip buffers for any off-host target, with the
in-source rationale that the intra-node fast path and the cross-node path should
work from one multi-protocol segment 'without requiring the operator to set
MC_DISABLE_HIP'. So every hip question in this kit is a single-node question and
none of it applies to cluster.2node.sh. The file previously implied otherwise.

Installation is unconditional -- transfer_engine_impl.cpp:402-414 is a bare
#ifdef USE_HIP. Selection is what MC_DISABLE_HIP gates, at
multi_transport.cpp:489, demoting hip from priority 4 to 0 so rdma wins for the
device KV pool.

That distinction is why 'HIP transport installed for intra-node GPU P2P' cannot
serve as a hip-off discriminator: it is an install-time log and the variable acts
at selection time, so it reads 4/4 in both states forever. A correct hip-off
deployment was discarded unmeasured on the strength of that non-flip. Verifying
such an arm needs MC_DISABLE_HIP=1 in /proc/<pid>/environ on both legs plus the
source read; no log line will confirm it.

Also records that MC_DISABLE_HIP_TRANSPORT -- which leg.sh:60 sets -- and
MC_ENABLE_HIP_TRANSPORT are absent from the binary entirely. Two dead names, one
live name whose effect is invisible to the natural check.

Signed-off-by: yihou <yihou@amd.com>
The section established that the KDA state is transferred and read as though a
Flash PD run were planned. It is not, and the file should not imply otherwise.

Retitled and headed with what the section actually is: a source read showing the
shape is possible, never a validation, with no Flash PD deployment ever brought
up. Recorded so the next person starts from the code reads instead of repeating
them, and so 'we did not do this' is not read as 'this does not work'.

Signed-off-by: yihou <yihou@amd.com>
Raised by an automated review of the packup scripts; the same patterns are in
the live kit, which is what people will actually run.

The scripts use --network=host and bind on all interfaces. That is fine for a
single-tenant benchmark box and wrong for a shared one, and the reference
cluster is shared -- three unrelated users logged into one of these nodes during
a single day of this work, and a colleague's job claimed all eight GPUs of
another without notice.

etcd is the one that matters: unauthenticated, on 0.0.0.0, holding the worker
discovery keys that tell the router where to send traffic. The router and KV
event sockets are also raw.

Left as validated rather than quietly re-bound, because changing a bind changes
a recipe that was measured -- but the README now says so explicitly and gives
the fix, which is cheap since router and workers are colocated.

Also records that --trust-remote-code is not removable (glm5_next is in no
released transformers), so the exposure is the checkpoint directory rather than
the flag: /apps/data/models is a shared NFS mount, and anyone who can write
there can execute code in your container.

Signed-off-by: yihou <yihou@amd.com>
…that candidate

The header named a missing chat template as the leading candidate for long-output
repetition, on the strength of apply_chat_template=False in the benchmark args
dump. That reading is wrong and the candidate is eliminated, not merely untested.

On this backend the flag is parsed and never consumed -- grep for it in sglang's
benchmark/serving.py returns one hit, an assignment that fires only for the
image/mmmu datasets. And --backend sglang-oai-chat posts messages to
/v1/chat/completions, which applies the model's chat template server-side by
definition. The template has been applied in every arm all along.

A flag that is parsed but unread reads exactly like a setting, which is why the
args dump was misleading rather than wrong.

What remains is stated: the prompt CONTENT is synthetic seeded-ShareGPT filler,
which is a different thing from missing framing, and the ROCm greedy fallback in
EAGLE verify -- noting that every arm measured as degenerate ran MTP ON, so that
path was live in all of them. The stale advice to add --apply-chat-template for
defensible long-OSL numbers is replaced with a note that it will not help.

Signed-off-by: yihou <yihou@amd.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant