Skip to content

fix(glm5.2): the remaining fixes for agentic serving — DSA indexer, ROCm hicache, PD/kvd wiring - #79

Merged
jiejingzhangamd merged 1 commit into
mainfrom
yihou.dev.glm52.agentic.final.pr
Aug 3, 2026
Merged

fix(glm5.2): the remaining fixes for agentic serving — DSA indexer, ROCm hicache, PD/kvd wiring#79
jiejingzhangamd merged 1 commit into
mainfrom
yihou.dev.glm52.agentic.final.pr

Conversation

@dorado269

@dorado269 dorado269 commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

What this is

Everything still missing from main that GLM-5.2 needs to run
Optimus-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 main by other routes — PR #58 (the DSA
set, since evolved by 1380228), PR #56, and the individual fixes 786f238,
05841f9, b398268+c178b69, e190d65, 2c31a3f. None of it is
re-carried here.
In particular main's NodePort guard and ready-timeout are
stronger than the versions that existed on the experiment branch, and its
args.py fp8 ordering is the correct one — all three were left alone.

Supersedes #59, which carried items 6–9 below against an older main plus
experiment 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.

commit fix symptom without it
9929c94 GLM52_P1V3 — the DSA indexer row count diverges in both directions Expected lengths.size(0) == B kills a decode scheduler rank, router drops to active_workers: 1. Reproducible ~13 min into Case A
b1d8103 ROCm hicache host allocator → hipHostMalloc Memory access fault by GPU node-N on address <host VA> the moment kvd writes back; gfx950 is xnack-, so a hard abort

infera correctness — startup failure or silent degradation (3)

commit fix symptom without it
7e9cf0d don't append the decode radix cache under speculative decoding SGLang rejects the flag outright: the MTP decode leg dies during argument parsing, before loading a weight
30300ad randomise the free-port-block scan start two PD legs on one host deterministically pick the same base; the second dies with ZMQError: Address already in use
f0c328d strip the bind-mount [subpath] from the findmnt source lsblk says "not a block device", so kvd's L3 silently degrades to buffered on hardware that qualifies for O_DIRECT

Behavioural optimisation — not a bug fix (1)

4b14403 — skip kvd wiring on a PD decode leg. SGLang issues no storage
prefetch 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.

commit covers
fc11a73 main's 05841f9 Python bigram decode — 175 lines of behavioural coverage
618bfec main's Rust as_u32_any. main has 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_hits pinned at 0, nothing errors)

Docs and patch bookkeeping (5)

157d535 kvd is no longer vLLM-only in the feature matrix, plus the SGLang
section · aabcb0c a 276-line operator guide for KV-aware + kvd · 7909361 a
README for deploy/docker/, which had none · 21a860b corrects a stale
portability claim about patch 01 · 28319cf gives the ROCm allocator patch the
upstream-status block and index row that deploy/docker/README.md requires of
every patch · e995e07 compresses over-long inline comments, scrubs cluster
identifiers, and records two upstream PRs that collide with patch 01's anchors
(see Review follow-ups).

Added then dropped (2)

4f9834d added Dockerfile.sglang.kvaware-kvd; 97c2ff5 removed it again
along with its two doc references. It was contents-identical to
Dockerfile.sglang, so it bought a second file to keep in sync and nothing
else. 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.post1 dsa_indexer.py exported from a real
SGLang checkout (not --dry-run, not git apply --check):
apply_sglang_dsa_patches.sh with DSA_PATCH_SET=indexer applies 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 in
9929c94) added _p1v2_rows beside _p1v2_trim because the latter alone could
not tell the one-directional revision from the fixed one. Confirmed by applying
main's pre-P1V3 patch 01 and running the same verification: _p1v2_trim
pyc=1 — it would have passed — while _p1v2_rows pyc=0 fails the build. The
extra marker is load-bearing, not decorative.

The ke_offset route is a real, precedented API. Read against the pinned
base: ke_offset is an existing parameter of DSAIndexerMetadata.topk_transform
whose sole effect is to override seq_lens_topk (dsa_backend.py:310-311), it
is already used that way at dsa_indexer.py:1217, and DSAIndexerMetadata is
the only concrete implementation — so no third-party subclass can hit a
TypeError on 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_flags fail; removing the randomisation makes
10 consecutive free_tcp_port_block(4) calls return the identical base 29996
and 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's pool_host/common.py was read
directly: ALLOC_MEMORY_FUNCS still overrides only "npu" and "musa", no HIP
entry, 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_P1V3 by two
independent 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 as
    having "two edit sites, byte-identical on both releases". It has five, and only
    the GLM52_P1V2 ones were re-read against v0.5.16. The gfx942 image is the one
    arm that depends on that claim, so the two files a reader consults before
    bumping that base were the two still asserting the stronger version.
  • 28319cfdeploy/docker/README.md, added in this branch, requires every
    patch to carry its upstream issue/PR and a row in patch.upstream.status.md.
    The sglang_rocm patch 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_offset variant moved to the patch header and README rather than
    deleted — 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 fixes
    this defect; both drift the anchors, which fails the build rather than
    mis-applying. This is precisely the gh search blind spot the header warns
    about, 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_P1V3 anchor on the gfx942 v0.5.16 base. Verified on
v0.5.15.post1 (above); on v0.5.16 it has been reasoned about — the added
_mask_init_and_local_tokens call sits before rather than inside the anchored
topk_transform call — but not measured, because there is no v0.5.16 checkout
here. 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 dev
workstation's cargo is 1.75 and cannot read this repo's v4 Cargo.lock
(-Znext-lockfile-bump). It is purely additive and rust/router/src/ is
untouched, but neither its compilation nor its own pre-fix failure has been
demonstrated. CI is the gate.

test_decode_radix_vs_speculative.py did not execute here — it is
importorskip("sglang") and skips outside the engine image. Its third case
depends on SGLang's own ServerArgs.__post_init__ raising, which is external
behaviour.

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-static 0.88 → 0.80 (an experiment-environment value,
not a defect — it stays in the reproduction kits) and the kvd --long-bytes
512G → 64G value (a single node's disk artefact, verified inapplicable
elsewhere).

@dorado269
dorado269 marked this pull request as draft August 3, 2026 10:33
@dorado269 dorado269 changed the title fix(glm5.2): the remaining fixes for agentic serving — DSA indexer, ROCm hicache, PD/kvd wiring [wip] fix(glm5.2): the remaining fixes for agentic serving — DSA indexer, ROCm hicache, PD/kvd wiring Aug 3, 2026
…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
dorado269 force-pushed the yihou.dev.glm52.agentic.final.pr branch from 251f709 to 9380f07 Compare August 3, 2026 12:55
@dorado269
dorado269 marked this pull request as ready for review August 3, 2026 12:55
@dorado269 dorado269 changed the title [wip] fix(glm5.2): the remaining fixes for agentic serving — DSA indexer, ROCm hicache, PD/kvd wiring fix(glm5.2): the remaining fixes for agentic serving — DSA indexer, ROCm hicache, PD/kvd wiring 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do within one week

@jiejingzhangamd
jiejingzhangamd merged commit 277b82d into main Aug 3, 2026
37 of 39 checks passed
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>
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.

3 participants