fix(glm5.2): the remaining fixes for agentic serving — DSA indexer, ROCm hicache, PD/kvd wiring - #79
Merged
Conversation
dorado269
requested review from
JohnQinAMD,
jiejingzhangamd,
limou102 and
xiaobochen-amd
as code owners
August 3, 2026 10:29
dorado269
marked this pull request as draft
August 3, 2026 10:33
…PD/kvd wiring
Everything still missing from main that GLM-5.2 needs to run an agentic workload
with kvaware + kvd + MTP + PD + DP-attention on at once. Established across
several debugging runs on two clusters; this is the formalised subset.
Engine correctness — the image crashes without these. Both vendor sglang inside
the image at build time and touch no infera runtime code. Both are ROCm-only
defects that upstream CI cannot see, because the CUDA path is correct by
accident of a platform difference.
patches/sglang_dsa/patch_dsa_indexer_hip_dp_padded_rows.py (GLM52_P1V3)
The aiter paged-MQA row count and `lengths` disagree in BOTH directions, not
just under DP padding: on an idle rank under MTP draft-extend q_offset
overcounts the rows in q_fp8, so there is nothing to trim and the lengths must
be clipped instead. Reconciles both sides to min(real, padded). Without it
"Expected lengths.size(0) == B" kills a decode scheduler rank ~13 minutes into
an agentic run and the router drops to active_workers: 1.
patches/sglang_rocm/patch_hicache_rocm_host_alloc.py (new)
hipHostRegister maps host pages at a device address that is not the host VA,
but the hicache pools hand raw host data_ptr()s to GPU kernels through
device-side pointer tables. The kernel dereferences an unmapped address and
the process aborts with "Memory access fault by GPU node-N on address <host
VA>" the moment kvd writes back; gfx950 is xnack-, so there is no migration
fallback. Routes HIP to hipHostMalloc, as "npu" and "musa" already are.
infera correctness — startup failure or silent degradation.
args.py don't append --disaggregation-decode-enable-radix-cache under
speculative decoding; sglang rejects the combination outright,
so the MTP decode leg dies during argument parsing.
net.py randomise the free-port-block scan start. The probe cannot hold
the block, so a fixed start made collisions deterministic: two
PD legs on one host picked the same base and the second died
with ZMQError: Address already in use.
storage_classify.py strip the bind-mount [subpath] from the findmnt source,
or lsblk reports "not a block device" and kvd's L3 silently
degrades to buffered on O_DIRECT-capable hardware.
Behavioural, not a bug fix.
kvd_wiring.py skip kvd on a PD decode leg. Sglang issues no storage prefetch
on the decode branch, so L3 there is write-only — 180 sets / 0
gets against a prefill leg's 102/102 on the same run.
Tests extend the files that already covered these areas: two cases for the port
randomisation, one for the findmnt strip, and a real-socket case for main's
bigram kv-event decode, whose failure mode is silent (empty view, cache_hits
pinned at 0, nothing errors).
patch.upstream.status.md gains a row for the new ROCm patch and one recording
two upstream PRs that rewrite what patch 01 anchors on (#32738, #31480) —
neither fixes this defect, both would drift the anchors. Upstream state
re-queried 2026-08-03; for the allocator, upstream main was read directly rather
than searched, and still has no HIP entry.
Verified: the real build script applies both arms end-to-end against a clean
v0.5.15.post1 tree and finds every marker in the bytecode; both infera fixes
fail their tests when reverted. Not verified here: the Rust test (local cargo
cannot read the v4 lockfile) and anything needing an engine image.
Signed-off-by: yihou <yihou@amd.com>
dorado269
force-pushed
the
yihou.dev.glm52.agentic.final.pr
branch
from
August 3, 2026 12:55
251f709 to
9380f07
Compare
dorado269
marked this pull request as ready for review
August 3, 2026 12:55
kzjeef
approved these changes
Aug 3, 2026
| the device-pointer measurements above are the evidence. Blocked | ||
| only on someone opening it. | ||
|
|
||
| Idempotent and self-locating. Run inside the container, then delete stale .pyc. |
There was a problem hiding this comment.
This really require a formal patch for upstream, it can be produce with SGLANG + HICache + DSA model .
This combo is leak of test case in upstream.
please submit a upstream fix for this bug.
Collaborator
Author
There was a problem hiding this comment.
will do within one week
jiejingzhangamd
added a commit
that referenced
this pull request
Aug 3, 2026
The GLM-5.2 header recorded 'No Address already in use' from the DP attention run, worded so it reads as 'main has this bug and we did not trip it'. Two things are wrong with that now. The run predates #79, which landed the randomised scan start in free_tcp_port_block on main -- the same fix #59 carried. So the risk is retired, not merely untriggered. And the observation proved less than the wording implied even at the time: that collision needs two engines on ONE host, and a cross-node PD pair cannot produce it. Recording a clean result from a topology that cannot fail the test reads as evidence when it is not. Both the manifest header and the README table now say this. Signed-off-by: Zhang, Jiejing <jiejing.zhang@amd.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.
What this is
Everything still missing from
mainthat GLM-5.2 needs to runOptimus-AgenticBench Case A with kvaware + kvd + MTP + PD + DP-attention all
on at once. The fixes were established across several debugging runs on two
clusters; this branch is the formalised subset, cut fresh off
main.Much of that work has already reached
mainby other routes — PR #58 (the DSAset, since evolved by
1380228), PR #56, and the individual fixes786f238,05841f9,b398268+c178b69,e190d65,2c31a3f. None of it isre-carried here. In particular
main's NodePort guard and ready-timeout arestronger than the versions that existed on the experiment branch, and its
args.pyfp8 ordering is the correct one — all three were left alone.Supersedes #59, which carried items 6–9 below against an older
mainplusexperiment packups. Close that one when this merges.
The commits, by kind
Engine correctness — the image crashes without these (2)
Both patch vendor SGLang inside the image at build time; neither touches infera
runtime code. Both are ROCm-only defects where the CUDA path is correct by
accident of a platform difference, which is why upstream CI cannot see them.
9929c94GLM52_P1V3— the DSA indexer row count diverges in both directionsExpected lengths.size(0) == Bkills a decode scheduler rank, router drops toactive_workers: 1. Reproducible ~13 min into Case Ab1d8103hipHostMallocMemory access fault by GPU node-N on address <host VA>the moment kvd writes back; gfx950 isxnack-, so a hard abortinfera correctness — startup failure or silent degradation (3)
7e9cf0d30300adZMQError: Address already in usef0c328d[subpath]from the findmnt sourcelsblksays "not a block device", so kvd's L3 silently degrades to buffered on hardware that qualifies for O_DIRECTBehavioural optimisation — not a bug fix (1)
4b14403— skip kvd wiring on a PD decode leg. SGLang issues no storageprefetch on the decode branch, so L3 there is write-only: measured at 180 sets /
0 gets against a prefill leg's 102/102 on the same run. Saves host memory and
D2H bandwidth.
Tests for fixes already on
main(2)Neither carries production code.
fc11a73main's05841f9Python bigram decode — 175 lines of behavioural coverage618bfecmain's Rustas_u32_any.mainhas the in-crate unit test but not the real-socket path, which is where a live deployment meets it — and the failure is silent (view stays empty,cache_hitspinned at 0, nothing errors)Docs and patch bookkeeping (5)
157d535kvd is no longer vLLM-only in the feature matrix, plus the SGLangsection ·
aabcb0ca 276-line operator guide for KV-aware + kvd ·7909361aREADME for
deploy/docker/, which had none ·21a860bcorrects a staleportability claim about patch 01 ·
28319cfgives the ROCm allocator patch theupstream-status block and index row that
deploy/docker/README.mdrequires ofevery patch ·
e995e07compresses over-long inline comments, scrubs clusteridentifiers, and records two upstream PRs that collide with patch 01's anchors
(see Review follow-ups).
Added then dropped (2)
4f9834daddedDockerfile.sglang.kvaware-kvd;97c2ff5removed it againalong with its two doc references. It was contents-identical to
Dockerfile.sglang, so it bought a second file to keep in sync and nothingelse. Net effect on the tree is zero — left as two commits rather than a
rewrite, since the branch is already under review.
Size
22 files, +1565/−69. Under
infera/the whole change is 4 files, +87 lines;the two engine patches plus their README are +428 but live entirely in
deploy/docker/patches/. The remaining ~1000 lines are tests (514) and docs.No experiment packups.
Verification
Patch 01 applies to the pinned base, and the build script proves it. Run
end-to-end against a clean
v0.5.15.post1dsa_indexer.pyexported from a realSGLang checkout (not
--dry-run, notgit apply --check):apply_sglang_dsa_patches.shwithDSA_PATCH_SET=indexerapplies the patch,byte-compiles it, finds both markers in the bytecode, and exits 0. A second
run reports "already present" — idempotent.
The second marker discriminates.
21a860b's companion change (already in9929c94) added_p1v2_rowsbeside_p1v2_trimbecause the latter alone couldnot tell the one-directional revision from the fixed one. Confirmed by applying
main's pre-P1V3 patch 01 and running the same verification:_p1v2_trimpyc=1 — it would have passed — while
_p1v2_rowspyc=0 fails the build. Theextra marker is load-bearing, not decorative.
The
ke_offsetroute is a real, precedented API. Read against the pinnedbase:
ke_offsetis an existing parameter ofDSAIndexerMetadata.topk_transformwhose sole effect is to override
seq_lens_topk(dsa_backend.py:310-311), itis already used that way at
dsa_indexer.py:1217, andDSAIndexerMetadataisthe only concrete implementation — so no third-party subclass can hit a
TypeErroron the added kwarg.Both new infera fixes fail without the fix. Verified with a revert harness
rather than by inspection, since a test that passes on the pre-fix code proves
nothing: removing the decode-leg guard makes
test_decode_leg_gets_no_hicache_flagsfail; removing the randomisation makes10 consecutive
free_tcp_port_block(4)calls return the identical base 29996and fails
test_repeated_calls_do_not_all_collide. Restored, 73 tests pass.Upstream status re-queried 2026-08-03, not taken from the header: #33059,
#32762, #31683 OPEN; #30378, #30427 MERGED — all matching what the patch header
claims. For the ROCm allocator, upstream
main'spool_host/common.pywas readdirectly:
ALLOC_MEMORY_FUNCSstill overrides only"npu"and"musa", no HIPentry, so main is affected too.
The two ROCm engine patches were each measured on hardware before being
formalised here — the allocator by a standalone micro-repro of the exact kernel
that faults and un-faults on the allocator alone, and
GLM52_P1V3by twoindependent Case A crashes followed by two clean ~4,000 s windows on two
different clusters.
Review follow-ups
Found reviewing this branch against the repo's own conventions. All
documentation-only, all fixed in-branch:
21a860b— the build script and the gfx942 recipe still described patch 01 ashaving "two edit sites, byte-identical on both releases". It has five, and only
the
GLM52_P1V2ones were re-read against v0.5.16. The gfx942 image is the onearm that depends on that claim, so the two files a reader consults before
bumping that base were the two still asserting the stronger version.
28319cf—deploy/docker/README.md, added in this branch, requires everypatch to carry its upstream issue/PR and a row in
patch.upstream.status.md.The
sglang_rocmpatch added in this same branch had neither.e995e07— three things at once, since they touched the same text:(a) nine inline comment blocks ran over the 3-line limit, up to 29 lines.
Compressed to what/why/how, with the case analysis and the rejected
0 < q_offsetvariant moved to the patch header and README rather thandeleted — that variant passes every functional test, so losing the note
invites a retry. (b) two cluster names, three pointers to scripts that
exist only in a private workspace, and an internal workload name were still
in files headed for a public repo; replaced with this README's existing
"internal reproduction kit, ask the patch author" convention, keeping the
evidence-strength qualifiers. (c) searching for the function rather than
the symptom surfaced two OPEN upstream PRs that rewrite what patch 01 anchors
on — #32738 (pads heads at
the same two aiter call sites) and
#31480 (extracts the
paged-MQA backend, restructuring the
is_aiter()dispatch). Neither fixesthis defect; both drift the anchors, which fails the build rather than
mis-applying. This is precisely the
gh searchblind spot the header warnsabout, and the P1V3 half had never been searched on its own terms before —
it now has been: still no upstream issue or PR.
What is NOT established yet
Patch 01's
GLM52_P1V3anchor on the gfx942 v0.5.16 base. Verified onv0.5.15.post1(above); on v0.5.16 it has been reasoned about — the added_mask_init_and_local_tokenscall sits before rather than inside the anchoredtopk_transformcall — but not measured, because there is no v0.5.16 checkouthere. A drift writes nothing and exits 1, so the failure mode is a failed build,
not a mis-applied patch. The patch header, the build script and the README all
now say this rather than claiming both bases are covered.
The Rust wire-level test (
618bfec) has not been compiled. The devworkstation's cargo is 1.75 and cannot read this repo's v4
Cargo.lock(
-Znext-lockfile-bump). It is purely additive andrust/router/src/isuntouched, but neither its compilation nor its own pre-fix failure has been
demonstrated. CI is the gate.
test_decode_radix_vs_speculative.pydid not execute here — it isimportorskip("sglang")and skips outside the engine image. Its third casedepends on SGLang's own
ServerArgs.__post_init__raising, which is externalbehaviour.
Cluster acceptance — build, kvd/kvaware feature proofs, Case A — runs next; I
will post results on this PR.
Deliberately out of scope
Prefill
--mem-fraction-static0.88 → 0.80 (an experiment-environment value,not a defect — it stays in the reproduction kits) and the kvd
--long-bytes512G → 64G value (a single node's disk artefact, verified inapplicable
elsewhere).