|
| 1 | +# SPDX-License-Identifier: Apache-2.0 |
| 2 | +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | +"""MUSA-0203: backport of vllm-project/vllm#34880 — llm_base_proposer.py. |
| 4 | +
|
| 5 | +In upstream PR #34880 these hunks target ``vllm/v1/spec_decode/eagle.py``. |
| 6 | +On v0.20.0-dev the EagleProposer implementation lives in |
| 7 | +``vllm/v1/spec_decode/llm_base_proposer.py`` (eagle.py is a 22-line |
| 8 | +stub). The hunks below re-target the same semantic changes to the |
| 9 | +v0.20.0-dev file structure. |
| 10 | +
|
| 11 | +Changes: |
| 12 | + 1. Import ``CUDAGraphWrapper`` + ``BatchDescriptor``. |
| 13 | + 2. ``CudagraphDispatcher(self.vllm_config)`` -> ``(..., for_draft_model=True)``. |
| 14 | + 3. ``initialize_cudagraph_keys``: pass through target's |
| 15 | + ``cudagraph_mode`` directly (was restricted to PIECEWISE). |
| 16 | + 4. ``load_model``: wrap ``self.model`` with |
| 17 | + ``CUDAGraphWrapper(runtime_mode=FULL)`` when target has FULL |
| 18 | + captures (no-op when target is PIECEWISE-only). |
| 19 | + 5. ``_determine_batch_execution_and_padding``: return 4-tuple |
| 20 | + (adds ``batch_desc``); thread ``uniform_decode`` + |
| 21 | + ``uniform_decode_query_len`` through. |
| 22 | + 6. ``propose``: pass ``batch_descriptor=batch_desc`` to both |
| 23 | + ``set_forward_context`` calls (first forward + per-step loop). |
| 24 | +
|
| 25 | +Skipped from PR #34880 in this version (lower-priority for MUSA |
| 26 | +PIECEWISE workload — can be added later): |
| 27 | + - ``target_model_batch_desc`` propose() parameter (gpu_model_runner |
| 28 | + caller change required). |
| 29 | + - ``dummy_run`` two-pass capture variant. |
| 30 | + - ``prepare_next_token_ids_padded`` / ``prepare_inputs_padded`` |
| 31 | + padding fixes. |
| 32 | +
|
| 33 | +When upstream PR #34880 merges (or v0.20.0-dev rebases onto it), this |
| 34 | +patch's anchors will stop matching and the file should be deleted. |
| 35 | +""" |
| 36 | + |
| 37 | +# ---- Hunk 1: import CUDAGraphWrapper + BatchDescriptor ---- |
| 38 | +_OLD_IMPORTS = """from vllm.distributed.parallel_state import get_pp_group |
| 39 | +from vllm.forward_context import set_forward_context""" |
| 40 | + |
| 41 | +_NEW_IMPORTS = """from vllm.compilation.cuda_graph import CUDAGraphWrapper |
| 42 | +from vllm.distributed.parallel_state import get_pp_group |
| 43 | +from vllm.forward_context import BatchDescriptor, set_forward_context""" |
| 44 | + |
| 45 | +# ---- Hunk 2: dispatcher init — for_draft_model=True ---- |
| 46 | +_OLD_DISPATCHER_INIT = """ self.cudagraph_dispatcher = CudagraphDispatcher(self.vllm_config)""" |
| 47 | + |
| 48 | +_NEW_DISPATCHER_INIT = """ # MUSA-0203 / PR #34880: dedicated dispatcher for the draft model so |
| 49 | + # FULL-mode capture keys are registered with uniform_decode_query_len=1 |
| 50 | + # (each Eagle decode step is 1 token per request). |
| 51 | + self.cudagraph_dispatcher = CudagraphDispatcher( |
| 52 | + self.vllm_config, for_draft_model=True |
| 53 | + )""" |
| 54 | + |
| 55 | +# ---- Hunk 3: initialize_cudagraph_keys — pass target mode through ---- |
| 56 | +_OLD_INIT_KEYS = """ \"\"\"Initialize cudagraph dispatcher keys for eagle. |
| 57 | +
|
| 58 | + Eagle only supports PIECEWISE cudagraphs (via mixed_mode). |
| 59 | + This should be called after adjust_cudagraph_sizes_for_spec_decode. |
| 60 | + \"\"\" |
| 61 | + if ( |
| 62 | + not self.speculative_config.enforce_eager |
| 63 | + and cudagraph_mode.mixed_mode() |
| 64 | + in [CUDAGraphMode.PIECEWISE, CUDAGraphMode.FULL] |
| 65 | + ): |
| 66 | + eagle_cudagraph_mode = CUDAGraphMode.PIECEWISE |
| 67 | + else: |
| 68 | + eagle_cudagraph_mode = CUDAGraphMode.NONE |
| 69 | +
|
| 70 | + self.cudagraph_dispatcher.initialize_cudagraph_keys(eagle_cudagraph_mode)""" |
| 71 | + |
| 72 | +_NEW_INIT_KEYS = """ \"\"\"Initialize cudagraph dispatcher keys for eagle. |
| 73 | +
|
| 74 | + MUSA-0203 / PR #34880: pass the target's cudagraph_mode through |
| 75 | + directly. With ``for_draft_model=True`` the dispatcher now |
| 76 | + registers both the legacy mixed-mode (PIECEWISE) keys AND the |
| 77 | + new FULL-mode keys at uniform_decode_query_len=1, so the draft |
| 78 | + model can dispatch FULL captures when the target uses FULL or |
| 79 | + FULL_AND_PIECEWISE. |
| 80 | + \"\"\" |
| 81 | + if self.speculative_config.enforce_eager: |
| 82 | + cudagraph_mode = CUDAGraphMode.NONE |
| 83 | + self.cudagraph_dispatcher.initialize_cudagraph_keys(cudagraph_mode)""" |
| 84 | + |
| 85 | +# ---- Hunk 4: load_model — wrap with CUDAGraphWrapper ---- |
| 86 | +_OLD_LOAD_MODEL = """self.model = self._get_model() |
| 87 | +
|
| 88 | + # Find draft layers""" |
| 89 | + |
| 90 | +_NEW_LOAD_MODEL = """self.model = self._get_model() |
| 91 | + # MUSA-0203 / PR #34880: wrap the draft model with FULL-mode |
| 92 | + # CUDAGraphWrapper when target uses FULL captures. CUDAGraphWrapper |
| 93 | + # is a no-op when the runtime mode at call time doesn't match FULL, |
| 94 | + # so this is safe when target is PIECEWISE-only. |
| 95 | + cudagraph_mode = self.compilation_config.cudagraph_mode |
| 96 | + if ( |
| 97 | + cudagraph_mode.has_full_cudagraphs() |
| 98 | + and not self.vllm_config.parallel_config.use_ubatching |
| 99 | + and not self.speculative_config.disable_padded_drafter_batch |
| 100 | + ): |
| 101 | + self.model = CUDAGraphWrapper( |
| 102 | + self.model, self.vllm_config, runtime_mode=CUDAGraphMode.FULL |
| 103 | + ) |
| 104 | +
|
| 105 | + # Find draft layers""" |
| 106 | + |
| 107 | +# ---- Hunk 5: _determine_batch_execution_and_padding signature + dispatch + return ---- |
| 108 | +_OLD_DETERMINE = """ def _determine_batch_execution_and_padding( |
| 109 | + self, |
| 110 | + num_tokens: int, |
| 111 | + use_cudagraphs: bool = True, |
| 112 | + ) -> tuple[CUDAGraphMode, int, torch.Tensor | None]: |
| 113 | + cudagraph_mode, batch_desc = self.cudagraph_dispatcher.dispatch( |
| 114 | + num_tokens, |
| 115 | + valid_modes=({CUDAGraphMode.NONE} if not use_cudagraphs else None),""" |
| 116 | + |
| 117 | +_NEW_DETERMINE = """ def _determine_batch_execution_and_padding( |
| 118 | + self, |
| 119 | + num_tokens: int, |
| 120 | + uniform_decode: bool = False, |
| 121 | + use_cudagraphs: bool = True, |
| 122 | + uniform_decode_query_len: int | None = None, |
| 123 | + ) -> tuple[CUDAGraphMode, BatchDescriptor, int, torch.Tensor | None]: |
| 124 | + cudagraph_mode, batch_desc = self.cudagraph_dispatcher.dispatch( |
| 125 | + num_tokens, |
| 126 | + uniform_decode, |
| 127 | + valid_modes=({CUDAGraphMode.NONE} if not use_cudagraphs else None), |
| 128 | + uniform_decode_query_len=uniform_decode_query_len,""" |
| 129 | + |
| 130 | +# Need to also patch the return statement of _determine_batch_execution_and_padding |
| 131 | +# to 4-tuple. Find the unique anchor. |
| 132 | +_OLD_DETERMINE_RETURN = """ return cudagraph_mode, num_tokens_padded, num_tokens_across_dp""" |
| 133 | + |
| 134 | +_NEW_DETERMINE_RETURN = """ return cudagraph_mode, batch_desc, num_tokens_padded, num_tokens_across_dp""" |
| 135 | + |
| 136 | +# ---- Hunk 6: propose() first-forward _determine_batch unpack ---- |
| 137 | +# In v0.20.0-dev the propose() first forward is: |
| 138 | +# cudagraph_runtime_mode, num_input_tokens, num_tokens_across_dp = ( |
| 139 | +# self._determine_batch_execution_and_padding(num_tokens) |
| 140 | +# ) |
| 141 | +# We need 4-tuple unpack now. |
| 142 | +_OLD_PROPOSE_FIRST_DET = """ cudagraph_runtime_mode, num_input_tokens, num_tokens_across_dp = ( |
| 143 | + self._determine_batch_execution_and_padding(num_tokens) |
| 144 | + )""" |
| 145 | + |
| 146 | +_NEW_PROPOSE_FIRST_DET = """ cudagraph_runtime_mode, batch_desc, num_input_tokens, num_tokens_across_dp = ( |
| 147 | + self._determine_batch_execution_and_padding(num_tokens) |
| 148 | + )""" |
| 149 | + |
| 150 | +# ---- Hunk 7: propose() first-forward set_forward_context — thread batch_desc ---- |
| 151 | +_OLD_FFC_FIRST = """ cudagraph_runtime_mode=cudagraph_runtime_mode, |
| 152 | + slot_mapping=self._get_slot_mapping( |
| 153 | + slot_mapping_size, common_attn_metadata.slot_mapping |
| 154 | + ),""" |
| 155 | + |
| 156 | +_NEW_FFC_FIRST = """ cudagraph_runtime_mode=cudagraph_runtime_mode, |
| 157 | + batch_descriptor=batch_desc, |
| 158 | + slot_mapping=self._get_slot_mapping( |
| 159 | + slot_mapping_size, common_attn_metadata.slot_mapping |
| 160 | + ),""" |
| 161 | + |
| 162 | +# ---- Hunk 8: propose() loop _determine_batch unpack ---- |
| 163 | +# The second occurrence is inside the loop, with `batch_size` not `num_tokens`. |
| 164 | +_OLD_PROPOSE_LOOP_DET = """ cudagraph_runtime_mode, input_batch_size, batch_size_across_dp = ( |
| 165 | + self._determine_batch_execution_and_padding(batch_size) |
| 166 | + )""" |
| 167 | + |
| 168 | +_NEW_PROPOSE_LOOP_DET = """ # MUSA-0203 / PR #34880: subsequent decode passes dispatch with |
| 169 | + # (batch_size, uniform=True, qdl=1) so the draft's FULL-mode capture |
| 170 | + # keys are exercised. |
| 171 | + cudagraph_runtime_mode, batch_desc, input_batch_size, batch_size_across_dp = ( |
| 172 | + self._determine_batch_execution_and_padding( |
| 173 | + batch_size, uniform_decode=True, uniform_decode_query_len=1 |
| 174 | + ) |
| 175 | + )""" |
| 176 | + |
| 177 | +# ---- Hunk 9: propose() loop set_forward_context — thread batch_desc ---- |
| 178 | +_OLD_FFC_LOOP = """ cudagraph_runtime_mode=cudagraph_runtime_mode, |
| 179 | + slot_mapping=self._get_slot_mapping(input_batch_size),""" |
| 180 | + |
| 181 | +_NEW_FFC_LOOP = """ cudagraph_runtime_mode=cudagraph_runtime_mode, |
| 182 | + batch_descriptor=batch_desc, |
| 183 | + slot_mapping=self._get_slot_mapping(input_batch_size),""" |
| 184 | + |
| 185 | +# ---- Hunk 10: dummy_run() unpack — match 4-tuple shape ---- |
| 186 | +_OLD_DUMMY_UNPACK = """ cudagraph_runtime_mode, num_input_tokens, num_tokens_across_dp = ( |
| 187 | + self._determine_batch_execution_and_padding( |
| 188 | + num_tokens, use_cudagraphs=use_cudagraphs |
| 189 | + ) |
| 190 | + )""" |
| 191 | + |
| 192 | +_NEW_DUMMY_UNPACK = """ cudagraph_runtime_mode, _, num_input_tokens, num_tokens_across_dp = ( |
| 193 | + self._determine_batch_execution_and_padding( |
| 194 | + num_tokens, use_cudagraphs=use_cudagraphs |
| 195 | + ) |
| 196 | + )""" |
| 197 | + |
| 198 | +PATCHES = [ |
| 199 | + (_OLD_IMPORTS, _NEW_IMPORTS), |
| 200 | + (_OLD_DISPATCHER_INIT, _NEW_DISPATCHER_INIT), |
| 201 | + (_OLD_INIT_KEYS, _NEW_INIT_KEYS), |
| 202 | + (_OLD_LOAD_MODEL, _NEW_LOAD_MODEL), |
| 203 | + (_OLD_DETERMINE, _NEW_DETERMINE), |
| 204 | + (_OLD_DETERMINE_RETURN, _NEW_DETERMINE_RETURN), |
| 205 | + (_OLD_PROPOSE_FIRST_DET, _NEW_PROPOSE_FIRST_DET), |
| 206 | + (_OLD_FFC_FIRST, _NEW_FFC_FIRST), |
| 207 | + (_OLD_PROPOSE_LOOP_DET, _NEW_PROPOSE_LOOP_DET), |
| 208 | + (_OLD_FFC_LOOP, _NEW_FFC_LOOP), |
| 209 | + (_OLD_DUMMY_UNPACK, _NEW_DUMMY_UNPACK), |
| 210 | +] |
0 commit comments