[Spec] Resolve shared-read ends from the backend declaration alone (#35059)

This commit is contained in:
Liangsheng Yin
2026-08-17 01:35:29 -07:00
committed by GitHub
parent b83d507cd7
commit 711bdacb82
7 changed files with 20 additions and 54 deletions
+2 -6
View File
@@ -1701,12 +1701,8 @@ class Scheduler(
dispatch_event_loop(self)
def _apply_war_barrier(self):
# Called right after each launch: order later schedule_stream work
# (result processing, next iteration's writes) behind the forward's
# shared-buffer reads. Fast path: wait on the read-done event the
# forward published after its snapshot (non-spec: decode graph; spec:
# draft_extend), then clear it. Else whole-forward wait_stream
# (forceable via SGLANG_FORCE_COARSE_WAR_BARRIER).
# WAR: keep later schedule_stream writes behind this forward's shared reads.
# Clearing matters: a phase that skips the publish then falls back to coarse.
if not self._war_barrier_enabled:
return
runner = self.model_worker.last_shared_read_runner
@@ -403,9 +403,8 @@ class ModelRunner:
# Init forward stream for overlap schedule
self.forward_stream = torch.get_device_module(self.device).Stream()
# Published by the step's last shared-buffer-reading phase (decode graph,
# eagle draft extend, or prefill); the scheduler's WAR barrier waits on it
# then clears it. None -> coarse whole-forward wait_stream.
# Read-done mailbox: the scheduler's WAR barrier reads it from the runner
# its worker names, and treats None as the coarse whole-forward fence.
self.shared_read_done_event: Optional[torch.cuda.Event] = None
# CPU offload
@@ -486,17 +486,7 @@ class DecodeCudaGraphRunner(BaseCudaGraphRunner):
return self.attn_backend
def _resolve_shared_read_ends(self, attn_backend, forward_mode) -> SharedReadEnds:
"""The backend's declaration, demoted when this runner cannot record
there. UNKNOWN records nothing (scheduler keeps the coarse fence)."""
if forward_mode.is_target_verify():
if not self.model_runner.spec_algorithm.is_last_shared_read_phase(
forward_mode
):
return SharedReadEnds.UNKNOWN
elif not forward_mode.is_decode():
return SharedReadEnds.UNKNOWN
declared = attn_backend.shared_read_ends(forward_mode)
if (
declared is SharedReadEnds.IN_REPLAY
and self.in_graph_metadata_prep_done is None
@@ -419,6 +419,8 @@ class NGRAMWorker(BaseSpecWorker):
batch_result = self.target_worker.forward_batch_generation(
batch, is_verify=True
)
# Verify reads shared state past the in-graph marker; keep it coarse.
self.target_worker.model_runner.shared_read_done_event = None
logits_output, can_run_cuda_graph = (
batch_result.logits_output,
@@ -127,14 +127,6 @@ class SpeculativeAlgorithm(Enum):
def supports_target_verify_for_draft(self) -> bool:
return self.is_dflash_family()
def is_last_shared_read_phase(self, forward_mode) -> bool:
# The step's last shared-buffer-reading phase owns the shared-read-done
# publish. DSPARK has no draft_extend: its draft samples inside the
# verify graph, so verify is that last phase.
if self.is_dflash_family() or self.is_dspark():
return forward_mode.is_target_verify()
return forward_mode.is_draft_extend_v2()
def supports_ragged_verify(self) -> bool:
"""Whether this algorithm's verify step may carry a RaggedVerifyLayout
(per-request verify lengths); gates the token-bucket-keyed verify
@@ -92,10 +92,6 @@ class CustomSpecAlgo:
def supports_target_verify_for_draft(self) -> bool:
return False
def is_last_shared_read_phase(self, forward_mode) -> bool:
# The step's last shared-buffer-reading phase owns the shared-read-done publish.
return forward_mode.is_draft_extend_v2()
def supports_ragged_verify(self) -> bool:
return False