Add rids/bootstrap-room int-hash plumbing for deterministic per-request identification (#26814)

This commit is contained in:
fzyzcjy
2026-05-31 09:57:22 +08:00
committed by GitHub
parent 9c43c3719f
commit 268f4c82f1
5 changed files with 131 additions and 0 deletions
+1
View File
@@ -753,6 +753,7 @@ class Envs:
# KV-Canary (testing-only)
# ===================================================================
SGLANG_KV_CANARY_RING_CAPACITY = EnvInt(1024)
SGLANG_KV_CANARY_ENABLE_TOKEN_ORACLE = EnvBool(False)
SGLANG_KV_CANARY_ENABLE_MHA_V = EnvBool(False)
@@ -149,6 +149,8 @@ class DecodeInputBuffers(ForwardInputBuffers):
encoder_lens: Optional[torch.Tensor]
pp_proxy_tensors: Optional[Dict[str, torch.Tensor]]
ngram_embedding_info: Optional["NgramEmbeddingInfo"]
rids_int: Optional[torch.Tensor]
bootstrap_room_ids_int: Optional[torch.Tensor]
@classmethod
def create(
@@ -240,6 +242,13 @@ class DecodeInputBuffers(ForwardInputBuffers):
else None
)
if envs.SGLANG_KV_CANARY_ENABLE_TOKEN_ORACLE.get():
rids_int = torch.zeros((max_bs,), dtype=torch.int64)
bootstrap_room_ids_int = torch.full((max_bs,), -1, dtype=torch.int64)
else:
rids_int = None
bootstrap_room_ids_int = None
# Keep seq_lens_cpu as a true CPU tensor, like the old implementation.
seq_lens_cpu = torch.full(
(max_bs,),
@@ -267,6 +276,8 @@ class DecodeInputBuffers(ForwardInputBuffers):
global_num_tokens_for_logprob_gpu=global_num_tokens_for_logprob_gpu,
pp_proxy_tensors=pp_proxy_tensors,
ngram_embedding_info=ngram_embedding_info,
rids_int=rids_int,
bootstrap_room_ids_int=bootstrap_room_ids_int,
)
def populate_from_forward_batch(
@@ -342,6 +353,16 @@ class DecodeInputBuffers(ForwardInputBuffers):
dsts.append(self.mrope_positions[:, :raw_num_token])
srcs.append(forward_batch.mrope_positions)
if self.rids_int is not None and forward_batch.rids_int is not None:
dsts.append(self.rids_int[:raw_bs])
srcs.append(forward_batch.rids_int)
if (
self.bootstrap_room_ids_int is not None
and forward_batch.bootstrap_room_ids_int is not None
):
dsts.append(self.bootstrap_room_ids_int[:raw_bs])
srcs.append(forward_batch.bootstrap_room_ids_int)
if require_gathered_buffer:
self.global_num_tokens_gpu.fill_(bs * num_tokens_per_bs)
self.global_num_tokens_for_logprob_gpu.fill_(bs * num_tokens_per_bs)
@@ -935,6 +956,12 @@ class CudaGraphRunner:
encoder_lens = None
mrope_positions = buffers.mrope_positions[:, :num_tokens]
next_token_logits_buffer = buffers.next_token_logits_buffer[:num_tokens]
rids_int = buffers.rids_int[:bs] if buffers.rids_int is not None else None
bootstrap_room_ids_int = (
buffers.bootstrap_room_ids_int[:bs]
if buffers.bootstrap_room_ids_int is not None
else None
)
# Adjust for attention TP if needed (matching replay path in
# populate_from_forward_batch).
@@ -1050,6 +1077,8 @@ class CudaGraphRunner:
num_token_non_padded=buffers.num_token_non_padded,
global_forward_mode=self.capture_forward_mode,
lora_ids=lora_ids,
rids_int=rids_int,
bootstrap_room_ids_int=bootstrap_room_ids_int,
)
# Trip the coordinator so the hisparse code path is captured into the
@@ -27,6 +27,7 @@ ScheduleBatch -> ForwardBatch
from __future__ import annotations
import hashlib
from dataclasses import dataclass
from enum import IntEnum, auto
from functools import total_ordering
@@ -449,6 +450,10 @@ class ForwardBatch(ForwardBatchDeepSeekMHAMixin):
# For ngram embedding
ngram_embedding_info: Optional[NgramEmbeddingInfo] = None
# For dumper: int-hashed request / bootstrap-room IDs (derived from rids)
rids_int: Optional[torch.Tensor] = None
bootstrap_room_ids_int: Optional[torch.Tensor] = None
# kv-canary token-id validator snapshot
req_all_ids_flat: Optional[torch.Tensor] = None
req_all_ids_lens: Optional[torch.Tensor] = None
@@ -568,6 +573,20 @@ class ForwardBatch(ForwardBatchDeepSeekMHAMixin):
device = model_runner.device
if envs.SGLANG_KV_CANARY_ENABLE_TOKEN_ORACLE.get():
hashed = _hash_rids_to_tensor(
rids=[req.rid for req in batch.reqs],
device=device,
)
bootstrap_room_ids = _bootstrap_rooms_to_tensor(
bootstrap_rooms=[req.bootstrap_room for req in batch.reqs],
device=device,
)
batch.sampling_info.rids_int = hashed
batch.sampling_info.bootstrap_room_ids_int = bootstrap_room_ids
ret.rids_int = hashed
ret.bootstrap_room_ids_int = bootstrap_room_ids
if batch.extend_input_logprob_token_ids is not None:
ret.extend_input_logprob_token_ids_gpu = (
batch.extend_input_logprob_token_ids.to(device, non_blocking=True)
@@ -1086,6 +1105,17 @@ class ForwardBatch(ForwardBatchDeepSeekMHAMixin):
if self.extend_seq_lens is not None:
self.extend_seq_lens = self._pad_tensor_to_size(self.extend_seq_lens, bs)
if self.rids_int is not None:
self.rids_int = self._pad_tensor_to_size(self.rids_int, bs)
if self.sampling_info is not None:
self.sampling_info.rids_int = self.rids_int
if self.bootstrap_room_ids_int is not None:
self.bootstrap_room_ids_int = self._pad_tensor_to_size(
self.bootstrap_room_ids_int, bs, value=-1
)
if self.sampling_info is not None:
self.sampling_info.bootstrap_room_ids_int = self.bootstrap_room_ids_int
if self.spec_info is not None and self.spec_info.is_draft_input():
spec_info = self.spec_info
self.output_cache_loc_backup = self.out_cache_loc
@@ -1321,3 +1351,18 @@ else:
clamp_position = _clamp_position_native
def _hash_rids_to_tensor(*, rids: List[str], device: torch.device) -> torch.Tensor:
values: List[int] = [_stable_hash_str_to_i64(rid) for rid in rids]
return torch.tensor(values, dtype=torch.int64, device=device)
def _bootstrap_rooms_to_tensor(
*, bootstrap_rooms: List[Optional[int]], device: torch.device
) -> torch.Tensor:
values: List[int] = [room if room is not None else -1 for room in bootstrap_rooms]
return torch.tensor(values, dtype=torch.int64, device=device)
def _stable_hash_str_to_i64(rid: str) -> int:
digest = hashlib.blake2b(rid.encode("utf-8"), digest_size=8).digest()
return int.from_bytes(digest, "little", signed=True)
@@ -42,6 +42,8 @@ class SamplingBatchInfo:
# Masking tensors for grammar-guided structured outputs
vocab_size: int
grammars: Optional[List] = None
rids_int: Optional[torch.Tensor] = None
bootstrap_room_ids_int: Optional[torch.Tensor] = None
vocab_mask: Optional[torch.Tensor] = None
apply_mask_func: Optional[Callable[[torch.Tensor, torch.Tensor], None]] = None
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Callable, Optional
import torch
from sglang.srt.environ import envs
from sglang.srt.layers.dp_attention import DpPaddingMode, set_dp_buffer_len
from sglang.srt.model_executor.cuda_graph_runner import (
CUDA_GRAPH_CAPTURE_FAILED_MSG,
@@ -46,6 +47,8 @@ class EagleDraftInputBuffers(ForwardInputBuffers):
out_cache_loc: torch.Tensor
positions: torch.Tensor
mrope_positions: torch.Tensor
rids_int: Optional[torch.Tensor]
bootstrap_room_ids_int: Optional[torch.Tensor]
seq_lens: torch.Tensor
seq_lens_cpu: torch.Tensor
extend_seq_lens: torch.Tensor
@@ -124,6 +127,16 @@ class EAGLEDraftCudaGraphRunner:
)
positions = torch.zeros((self.max_num_token,), dtype=torch.int64)
mrope_positions = torch.zeros((3, self.max_num_token), dtype=torch.int64)
rids_int = (
torch.zeros((self.max_bs,), dtype=torch.int64)
if envs.SGLANG_KV_CANARY_ENABLE_TOKEN_ORACLE.get()
else None
)
bootstrap_room_ids_int = (
torch.full((self.max_bs,), -1, dtype=torch.int64)
if envs.SGLANG_KV_CANARY_ENABLE_TOKEN_ORACLE.get()
else None
)
seq_lens = torch.full(
(self.max_bs,), self.seq_len_fill_value, dtype=torch.int32
)
@@ -164,6 +177,8 @@ class EAGLEDraftCudaGraphRunner:
out_cache_loc=out_cache_loc,
positions=positions,
mrope_positions=mrope_positions,
rids_int=rids_int,
bootstrap_room_ids_int=bootstrap_room_ids_int,
seq_lens=seq_lens,
seq_lens_cpu=seq_lens_cpu,
extend_seq_lens=extend_seq_lens,
@@ -259,6 +274,12 @@ class EAGLEDraftCudaGraphRunner:
out_cache_loc = buffers.out_cache_loc[: num_tokens * self.speculative_num_steps]
positions = buffers.positions[:num_tokens]
mrope_positions = buffers.mrope_positions[:, :num_tokens]
rids_int = buffers.rids_int[:num_seqs] if buffers.rids_int is not None else None
bootstrap_room_ids_int = (
buffers.bootstrap_room_ids_int[:num_seqs]
if buffers.bootstrap_room_ids_int is not None
else None
)
hidden_states = (
buffers.hidden_states[:num_seqs]
if buffers.hidden_states is not None
@@ -341,6 +362,8 @@ class EAGLEDraftCudaGraphRunner:
global_dp_buffer_len=global_dp_buffer_len,
spec_algorithm=self.model_runner.spec_algorithm,
spec_info=spec_info,
rids_int=rids_int,
bootstrap_room_ids_int=bootstrap_room_ids_int,
capture_hidden_mode=(
spec_info.capture_hidden_mode if spec_info else CaptureHiddenMode.NULL
),
@@ -412,6 +435,10 @@ class EAGLEDraftCudaGraphRunner:
buffers.seq_lens.fill_(self.seq_len_fill_value)
buffers.out_cache_loc.zero_()
buffers.positions.zero_()
if buffers.rids_int is not None:
buffers.rids_int.zero_()
if buffers.bootstrap_room_ids_int is not None:
buffers.bootstrap_room_ids_int.fill_(-1)
buffers.topk_p.zero_()
buffers.topk_index.zero_()
if buffers.hidden_states is not None:
@@ -426,6 +453,15 @@ class EAGLEDraftCudaGraphRunner:
forward_batch.out_cache_loc
)
buffers.positions[:raw_num_token].copy_(forward_batch.positions)
if buffers.rids_int is not None and forward_batch.rids_int is not None:
buffers.rids_int[:raw_bs].copy_(forward_batch.rids_int)
if (
buffers.bootstrap_room_ids_int is not None
and forward_batch.bootstrap_room_ids_int is not None
):
buffers.bootstrap_room_ids_int[:raw_bs].copy_(
forward_batch.bootstrap_room_ids_int
)
maybe_detect_nan(
forward_batch.spec_info.topk_p,
"EagleDraftCudaGraphRunner.replay: topk_p",
@@ -457,6 +493,15 @@ class EAGLEDraftCudaGraphRunner:
forward_batch.seq_lens = buffers.seq_lens[:bs]
forward_batch.req_pool_indices = buffers.req_pool_indices[:bs]
forward_batch.positions = buffers.positions[:num_tokens]
if buffers.rids_int is not None and forward_batch.rids_int is not None:
forward_batch.rids_int = buffers.rids_int[:bs]
if (
buffers.bootstrap_room_ids_int is not None
and forward_batch.bootstrap_room_ids_int is not None
):
forward_batch.bootstrap_room_ids_int = buffers.bootstrap_room_ids_int[
:bs
]
if forward_batch.seq_lens_cpu is not None:
if bs != raw_bs:
@@ -481,6 +526,15 @@ class EAGLEDraftCudaGraphRunner:
forward_batch.positions = buffers.positions[:raw_num_token]
forward_batch.seq_lens = buffers.seq_lens[:raw_bs]
forward_batch.req_pool_indices = buffers.req_pool_indices[:raw_bs]
if buffers.rids_int is not None and forward_batch.rids_int is not None:
forward_batch.rids_int = buffers.rids_int[:raw_bs]
if (
buffers.bootstrap_room_ids_int is not None
and forward_batch.bootstrap_room_ids_int is not None
):
forward_batch.bootstrap_room_ids_int = buffers.bootstrap_room_ids_int[
:raw_bs
]
if forward_batch.seq_lens_cpu is not None:
forward_batch.seq_lens_cpu = buffers.seq_lens_cpu[:raw_bs]