[Model Runner V2][Spec Decode] Skip DP sync before EAGLE/MTP draft prefill (#53694)
Giancarlo Delfin committed
Aug 26, 2026 at 20:59 UTC
5acc1c4e4b8730298cbff7a4a7c68c814dc24fd7
8 files changed
+156
-36
tests/v1/worker/test_gpu_model_runner_v2_eplb.py
+1
-1
@@ -179,10 +179,10 @@ def test_v2_sample_tokens_runs_eplb_on_non_last_pp_rank(monkeypatch):
179
slot_mappings_by_layer=None,
180
hidden_states=None,
181
aux_hidden_states=None,
182
+ dp_sync=None,
183
finished_req_ids=set(),
184
ec_connector_output=None,
185
routed_experts=None,
185
- num_tokens_across_dp=None,
186
)
187
runner.req_states = SimpleNamespace()
188
vllm/v1/worker/gpu/dp_utils.py
+106
-18
@@ -2,6 +2,8 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
from __future__ import annotations
4
5
+from dataclasses import dataclass, replace
6
+
7
import torch
8
import torch.distributed as dist
9
@@ -13,6 +15,26 @@ from vllm.v1.worker.gpu.cudagraph_utils import (
15
)
16
17
18
+@dataclass(frozen=True)
19
+class DPSyncState:
20
+ """What a `dispatch_cg_and_sync_dp` call agreed across DP ranks.
21
+
22
+ Every field is identical on every rank, so callers can branch on them
23
+ without disagreeing about whether to run a collective. Never add a per-rank
24
+ value here.
25
+ """
26
+
27
+ # Per-rank token counts, for the forward context. All entries hold the
28
+ # agreed padded count, unless `eager`, where nothing was padded.
29
+ num_tokens_across_dp: torch.Tensor
30
+ # Agreed uniform decode length. None means the ranks disagreed, which is an
31
+ # answer, not "unknown".
32
+ uniform_token_count: int | None
33
+ # Whether the ranks agreed to run eager. A dispatch reusing this must run
34
+ # eager too; no shape was agreed, so picking a graph per rank would diverge.
35
+ eager: bool
36
+
37
+
38
def sync_cudagraph_and_dp_padding(
39
cudagraph_manager: CudaGraphManager | None,
40
desired_batch_desc: BatchExecutionDescriptor,
@@ -23,11 +45,11 @@ def sync_cudagraph_and_dp_padding(
45
dp_rank: int,
46
max_query_len: int | None = None,
47
num_active_loras: int = 0,
26
-) -> tuple[BatchExecutionDescriptor, torch.Tensor | None]:
48
+) -> tuple[BatchExecutionDescriptor, DPSyncState | None]:
49
"""
50
Coordinates the batch descriptor and DP padding across all ranks.
51
30
- Returns (synced_batch_desc, num_tokens_across_dp).
52
+ Returns (synced_batch_desc, sync). `sync` is None when no rank has work.
53
"""
54
assert dp_size > 1, "DP size must be greater than 1"
55
group = get_dp_group().cpu_group
@@ -43,6 +65,13 @@ def sync_cudagraph_and_dp_padding(
65
uniform_token_counts_across_dp = tensor[2]
66
max_query_lens_across_dp = tensor[3]
67
68
+ # If ranks disagree on the uniform token count, or its 0 (means None) set to None
69
+ synced_uniform_token_count: int | None = int(uniform_token_counts_across_dp[0])
70
+ if synced_uniform_token_count == 0 or not torch.all(
71
+ uniform_token_counts_across_dp == synced_uniform_token_count
72
+ ):
73
+ synced_uniform_token_count = None
74
+
75
if torch.all(num_tokens_across_dp == 0).item():
76
synced_desc = BatchExecutionDescriptor(
77
cg_mode=CUDAGraphMode.NONE, num_tokens=0, num_reqs=0
@@ -53,24 +82,25 @@ def sync_cudagraph_and_dp_padding(
82
83
# If any rank wants to run eager, all ranks run eager
84
if synced_cg_mode == CUDAGraphMode.NONE:
56
- return BatchExecutionDescriptor(
57
- cg_mode=CUDAGraphMode.NONE,
58
- num_tokens=num_tokens,
59
- num_reqs=num_reqs,
60
- num_active_loras=desired_batch_desc.num_active_loras,
61
- ), num_tokens_across_dp
85
+ return (
86
+ BatchExecutionDescriptor(
87
+ cg_mode=CUDAGraphMode.NONE,
88
+ num_tokens=num_tokens,
89
+ num_reqs=num_reqs,
90
+ num_active_loras=desired_batch_desc.num_active_loras,
91
+ ),
92
+ DPSyncState(
93
+ num_tokens_across_dp=num_tokens_across_dp,
94
+ uniform_token_count=synced_uniform_token_count,
95
+ eager=True,
96
+ ),
97
+ )
98
99
assert cudagraph_manager is not None, (
100
"cudagraph_manager should only be None during profile run, "
101
"where synced_cg_mode must be NONE across all DP ranks"
102
)
103
synced_num_tokens = int(num_tokens_across_dp.max().item())
68
- synced_uniform_token_count = uniform_token_counts_across_dp[0]
69
- # If ranks disagree on the uniform token count, or its 0 (means None) set to None
70
- if synced_uniform_token_count == 0 or not torch.all(
71
- uniform_token_counts_across_dp == synced_uniform_token_count
72
- ):
73
- synced_uniform_token_count = None
104
105
# Varlen decode graphs are selected by the query-length bound, so ranks must agree
106
# on it or they pad to different token counts below.
@@ -92,7 +122,11 @@ def sync_cudagraph_and_dp_padding(
122
# Update num_tokens_across_dp to reflect padded size.
123
num_tokens_across_dp[:] = synced_desc.num_tokens
124
95
- return synced_desc, num_tokens_across_dp
125
+ return synced_desc, DPSyncState(
126
+ num_tokens_across_dp=num_tokens_across_dp,
127
+ uniform_token_count=synced_uniform_token_count,
128
+ eager=False,
129
+ )
130
131
132
def dispatch_cg_and_sync_dp(
@@ -105,8 +139,43 @@ def dispatch_cg_and_sync_dp(
139
max_query_len: int | None = None,
140
need_eager: bool = False,
141
num_active_loras: int = 0,
108
-) -> tuple[BatchExecutionDescriptor, torch.Tensor | None]:
109
- if need_eager:
142
+ dp_sync: DPSyncState | None = None,
143
+) -> tuple[BatchExecutionDescriptor, DPSyncState | None]:
144
+ """Pick a cudagraph descriptor for this batch, agreeing it across DP ranks.
145
+
146
+ Runs a collective when dp_size > 1 so every rank dispatches to the same
147
+ shape. Pass `dp_sync` from a dispatch already made over this same batch (a
148
+ drafter's prefill runs the target's batch shape) to reuse that agreement
149
+ instead, with no collective.
150
+
151
+ Args:
152
+ cudagraph_manager: Manager to dispatch against. May be None only when
153
+ `need_eager` is True (profile run).
154
+ num_reqs: Requests in this rank's batch.
155
+ num_tokens: Tokens in this rank's batch, already padded by the caller.
156
+ uniform_token_count: Per-request token count if this rank's batch is a
157
+ uniform decode, else None. `dp_sync.uniform_token_count` takes its
158
+ place when a sync is reused, since that one is agreed across ranks.
159
+ dp_size: Data-parallel world size. 1 skips all cross-rank work.
160
+ dp_rank: This rank's index in the DP group.
161
+ max_query_len: Upper bound on per-request query length, for selecting
162
+ varlen decode graphs. None means the graph must not constrain it.
163
+ need_eager: Force `CUDAGraphMode.NONE` instead of dispatching.
164
+ num_active_loras: Active LoRA count for this rank. Does not need
165
+ cross-rank agreement; it never changes a bucket's token count.
166
+ dp_sync: Agreement from a prior dispatch over this same batch, to reuse.
167
+ Must come from a batch with this same padded `num_tokens` and the
168
+ same `uniform_token_count`; `num_reqs` may differ, as neither
169
+ depends on it. Passing a sync from a different batch is a caller
170
+ error and trips an assert.
171
+
172
+ Returns:
173
+ (batch_desc, sync), where `sync` is this batch's agreement for a later
174
+ dispatch to reuse. It is None when `dp_size` is 1 or no rank has work.
175
+ """
176
+ reuse_eager = dp_sync is not None and dp_sync.eager
177
+
178
+ if need_eager or reuse_eager:
179
batch_desc = BatchExecutionDescriptor(
180
cg_mode=CUDAGraphMode.NONE,
181
num_tokens=num_tokens,
@@ -121,7 +190,7 @@ def dispatch_cg_and_sync_dp(
190
batch_desc = cudagraph_manager.dispatch(
191
num_reqs,
192
num_tokens,
124
- uniform_token_count,
193
+ dp_sync.uniform_token_count if dp_sync is not None else uniform_token_count,
194
num_active_loras=num_active_loras,
195
max_query_len=max_query_len,
196
)
@@ -129,6 +198,25 @@ def dispatch_cg_and_sync_dp(
198
if dp_size == 1:
199
return batch_desc, None
200
201
+ if dp_sync is not None:
202
+ assert dp_sync.num_tokens_across_dp[dp_rank] == num_tokens, (
203
+ "reusing a DP sync taken over a different batch"
204
+ )
205
+ assert (
206
+ dp_sync.uniform_token_count is None
207
+ or uniform_token_count == dp_sync.uniform_token_count
208
+ ), "reusing a DP sync taken over a different batch"
209
+ if not dp_sync.eager and batch_desc.num_tokens != num_tokens:
210
+ # Capture sizes can differ between managers, so this one may
211
+ # pad further. Every rank pads alike, so report what will run.
212
+ dp_sync = replace(
213
+ dp_sync,
214
+ num_tokens_across_dp=torch.full_like(
215
+ dp_sync.num_tokens_across_dp, batch_desc.num_tokens
216
+ ),
217
+ )
218
+ return batch_desc, dp_sync
219
+
220
return sync_cudagraph_and_dp_padding(
221
cudagraph_manager,
222
batch_desc,
vllm/v1/worker/gpu/model_runner.py
+11
-3
@@ -97,7 +97,7 @@ from vllm.v1.worker.gpu.cudagraph_utils import (
97
from vllm.v1.worker.gpu.cudagraph_utils import (
98
profile_cudagraph_memory as _profile_cudagraph_memory,
99
)
100
-from vllm.v1.worker.gpu.dp_utils import dispatch_cg_and_sync_dp
100
+from vllm.v1.worker.gpu.dp_utils import DPSyncState, dispatch_cg_and_sync_dp
101
from vllm.v1.worker.gpu.ec_connector import get_ec_connector
102
from vllm.v1.worker.gpu.eplb_utils import EPLBController, step_eplb_after
103
from vllm.v1.worker.gpu.input_batch import (
@@ -752,6 +752,7 @@ class GPUModelRunner(LoRAModelRunnerMixin):
752
slot_mappings_by_layer = self.execute_model_state.slot_mappings_by_layer
753
hidden_states = self.execute_model_state.hidden_states
754
aux_hidden_states = self.execute_model_state.aux_hidden_states
755
+ dp_sync = self.execute_model_state.dp_sync
756
self.execute_model_state = None
757
758
self.step_timing.forward_end()
@@ -796,6 +797,7 @@ class GPUModelRunner(LoRAModelRunnerMixin):
797
next_prefill_tokens=self.req_states.next_prefill_tokens,
798
temperature=self.sampler.sampling_states.temperature.gpu,
799
seeds=self.sampler.sampling_states.seeds.gpu,
800
+ dp_sync=dp_sync,
801
dummy_run=True,
802
skip_attn_for_dummy_run=skip_attn,
803
mm_inputs=mm_inputs,
@@ -1544,7 +1546,7 @@ class GPUModelRunner(LoRAModelRunnerMixin):
1546
# cross-attention cache with dynamic encoder outputs.
1547
skip_compiled = True
1548
1547
- batch_desc, num_tokens_across_dp = dispatch_cg_and_sync_dp(
1549
+ batch_desc, dp_sync = dispatch_cg_and_sync_dp(
1550
self.cudagraph_manager,
1551
num_reqs,
1552
num_toks,
@@ -1731,7 +1733,9 @@ class GPUModelRunner(LoRAModelRunnerMixin):
1733
self.vllm_config,
1734
num_tokens=input_batch.num_tokens_after_padding,
1735
cudagraph_runtime_mode=batch_desc.cg_mode,
1734
- num_tokens_across_dp=num_tokens_across_dp,
1736
+ num_tokens_across_dp=(
1737
+ dp_sync.num_tokens_across_dp if dp_sync is not None else None
1738
+ ),
1739
batch_descriptor=batch_descriptor,
1740
slot_mapping=slot_mappings_by_layer,
1741
skip_compiled=skip_compiled,
@@ -1777,6 +1781,7 @@ class GPUModelRunner(LoRAModelRunnerMixin):
1781
slot_mappings_by_layer=slot_mappings_by_layer,
1782
hidden_states=hidden_states,
1783
aux_hidden_states=aux_hidden_states,
1784
+ dp_sync=dp_sync,
1785
finished_req_ids=finished_req_ids,
1786
ec_connector_output=ec_connector_output,
1787
routed_experts=routed_experts,
@@ -1801,6 +1806,7 @@ class GPUModelRunner(LoRAModelRunnerMixin):
1806
slot_mappings_by_layer = self.execute_model_state.slot_mappings_by_layer
1807
hidden_states = self.execute_model_state.hidden_states
1808
aux_hidden_states = self.execute_model_state.aux_hidden_states
1809
+ dp_sync = self.execute_model_state.dp_sync
1810
finished_req_ids = self.execute_model_state.finished_req_ids
1811
ec_connector_output = self.execute_model_state.ec_connector_output
1812
routed_experts = self.execute_model_state.routed_experts
@@ -1922,6 +1928,7 @@ class GPUModelRunner(LoRAModelRunnerMixin):
1928
self.req_states.next_prefill_tokens,
1929
self.sampler.sampling_states.temperature.gpu,
1930
self.sampler.sampling_states.seeds.gpu,
1931
+ dp_sync=dp_sync,
1932
mm_inputs=mm_inputs,
1933
)
1934
self.req_states.draft_tokens[input_batch.idx_mapping] = draft_tokens
@@ -2066,6 +2073,7 @@ class ExecuteModelState(NamedTuple):
2073
slot_mappings_by_layer: dict[str, torch.Tensor] | None
2074
hidden_states: torch.Tensor | None
2075
aux_hidden_states: list[torch.Tensor] | None
2076
+ dp_sync: DPSyncState | None
2077
finished_req_ids: set[str]
2078
ec_connector_output: ECConnectorOutput | None
2079
routed_experts: RoutedExpertsTensors | None
vllm/v1/worker/gpu/spec_decode/autoregressive/speculator.py
+15
-4
@@ -14,7 +14,7 @@ from vllm.v1.kv_cache_interface import KVCacheConfig
14
from vllm.v1.worker.gpu.attn_utils import build_slot_mappings_by_layer
15
from vllm.v1.worker.gpu.block_table import BlockTables
16
from vllm.v1.worker.gpu.cudagraph_utils import BatchExecutionDescriptor
17
-from vllm.v1.worker.gpu.dp_utils import dispatch_cg_and_sync_dp
17
+from vllm.v1.worker.gpu.dp_utils import DPSyncState, dispatch_cg_and_sync_dp
18
from vllm.v1.worker.gpu.input_batch import InputBatch, InputBuffers
19
from vllm.v1.worker.gpu.model_states.interface import ModelState
20
from vllm.v1.worker.gpu.spec_decode.autoregressive.cudagraph_utils import (
@@ -219,7 +219,7 @@ class AutoRegressiveSpeculator(DraftModelSpeculator):
219
temperature: torch.Tensor,
220
# [max_num_reqs]
221
seeds: torch.Tensor,
222
- num_tokens_across_dp: torch.Tensor | None = None,
222
+ dp_sync: DPSyncState | None = None,
223
dummy_run: bool = False,
224
skip_attn_for_dummy_run: bool = False,
225
mm_inputs: tuple[list[torch.Tensor], torch.Tensor] | None = None,
@@ -279,7 +279,7 @@ class AutoRegressiveSpeculator(DraftModelSpeculator):
279
max_query_len,
280
input_batch.has_prefill,
281
)
282
- prefill_batch_desc, num_tokens_across_dp = dispatch_cg_and_sync_dp(
282
+ prefill_batch_desc, prefill_batch_sync = dispatch_cg_and_sync_dp(
283
self.prefill_cudagraph_manager,
284
num_reqs,
285
num_tokens_padded,
@@ -287,6 +287,12 @@ class AutoRegressiveSpeculator(DraftModelSpeculator):
287
dp_size=self.dp_size,
288
dp_rank=self.dp_rank,
289
need_eager=is_profile,
290
+ dp_sync=dp_sync,
291
+ )
292
+ num_tokens_across_dp = (
293
+ prefill_batch_sync.num_tokens_across_dp
294
+ if prefill_batch_sync is not None
295
+ else None
296
)
297
298
self._prepare_eplb_forward(num_tokens)
@@ -328,7 +334,7 @@ class AutoRegressiveSpeculator(DraftModelSpeculator):
334
335
# Each request produces exactly 1 token per draft generation step,
336
# enabling FULL graph replay.
331
- decode_batch_desc, num_tokens_across_dp = dispatch_cg_and_sync_dp(
337
+ decode_batch_desc, decode_batch_sync = dispatch_cg_and_sync_dp(
338
self.decode_cudagraph_manager,
339
num_reqs,
340
num_reqs,
@@ -337,6 +343,11 @@ class AutoRegressiveSpeculator(DraftModelSpeculator):
343
dp_rank=self.dp_rank,
344
need_eager=is_profile,
345
)
346
+ num_tokens_across_dp = (
347
+ decode_batch_sync.num_tokens_across_dp
348
+ if decode_batch_sync is not None
349
+ else None
350
+ )
351
352
self.on_multi_step_decode_begin(num_reqs)
353
# Generate the remaining num_speculative_steps - 1 draft tokens.
vllm/v1/worker/gpu/spec_decode/dflash/speculator.py
+9
-4
@@ -19,7 +19,7 @@ from vllm.v1.kv_cache_interface import KVCacheConfig
19
from vllm.v1.worker.gpu.attn_utils import build_slot_mappings_by_layer
20
from vllm.v1.worker.gpu.block_table import BlockTables
21
from vllm.v1.worker.gpu.cp_utils import cp_local_slot, prepare_dcp_local_seq_lens
22
-from vllm.v1.worker.gpu.dp_utils import dispatch_cg_and_sync_dp
22
+from vllm.v1.worker.gpu.dp_utils import DPSyncState, dispatch_cg_and_sync_dp
23
from vllm.v1.worker.gpu.input_batch import InputBatch, InputBuffers
24
from vllm.v1.worker.gpu.model_states.interface import ModelState
25
from vllm.v1.worker.gpu.spec_decode.dflash.cudagraph import DFlashCudaGraphManager
@@ -335,7 +335,7 @@ class DFlashSpeculator(DraftModelSpeculator):
335
temperature: torch.Tensor,
336
# [max_num_reqs]
337
seeds: torch.Tensor,
338
- num_tokens_across_dp: torch.Tensor | None = None,
338
+ dp_sync: DPSyncState | None = None,
339
dummy_run: bool = False,
340
skip_attn_for_dummy_run: bool = False,
341
mm_inputs: tuple[list[torch.Tensor], torch.Tensor] | None = None,
@@ -377,7 +377,9 @@ class DFlashSpeculator(DraftModelSpeculator):
377
num_query_tokens,
378
attn_metadata=None,
379
slot_mappings=None,
380
- num_tokens_across_dp=num_tokens_across_dp,
380
+ num_tokens_across_dp=(
381
+ dp_sync.num_tokens_across_dp if dp_sync is not None else None
382
+ ),
383
cudagraph_runtime_mode=CUDAGraphMode.NONE,
384
)
385
return self.draft_tokens[:num_reqs]
@@ -438,7 +440,7 @@ class DFlashSpeculator(DraftModelSpeculator):
440
)
441
442
# Every DFlash step has exactly num_query_per_req tokens, so we can use FULL CGs
441
- batch_desc, num_tokens_across_dp = dispatch_cg_and_sync_dp(
443
+ batch_desc, batch_sync = dispatch_cg_and_sync_dp(
444
self.query_cudagraph_manager,
445
num_reqs,
446
num_query_tokens,
@@ -450,6 +452,9 @@ class DFlashSpeculator(DraftModelSpeculator):
452
453
num_reqs_padded = batch_desc.num_reqs or num_reqs
454
num_tokens_padded = batch_desc.num_tokens
455
+ num_tokens_across_dp = (
456
+ batch_sync.num_tokens_across_dp if batch_sync is not None else None
457
+ )
458
459
# Rebuild the draft attention metadata even when replaying the FULL
460
# graph so that any attention metadata builder state is updated.
vllm/v1/worker/gpu/spec_decode/extract_hidden_states.py
+5
-2
@@ -10,6 +10,7 @@ from vllm.config import VllmConfig
10
from vllm.config.compilation import CUDAGraphMode
11
from vllm.forward_context import set_forward_context
12
from vllm.model_executor.model_loader import get_model
13
+from vllm.v1.worker.gpu.dp_utils import DPSyncState
14
from vllm.v1.worker.gpu.input_batch import InputBatch
15
from vllm.v1.worker.gpu.spec_decode.speculator import DraftModelSpeculator
16
@@ -97,7 +98,7 @@ class ExtractHiddenStatesSpeculator(DraftModelSpeculator):
98
next_prefill_tokens: torch.Tensor,
99
temperature: torch.Tensor,
100
seeds: torch.Tensor,
100
- num_tokens_across_dp: torch.Tensor | None = None,
101
+ dp_sync: DPSyncState | None = None,
102
dummy_run: bool = False,
103
skip_attn_for_dummy_run: bool = False,
104
mm_inputs: tuple[list[torch.Tensor], torch.Tensor] | None = None,
@@ -143,7 +144,9 @@ class ExtractHiddenStatesSpeculator(DraftModelSpeculator):
144
draft_attn_metadata,
145
self.vllm_config,
146
num_tokens=num_tokens,
146
- num_tokens_across_dp=num_tokens_across_dp,
147
+ num_tokens_across_dp=(
148
+ dp_sync.num_tokens_across_dp if dp_sync is not None else None
149
+ ),
150
cudagraph_runtime_mode=CUDAGraphMode.NONE,
151
slot_mapping=draft_slot_mappings,
152
is_padding=input_batch.is_padding[:num_tokens],
vllm/v1/worker/gpu/spec_decode/multi_module_mtp/speculator.py
+7
-3
@@ -12,7 +12,7 @@ from vllm.logger import init_logger
12
from vllm.triton_utils import tl, triton
13
from vllm.v1.attention.backends.utils import PAD_SLOT_ID
14
from vllm.v1.worker.gpu.attn_utils import build_slot_mappings_by_layer
15
-from vllm.v1.worker.gpu.dp_utils import dispatch_cg_and_sync_dp
15
+from vllm.v1.worker.gpu.dp_utils import DPSyncState, dispatch_cg_and_sync_dp
16
from vllm.v1.worker.gpu.input_batch import InputBatch, InputBuffers
17
from vllm.v1.worker.gpu.spec_decode.autoregressive.cudagraph_utils import (
18
SpeculatorCudaGraphManager,
@@ -150,7 +150,7 @@ class MultiModuleMTPSpeculator(DraftModelSpeculator):
150
temperature: torch.Tensor,
151
# [max_num_reqs]
152
seeds: torch.Tensor,
153
- num_tokens_across_dp: torch.Tensor | None = None,
153
+ dp_sync: DPSyncState | None = None,
154
dummy_run: bool = False,
155
skip_attn_for_dummy_run: bool = False,
156
mm_inputs: tuple[list[torch.Tensor], torch.Tensor] | None = None,
@@ -191,7 +191,7 @@ class MultiModuleMTPSpeculator(DraftModelSpeculator):
191
uniform_token_count = get_uniform_decode_token_count(
192
num_reqs, num_tokens, max_query_len, input_batch.has_prefill
193
)
194
- batch_desc, num_tokens_across_dp = dispatch_cg_and_sync_dp(
194
+ batch_desc, batch_sync = dispatch_cg_and_sync_dp(
195
self.cudagraph_manager,
196
num_reqs,
197
input_batch.num_tokens_after_padding,
@@ -199,6 +199,10 @@ class MultiModuleMTPSpeculator(DraftModelSpeculator):
199
dp_size=self.dp_size,
200
dp_rank=self.dp_rank,
201
need_eager=is_profile,
202
+ dp_sync=dp_sync,
203
+ )
204
+ num_tokens_across_dp = (
205
+ batch_sync.num_tokens_across_dp if batch_sync is not None else None
206
)
207
208
# Rebuild the slot mappings and attention metadata.
vllm/v1/worker/gpu/spec_decode/speculator.py
+2
-1
@@ -21,6 +21,7 @@ from vllm.v1.worker.gpu.attn_utils import (
21
init_attn_backend,
22
)
23
from vllm.v1.worker.gpu.block_table import BlockTables
24
+from vllm.v1.worker.gpu.dp_utils import DPSyncState
25
from vllm.v1.worker.gpu.input_batch import InputBatch, InputBuffers
26
from vllm.v1.worker.gpu.model_states.interface import ModelState
27
from vllm.v1.worker.gpu.sample.gumbel import gumbel_sample
@@ -60,7 +61,7 @@ class BaseSpeculator(ABC):
61
temperature: torch.Tensor,
62
# [max_num_reqs]
63
seeds: torch.Tensor,
63
- num_tokens_across_dp: torch.Tensor | None = None,
64
+ dp_sync: DPSyncState | None = None,
65
dummy_run: bool = False,
66
skip_attn_for_dummy_run: bool = False,
67
mm_inputs: tuple[list[torch.Tensor], torch.Tensor] | None = None,