[DSV4] Avoid host syncs in EAGLE prefill (#33662)
Co-authored-by: weireweire <20922698+weireweire@users.noreply.github.com>
This commit is contained in:
@@ -1824,6 +1824,14 @@ class DeepseekV4AttnBackend(
|
||||
if cache is None:
|
||||
seq_lens_cpu = forward_batch.seq_lens_cpu
|
||||
assert seq_lens_cpu is not None
|
||||
extend_seq_lens_cpu = forward_batch.extend_seq_lens_cpu
|
||||
assert extend_seq_lens_cpu is not None
|
||||
total_swa = sum(
|
||||
min(int(seq_len), int(extend_len) + SWA_WINDOW - 1)
|
||||
for seq_len, extend_len in zip(
|
||||
seq_lens_cpu.tolist(), extend_seq_lens_cpu, strict=True
|
||||
)
|
||||
)
|
||||
# ``swa_window_size`` on the pool is its storage page size, not
|
||||
# the model's SWA window — pass both explicitly.
|
||||
cache = SparsePrefillChunkCache.build(
|
||||
@@ -1836,6 +1844,7 @@ class DeepseekV4AttnBackend(
|
||||
swa_page_size=token_to_kv_pool.swa_window_size,
|
||||
num_qo_tokens=q_flat.shape[0],
|
||||
max_seq_len=int(seq_lens_cpu.max().item()),
|
||||
total_swa=total_swa,
|
||||
)
|
||||
self.forward_metadata.sparse_prefill_cache = cache
|
||||
|
||||
|
||||
@@ -195,6 +195,7 @@ def build_swa_token_ids(
|
||||
req_to_token: torch.Tensor,
|
||||
full_to_swa: torch.Tensor,
|
||||
swa_window: int,
|
||||
total_swa: int,
|
||||
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
||||
"""Build a flat list of physical SWA-cache token IDs covering each
|
||||
request's positional union of every query's SWA window.
|
||||
@@ -216,6 +217,7 @@ def build_swa_token_ids(
|
||||
full_to_swa: (full_pool_size + extra,) int64. Maps full kv id to
|
||||
SWA-cache id.
|
||||
swa_window: int. SWA window size.
|
||||
total_swa: Number of token IDs to allocate, computed from CPU lengths.
|
||||
|
||||
Returns:
|
||||
swa_token_ids: (total_swa,) int32, flat physical SWA-cache token IDs.
|
||||
@@ -238,8 +240,6 @@ def build_swa_token_ids(
|
||||
swa_first_pos = (seq_lens - swa_gather_lens).to(torch.int32)
|
||||
swa_offsets = torch.zeros(num_reqs + 1, dtype=torch.int32, device=device)
|
||||
swa_offsets[1:] = torch.cumsum(swa_gather_lens, dim=0).to(torch.int32)
|
||||
total_swa = int(swa_offsets[-1].item()) # one CPU sync per chunk
|
||||
|
||||
swa_token_ids = torch.empty(total_swa, dtype=torch.int32, device=device)
|
||||
if total_swa == 0:
|
||||
return swa_token_ids, swa_first_pos, swa_gather_lens, swa_offsets
|
||||
@@ -322,6 +322,7 @@ class SparsePrefillChunkCache:
|
||||
swa_page_size: int,
|
||||
num_qo_tokens: int,
|
||||
max_seq_len: int,
|
||||
total_swa: int,
|
||||
) -> "SparsePrefillChunkCache":
|
||||
device = seq_lens.device
|
||||
num_reqs = seq_lens.shape[0]
|
||||
@@ -337,6 +338,7 @@ class SparsePrefillChunkCache:
|
||||
req_to_token=req_to_token,
|
||||
full_to_swa=full_to_swa,
|
||||
swa_window=swa_window_size,
|
||||
total_swa=total_swa,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -92,7 +92,10 @@ def _eagle_prefill_tail_tokens(
|
||||
for i, r in enumerate(batch.reqs):
|
||||
if r is batch.chunked_req:
|
||||
tail_tokens = tail_tokens.clone()
|
||||
tail_tokens[i] = next_prompt_token
|
||||
# Keep the scalar as a kernel argument. Assigning a Python scalar
|
||||
# through scalar indexing issues a pageable H2D copy and
|
||||
# synchronizes the current CUDA stream before draft extend.
|
||||
tail_tokens[i : i + 1].fill_(next_prompt_token)
|
||||
break
|
||||
return tail_tokens
|
||||
|
||||
|
||||
Reference in New Issue
Block a user