[Refactor] Clarify DeepSeek V4 metadata names for V4.1 (#38947)
This commit is contained in:
@@ -25,8 +25,8 @@ class StateType(str, enum.Enum):
|
||||
# DeepSeek-V4 unified_kv SWA ring: addressed per-row by ring slot
|
||||
# (req_pool_idx * ring_stride + pos % ring_stride), needs its own component.
|
||||
SWA_RING = "swa_ring"
|
||||
# DeepSeek-V4 online C128 request-scoped state.
|
||||
C128_STATE = "c128_state"
|
||||
# DeepSeek-V4 request-scoped compression state; preserve the legacy wire value.
|
||||
DSV4_REQUEST_STATE = "c128_state"
|
||||
# A block-scaled KV dtype keeps its per-block scales in buffers parallel to
|
||||
# K/V, one component per sub-pool so each carries the index payload of the
|
||||
# KV it describes (whole sequence for full attention, window for SWA).
|
||||
|
||||
@@ -972,10 +972,8 @@ class CommonKVManager(BaseKVManager):
|
||||
|
||||
mla_ratios = getattr(self.kv_args, "mla_compression_ratios", None)
|
||||
if mla_ratios:
|
||||
# Compressed-MLA (e.g. DeepSeek V4): the flat list is organized
|
||||
# by buffer type (compression-ratio bucket) rather than by
|
||||
# layer, so we locate the sub-range for this PP stage inside each
|
||||
# section of the dst flat list.
|
||||
# Compressed-MLA pointers are grouped by buffer type;
|
||||
# each group needs its own PP-stage slice.
|
||||
sliced_src_kv_ptrs, sliced_dst_kv_ptrs = self._mla_slice_ptrs_for_pp(
|
||||
src_kv_ptrs, dst_kv_ptrs, mla_ratios, state_type
|
||||
)
|
||||
@@ -999,37 +997,11 @@ class CommonKVManager(BaseKVManager):
|
||||
mla_ratios: List[int],
|
||||
state_type: Optional[StateType] = None,
|
||||
) -> Tuple[List[int], List[int]]:
|
||||
"""Produce aligned (src, dst) pointer lists for compressed-MLA
|
||||
pools (e.g. DeepSeek V4) under PP.
|
||||
|
||||
The pool produces two possible flat-list layouts (selected via dst
|
||||
length):
|
||||
|
||||
- kv_data layout, length = 2 * c4_L + c128_L:
|
||||
[c4_layer_{0..c4_L-1},
|
||||
c4_indexer_layer_{0..c4_L-1},
|
||||
c128_layer_{0..c128_L-1}]
|
||||
Each section is indexed by compressed-layer id within that
|
||||
compression bucket.
|
||||
|
||||
- SWA state_data layout, length = swa_L + 2 * c4_L:
|
||||
[swa_layer_{0..swa_L-1},
|
||||
c4_compress_state_{0..c4_L-1},
|
||||
c4_indexer_compress_state_{0..c4_L-1}]
|
||||
``swa_L`` is the SWA pool's actual buffer count
|
||||
(``num_effective_layers``), which can be smaller than
|
||||
``len(mla_ratios)`` when the HF config's ``compress_ratios``
|
||||
list contains entries for layers not materialized into the SWA
|
||||
pool (e.g. an MTP/nextn slot at the tail).
|
||||
|
||||
- C128_STATE layout, length = c128_L:
|
||||
[c128_compress_state_{0..c128_L-1}]
|
||||
|
||||
src is already PP-filtered on the prefill side. dst is the
|
||||
decode-side full-model list (when decode is PP=1). We slice dst to
|
||||
match src's PP stage. If src itself is also full-model, it is
|
||||
returned unchanged.
|
||||
"""
|
||||
# Match the pool's flat buffer order, with layers grouped by ratio:
|
||||
# KV: [C4 KV, C4 indexer KV, C128 KV].
|
||||
# SWA state: [SWA KV, C4 compressor state, C4 indexer state].
|
||||
# DSV4_REQUEST_STATE: [C128 compressor state]; SWA_RING: [SWA rings].
|
||||
# Prefill src is stage-local; decode dst may cover the full model.
|
||||
start_layer = self.kv_args.prefill_start_layer
|
||||
end_layer = self.kv_args.prefill_end_layer
|
||||
assert end_layer is not None, (
|
||||
@@ -1045,7 +1017,7 @@ class CommonKVManager(BaseKVManager):
|
||||
c128_off_s = sum(1 for r in mla_ratios[:start_layer] if r == 128)
|
||||
c128_off_e = sum(1 for r in mla_ratios[:end_layer] if r == 128)
|
||||
|
||||
if state_type == StateType.C128_STATE:
|
||||
if state_type == StateType.DSV4_REQUEST_STATE:
|
||||
return src_kv_ptrs, list(dst_kv_ptrs[c128_off_s:c128_off_e])
|
||||
|
||||
if state_type == StateType.SWA_RING:
|
||||
@@ -1054,7 +1026,8 @@ class CommonKVManager(BaseKVManager):
|
||||
return src_kv_ptrs, list(dst_kv_ptrs[swa_s:swa_e])
|
||||
|
||||
if (
|
||||
state_type not in (StateType.SWA, StateType.SWA_RING, StateType.C128_STATE)
|
||||
state_type
|
||||
not in (StateType.SWA, StateType.SWA_RING, StateType.DSV4_REQUEST_STATE)
|
||||
and len(dst_kv_ptrs) == kv_layout_len
|
||||
):
|
||||
sliced_dst = (
|
||||
@@ -1064,11 +1037,8 @@ class CommonKVManager(BaseKVManager):
|
||||
)
|
||||
return src_kv_ptrs, sliced_dst
|
||||
|
||||
# SWA state-data layout. ``swa_L`` is derived from the actual dst
|
||||
# length so we tolerate cases where the SWA pool has fewer buffers
|
||||
# than ``len(mla_ratios)`` (e.g. nextn padding). C128 state ships as
|
||||
# a separate StateType.C128_STATE component and must not be counted
|
||||
# here.
|
||||
# SWA may omit nextn entries present in mla_ratios; use its buffer count.
|
||||
# C128 state ships separately as DSV4_REQUEST_STATE.
|
||||
swa_L = len(dst_kv_ptrs) - 2 * c4_full
|
||||
if swa_L < 0 or swa_L > len(mla_ratios):
|
||||
raise ValueError(
|
||||
|
||||
@@ -1449,7 +1449,7 @@ class DecodePreallocQueue(DecodeHiCachePreallocMixin):
|
||||
)
|
||||
|
||||
state_types = self.kv_manager.kv_args.state_types
|
||||
if StateType.C128_STATE in state_types:
|
||||
if StateType.DSV4_REQUEST_STATE in state_types:
|
||||
clear_c128_state = getattr(
|
||||
self.token_to_kv_pool, "clear_c128_req_state", None
|
||||
)
|
||||
@@ -1462,7 +1462,7 @@ class DecodePreallocQueue(DecodeHiCachePreallocMixin):
|
||||
StateType.DSA_TAIL: _dsa_tail_payload,
|
||||
StateType.MINIMAX_INDEX_K: _full_kv_pages_payload,
|
||||
StateType.SWA_RING: _swa_ring_payload,
|
||||
StateType.C128_STATE: _c128_state_payload,
|
||||
StateType.DSV4_REQUEST_STATE: _c128_state_payload,
|
||||
StateType.BLOCK_SCALE: _full_kv_pages_payload,
|
||||
StateType.BLOCK_SCALE_SWA: _swa_payload,
|
||||
}
|
||||
|
||||
@@ -1343,14 +1343,14 @@ class MooncakeKVManager(StagingManagerMixin, CommonKVManager):
|
||||
StateType.SWA,
|
||||
StateType.DSA,
|
||||
StateType.SWA_RING,
|
||||
StateType.C128_STATE,
|
||||
StateType.DSV4_REQUEST_STATE,
|
||||
StateType.BLOCK_SCALE,
|
||||
StateType.BLOCK_SCALE_SWA,
|
||||
)
|
||||
|
||||
def _requires_exact_state_index_match(self, st: StateType) -> bool:
|
||||
"""State types whose page lists are positional and must not be truncated."""
|
||||
return st in (StateType.SWA_RING, StateType.C128_STATE)
|
||||
return st in (StateType.SWA_RING, StateType.DSV4_REQUEST_STATE)
|
||||
|
||||
def maybe_send_extra(
|
||||
self,
|
||||
@@ -1495,7 +1495,7 @@ class MooncakeKVManager(StagingManagerMixin, CommonKVManager):
|
||||
src_indices = list(indices)
|
||||
dst_indices_local = list(dst_indices)
|
||||
if (
|
||||
st == StateType.C128_STATE
|
||||
st == StateType.DSV4_REQUEST_STATE
|
||||
and len(src_indices) == 0
|
||||
and len(dst_indices_local) == 0
|
||||
):
|
||||
|
||||
@@ -2458,13 +2458,17 @@ class NixlKVManager(StagingManagerMixin, CommonKVManager):
|
||||
state_type=st,
|
||||
force_flat=True,
|
||||
)
|
||||
elif st in (StateType.SWA, StateType.SWA_RING, StateType.C128_STATE):
|
||||
elif st in (
|
||||
StateType.SWA,
|
||||
StateType.SWA_RING,
|
||||
StateType.DSV4_REQUEST_STATE,
|
||||
):
|
||||
if not self.is_mla_backend and self.attn_tp_size != decode_tp_size:
|
||||
raise RuntimeError(
|
||||
f"PD Disaggregation does NOT support PD different TP sizes for non-MLA {st.upper()} hybrid models yet."
|
||||
)
|
||||
if (
|
||||
st == StateType.C128_STATE
|
||||
st == StateType.DSV4_REQUEST_STATE
|
||||
and len(src_indices) == 0
|
||||
and len(dst_indices) == 0
|
||||
):
|
||||
|
||||
@@ -1384,7 +1384,7 @@ class SchedulerDisaggregationPrefillMixin:
|
||||
StateType.DSA_TAIL: _dsa_tail_payload,
|
||||
StateType.MINIMAX_INDEX_K: _full_kv_pages_payload,
|
||||
StateType.SWA_RING: _swa_ring_payload,
|
||||
StateType.C128_STATE: _c128_state_payload,
|
||||
StateType.DSV4_REQUEST_STATE: _c128_state_payload,
|
||||
StateType.BLOCK_SCALE: _full_kv_pages_payload,
|
||||
StateType.BLOCK_SCALE_SWA: _swa_payload,
|
||||
}
|
||||
|
||||
@@ -89,13 +89,8 @@ def get_dsv4_c4_state_indices(
|
||||
*,
|
||||
ring_size: int,
|
||||
) -> np.ndarray:
|
||||
"""Return physical rows for the live C4 compressor history.
|
||||
|
||||
Prefill and decode may use different C4 ring sizes (8 without speculative
|
||||
decoding and 16 with EAGLE/MTP). State transfer must therefore pair rows
|
||||
by logical token position instead of copying a whole request-local bank.
|
||||
The C4 overlap compressor keeps ``seq_len % 4 + 4`` live rows.
|
||||
"""
|
||||
# Prefill and decode can have different ring sizes (8 or 16 with EAGLE/MTP);
|
||||
# pair the overlap compressor's live rows by logical token position.
|
||||
if ring_size < 8 or ring_size % 4 != 0:
|
||||
raise ValueError(
|
||||
f"C4 ring_size must be a multiple of 4 and at least 8, got {ring_size}"
|
||||
@@ -1276,10 +1271,6 @@ def setup_state_kv_args(
|
||||
total_kv_layers: int = None,
|
||||
req_to_token_pool=None,
|
||||
) -> None:
|
||||
"""Populate ``kv_args`` state-buffer fields from the given pool.
|
||||
Shared by prefill and decode bootstrap paths so the state_type dispatch
|
||||
lives in one place.
|
||||
"""
|
||||
from sglang.srt.disaggregation.base.conn import StateType
|
||||
from sglang.srt.hardware_backend.npu.memory_pool_npu import NPUMLATokenToKVPool
|
||||
from sglang.srt.mem_cache.base_swa_memory_pool import BaseSWAKVPool
|
||||
@@ -1373,14 +1364,14 @@ def setup_state_kv_args(
|
||||
ring_lens,
|
||||
ring_item_lens,
|
||||
)
|
||||
if hasattr(token_to_kv_pool, "get_c128_state_buf_infos"):
|
||||
if hasattr(token_to_kv_pool, "get_request_state_buf_infos"):
|
||||
c128_ptrs, c128_lens, c128_item_lens = (
|
||||
token_to_kv_pool.get_c128_state_buf_infos()
|
||||
token_to_kv_pool.get_request_state_buf_infos()
|
||||
)
|
||||
if c128_ptrs:
|
||||
append_state_component(
|
||||
kv_args,
|
||||
StateType.C128_STATE,
|
||||
StateType.DSV4_REQUEST_STATE,
|
||||
c128_ptrs,
|
||||
c128_lens,
|
||||
c128_item_lens,
|
||||
|
||||
@@ -75,7 +75,7 @@ def dsv4_state_payloads(
|
||||
"""Build NPU-specific DSV4 PD payloads.
|
||||
|
||||
Returns payloads for components that are addressed differently from the
|
||||
cross-hardware ``StateType.SWA`` / ``StateType.C128_STATE`` defaults:
|
||||
cross-hardware ``StateType.SWA`` / ``StateType.DSV4_REQUEST_STATE`` defaults:
|
||||
|
||||
* ``DSV4_C128`` — C128 KV pages from ``req_to_c128_sidecar``.
|
||||
* ``DSV4_C4_STATE`` (A5 only) — live C4 compress-state rows. Prefill
|
||||
|
||||
@@ -179,8 +179,7 @@ class DSV4AttnMetadata:
|
||||
swa_topk_lengths: torch.Tensor
|
||||
|
||||
c4_sparse_topk: int
|
||||
# SWA KV-store write target (out_cache_loc translated to SWA space), computed
|
||||
# once per iteration in make_core_attn_metadata and read by the store path.
|
||||
# Shared by all layer stores; locations are in SWA space.
|
||||
swa_out_cache_loc: Optional[torch.Tensor] = None
|
||||
c4_out_loc: Optional[torch.Tensor] = None
|
||||
c4_topk_lengths_raw: Optional[torch.Tensor] = None
|
||||
@@ -205,7 +204,7 @@ class DSV4AttnMetadata:
|
||||
trtllm_prefill_c4_indices: Optional[torch.Tensor] = None
|
||||
trtllm_prefill_c128: Optional[tuple] = None
|
||||
|
||||
c1_flashmla_metadata: FlashMLASchedMeta = field(init=False, repr=False)
|
||||
c0_flashmla_metadata: FlashMLASchedMeta = field(init=False, repr=False)
|
||||
c4_flashmla_metadata: FlashMLASchedMeta = field(init=False, repr=False)
|
||||
c128_flashmla_metadata: FlashMLASchedMeta = field(init=False, repr=False)
|
||||
|
||||
@@ -215,7 +214,7 @@ class DSV4AttnMetadata:
|
||||
|
||||
def get_flashmla_metadata(self, compress_ratio: Literal[0, 4, 128]):
|
||||
if compress_ratio == 0:
|
||||
return self.c1_flashmla_metadata
|
||||
return self.c0_flashmla_metadata
|
||||
elif compress_ratio == 4:
|
||||
return self.c4_flashmla_metadata
|
||||
elif compress_ratio == 128:
|
||||
@@ -258,7 +257,7 @@ class DSV4AttnMetadata:
|
||||
# Recomputed by the recorded init_forward_metadata_in_graph op
|
||||
# each forward; not copied across replays.
|
||||
"swa_out_cache_loc",
|
||||
"c1_flashmla_metadata",
|
||||
"c0_flashmla_metadata",
|
||||
"c4_flashmla_metadata",
|
||||
"c128_flashmla_metadata",
|
||||
# Eager-only lazy caches are assigned, not content-copied.
|
||||
@@ -296,7 +295,7 @@ class DSV4AttnMetadata:
|
||||
"swa_topk_lengths",
|
||||
"c128_page_indices",
|
||||
"c128_topk_lengths_clamp1",
|
||||
"c1_flashmla_metadata",
|
||||
"c0_flashmla_metadata",
|
||||
"c4_flashmla_metadata",
|
||||
"c128_flashmla_metadata",
|
||||
# Reset eager-only caches so a replay cannot reuse another shape.
|
||||
@@ -428,7 +427,7 @@ class DSV4AttnMetadata:
|
||||
self.c4_sparse_page_indices = _pad_last_dim(self.c4_sparse_page_indices)
|
||||
if is_prefill:
|
||||
self.c4_sparse_raw_indices = torch.empty_like(self.c4_sparse_page_indices)
|
||||
self.c1_flashmla_metadata = _create_flashmla_metadata()
|
||||
self.c0_flashmla_metadata = _create_flashmla_metadata()
|
||||
self.c4_flashmla_metadata = _create_flashmla_metadata()
|
||||
self.c128_flashmla_metadata = _create_flashmla_metadata()
|
||||
|
||||
@@ -780,7 +779,7 @@ class DeepseekV4AttnBackend(
|
||||
return PagedIndexerMetadata(
|
||||
page_size=self.page_size,
|
||||
page_table=core_attn_metadata.page_table,
|
||||
c4_seq_lens=core_attn_metadata.c4_topk_lengths_raw,
|
||||
compressed_seq_lens=core_attn_metadata.c4_topk_lengths_raw,
|
||||
use_topk_v2=self.dsa_topk_backend.should_use_topk_v2() and not _is_xpu,
|
||||
# The SM120 FP4 kernel schedules split_kv=128, while the generic
|
||||
# JIT metadata planner encodes split_kv=256.
|
||||
@@ -1176,9 +1175,7 @@ class DeepseekV4AttnBackend(
|
||||
return buf[:n]
|
||||
|
||||
def init_forward_metadata_in_graph(self, forward_batch: ForwardBatch) -> None:
|
||||
# Upgrade Raw->Full so the c4/c128 compress + core_attn + indexer
|
||||
# materialization is recorded inside the cuda graph; a no-op (Full
|
||||
# already) when PREP_IN_CUDA_GRAPH=0.
|
||||
# Raw metadata must be materialized inside the graph to refresh on replay.
|
||||
if isinstance(self.forward_metadata, DSV4RawVerifyMetadata):
|
||||
self.forward_metadata = self.make_forward_metadata_from_raw_verify(
|
||||
raw_metadata=self.forward_metadata,
|
||||
@@ -1189,11 +1186,9 @@ class DeepseekV4AttnBackend(
|
||||
raw_metadata=self.forward_metadata,
|
||||
)
|
||||
|
||||
# Compute the SWA KV-store write target once per forward and cache it on
|
||||
# the metadata for every layer's store. This is recorded inside the cuda
|
||||
# graph, so replay re-reads the live out_cache_loc buffer (spec-v2 and DP
|
||||
# padding rebind out_cache_loc after out-graph metadata prep). flash_mla
|
||||
# kernels require int32 indices.
|
||||
# Spec-v2 and DP padding can rebind out_cache_loc after out-graph prep;
|
||||
# capture the translation here so replay reads live locations.
|
||||
# FlashMLA requires int32 indices.
|
||||
metadata = self.forward_metadata
|
||||
if (
|
||||
isinstance(metadata, DSV4Metadata)
|
||||
@@ -1703,7 +1698,7 @@ class DeepseekV4AttnBackend(
|
||||
metadata.core_attn_metadata, DSV4AttnMetadata
|
||||
):
|
||||
core = metadata.core_attn_metadata
|
||||
core.c1_flashmla_metadata = _create_flashmla_metadata()
|
||||
core.c0_flashmla_metadata = _create_flashmla_metadata()
|
||||
core.c4_flashmla_metadata = _create_flashmla_metadata()
|
||||
core.c128_flashmla_metadata = _create_flashmla_metadata()
|
||||
|
||||
@@ -1714,15 +1709,7 @@ class DeepseekV4AttnBackend(
|
||||
self.forward_metadata = current_raw
|
||||
|
||||
def get_swa_out_cache_loc(self, forward_batch: ForwardBatch) -> torch.Tensor:
|
||||
"""Resolve the SWA KV-store write target for the current forward.
|
||||
|
||||
Prefer the value cached by the metadata init: in-graph for
|
||||
decode/verify, the hoisted cuda_graph_swa_out_cache_loc buffer for
|
||||
draft-extend. Translate at store time when nothing matching is cached
|
||||
(paths that skip the init, or a batch re-padded after init). Idle
|
||||
always falls back: its metadata may be stale, and
|
||||
translating the zero-padded out_cache_loc writes to the dummy slot.
|
||||
"""
|
||||
# Idle metadata may be stale; zero-padded locations target the dummy slot.
|
||||
out_cache_loc = forward_batch.out_cache_loc
|
||||
core = getattr(self.forward_metadata, "core_attn_metadata", None)
|
||||
cached = core.swa_out_cache_loc if core is not None else None
|
||||
@@ -2366,7 +2353,7 @@ class DeepseekV4AttnBackend(
|
||||
core_attn_metadata.c4_sparse_topk_lengths = None
|
||||
core_attn_metadata.c4_sparse_page_indices = None
|
||||
core_attn_metadata.c4_sparse_raw_indices = None
|
||||
core_attn_metadata.c1_flashmla_metadata = _create_flashmla_metadata()
|
||||
core_attn_metadata.c0_flashmla_metadata = _create_flashmla_metadata()
|
||||
core_attn_metadata.c4_flashmla_metadata = None
|
||||
core_attn_metadata.c128_flashmla_metadata = None
|
||||
if self.trtllm_attn:
|
||||
|
||||
@@ -162,8 +162,7 @@ class DSV4AttnMetadata:
|
||||
swa_topk_lengths: torch.Tensor
|
||||
|
||||
c4_sparse_topk: int
|
||||
# SWA KV-store write target (out_cache_loc translated to SWA space), computed
|
||||
# once per iteration in make_core_attn_metadata and read by the store path.
|
||||
# Shared by all layer stores; locations are in SWA space.
|
||||
swa_out_cache_loc: Optional[torch.Tensor] = None
|
||||
c4_out_loc: Optional[torch.Tensor] = None
|
||||
c4_topk_lengths_raw: Optional[torch.Tensor] = None
|
||||
@@ -181,7 +180,7 @@ class DSV4AttnMetadata:
|
||||
# unified-kv metadata
|
||||
unified: Optional[UnifiedKvMetadata] = None
|
||||
|
||||
c1_flashmla_metadata: FlashMLASchedMeta = field(init=False, repr=False)
|
||||
c0_flashmla_metadata: FlashMLASchedMeta = field(init=False, repr=False)
|
||||
c4_flashmla_metadata: FlashMLASchedMeta = field(init=False, repr=False)
|
||||
c128_flashmla_metadata: FlashMLASchedMeta = field(init=False, repr=False)
|
||||
|
||||
@@ -191,7 +190,7 @@ class DSV4AttnMetadata:
|
||||
|
||||
def get_flashmla_metadata(self, compress_ratio: Literal[0, 4, 128]):
|
||||
if compress_ratio == 0:
|
||||
return self.c1_flashmla_metadata
|
||||
return self.c0_flashmla_metadata
|
||||
elif compress_ratio == 4:
|
||||
return self.c4_flashmla_metadata
|
||||
elif compress_ratio == 128:
|
||||
@@ -232,7 +231,7 @@ class DSV4AttnMetadata:
|
||||
# Recomputed by the recorded init_forward_metadata_in_graph op
|
||||
# each forward; not copied across replays.
|
||||
"swa_out_cache_loc",
|
||||
"c1_flashmla_metadata",
|
||||
"c0_flashmla_metadata",
|
||||
"c4_flashmla_metadata",
|
||||
"c128_flashmla_metadata",
|
||||
],
|
||||
@@ -347,7 +346,7 @@ class DSV4AttnMetadata:
|
||||
self.c4_sparse_page_indices = _pad_last_dim(self.c4_sparse_page_indices)
|
||||
if is_prefill:
|
||||
self.c4_sparse_raw_indices = torch.empty_like(self.c4_sparse_page_indices)
|
||||
self.c1_flashmla_metadata = _create_flashmla_metadata()
|
||||
self.c0_flashmla_metadata = _create_flashmla_metadata()
|
||||
self.c4_flashmla_metadata = _create_flashmla_metadata()
|
||||
self.c128_flashmla_metadata = _create_flashmla_metadata()
|
||||
|
||||
@@ -509,7 +508,7 @@ class DeepseekV4HipRadixBackend(
|
||||
return PagedIndexerMetadata(
|
||||
page_size=self.page_size,
|
||||
page_table=core_attn_metadata.page_table,
|
||||
c4_seq_lens=core_attn_metadata.c4_topk_lengths_raw,
|
||||
compressed_seq_lens=core_attn_metadata.c4_topk_lengths_raw,
|
||||
use_topk_v2=self.dsa_topk_backend.should_use_topk_v2(),
|
||||
)
|
||||
|
||||
@@ -842,9 +841,7 @@ class DeepseekV4HipRadixBackend(
|
||||
)
|
||||
|
||||
def init_forward_metadata_in_graph(self, forward_batch: ForwardBatch) -> None:
|
||||
# Upgrade Raw->Full so the c4/c128 compress + core_attn + indexer
|
||||
# materialization is recorded inside the cuda graph; a no-op (Full
|
||||
# already) when PREP_IN_CUDA_GRAPH=0.
|
||||
# Raw metadata must be materialized inside the graph to refresh on replay.
|
||||
if isinstance(self.forward_metadata, DSV4RawVerifyMetadata):
|
||||
self.forward_metadata = self.make_forward_metadata_from_raw_verify(
|
||||
raw_metadata=self.forward_metadata,
|
||||
@@ -854,11 +851,9 @@ class DeepseekV4HipRadixBackend(
|
||||
raw_metadata=self.forward_metadata,
|
||||
)
|
||||
|
||||
# Compute the SWA KV-store write target once per forward and cache it on
|
||||
# the metadata for every layer's store. This is recorded inside the cuda
|
||||
# graph, so replay re-reads the live out_cache_loc buffer (spec-v2 and DP
|
||||
# padding rebind out_cache_loc after out-graph metadata prep). flash_mla
|
||||
# kernels require int32 indices.
|
||||
# Spec-v2 and DP padding can rebind out_cache_loc after out-graph prep;
|
||||
# capture the translation here so replay reads live locations.
|
||||
# FlashMLA requires int32 indices.
|
||||
metadata = self.forward_metadata
|
||||
if (
|
||||
isinstance(metadata, DSV4Metadata)
|
||||
@@ -911,7 +906,7 @@ class DeepseekV4HipRadixBackend(
|
||||
indexer_metadata = metadata.indexer_metadata
|
||||
metadata.fp4_decode_workspace = prepare_fp4_decode_workspace(
|
||||
indexer_metadata.page_table,
|
||||
indexer_metadata.c4_seq_lens,
|
||||
indexer_metadata.compressed_seq_lens,
|
||||
)
|
||||
|
||||
def _fp4_workspaces_enabled(self, metadata) -> bool:
|
||||
@@ -957,7 +952,7 @@ class DeepseekV4HipRadixBackend(
|
||||
indexer_metadata = metadata.indexer_metadata
|
||||
metadata.fp4_prefill_workspace = prepare_fp4_prefill_workspace(
|
||||
indexer_metadata.page_table,
|
||||
indexer_metadata.c4_seq_lens,
|
||||
indexer_metadata.compressed_seq_lens,
|
||||
workspace=metadata.fp4_prefill_workspace,
|
||||
)
|
||||
|
||||
@@ -1215,7 +1210,7 @@ class DeepseekV4HipRadixBackend(
|
||||
metadata.core_attn_metadata, DSV4AttnMetadata
|
||||
):
|
||||
core = metadata.core_attn_metadata
|
||||
core.c1_flashmla_metadata = _create_flashmla_metadata()
|
||||
core.c0_flashmla_metadata = _create_flashmla_metadata()
|
||||
core.c4_flashmla_metadata = _create_flashmla_metadata()
|
||||
core.c128_flashmla_metadata = _create_flashmla_metadata()
|
||||
|
||||
@@ -1228,12 +1223,8 @@ class DeepseekV4HipRadixBackend(
|
||||
def _attach_unified_kv_decode_streams(
|
||||
self, core: DSV4AttnMetadata, state_slot: torch.Tensor
|
||||
) -> None:
|
||||
"""build the ragged decode index streams once per forward.
|
||||
|
||||
``state_slot`` is the per-row req-slot map: decode passes
|
||||
``req_pool_indices`` (1 token per req), target-verify passes
|
||||
``req_pool_indices_repeated`` (the per-token num_draft*bs -> bs map) so
|
||||
the same builder produces per-draft-token decode streams."""
|
||||
# state_slot maps each query token to its request slot;
|
||||
# target-verify repeats request slots for the draft tokens.
|
||||
from sglang.kernels.ops.attention.dsv4.unified_kv_kernels.env_gate import (
|
||||
is_unified_kv_triton,
|
||||
)
|
||||
@@ -1502,18 +1493,7 @@ class DeepseekV4HipRadixBackend(
|
||||
return o
|
||||
|
||||
def get_swa_out_cache_loc(self, forward_batch: ForwardBatch) -> torch.Tensor:
|
||||
"""Resolve the SWA KV-store write target for the current forward.
|
||||
|
||||
Fast path: the per-forward value cached by init_forward_metadata_in_graph
|
||||
(recorded inside cuda graphs, so replay re-reads live buffers). Fallback:
|
||||
translate at store time, matching the pre-cache behavior, for paths that
|
||||
never run the in-graph init — eager idle (forward_idle skips attn init),
|
||||
runners that only run the out-graph prep (e.g.
|
||||
EAGLEDraftExtendCudaGraphRunner) — or whose batch was re-padded after
|
||||
init (shape mismatch). Idle always falls back: its metadata is absent or
|
||||
left over from a previous forward, and translating the zero-padded
|
||||
out_cache_loc writes to the dummy slot.
|
||||
"""
|
||||
# Idle metadata may be stale; zero-padded locations target the dummy slot.
|
||||
out_cache_loc = forward_batch.out_cache_loc
|
||||
core = getattr(self.forward_metadata, "core_attn_metadata", None)
|
||||
cached = core.swa_out_cache_loc if core is not None else None
|
||||
@@ -1528,18 +1508,7 @@ class DeepseekV4HipRadixBackend(
|
||||
)
|
||||
|
||||
def get_unified_swa_loc(self, forward_batch: ForwardBatch) -> torch.Tensor:
|
||||
"""SWA ring write target for unified_kv, shared by all layers.
|
||||
|
||||
Fast path: the per-forward value cached in _attach_unified_kv_decode_streams
|
||||
(recorded inside cuda graphs, so replay re-reads live buffers). Fallback:
|
||||
recompute at store time, matching the pre-cache per-layer behavior, for
|
||||
paths that never ran the decode-stream init (eager prefill/extend, idle,
|
||||
or a batch re-padded after init -> shape mismatch).
|
||||
|
||||
Cached swa_loc is computed once from committed positions, so every draft-decode
|
||||
step would reuse the same ring slot and break the chain. Recompute from the live
|
||||
per-step positions; only the draft path is affected, the rest keeps the fast path.
|
||||
"""
|
||||
# Cached slots use committed positions; draft steps need live positions.
|
||||
positions = forward_batch.positions
|
||||
core = getattr(self.forward_metadata, "core_attn_metadata", None)
|
||||
unified = getattr(core, "unified", None) if core is not None else None
|
||||
@@ -1818,7 +1787,7 @@ class DeepseekV4HipRadixBackend(
|
||||
core_attn_metadata.c4_sparse_topk_lengths_raw = None
|
||||
core_attn_metadata.c4_sparse_page_indices = None
|
||||
core_attn_metadata.c4_sparse_raw_indices = None
|
||||
core_attn_metadata.c1_flashmla_metadata = _create_flashmla_metadata()
|
||||
core_attn_metadata.c0_flashmla_metadata = _create_flashmla_metadata()
|
||||
core_attn_metadata.c4_flashmla_metadata = None
|
||||
core_attn_metadata.c128_flashmla_metadata = None
|
||||
return core_attn_metadata
|
||||
|
||||
@@ -632,7 +632,7 @@ class C4IndexerBackendMixin:
|
||||
# reading logits, so DeepGEMM can receive an empty range for them.
|
||||
if self.dsa_topk_backend.is_sgl_kernel():
|
||||
ke = torch.where(ke - ks > c4_indexer.index_topk, ke, ks)
|
||||
c4_page_size = indexer_metadata.c4_page_size
|
||||
c4_page_size = indexer_metadata.compressed_page_size
|
||||
max_seqlen_k = (final_c4_len + c4_page_size - 1) // c4_page_size * c4_page_size
|
||||
plan = NonPagedIndexerPlan(
|
||||
page_table=request_page_table,
|
||||
@@ -793,7 +793,7 @@ class C4IndexerBackendMixin:
|
||||
return F.pad(tensor, pad, value=value)
|
||||
|
||||
c4_seq_lens = match_num_queries(
|
||||
indexer_metadata.c4_seq_lens, value=0 if use_aiter_fp4 else 1
|
||||
indexer_metadata.compressed_seq_lens, value=0 if use_aiter_fp4 else 1
|
||||
)
|
||||
_c4sl = c4_seq_lens
|
||||
page_table = match_num_queries(indexer_metadata.page_table, value=0)
|
||||
@@ -856,7 +856,7 @@ class C4IndexerBackendMixin:
|
||||
c4_seq_lens[rows],
|
||||
page_table[rows],
|
||||
c4_sparse_page_indices[rows],
|
||||
indexer_metadata.c4_page_size,
|
||||
indexer_metadata.compressed_page_size,
|
||||
row_raw_indices,
|
||||
)
|
||||
elif self.dsa_topk_backend.is_flashinfer():
|
||||
@@ -865,7 +865,7 @@ class C4IndexerBackendMixin:
|
||||
c4_seq_lens[rows],
|
||||
page_table[rows],
|
||||
c4_sparse_page_indices[rows],
|
||||
indexer_metadata.c4_page_size,
|
||||
indexer_metadata.compressed_page_size,
|
||||
row_raw_indices,
|
||||
)
|
||||
elif self.dsa_topk_backend.should_use_topk_v2() and raw_indices is None:
|
||||
@@ -874,7 +874,7 @@ class C4IndexerBackendMixin:
|
||||
c4_seq_lens[rows],
|
||||
page_table[rows],
|
||||
c4_sparse_page_indices[rows],
|
||||
indexer_metadata.c4_page_size,
|
||||
indexer_metadata.compressed_page_size,
|
||||
# The cached plan routes rows by their index in the full
|
||||
# range, so a chunk needs one built over its own rows.
|
||||
(
|
||||
@@ -889,7 +889,7 @@ class C4IndexerBackendMixin:
|
||||
c4_seq_lens[rows],
|
||||
page_table[rows],
|
||||
c4_sparse_page_indices[rows],
|
||||
indexer_metadata.c4_page_size,
|
||||
indexer_metadata.compressed_page_size,
|
||||
row_raw_indices,
|
||||
)
|
||||
|
||||
@@ -964,7 +964,7 @@ class C4IndexerBackendMixin:
|
||||
_c4sl[rows],
|
||||
page_table[rows],
|
||||
metadata,
|
||||
indexer_metadata.max_c4_seq_len,
|
||||
indexer_metadata.max_compressed_seq_len,
|
||||
False,
|
||||
)
|
||||
run_topk_transform(rows, logits)
|
||||
@@ -990,7 +990,7 @@ class C4IndexerBackendMixin:
|
||||
core_metadata.c4_sparse_page_indices = (
|
||||
hisparse_coordinator.swap_in_selected_pages(
|
||||
req_pool_indices=forward_batch.req_pool_indices,
|
||||
compressed_seq_lens=indexer_metadata.c4_seq_lens,
|
||||
compressed_seq_lens=indexer_metadata.compressed_seq_lens,
|
||||
top_k_result=raw_indices,
|
||||
layer_id=compress_layer_id,
|
||||
)
|
||||
|
||||
@@ -45,8 +45,8 @@ positions:
|
||||
|
||||
Some other notes:
|
||||
c4_ / c128_: means "compressed by 4" / "compressed by 128".
|
||||
c4_page_size: page_size // 4
|
||||
c4_seq_lens: seq_lens // 4, but bounded by at least 1, due to flash_mla requirement.
|
||||
compressed_page_size: page_size // 4
|
||||
compressed_seq_lens: seq_lens // 4, but bounded by at least 1, due to flash_mla requirement.
|
||||
c4_sparse: means "compressed by 4" but only attend to top-512 tokens.
|
||||
all related length will be clipped to 512.
|
||||
"""
|
||||
@@ -115,7 +115,7 @@ class NonPagedIndexerPlan:
|
||||
class PagedIndexerMetadata:
|
||||
page_size: int
|
||||
page_table: torch.Tensor
|
||||
c4_seq_lens: torch.Tensor
|
||||
compressed_seq_lens: torch.Tensor
|
||||
use_topk_v2: bool
|
||||
force_deep_gemm_metadata: bool = False
|
||||
use_prefill_cuda_graph: bool = False
|
||||
@@ -135,7 +135,7 @@ class PagedIndexerMetadata:
|
||||
|
||||
use_jit_indexer = not self.force_deep_gemm_metadata and (
|
||||
envs.SGLANG_OPT_USE_JIT_INDEXER_METADATA.get()
|
||||
or self.c4_seq_lens.numel() > _LARGE_INDEXER_QUERY_THRESHOLD
|
||||
or self.compressed_seq_lens.numel() > _LARGE_INDEXER_QUERY_THRESHOLD
|
||||
)
|
||||
if use_jit_indexer:
|
||||
from sglang.kernels.ops.attention.dsv4 import (
|
||||
@@ -144,25 +144,25 @@ class PagedIndexerMetadata:
|
||||
else:
|
||||
from deep_gemm import get_paged_mqa_logits_metadata
|
||||
|
||||
_c4 = self.c4_seq_lens.to(torch.int32)
|
||||
if _c4.dim() == 1:
|
||||
_c4 = _c4.unsqueeze(-1)
|
||||
if _IS_SM120 and _c4.shape[0] > _SM120_INDEXER_M_CHUNK:
|
||||
# Chunk metadata is identical for every layer in the forward
|
||||
# pass; compute the per-chunk list once here instead of per
|
||||
# layer in the indexer.
|
||||
compressed_seq_lens = self.compressed_seq_lens.to(torch.int32)
|
||||
if compressed_seq_lens.dim() == 1:
|
||||
compressed_seq_lens = compressed_seq_lens.unsqueeze(-1)
|
||||
if _IS_SM120 and compressed_seq_lens.shape[0] > _SM120_INDEXER_M_CHUNK:
|
||||
# Chunk metadata is shared by all indexer layers in this forward.
|
||||
self.deep_gemm_metadata = [
|
||||
get_paged_mqa_logits_metadata(
|
||||
_c4[_s : _s + _SM120_INDEXER_M_CHUNK],
|
||||
self.c4_page_size,
|
||||
compressed_seq_lens[_s : _s + _SM120_INDEXER_M_CHUNK],
|
||||
self.compressed_page_size,
|
||||
deep_gemm.get_num_sms(),
|
||||
)
|
||||
for _s in range(0, _c4.shape[0], _SM120_INDEXER_M_CHUNK)
|
||||
for _s in range(
|
||||
0, compressed_seq_lens.shape[0], _SM120_INDEXER_M_CHUNK
|
||||
)
|
||||
]
|
||||
else:
|
||||
self.deep_gemm_metadata = get_paged_mqa_logits_metadata(
|
||||
_c4,
|
||||
self.c4_page_size,
|
||||
compressed_seq_lens,
|
||||
self.compressed_page_size,
|
||||
deep_gemm.get_num_sms(),
|
||||
)
|
||||
|
||||
@@ -171,14 +171,14 @@ class PagedIndexerMetadata:
|
||||
if self.use_topk_v2:
|
||||
from sglang.kernels.ops.attention.dsv4 import plan_topk_v2
|
||||
|
||||
self.topk_metadata = plan_topk_v2(self.c4_seq_lens)
|
||||
self.topk_metadata = plan_topk_v2(self.compressed_seq_lens)
|
||||
else:
|
||||
self.topk_metadata = torch.empty((0,))
|
||||
|
||||
assert self.page_size == 256, "the system hardcodes page_size=256"
|
||||
|
||||
@property
|
||||
def c4_page_size(self) -> int:
|
||||
def compressed_page_size(self) -> int:
|
||||
return self.page_size // 4
|
||||
|
||||
@property
|
||||
@@ -186,15 +186,15 @@ class PagedIndexerMetadata:
|
||||
return self.page_table.shape[1] * self.page_size
|
||||
|
||||
@property
|
||||
def max_c4_seq_len(self) -> int:
|
||||
return self.page_table.shape[1] * self.c4_page_size
|
||||
def max_compressed_seq_len(self) -> int:
|
||||
return self.page_table.shape[1] * self.compressed_page_size
|
||||
|
||||
def copy_(self, other: PagedIndexerMetadata):
|
||||
if is_hip():
|
||||
copy_fields = ["page_table", "c4_seq_lens"]
|
||||
copy_fields = ["page_table", "compressed_seq_lens"]
|
||||
assign_fields = ["deep_gemm_metadata", "nonpaged_plan"]
|
||||
else:
|
||||
copy_fields = ["page_table", "c4_seq_lens", "deep_gemm_metadata"]
|
||||
copy_fields = ["page_table", "compressed_seq_lens", "deep_gemm_metadata"]
|
||||
assign_fields = ["nonpaged_plan"]
|
||||
copy_fields += ["topk_metadata"]
|
||||
copy_metadata(
|
||||
|
||||
@@ -42,9 +42,8 @@ def get_compress_state_ring_size(
|
||||
compress_ratio: int, is_speculative: bool = False
|
||||
) -> int:
|
||||
assert compress_ratio in [4, 128], f"Unsupported {compress_ratio = }"
|
||||
# Online c128 keeps a single (max, sum, kv) state per index instead of a
|
||||
# 128-slot ring buffer of raw tokens, so ring_size collapses to 1. Online
|
||||
# is incompatible with speculative decode for now.
|
||||
# Online C128 stores one (max, sum, kv) state per index;
|
||||
# speculative decoding requires the experimental online C128 MTP path.
|
||||
if compress_ratio == 128 and ONLINE_C128:
|
||||
if is_speculative and not envs.SGLANG_EXPERIMENTAL_ONLINE_C128_MTP.get():
|
||||
raise AssertionError("online c128 does not support MTP")
|
||||
@@ -56,9 +55,8 @@ def get_compress_state_ring_size(
|
||||
|
||||
|
||||
def get_compress_state_write_pad(compress_ratio: int, ring_size: int) -> int:
|
||||
"""Largest draft-token count this ring can serve; mirrors `mtp_pad` in `c_plan.cuh`
|
||||
(the bound is derived there). Zero for a non-speculative ring, which is exactly one
|
||||
window wide."""
|
||||
# Draft-token capacity must match mtp_pad in c_plan.cuh;
|
||||
# a non-speculative ring has no write padding.
|
||||
window_size = compress_ratio * (2 if compress_ratio == 4 else 1)
|
||||
return ring_size - window_size + 2 if ring_size > window_size else 0
|
||||
|
||||
@@ -620,9 +618,8 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
|
||||
)
|
||||
|
||||
self.max_num_reqs = max_num_reqs
|
||||
# SWA ring needs one slot per addressable req_pool_idx. PD decode inflates
|
||||
# req_to_token past max_num_reqs (pre-alloc), so the caller passes the real
|
||||
# capacity; sizing as max_num_reqs+1 overflows ("length out of range").
|
||||
# PD preallocation can exceed max_num_reqs;
|
||||
# the SWA ring must cover every addressable req_pool_idx.
|
||||
self.num_req_slots = (
|
||||
num_req_slots if num_req_slots is not None else max_num_reqs + 1
|
||||
)
|
||||
@@ -648,9 +645,7 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
|
||||
self.c4_state_pool_size = c4_state_pool_size
|
||||
c128_ring_size = self.get_ring_size(128)
|
||||
if ONLINE_C128:
|
||||
# Request-scoped online C128 state is indexed by req_pool_idx.
|
||||
# PD decode can allocate pre-transfer slots beyond
|
||||
# max_num_reqs, so size to the actual req_to_token row count.
|
||||
# Request-scoped C128 state must also cover PD preallocation slots.
|
||||
c128_state_pool_size = max(c128_state_pool_size, self.num_req_slots)
|
||||
else:
|
||||
# Offline C128 keeps a per-request raw state ring.
|
||||
@@ -860,8 +855,8 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
|
||||
return data_ptrs, data_lens, item_lens
|
||||
|
||||
def get_unified_swa_ring_buf_infos(self) -> Tuple[List[int], List[int], List[int]]:
|
||||
"""SWA-ring region [0, swa_pages) of every unified_kv layer, addressed
|
||||
per-row by ring slot. Shipped as the StateType.SWA_RING PD component."""
|
||||
# StateType.SWA_RING transfers [0, swa_pages) of each unified_kv layer;
|
||||
# its indices address individual ring rows.
|
||||
# TODO(billishyahao): validate PP layer-slicing for SWA_RING.
|
||||
data_ptrs: List[int] = []
|
||||
data_lens: List[int] = []
|
||||
@@ -878,12 +873,8 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
|
||||
return data_ptrs, data_lens, item_lens
|
||||
|
||||
def unified_region_buffers(self, ratio: int) -> Tuple[List[torch.Tensor], int]:
|
||||
"""
|
||||
In unified_kv, swa/c4/c128 share one buffer with one slot per row. But the
|
||||
HiCache host pool transfers a whole page per indexed row, so we reshape the
|
||||
compressed region into the layout it expects: skip the SWA segment, reshape to
|
||||
one row per page, then cast to uint8.
|
||||
"""
|
||||
# HiCache expects byte rows containing whole pages;
|
||||
# the unified pool stores individual token rows after its SWA region.
|
||||
assert self._unified_kv, "unified_region_buffers requires unified_kv layout"
|
||||
assert ratio in (4, 128), f"unsupported compression ratio: {ratio}"
|
||||
|
||||
@@ -943,7 +934,7 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
|
||||
|
||||
return data_ptrs, data_lens, item_lens
|
||||
|
||||
def get_c128_state_buf_infos(
|
||||
def get_request_state_buf_infos(
|
||||
self,
|
||||
) -> Tuple[List[int], List[int], List[int]]:
|
||||
data_ptrs: List[int] = []
|
||||
@@ -1076,7 +1067,7 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
|
||||
)
|
||||
|
||||
def _init_compressed_layer_mapping(self):
|
||||
c1_cnt = c4_cnt = c128_cnt = 0
|
||||
c0_cnt = c4_cnt = c128_cnt = 0
|
||||
total_L = len(self.compression_ratios)
|
||||
self.layer_mapping: List[Optional[DeepSeekV4LayerItem]] = [None] * total_L
|
||||
|
||||
@@ -1085,9 +1076,9 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
|
||||
if ratio == 0:
|
||||
self.layer_mapping[idx] = DeepSeekV4LayerItem(
|
||||
compress_ratio=0,
|
||||
compress_layer_id=c1_cnt,
|
||||
compress_layer_id=c0_cnt,
|
||||
)
|
||||
c1_cnt += 1
|
||||
c0_cnt += 1
|
||||
elif ratio == 4:
|
||||
self.layer_mapping[idx] = DeepSeekV4LayerItem(
|
||||
compress_ratio=4,
|
||||
@@ -1188,9 +1179,8 @@ class DeepSeekV4TokenToKVPool(BaseSWAKVPool):
|
||||
accept_lens: torch.Tensor,
|
||||
num_draft_tokens: int,
|
||||
) -> None:
|
||||
"""Clear offline C128 ring slots written for rejected speculative tokens.
|
||||
C4 needs no counterpart: its draft states are overwritten in position order
|
||||
before any read; a C128 compression boundary can read a stale draft slot."""
|
||||
# C128 compression can read rejected draft slots at a boundary;
|
||||
# C4 overwrites its draft slots before reading them.
|
||||
if ONLINE_C128 or num_draft_tokens <= 1 or req_pool_indices.numel() == 0:
|
||||
return
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ class TestDSV4BreakableCudaGraphMetadataContract(CustomTestCase):
|
||||
metadata.c128_topk_lengths_clamp1 = torch.tensor(
|
||||
[base + 39, base + 40], dtype=torch.int32
|
||||
)
|
||||
metadata.c1_flashmla_metadata = object()
|
||||
metadata.c0_flashmla_metadata = object()
|
||||
metadata.c4_flashmla_metadata = object()
|
||||
metadata.c128_flashmla_metadata = object()
|
||||
return metadata
|
||||
@@ -377,10 +377,7 @@ class TestDSV4BreakableCudaGraphMetadataContract(CustomTestCase):
|
||||
)
|
||||
from sglang.srt.server_args import ServerArgs
|
||||
|
||||
# cg-refactor folded the legacy enable_breakable_cuda_graph flag
|
||||
# into cuda_graph_config. Verify the per-phase backend selectors
|
||||
# default to None (i.e. nothing opted into BREAKABLE without an
|
||||
# explicit CLI flag).
|
||||
# Breakable graphs require explicit opt-in for each phase.
|
||||
sa = ServerArgs(model_path="dummy")
|
||||
self.assertNotEqual(sa.cuda_graph_backend_decode, "breakable")
|
||||
self.assertNotEqual(sa.cuda_graph_backend_prefill, "breakable")
|
||||
@@ -519,7 +516,7 @@ class TestDSV4BreakableCudaGraphMetadataContract(CustomTestCase):
|
||||
"swa_topk_lengths",
|
||||
"c128_page_indices",
|
||||
"c128_topk_lengths_clamp1",
|
||||
"c1_flashmla_metadata",
|
||||
"c0_flashmla_metadata",
|
||||
"c4_flashmla_metadata",
|
||||
"c128_flashmla_metadata",
|
||||
]
|
||||
@@ -688,13 +685,8 @@ class TestDSV4BreakableCudaGraphMetadataContract(CustomTestCase):
|
||||
|
||||
|
||||
class TestDSV4SwaOutCacheLocResolution(CustomTestCase):
|
||||
"""`get_swa_out_cache_loc`: cached fast path vs store-time fallback.
|
||||
|
||||
The KV-store consumers run in paths that never invoke
|
||||
`init_forward_metadata_in_graph` (eager idle, runners that only run the
|
||||
out-graph prep) or whose batch is re-padded after init (DP attention).
|
||||
The resolver must use the per-forward cached value only when it is
|
||||
provably current and fall back to translating `out_cache_loc` otherwise.
|
||||
"""SWA writes must translate live locations for idle or missing/mismatched caches.
|
||||
A matching cache on an active forward must be reused.
|
||||
"""
|
||||
|
||||
def _make_backend(self, mapping: torch.Tensor):
|
||||
|
||||
@@ -654,7 +654,7 @@ def _make_dsv4_target(*, unified, mapping=None):
|
||||
pool.get_unified_swa_ring_buf_infos = lambda: (
|
||||
_buf_infos(12) if unified else ([], [], [])
|
||||
)
|
||||
pool.get_c128_state_buf_infos = lambda: ([], [], [])
|
||||
pool.get_request_state_buf_infos = lambda: ([], [], [])
|
||||
return pool
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class TestDSV4PagedIndexerMetadata(CustomTestCase):
|
||||
metadata = PagedIndexerMetadata(
|
||||
page_size=256,
|
||||
page_table=torch.zeros((1, 1), dtype=torch.int32),
|
||||
c4_seq_lens=torch.tensor([65], dtype=torch.int32),
|
||||
compressed_seq_lens=torch.tensor([65], dtype=torch.int32),
|
||||
use_topk_v2=False,
|
||||
force_deep_gemm_metadata=True,
|
||||
)
|
||||
@@ -68,7 +68,7 @@ class TestDSV4PagedIndexerMetadata(CustomTestCase):
|
||||
metadata = PagedIndexerMetadata(
|
||||
page_size=256,
|
||||
page_table=torch.zeros((1, 1), dtype=torch.int32),
|
||||
c4_seq_lens=torch.tensor([65], dtype=torch.int32),
|
||||
compressed_seq_lens=torch.tensor([65], dtype=torch.int32),
|
||||
use_topk_v2=False,
|
||||
)
|
||||
|
||||
@@ -84,7 +84,7 @@ class TestDSV4PagedIndexerMetadata(CustomTestCase):
|
||||
metadata = PagedIndexerMetadata(
|
||||
page_size=256,
|
||||
page_table=torch.zeros((1, 1), dtype=torch.int32),
|
||||
c4_seq_lens=torch.tensor([65], dtype=torch.int32),
|
||||
compressed_seq_lens=torch.tensor([65], dtype=torch.int32),
|
||||
use_topk_v2=False,
|
||||
)
|
||||
|
||||
@@ -253,7 +253,7 @@ class TestDSV4NonPagedIndexer(CustomTestCase):
|
||||
extend_start_loc=torch.tensor([0], dtype=torch.int32),
|
||||
extend_num_tokens=query_rows,
|
||||
)
|
||||
metadata = SimpleNamespace(nonpaged_plan=None, c4_page_size=64)
|
||||
metadata = SimpleNamespace(nonpaged_plan=None, compressed_page_size=64)
|
||||
page_table = torch.tensor([[3, 1]], dtype=torch.int32).repeat(query_rows, 1)
|
||||
c4_seq_lens = torch.tensor([62, 63, 64, 65], dtype=torch.int32)
|
||||
|
||||
@@ -301,7 +301,7 @@ class TestDSV4NonPagedIndexer(CustomTestCase):
|
||||
extend_start_loc=torch.tensor([0], dtype=torch.int32),
|
||||
extend_num_tokens=query_rows,
|
||||
)
|
||||
metadata = SimpleNamespace(nonpaged_plan=None, c4_page_size=64)
|
||||
metadata = SimpleNamespace(nonpaged_plan=None, compressed_page_size=64)
|
||||
page_table = torch.zeros((query_rows, 1), dtype=torch.int32)
|
||||
c4_seq_lens = torch.tensor(
|
||||
[124_997, 124_998, 124_999, 125_000], dtype=torch.int32
|
||||
@@ -339,7 +339,7 @@ class TestDSV4NonPagedIndexer(CustomTestCase):
|
||||
backend = SimpleNamespace(_can_use_nonpaged_indexer=can_use_nonpaged_indexer)
|
||||
backend.dsa_topk_backend = SimpleNamespace(is_sgl_kernel=lambda: True)
|
||||
c4_indexer = SimpleNamespace(use_fp4_indexer=False, index_topk=512)
|
||||
metadata = SimpleNamespace(nonpaged_plan=None, c4_page_size=64)
|
||||
metadata = SimpleNamespace(nonpaged_plan=None, compressed_page_size=64)
|
||||
|
||||
def build_plan(query_rows):
|
||||
batch = SimpleNamespace(
|
||||
|
||||
Reference in New Issue
Block a user