main
py 193 lines 6.08 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from dataclasses import dataclass
5 from typing import Any
6
7 import torch
8
9 from vllm.model_executor.warmup.jit_warmup import kernel_launcher
10 from vllm.model_executor.warmup.jit_warmup_triton_helper import (
11 LaunchSpec,
12 TritonWarmupTensor,
13 VllmTritonJitKernel,
14 )
15 from vllm.triton_utils import tl, triton
16 from vllm.utils.math_utils import next_power_of_2
17
18
19 class SavePartialStatesKernel(
20 VllmTritonJitKernel["SavePartialStatesKernel.CompileKey"]
21 ):
22 @dataclass(frozen=True)
23 class CompileKey:
24 head_size: int
25 triton_block_size: int
26 state_width: int
27 compress_ratio: int
28 kv_stride: int
29 score_stride: int
30 ape_stride: int
31 state_cache_stride0: int
32 state_cache_stride1: int
33 block_size: int
34
35 @staticmethod
36 @triton.jit
37 def kernel(
38 kv_ptr,
39 kv_stride,
40 score_ptr,
41 score_stride,
42 ape_ptr,
43 ape_stride,
44 positions_ptr,
45 state_cache_ptr,
46 state_cache_stride0,
47 state_cache_stride1,
48 slot_mapping_ptr,
49 block_size,
50 HEAD_SIZE: tl.constexpr,
51 TRITON_BLOCK_SIZE: tl.constexpr,
52 # state_cache last dim packs [kv_state, score_state], each STATE_WIDTH wide.
53 STATE_WIDTH: tl.constexpr,
54 COMPRESS_RATIO: tl.constexpr,
55 ):
56 token_idx = tl.program_id(0)
57 slot_id = tl.load(slot_mapping_ptr + token_idx)
58
59 # Skip padded / invalid tokens (slot_id == -1 is the PAD sentinel used
60 # by vLLM). During CUDA graph replay the batch may contain padding
61 # tokens whose slot_mapping is -1; writing to kv_state[-1] would be an
62 # illegal memory access.
63 if slot_id < 0:
64 return
65
66 block_idx = slot_id // block_size
67 pos_in_block = slot_id % block_size
68 base_ptr = (
69 state_cache_ptr
70 + block_idx * state_cache_stride0
71 + pos_in_block * state_cache_stride1
72 )
73
74 block = tl.arange(0, TRITON_BLOCK_SIZE)
75 mask = block < HEAD_SIZE
76
77 kv = tl.load(kv_ptr + token_idx * kv_stride + block, mask=mask)
78 tl.store(base_ptr + block, kv, mask=mask)
79
80 # Fused: score += ape[position % compress_ratio]
81 position = tl.load(positions_ptr + token_idx)
82 ape_row = position % COMPRESS_RATIO
83 ape = tl.load(ape_ptr + ape_row * ape_stride + block, mask=mask)
84 score = tl.load(score_ptr + token_idx * score_stride + block, mask=mask)
85 tl.store(
86 base_ptr + STATE_WIDTH + block,
87 score + ape,
88 mask=mask,
89 )
90
91 def dispatch( # type: ignore[override]
92 self,
93 *,
94 head_size: int,
95 **compile_key_fields: int,
96 ) -> CompileKey:
97 return self.CompileKey(
98 **compile_key_fields,
99 head_size=head_size,
100 triton_block_size=next_power_of_2(head_size),
101 )
102
103 def get_warmup_keys(
104 self,
105 *,
106 head_dim: int,
107 compress_ratio: int,
108 ) -> list[CompileKey]:
109 if head_dim <= 0 or compress_ratio not in (4, 128):
110 return []
111
112 coefficient = 2 if compress_ratio == 4 else 1
113 return self._trace_dispatch(self.dispatch)(
114 head_size=coefficient * head_dim,
115 state_width=coefficient * head_dim,
116 compress_ratio=compress_ratio,
117 kv_stride=2 * coefficient * head_dim,
118 score_stride=2 * coefficient * head_dim,
119 ape_stride=coefficient * head_dim,
120 state_cache_stride0=8 * coefficient * head_dim,
121 state_cache_stride1=2 * coefficient * head_dim,
122 block_size=4 if compress_ratio == 4 else 8,
123 )
124
125 def warmup_inputs(self, compile_key: CompileKey) -> dict[str, Any]:
126 return dict(
127 kv=TritonWarmupTensor(
128 torch.float32,
129 shape=(1, compile_key.head_size),
130 strides=(compile_key.kv_stride, 1),
131 ),
132 score=TritonWarmupTensor(
133 torch.float32,
134 shape=(1, 1),
135 strides=(compile_key.score_stride, 1),
136 ),
137 ape=TritonWarmupTensor(
138 torch.float32,
139 shape=(1, 1),
140 strides=(compile_key.ape_stride, 1),
141 ),
142 positions=TritonWarmupTensor(torch.int64),
143 state_cache=TritonWarmupTensor(
144 torch.float32,
145 shape=(1, 1, compile_key.state_width),
146 strides=(
147 compile_key.state_cache_stride0,
148 compile_key.state_cache_stride1,
149 1,
150 ),
151 ),
152 slot_mapping=TritonWarmupTensor(torch.int64),
153 block_size=compile_key.block_size,
154 state_width=compile_key.state_width,
155 compress_ratio=compile_key.compress_ratio,
156 )
157
158 @kernel_launcher
159 def __call__(
160 self,
161 kv: torch.Tensor,
162 score: torch.Tensor,
163 ape: torch.Tensor,
164 positions: torch.Tensor,
165 state_cache: torch.Tensor,
166 slot_mapping: torch.Tensor,
167 block_size: int,
168 state_width: int,
169 compress_ratio: int,
170 pdl_kwargs: dict | None = None,
171 ) -> LaunchSpec:
172 """Write packed [kv, score+ape] partial states into the compressor cache.
173
174 One program per token; pads (slot_id == -1) are skipped.
175 """
176 num_actual = slot_mapping.shape[0]
177 head_size = kv.shape[-1]
178 return (num_actual,), dict(
179 kv_stride=kv.stride(0),
180 score_stride=score.stride(0),
181 ape_stride=ape.stride(0),
182 state_cache_stride0=state_cache.stride(0),
183 state_cache_stride1=state_cache.stride(1),
184 block_size=block_size,
185 HEAD_SIZE=head_size,
186 TRITON_BLOCK_SIZE=next_power_of_2(head_size),
187 STATE_WIDTH=state_width,
188 COMPRESS_RATIO=compress_ratio,
189 **(pdl_kwargs or {}),
190 )
191
192
193 _SAVE_PARTIAL_STATES_KERNEL = SavePartialStatesKernel()