[ATOM SGLang] GLM 5.2 MTP#1694
Conversation
Add the plugin-owned GLM-5.2 MTP metadata bridge and fixed-shape CUDA graph support for draft decode, target verify, and draft extend. Keep SGLang request/KV ownership and route the draft model through the general ATOM AITER attention backend.
Keep the PR branch limited to the general ATOM draft attention route by removing hybrid native-attention cache and layer-id compatibility.
Keep the GLM-5.2 PR route fixed on the validated plugin-owned draft-extend implementation and remove the upstream-handler environment switch.
Remove GLM-5.2 phase and capacity environment switches. Let SGLang's native disable_cuda_graph server argument control graph capture, with all speculative graph phases enabled by default and an internal fixed metadata capacity.
🏷️ CI GuideRuns automatically on every eligible PR before approval:
Heavy model tests:
|
There was a problem hiding this comment.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
ruff
Use X | None for type annotations
Use X | None for type annotations
Use X | None for type annotations
Use X | None for type annotations
Use X | None for type annotations
Use X | None for type annotations
Use X | None for type annotations
Use X | None for type annotations
Use X | None for type annotations
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/glm52_dsa_bridge.py
Lines 17 to 49 in 65173c1
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/glm52_mtp/__init__.py
Lines 23 to 38 in 65173c1
Do not call getattr with a constant attribute value. It is not any safer than normal property access.
Import block is un-sorted or un-formatted
Do not catch blind exception: Exception
Do not catch blind exception: Exception
Replace if statement with min call
ATOM/atom/plugin/sglang/glm52_mtp/common.py
Lines 176 to 177 in 65173c1
Do not call getattr with a constant attribute value. It is not any safer than normal property access.
ATOM/atom/plugin/sglang/glm52_mtp/common.py
Line 409 in 65173c1
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/glm52_mtp/decode_graph.py
Lines 3 to 18 in 65173c1
atom.plugin.sglang.glm52_mtp.common.compute_mtp_sparse_per_token_kv_lens imported but unused
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/glm52_mtp/draft_extend.py
Lines 3 to 16 in 65173c1
Return the condition directly
ATOM/atom/plugin/sglang/glm52_mtp/draft_extend.py
Lines 83 to 85 in 65173c1
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/glm52_mtp/multi_token.py
Lines 3 to 25 in 65173c1
Return the negated condition directly
ATOM/atom/plugin/sglang/glm52_mtp/prefill.py
Lines 46 to 48 in 65173c1
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/glm52_mtp/target_verify.py
Lines 3 to 10 in 65173c1
Local variable bs is assigned to but never used
contextlib imported but unused
Import from collections.abc instead: Iterable
typing.Tuple is deprecated, use tuple instead
Do not explicitly return None in function if it is the only possible return value
Do not explicitly return None in function if it is the only possible return value
Do not catch blind exception: Exception
Do not call setattr with a constant attribute value. It is not any safer than normal property access.
ATOM/atom/plugin/sglang/runtime/forward_context.py
Lines 324 to 328 in 65173c1
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/runtime/model_arch.py
Lines 3 to 9 in 65173c1
Import from collections.abc instead: Callable
| import time | ||
| from glob import glob | ||
| from typing import Generator, Tuple | ||
| from typing import Callable, Generator, Tuple |
| import time | ||
| from glob import glob | ||
| from typing import Generator, Tuple | ||
| from typing import Callable, Generator, Tuple |
| *, | ||
| shard_files: list[str] | None = None, | ||
| key_filter: Callable[[str], bool] | None = None, | ||
| ) -> Generator[Tuple[str, torch.Tensor], None, None]: |
| yield name, param | ||
| else: | ||
| with safetensors.safe_open(st_file, framework="pt", device="cpu") as f: | ||
| for name in f.keys(): |
| if remapped is None: | ||
| return False | ||
| name = remapped | ||
| for mapping_part in weights_mapping.keys(): |
| last_page_len: torch.Tensor | ||
| use_fast_metadata: bool | ||
| work_metadata: Optional[torch.Tensor] = None | ||
| work_indptr: Optional[torch.Tensor] = None |
| use_fast_metadata: bool | ||
| work_metadata: Optional[torch.Tensor] = None | ||
| work_indptr: Optional[torch.Tensor] = None | ||
| work_info_set: Optional[torch.Tensor] = None |
| work_metadata: Optional[torch.Tensor] = None | ||
| work_indptr: Optional[torch.Tensor] = None | ||
| work_info_set: Optional[torch.Tensor] = None | ||
| reduce_indptr: Optional[torch.Tensor] = None |
| work_indptr: Optional[torch.Tensor] = None | ||
| work_info_set: Optional[torch.Tensor] = None | ||
| reduce_indptr: Optional[torch.Tensor] = None | ||
| reduce_final_map: Optional[torch.Tensor] = None |
| work_info_set: Optional[torch.Tensor] = None | ||
| reduce_indptr: Optional[torch.Tensor] = None | ||
| reduce_final_map: Optional[torch.Tensor] = None | ||
| reduce_partial_map: Optional[torch.Tensor] = None |
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
ATOM/atom/model_loader/loader.py
Lines 4 to 22 in 65173c1
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/attention_backend/sparse_mla_indexer.py
Lines 6 to 33 in 65173c1
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/models/deepseek_nextn_wrapper.py
Lines 8 to 33 in 65173c1
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/models/deepseek_nextn_wrapper.py
Lines 205 to 210 in 65173c1
Keep target attention on the native ATOM GLM-5.2 backend and draft attention on the general AITER backend without a runtime mode switch. Remove debug metadata hooks, allocation pointer logs, and route-only logging wrappers.
There was a problem hiding this comment.
Remaining comments which cannot be posted as a review comment to avoid GitHub Rate Limit
ruff
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/glm52_mtp/multi_token.py
Lines 3 to 22 in 7bf17aa
Return the negated condition directly
ATOM/atom/plugin/sglang/glm52_mtp/prefill.py
Lines 46 to 48 in 7bf17aa
Import block is un-sorted or un-formatted
ATOM/atom/plugin/sglang/glm52_mtp/target_verify.py
Lines 3 to 10 in 7bf17aa
Local variable bs is assigned to but never used
contextlib imported but unused
Import from collections.abc instead: Iterable
typing.Tuple is deprecated, use tuple instead
Do not explicitly return None in function if it is the only possible return value
Do not explicitly return None in function if it is the only possible return value
Do not catch blind exception: Exception
Do not call setattr with a constant attribute value. It is not any safer than normal property access.
ATOM/atom/plugin/sglang/runtime/forward_context.py
Lines 324 to 328 in 7bf17aa
| from atom.plugin.sglang.glm52_mtp.common import ( | ||
| GLM52_GRAPH_SEQ_LEN_CAPACITY, | ||
| ) | ||
| except Exception as exc: |
| @@ -204,6 +213,43 @@ def _is_dsv4_nextn_runner(runner) -> bool: | |||
| except Exception: | |||
| or "DeepseekV3ForCausalLMNextN" in str(arch) | ||
| for arch in arches | ||
| ) | ||
| except Exception: |
| return model_type == "glm_moe_dsa" or any( | ||
| "GlmMoeDsaForCausalLM" in str(arch) for arch in arches | ||
| ) | ||
| except Exception: |
| except Exception: | ||
| pass |
|
|
||
| def local_num_attention_heads(atom_config) -> int: | ||
| hf_config = atom_config.hf_config | ||
| num_heads = int(getattr(hf_config, "num_attention_heads")) |
There was a problem hiding this comment.
| from __future__ import annotations | ||
|
|
||
| import torch | ||
| from aiter import get_mla_metadata_v1 | ||
| from sglang.srt.layers.attention.utils import create_flashinfer_kv_indices_triton | ||
|
|
||
| from atom.plugin.sglang.glm52_mtp.common import ( | ||
| DECODE_GRAPH_BUFFERS_ATTR, | ||
| SHARED_SPARSE_INDICES_ATTR, | ||
| get_index_topk, | ||
| local_num_attention_heads, | ||
| make_mla_work_buffers, | ||
| metadata_dtype, | ||
| validate_page_size, | ||
| attention_page_size, | ||
| ) | ||
|
|
||
|
|
||
| class GLM52DecodeGraphBuffers: |
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
| from __future__ import annotations | |
| import torch | |
| from aiter import get_mla_metadata_v1 | |
| from sglang.srt.layers.attention.utils import create_flashinfer_kv_indices_triton | |
| from atom.plugin.sglang.glm52_mtp.common import ( | |
| DECODE_GRAPH_BUFFERS_ATTR, | |
| SHARED_SPARSE_INDICES_ATTR, | |
| get_index_topk, | |
| local_num_attention_heads, | |
| make_mla_work_buffers, | |
| metadata_dtype, | |
| validate_page_size, | |
| attention_page_size, | |
| ) | |
| class GLM52DecodeGraphBuffers: | |
| from __future__ import annotations | |
| import torch | |
| from aiter import get_mla_metadata_v1 | |
| from sglang.srt.layers.attention.utils import create_flashinfer_kv_indices_triton | |
| from atom.plugin.sglang.glm52_mtp.common import ( | |
| DECODE_GRAPH_BUFFERS_ATTR, | |
| SHARED_SPARSE_INDICES_ATTR, | |
| attention_page_size, | |
| get_index_topk, | |
| local_num_attention_heads, | |
| make_mla_work_buffers, | |
| metadata_dtype, | |
| validate_page_size, | |
| ) | |
| class GLM52DecodeGraphBuffers: |
| from atom.plugin.sglang.glm52_mtp.common import ( | ||
| DRAFT_SUB_STEP_ATTR, | ||
| attention_page_size, | ||
| build_draft_decode_token_table, | ||
| build_token_table, | ||
| compute_mtp_sparse_per_token_kv_lens, | ||
| counts_to_indptr, | ||
| ensure_shared_sparse_buffer, | ||
| flatten_kv_indices, | ||
| get_index_topk, | ||
| get_seq_lens_cpu, | ||
| local_num_attention_heads, | ||
| make_mla_work_buffers, | ||
| make_sparse_mtp_work_buffers, | ||
| metadata_dtype, | ||
| resolve_draft_decode_context_lens, | ||
| resolve_speculative_num_steps, | ||
| validate_page_size, | ||
| ) |
There was a problem hiding this comment.
atom.plugin.sglang.glm52_mtp.common.compute_mtp_sparse_per_token_kv_lens imported but unused
| from atom.plugin.sglang.glm52_mtp.common import ( | |
| DRAFT_SUB_STEP_ATTR, | |
| attention_page_size, | |
| build_draft_decode_token_table, | |
| build_token_table, | |
| compute_mtp_sparse_per_token_kv_lens, | |
| counts_to_indptr, | |
| ensure_shared_sparse_buffer, | |
| flatten_kv_indices, | |
| get_index_topk, | |
| get_seq_lens_cpu, | |
| local_num_attention_heads, | |
| make_mla_work_buffers, | |
| make_sparse_mtp_work_buffers, | |
| metadata_dtype, | |
| resolve_draft_decode_context_lens, | |
| resolve_speculative_num_steps, | |
| validate_page_size, | |
| ) | |
| from atom.plugin.sglang.glm52_mtp.common import ( | |
| DRAFT_SUB_STEP_ATTR, | |
| attention_page_size, | |
| build_draft_decode_token_table, | |
| build_token_table, | |
| counts_to_indptr, | |
| ensure_shared_sparse_buffer, | |
| flatten_kv_indices, | |
| get_index_topk, | |
| get_seq_lens_cpu, | |
| local_num_attention_heads, | |
| make_mla_work_buffers, | |
| make_sparse_mtp_work_buffers, | |
| metadata_dtype, | |
| resolve_draft_decode_context_lens, | |
| resolve_speculative_num_steps, | |
| validate_page_size, | |
| ) |
| from __future__ import annotations | ||
|
|
||
| import os | ||
|
|
||
| import numpy as np | ||
| import torch | ||
|
|
||
| from atom.plugin.sglang.glm52_mtp.common import ( | ||
| get_extend_lens_cpu, | ||
| get_extend_prefix_lens_cpu, | ||
| get_seq_lens_cpu, | ||
| is_draft_extend_mode, | ||
| ) | ||
| from atom.plugin.sglang.glm52_mtp.multi_token import build_mtp_multi_token_decode_metadata | ||
|
|
||
|
|
||
| def draft_extend_k_only() -> bool: |
There was a problem hiding this comment.
Import block is un-sorted or un-formatted
| from __future__ import annotations | |
| import os | |
| import numpy as np | |
| import torch | |
| from atom.plugin.sglang.glm52_mtp.common import ( | |
| get_extend_lens_cpu, | |
| get_extend_prefix_lens_cpu, | |
| get_seq_lens_cpu, | |
| is_draft_extend_mode, | |
| ) | |
| from atom.plugin.sglang.glm52_mtp.multi_token import build_mtp_multi_token_decode_metadata | |
| def draft_extend_k_only() -> bool: | |
| from __future__ import annotations | |
| import os | |
| import numpy as np | |
| import torch | |
| from atom.plugin.sglang.glm52_mtp.common import ( | |
| get_extend_lens_cpu, | |
| get_extend_prefix_lens_cpu, | |
| get_seq_lens_cpu, | |
| is_draft_extend_mode, | |
| ) | |
| from atom.plugin.sglang.glm52_mtp.multi_token import ( | |
| build_mtp_multi_token_decode_metadata, | |
| ) | |
| def draft_extend_k_only() -> bool: |
| if int(getattr(forward_batch, "_graph_cache_bs", 0) or 0) > 0: | ||
| return True | ||
| return False |
Motivation
Enable GLM 5.2 MTP at sglang plugin
Technical Details
Test Plan
Test Result
Submission Checklist