22import triton
33import triton .language as tl
44from typing import Optional
5- from lightllm .common .triton_utils .autotuner import autotune , Autotuner
5+ from lightllm .common .triton_utils .autotuner import autotune , Autotuner , AutotuneKernelType , AutotuneLevel
6+ from lightllm .utils .envs_utils import get_decode_attn_autotune_seq_len , get_triton_autotune_level
67
78
89@triton .jit
@@ -138,27 +139,92 @@ def get_test_configs():
138139 return configs
139140
140141
141- def get_static_key (q , k , block_seq ):
142+ def get_static_key (q , k , block_seq , sliding_window ):
142143 key_params = {
143144 "gqa_group_size" : int (q .shape [1 ] // k .shape [1 ]),
144145 "q_head_dim" : int (q .shape [2 ]),
145146 "block_seq" : block_seq ,
147+ "sliding_window" : tuple (sliding_window ),
146148 "out_dtype" : str (q .dtype ),
147149 }
148150 return key_params
149151
150152
151153def get_run_key (q , max_len_in_batch ):
152154 batch_size = q .shape [0 ]
153- return batch_size * 1000 * 1000 * 1000 + max_len_in_batch
155+ # 正常执行使用调用方在 CPU 上保存的真实 KV 长度,不读取 GPU 长度张量或 Graph 的容量上限。
156+ max_kv_len = int (max_len_in_batch )
157+ if Autotuner .is_kernel_autotune_warmup (AutotuneKernelType .DECODE_ATTENTION ) and get_triton_autotune_level () in [
158+ AutotuneLevel .ADAPTIVE_AUTOTUNE ,
159+ AutotuneLevel .FORCE_AUTOTUNE ,
160+ ]:
161+ max_kv_len = get_decode_attn_autotune_seq_len ()
162+ # 调优和正常查找统一按 512 token 向上分桶,同一区间复用配置匹配结果。
163+ max_kv_len = (max_kv_len + 511 ) // 512 * 512
164+ return batch_size * 1000 * 1000 * 1000 + max_kv_len
165+
166+
167+ def rebuild_inputs (
168+ q : torch .Tensor ,
169+ k : torch .Tensor ,
170+ v : torch .Tensor ,
171+ Req_to_tokens : torch .Tensor ,
172+ B_req_idx : torch .Tensor ,
173+ B_Seqlen : torch .Tensor ,
174+ max_len_in_batch : int ,
175+ mid_out : torch .Tensor ,
176+ mid_out_logsumexp : torch .Tensor ,
177+ block_seq : int ,
178+ sliding_window = (- 1 , - 1 ),
179+ ** kwargs ,
180+ ):
181+ # Graph 初始化时真实请求很短,Req_to_tokens 的宽度则是容量上限,都不代表期望调优的长度。
182+ # 仅在实际搜索配置前重建一次输入,构造开销不计入 benchmark;正常执行和 Graph 捕获使用原输入。
183+ batch_size = q .shape [0 ]
184+ # 与调优时的 run key 共用该环境变量,默认 32768 token;实际计算保持精确长度,不做 512 分桶。
185+ max_len_in_batch = get_decode_attn_autotune_seq_len ()
186+ assert k .shape [0 ] == v .shape [0 ], "K/V caches must have the same number of tokens"
187+ num_tokens = k .shape [0 ]
188+ if num_tokens == 0 :
189+ raise ValueError ("GQA decode autotuning requires a non-empty KV cache" )
190+
191+ # 新建每个请求到物理 token 的映射,不能直接扩展 B_Seqlen 后读取原映射中未初始化的条目。
192+ # 物理 token 充足时各请求使用不同位置,不足时取模循环复用,保证所有索引均落在 K/V 缓存内。
193+ # 复用已有 K/V 可以避免分配完整的长请求缓存,但可能提高 GPU 缓存命中率,影响调优的访存特征。
194+ Req_to_tokens = torch .arange (batch_size * max_len_in_batch , dtype = Req_to_tokens .dtype , device = Req_to_tokens .device )
195+ Req_to_tokens = Req_to_tokens .remainder_ (num_tokens ).view (batch_size , max_len_in_batch )
196+ # 新映射只有 batch_size 行,请求索引也必须重建,避免继续使用原全局请求表中的行号。
197+ B_req_idx = torch .arange (batch_size , dtype = B_req_idx .dtype , device = B_req_idx .device )
198+ B_Seqlen = torch .full_like (B_Seqlen , max_len_in_batch )
199+
200+ # 保留 Q、滑窗语义、BLOCK_SEQ 和中间缓冲区布局;一个 program 可循环处理多个 KV 块,
201+ # 无需按调优长度扩容 mid_out。调优结束后 stage1 使用原始输入重新覆盖有效中间块,
202+ # stage2 仍按相同 BLOCK_SEQ 和缓冲区中的 block_num 归约。
203+ return (
204+ q ,
205+ k ,
206+ v ,
207+ Req_to_tokens ,
208+ B_req_idx ,
209+ B_Seqlen ,
210+ max_len_in_batch ,
211+ mid_out ,
212+ mid_out_logsumexp ,
213+ block_seq ,
214+ sliding_window ,
215+ ), kwargs
154216
155217
156218@autotune (
157- kernel_name = "_fwd_kernel_gqa_flash_decode_stage1:v3" ,
219+ kernel_name = "_fwd_kernel_gqa_flash_decode_stage1:v4" ,
220+ kernel_type = AutotuneKernelType .DECODE_ATTENTION ,
158221 configs_gen_func = get_test_configs ,
159222 static_key_func = get_static_key ,
160223 run_key_func = get_run_key ,
161- mutates_args = ["mid_out" , "mid_out_logsumexp" ],
224+ rebuild_input_func = rebuild_inputs ,
225+ # stage1 对有效中间块执行覆盖写,候选配置不会读取已有输出,正式执行也会重新覆盖真实请求的有效块。
226+ # 不标记这两个大缓冲区,避免每个候选配置 benchmark 时反复 clone,增加显存峰值和拷贝开销。
227+ # mutates_args=["mid_out", "mid_out_logsumexp"],
162228)
163229@torch .no_grad ()
164230def flash_decode_stage1 (
@@ -246,8 +312,6 @@ def flash_decode_stage1(
246312
247313
248314if __name__ == "__main__" :
249- from lightllm .utils .envs_utils import get_triton_autotune_level
250-
251315 if get_triton_autotune_level () != 2 :
252316 raise Exception ("you need set env LIGHTLLM_TRITON_AUTOTUNE_LEVEL=2 to start program." )
253317
@@ -258,11 +322,11 @@ def flash_decode_stage1(
258322 out_dtype = torch .bfloat16
259323
260324 batch_sizes = [1 , 8 , 16 , 32 , 64 , 128 ]
261- decode_lengths = [1024 , 2048 , 8192 , 16384 ]
325+ decode_lengths = [get_decode_attn_autotune_seq_len () ]
262326
263327 q_head_num = gqa_group_size
264328
265- Autotuner .start_autotune_warmup ()
329+ Autotuner .start_autotune_warmup (AutotuneKernelType . DECODE_ATTENTION )
266330 # autotuing kernel
267331 for batch_size in batch_sizes :
268332 for length in decode_lengths :
0 commit comments