vllm.v1.attention.backends.utils
¶
Classes:
-
PerLayerParameters–Currently, FlashInfer backend only support models in which all layers share
Functions:
-
compute_mm_prefix_range_tensor–Convert mm_prefix_range dict to padded tensor for Triton kernel.
-
compute_mm_prefix_ranges–Per-request PrefixLM bidirectional ranges for image/video tokens.
-
fill_mm_prefix_query_ranges–Map each scheduled query token to the mm_prefix range containing it.
-
get_dcp_local_seq_lens–While using dcp, kv_cache size stored on each rank may be different,
-
get_flashinfer_layout_string–Return the layout name in FlashInfer's convention (NHD/HND).
-
get_num_attention_heads_from_layers–Per-TP-rank
num_headsshared by the named Attention layers. -
get_per_layer_parameters–Scan layers in
layer_namesand determine some hyperparameters -
get_supported_kv_cache_layouts–Layouts every one of the worker's backends supports, most preferred first.
-
infer_global_hyperparameters–Currently, FlashInfer backend other than trtllm-gen
-
log2_lse_to_ln–Convert a base-2 log-sum-exp tensor to natural-log units.
-
mamba_get_block_table_tensor–Get the block table tensor for mamba kernels from the input
-
record_kv_cache_layout–Adopt a layout resolved elsewhere (the engine core) in this process.
-
reorder_batch_to_split_decodes_and_prefills–Reorders the batch to split into prefill and decode requests; places all
-
reshape_attn_output_for_spec_decode–Reshapes the attention output tensor, so that
-
reshape_query_for_spec_decode–Reshapes the query tensor for the specified batch size, so that
-
resolve_kv_cache_layout–Resolve one KV cache layout for the whole model.
-
set_triton_ptr_range–Bound the bytes Triton kernels may access through
views. -
split_decodes_and_prefills–Assuming a reordered batch, finds the boundary between prefill and decode
-
split_decodes_prefills_and_extends–Assuming a reordered batch, finds the boundary between prefill and decode
-
split_prefill_chunks–Split the prefill requests into chunks such that the total sequence length
PerLayerParameters
dataclass
¶
Currently, FlashInfer backend only support models in which all layers share the same values for the following hyperparameters. Should not be used for trtllm-gen backend since it supports different values for the following hyperparameters.
Source code in vllm/v1/attention/backends/utils.py
_mamba_align_block_table_kernel(out_ptr, block_table_ptr, block_table_stride_0, block_table_stride_1, seq_lens_ptr, seq_lens_stride, block_size, n_out, BLOCK)
¶
Gather the last n_out block-table entries of each request.
One program per request. This replaces a five-statement PyTorch expression
that expanded to seven kernels over a (num_reqs,) tensor -- one element
in a single-request decode -- so almost all of its cost was launch
overhead rather than work.
Both block-table strides are passed explicitly. The expression this replaces
was torch.gather(block_table, 1, ...), which honours any layout, and
this is a shared utility -- gdn_attn, mamba_attn, short_conv_attn
and linear_attn all call it -- so assuming a column stride of 1 would
silently read the wrong slots for a caller holding a non-contiguous view.
kimi_k3/nvidia/kda_metadata.py passes both strides for the same reason.
Two annotations above are load-bearing and easy to drop by accident:
block_table_stride_0: tl.int64
Without it req_idx * block_table_stride_0 is computed in i32 --
program_id is i32 and Triton specializes a stride below 2^31 to
i32 -- so the product wraps once a row offset reaches 2^31 elements
(a 4096 x 625000 table faults from row 3436 on MI355X).
torch.gather, which this replaces, indexes in 64-bit and has no
such limit, so narrowing it would be a regression.
mamba_utils.py:43 annotates its row stride the same way.
do_not_specialize_on_alignment on the three pointers
Triton puts pointer alignment in the specialization key, and the MRV1
DBO path hands this kernel seq_lens[request_slice] /
block_table_tensor[request_slice] VIEWS (ubatch_utils.py:278/316).
When a ubatch starts at a request index that is not a multiple of 4
the view is differently aligned and a fresh variant JIT-compiles
mid-step -- 25-28 ms cold, ~1.5 ms warm, and an error under
jit_monitor_mode=error. The torch expression this replaced never
compiled anything, so that recompile would be a regression introduced
by this change.
Source code in vllm/v1/attention/backends/utils.py
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | |
_merge_supported_layouts(supported_layouts_lists)
¶
Layouts in every supported set, merged as in
get_supported_kv_cache_layouts.
Source code in vllm/v1/attention/backends/utils.py
compute_mm_prefix_range_tensor(mm_prefix_range, num_seqs, device)
¶
Convert mm_prefix_range dict to padded tensor for Triton kernel.
Returns shape: (num_seqs, max_ranges, 2) with 0-padding for empty ranges. Empty ranges have start==end==0, which kernel skips via is_valid check.
Source code in vllm/v1/attention/backends/utils.py
compute_mm_prefix_ranges(mm_features_per_req, sliding_window=None, clamp_sliding_window=False, span_pad=0)
¶
Per-request PrefixLM bidirectional ranges for image/video tokens.
Source code in vllm/v1/attention/backends/utils.py
fill_mm_prefix_query_ranges(out, mm_prefix_range, query_start_loc_cpu, seq_lens_cpu)
¶
Map each scheduled query token to the mm_prefix range containing it.
Writes into out, a caller-owned (max_num_batched_tokens, 2) int32
staging buffer, and returns the number of rows written (0 if no range
covers any scheduled query token, in which case out is untouched and
the caller should skip the mask_mod entirely). Row i holds the absolute
[start, end] bounds of the bidirectional range that query token i
belongs to, or (-1, -1) when it is outside every range.
mm_prefix ranges never overlap, so "query and key share a range" is
equivalent to "the key lies inside the query's own range". The kernel
therefore needs no key-side lookup, and this metadata is sized by scheduled
query tokens rather than by context length -- bounded by
max_num_batched_tokens instead of num_seqs * max_seq_len.
Ranges are absolute prompt positions and may extend past the tokens
scheduled so far under chunked prefill; the portion outside the current
chunk is simply not recorded. Degenerate ranges (start >= end) are
skipped to match the Triton path's start < end validity check.
seq_lens_cpu only needs to be exact for prefill rows, since mm_prefix
ranges cover prompt tokens: an over-estimate on a decode row shifts that
row's query position further past every range, which still matches nothing.
Source code in vllm/v1/attention/backends/utils.py
get_dcp_local_seq_lens(seq_lens, dcp_size=1, dcp_rank=None, cp_kv_cache_interleave_size=1)
¶
While using dcp, kv_cache size stored on each rank may be different, use this function to calculate split decode seq_lens of each dcp rank. Only consider dcp now, we can extend the case of cp based on this.
Source code in vllm/v1/attention/backends/utils.py
get_flashinfer_layout_string(layout)
¶
Return the layout name in FlashInfer's convention (NHD/HND).
Source code in vllm/v1/attention/backends/utils.py
get_num_attention_heads_from_layers(vllm_config, layer_names)
¶
Per-TP-rank num_heads shared by the named Attention layers.
Use in metadata builders whose plan-time allocations depend on the
head count: the model-wide get_num_attention_heads() is wrong
for models with non-uniform per-layer head counts. All layers in
one attention group must agree on num_heads; this is asserted.
Returns None when no matching Attention layer is found.
Source code in vllm/v1/attention/backends/utils.py
get_per_layer_parameters(vllm_config, layer_names, cls_)
¶
Scan layers in layer_names and determine some hyperparameters
to use during plan.
Source code in vllm/v1/attention/backends/utils.py
get_supported_kv_cache_layouts(backends)
¶
Layouts every one of the worker's backends supports, most preferred first.
Every backend declares the layouts its kernels support, most preferred first
(supported_kv_cache_layouts), or None when any layout works; workers where
nothing declares follow the default preference. Identical declarations keep
their order; otherwise the layout the most backends put first wins, ties
keeping the enum order. An empty intersection is a hard error.
Source code in vllm/v1/attention/backends/utils.py
infer_global_hyperparameters(per_layer_params)
¶
Currently, FlashInfer backend other than trtllm-gen
only support models in which all layers share
the same values for the following hyperparameters:
- window_left
- logits_soft_cap
- sm_scale
So this function asserts that all layers share the same values for these hyperparameters and returns the global values.
Source code in vllm/v1/attention/backends/utils.py
log2_lse_to_ln(lse)
¶
mamba_get_block_table_tensor(block_table, seq_lens, kv_cache_spec, mamba_cache_mode)
¶
Get the block table tensor for mamba kernels from the input common_attn_metadata.block_table_tensor given different mamba cache modes.
-
"none": input (#requests, 1 + num_speculative_blocks); output (#requests, 1 + num_speculative_blocks).
-
"align": input (#requests, cdiv(max_model_len, block_size)); output (#requests, 1 + num_speculative_blocks), which are the last 1 + num_speculative_blocks of each request.
Source code in vllm/v1/attention/backends/utils.py
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 | |
record_kv_cache_layout(cache_config, layout_name)
¶
Adopt a layout resolved elsewhere (the engine core) in this process.
Source code in vllm/v1/attention/backends/utils.py
reorder_batch_to_split_decodes_and_prefills(input_batch, scheduler_output, decode_threshold=1)
¶
Reorders the batch to split into prefill and decode requests; places all requests with <= decode_threshold tokens at the front of the batch.
The batch is reordered into 4 regions
decode: (num_scheduled <= threshold AND is not prefilling) short_extend: (num_scheduled <= threshold AND is chunked prefilling) long_extend: (num_scheduled > threshold AND is chunked prefilling) prefill: (num_computed == 0) # First chunks
Returns:
-
bool–True if the batch was modified, False otherwise.
Source code in vllm/v1/attention/backends/utils.py
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 | |
reshape_attn_output_for_spec_decode(attn_output)
¶
Reshapes the attention output tensor, so that the batch_size and seq_len dimensions are combined.
Source code in vllm/v1/attention/backends/utils.py
reshape_query_for_spec_decode(query, batch_size)
¶
Reshapes the query tensor for the specified batch size, so that it has shape (batch_size, seq_len, num_heads, head_dim).
Source code in vllm/v1/attention/backends/utils.py
resolve_kv_cache_layout(vllm_config, supported_layouts, kv_cache_specs=None)
¶
Resolve one KV cache layout for the whole model.
Runs once in the engine core. Every worker reports the layouts its backends
support, most preferred first (get_supported_kv_cache_layouts). Pipeline
stages hold different layers, so their lists may differ; the candidates are
the layouts every worker supports, and the layout the most workers put first
wins. Workers whose backends declare nothing do not vote. Specs mixing HNC
shapes narrow the candidates to block-compact layouts. An explicit
VLLM_KV_CACHE_LAYOUT must be one of the candidates or resolution fails,
with the legacy NHD/HND names as aliases for LBNHC/LBHNC; the
connector's preference is used when compatible and dropped with a warning
otherwise. A layout already present on cache_config wins outright, and
the result is recorded there (see CacheConfig.kv_cache_layout); it
reaches workers through the set_kv_cache_layout RPC and
KVCacheConfig.kv_cache_layout.
Source code in vllm/v1/attention/backends/utils.py
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | |
set_triton_ptr_range(region, *views)
¶
Bound the bytes Triton kernels may access through views.
Triton's AMD backend uses 32-bit buffer addressing only for pointer
arguments within 2 GiB. It checks ptr_range() first and otherwise the
size of the whole storage, so views into one large allocation (such as a
layer of the KV cache) lose it. Each view gets the distance from its
data_ptr() to the end of region; kernels must not access past it.
Source code in vllm/v1/attention/backends/utils.py
split_decodes_and_prefills(common_attn_metadata, decode_threshold=1, require_uniform=False, treat_short_extends_as_decodes=True)
¶
Assuming a reordered batch, finds the boundary between prefill and decode requests.
The batch is expected to be ordered as
decode → short_extend → long_extend → prefill
Parameters:
-
(common_attn_metadata¶CommonAttentionMetadata) –CommonAttentionMetadata object containing the batch metadata.
-
(decode_threshold¶int, default:1) –The maximum query length to be considered a decode.
-
(require_uniform¶bool, default:False) –If True, requires that all decode requests have the same query length. When set, some queries may be considered prefills even if they are <= decode_threshold, in order to ensure uniformity.
-
(treat_short_extends_as_decodes¶bool, default:True) –If True (default), short extends (query_len <= threshold but still prefilling) are counted as decodes. If False, they are counted as prefills.
Returns:
-
num_decodes(int) –The number of decode requests.
-
num_prefills(int) –The number of prefill requests.
-
num_decode_tokens(int) –The number of tokens in the decode requests.
-
num_prefill_tokens(int) –The number of tokens in the prefill requests.
Source code in vllm/v1/attention/backends/utils.py
split_decodes_prefills_and_extends(common_attn_metadata, decode_threshold=1)
¶
Assuming a reordered batch, finds the boundary between prefill and decode requests.
Parameters:
-
(common_attn_metadata¶CommonAttentionMetadata) –CommonAttentionMetadata object containing the batch metadata.
-
(decode_threshold¶int, default:1) –The maximum query length to be considered a decode.
Returns:
-
num_decodes(int) –The number of decode requests.
-
num_extends(int) –The number of extend requests.
-
num_prefills(int) –The number of prefill requests.
-
num_decode_tokens(int) –The number of tokens in the decode requests.
-
num_extend_tokens(int) –The number of tokens in the extend requests.
-
num_prefill_tokens(int) –The number of tokens in the prefill requests.
Source code in vllm/v1/attention/backends/utils.py
split_prefill_chunks(seq_lens_cpu, workspace_size, request_offset=0)
¶
Split the prefill requests into chunks such that the total sequence length of each chunk is less than or equal to the workspace size.
Parameters:
-
(seq_lens_cpu¶Tensor) –The sequence lengths of the prefill requests on CPU.
-
(workspace_size¶int) –The maximum workspace size (in tokens) per chunk.
-
(request_offset¶int, default:0) –The offset to add to the request indices.
Returns: