Skip to content

Bump sglang to v0.5.16 and add GLM-5.2 support - #13

Open
TerrenceZhangX wants to merge 3 commits into
mainfrom
bump-sglang-v0.5.16
Open

Bump sglang to v0.5.16 and add GLM-5.2 support#13
TerrenceZhangX wants to merge 3 commits into
mainfrom
bump-sglang-v0.5.16

Conversation

@TerrenceZhangX

Copy link
Copy Markdown
Contributor

The pinned sglang v0.5.5 predates GLM-5.2, so the model could not be profiled at all. v0.5.16 registers GlmMoeDsaForCausalLM natively.

sglang submodule: 0c006b8 (v0.5.5) -> fdebc93 (v0.5.16).

  • workload/framework/patches/hook-v0516.patch: port of hook.patch to v0.5.16, whose triton kernels moved into the new sglang/kernels/ops/ package. apply_auto_profile() patches a module attribute, and call sites use from X import y (early binding), so hooks must be registered on the consumer module rather than the definition site. That makes most of the original source edits unnecessary: only raw triton.JITFunction objects still need a launch_* wrapper extracted, since wrapping one directly breaks kernel[grid](...) syntax. Also fixes a KeyError in the launcher hook (env["..."] on an unset var).

  • dockerfiles/sglang-cu130.dockerfile: layer FlowSim on the official lmsysorg/sglang release image instead of building sglang from source. cuda12.6.dockerfile targets sm_90 and below, so it cannot run on Blackwell (GB200/B200, sm_100+), and building sglang + DeepGEMM from source on aarch64 is slow and fragile. The base image is a git checkout of the pinned commit with sglang installed editable, so the patch applies to it directly. Needs no network access, which GPU hosts frequently lack.

  • workload/models/configs/GLM-5.2: truncated config following the existing deepseek convention (num_hidden_layers 2 + first_k_dense_replace 1 => one dense layer and one MoE layer, full 256 experts). config_full.json keeps the upstream config so the truncation stays auditable.

  • utils/shape_merge: don't fail when a kernel's launch count differs between the CUDA-graph and eager passes. Disabling CUDA graphs can legitimately change the launch sequence -- GLM-5.2's DSA decode backend replays one fused _fused_dsa_decode_metadata_kernel under CUDA graph but issues arange/fill/cumsum/index/add separately in eager mode. Positional matching would attach the wrong shapes to those rows, so they now keep their timing-pass values and are reported; strict=True restores the old behaviour. Previously this aborted the whole merge over a handful of metadata kernels.

  • tests/integration/test_model_config.py: --batch is ambiguous in v0.5.16 (--batch-notify-size vs --batch-size); cap --context-length so GLM-5.2's 1M max_position_embeddings doesn't OOM the KV pool.

Verified on GB200 (aarch64, CUDA 13.0, TP=1): --collect all completes for GLM-5.2 and produces merged EXTEND and DECODE kernel CSVs.

TerrenceZhangX and others added 3 commits July 31, 2026 13:41
The pinned sglang v0.5.5 predates GLM-5.2, so the model could not be
profiled at all. v0.5.16 registers GlmMoeDsaForCausalLM natively.

sglang submodule: 0c006b8 (v0.5.5) -> fdebc93 (v0.5.16).

- workload/framework/patches/hook-v0516.patch: port of hook.patch to
  v0.5.16, whose triton kernels moved into the new sglang/kernels/ops/
  package. apply_auto_profile() patches a module attribute, and call
  sites use `from X import y` (early binding), so hooks must be
  registered on the *consumer* module rather than the definition site.
  That makes most of the original source edits unnecessary: only raw
  triton.JITFunction objects still need a launch_* wrapper extracted,
  since wrapping one directly breaks `kernel[grid](...)` syntax. Also
  fixes a KeyError in the launcher hook (env["..."] on an unset var).

- dockerfiles/sglang-cu130.dockerfile: layer FlowSim on the official
  lmsysorg/sglang release image instead of building sglang from source.
  cuda12.6.dockerfile targets sm_90 and below, so it cannot run on
  Blackwell (GB200/B200, sm_100+), and building sglang + DeepGEMM from
  source on aarch64 is slow and fragile. The base image is a git
  checkout of the pinned commit with sglang installed editable, so the
  patch applies to it directly. Needs no network access, which GPU
  hosts frequently lack.

- workload/models/configs/GLM-5.2: truncated config following the
  existing deepseek convention (num_hidden_layers 2 +
  first_k_dense_replace 1 => one dense layer and one MoE layer, full
  256 experts). config_full.json keeps the upstream config so the
  truncation stays auditable.

- utils/shape_merge: don't fail when a kernel's launch count differs
  between the CUDA-graph and eager passes. Disabling CUDA graphs can
  legitimately change the launch sequence -- GLM-5.2's DSA decode
  backend replays one fused _fused_dsa_decode_metadata_kernel under
  CUDA graph but issues arange/fill/cumsum/index/add separately in
  eager mode. Positional matching would attach the wrong shapes to
  those rows, so they now keep their timing-pass values and are
  reported; strict=True restores the old behaviour. Previously this
  aborted the whole merge over a handful of metadata kernels.

- tests/integration/test_model_config.py: --batch is ambiguous in
  v0.5.16 (--batch-notify-size vs --batch-size); cap --context-length
  so GLM-5.2's 1M max_position_embeddings doesn't OOM the KV pool.

Verified on GB200 (aarch64, CUDA 13.0, TP=1): --collect all completes
for GLM-5.2 and produces merged EXTEND and DECODE kernel CSVs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GLM-5.2 selects the DeepSeek sparse-attention backend, so the existing
FlashInfer-MLA registrations were no-ops for it, and its attention, MoE
and norm work is launched from FlashInfer / TensorRT-LLM / DeepGEMM
custom ops that never reach aten dispatch. The profiler's own
record_shapes cannot see those, so the kernels that matter most for
simulation arrived in the CSVs with Dims=N/A: MLA attention
(fmhaSm100, bmm), MoE routing/finalize, the DSA indexer
(paged_mqa_logits, topk) and RMSNorm.

Register the launchers that actually sit on GLM-5.2's path, chosen by
walking the call stacks of the shape-less kernels in a real trace:
DeepseekSparseAttnBackend (forward_extend/forward_decode plus the
one-shot MHA, paged-MQA-schedule, topk-plan and cuda-graph-metadata
helpers), Indexer.forward_cuda and its fused K prepare/store,
DeepseekV2MoE.forward and the trtllm-gen bf16 runner, RMSNorm.forward_cuda,
and the paged allocator decode path.

Measured on GB200 (bs=1, input=2048, TP=1), share of kernels lacking
Dims:

  prefill  19% -> 2%   (by kernel time 36% -> 0%)
  decode   34% -> 6%   (by kernel time 21% -> 2%)

What remains is metadata kernels worth ~0.3% (prefill) and ~2% (decode)
of kernel time, which FlowSim resolves by name via kernels.json. Total
kernel time is unchanged (3.60 -> 3.61 ms extend, 2.95 -> 2.96 ms
decode), so the added record_function ranges cost under 0.5%.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Profiling a MoE model with --load-format dummy gives an untrained router. On
GLM-5.2 that router collapses onto a small subset of the 256 experts, so the
grouped-GEMM launches stream far less expert weight than a real deployment
would and the kernel timings understate MoE cost. Measured on GB200 at bs=1,
input_len=2048: prefill GateUp took 612 us, but DRAM peak over 612 us moves
only 4.59 GB against the 12.88 GB that 256 BF16 experts require, so at most
84 experts can have been active.

Patch 0004 already added SGLANG_BALANCED_MOE, but it does not reach GLM-5.2:
it rewrites topk_ids inside fused_moe_triton while GLM uses the TRT-LLM
grouped GEMM, it hooks DeepseekV2MoE.forward while GLM's decoder layer builds
Glm4MoeSparseMoeBlock, and with the flashinfer/trtllm backend
TopK.forward_cuda returns a BypassedTopKOutput so topk_ids never materialises
in Python at all -- routing happens inside moe::dev::routing from
router_logits.

Rewriting router_logits is therefore the only injection point that works.
This hooks TopK itself rather than any one model's forward, because
Glm4MoeSparseMoeBlock has three routing paths (forward_normal,
forward_normal_dual_stream under CUDA-graph capture, and forward_deepep) and
every one of them funnels into TopK; patching the model class covers only
whichever path that deployment happens to take. GLM-5.2 has n_group=1 and
topk_group=1, so grouped top-k degenerates to plain top-k over all experts
and a large logit margin deterministically selects the forced set. The
noaux_tc correction bias is zeroed too, since sigmoid scoring saturates at
1.0 and a dummy-initialised bias would otherwise outrank the forced choice.

With this applied, the same prefill GateUp launch takes 1765 us at 99.9% of
DRAM peak, and Down 911 us at 98.4% -- both the DRAM-bound answer for 2048
tokens spread evenly over 256 experts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.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