[Spec][PP] Launch extend microbatches before the spec output exchange (#40499)

This commit is contained in:
YAMY
2026-09-21 15:47:03 -07:00
committed by GitHub
parent 0c53fec476
commit 0229025127
3 changed files with 47 additions and 13 deletions
+6 -3
View File
@@ -4525,10 +4525,13 @@ class Scheduler(
if is_verify_round
else batch_result.next_draft_input
)
if batch_result.new_seq_lens is not None:
batch.seq_lens = batch_result.new_seq_lens
new_seq_lens = batch_result.new_seq_lens
# Extend rounds return batch.seq_lens itself; copying it back
# would block the scheduler until the whole forward has run.
if new_seq_lens is not None and new_seq_lens is not batch.seq_lens:
batch.seq_lens = new_seq_lens
if batch.seq_lens_cpu is not None:
batch.seq_lens_cpu = batch_result.new_seq_lens.to("cpu")
batch.seq_lens_cpu = new_seq_lens.to("cpu")
batch.seq_lens_sum = int(batch.seq_lens_cpu.sum())
batch.input_ids = None # rebuilt next iter from draft_token
self.update_cache_from_scheduler(batch, batch_result)
@@ -55,6 +55,22 @@ def _pp_can_skip_output_comm(batch: ScheduleBatch) -> bool:
)
def _pp_exchange_outputs_before_forward(
cur_batch: Optional[ScheduleBatch],
spec_relay: bool,
is_last_rank: bool,
async_batch_depth: int,
) -> bool:
"""Extend microbatches launch first: they need nothing from the relay, and
exchanging first caps every stage at (pp_size - 1) / pp_size. A verify round
must exchange first or the ring deadlocks on its tree rebuild."""
if async_batch_depth > 0:
return True
if not spec_relay or is_last_rank or cur_batch is None:
return False
return not (cur_batch.forward_mode.is_extend() or cur_batch.is_extend_in_batch)
@dataclass
class PPBatchMetadata:
can_run_cuda_graph: bool
@@ -131,15 +147,11 @@ class SchedulerPPMixin:
next_pp_outputs = None
next_batch_result = None
d2h_event = None
# With zero async depth, non-last speculative ranks must
# exchange the previous outputs before launching the next batch.
# Tree planning synchronizes CUDA on the host; sending alone
# leaves the peer's return send unmatched and can block that
# synchronization while the peer waits for our next proxy.
# The last rank must launch first to produce its output.
exchange_outputs_before_forward = (
get_parallel().pp_async_batch_depth > 0
or (self._pp_spec_relay and not self.pp_group.is_last_rank)
exchange_outputs_before_forward = _pp_exchange_outputs_before_forward(
cur_batch=cur_batch,
spec_relay=self._pp_spec_relay,
is_last_rank=self.pp_group.is_last_rank,
async_batch_depth=get_parallel().pp_async_batch_depth,
)
if exchange_outputs_before_forward:
next_pp_outputs, next_batch_result, d2h_event = (