| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- # SPDX-License-Identifier: Apache-2.0
- # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
- import torch
- from vllm.triton_utils import tl, triton
- @triton.jit
- def _max_with_nan(a, b):
- return tl.maximum(a, b, propagate_nan=tl.PropagateNan.ALL)
- @triton.jit(do_not_specialize=["width", "nblocks"])
- def _block_scores_kernel(
- logits,
- starts,
- ends,
- scores,
- stride_row,
- stride_col,
- stride_start,
- stride_end,
- width,
- nblocks,
- BLOCK_SIZE: tl.constexpr,
- HAS_STARTS: tl.constexpr,
- ROW_REPEAT: tl.constexpr,
- TILE: tl.constexpr,
- ):
- row = tl.program_id(0).to(tl.int64)
- blocks = tl.program_id(1) * TILE + tl.arange(0, TILE)
- start = tl.load(starts + row // ROW_REPEAT * stride_start) if HAS_STARTS else 0
- end = tl.load(ends + row // ROW_REPEAT * stride_end)
- offsets = tl.arange(0, triton.next_power_of_2(BLOCK_SIZE))
- cols = start + blocks[:, None] * BLOCK_SIZE + offsets[None, :]
- values = tl.load(
- logits + row * stride_row + cols * stride_col,
- (blocks[:, None] < nblocks)
- & (offsets[None, :] < BLOCK_SIZE)
- & (cols < end)
- & (cols < width),
- other=-float("inf"),
- )
- reduced = tl.reduce(values, 1, _max_with_nan)
- reduced = tl.where(
- (end > start) & (blocks == (end - start - 1) // BLOCK_SIZE),
- float("inf"),
- reduced,
- )
- tl.store(scores + row * nblocks + blocks, reduced, blocks < nblocks)
- @triton.jit(do_not_specialize=["k"])
- def _store_candidates_kernel(
- values,
- indices,
- output,
- out_stride_row,
- out_stride_col,
- k,
- OUT_K: tl.constexpr,
- TILE: tl.constexpr,
- ):
- row = tl.program_id(0).to(tl.int64)
- cols = tl.program_id(1) * TILE + tl.arange(0, TILE)
- value = tl.load(values + row * k + cols, cols < k, other=-float("inf"))
- index = tl.load(indices + row * k + cols, cols < k, other=-1)
- tl.store(
- output + row * out_stride_row + cols * out_stride_col,
- tl.where(value > -float("inf"), index, -1),
- cols < OUT_K,
- )
- @triton.jit(do_not_specialize=["width", "nblocks"])
- def _candidate_flags_kernel(
- candidates,
- starts,
- flags,
- stride_row,
- stride_col,
- stride_start,
- width,
- nblocks,
- BLOCK_SIZE: tl.constexpr,
- K: tl.constexpr,
- HAS_STARTS: tl.constexpr,
- ROW_REPEAT: tl.constexpr,
- ):
- row = tl.program_id(0).to(tl.int64)
- offsets = tl.arange(0, 1024)
- for tile in range(tl.cdiv(nblocks + 1, 1024)):
- slots = tile * 1024 + offsets
- tl.store(flags + row * (nblocks + 1) + slots, 0, slots <= nblocks)
- start = tl.load(starts + row // ROW_REPEAT * stride_start) if HAS_STARTS else 0
- cols = tl.arange(0, triton.next_power_of_2(K))
- block = tl.load(
- candidates + row * stride_row + cols * stride_col, cols < K, other=-1
- ).to(tl.int64)
- # Preserve the packed-column clamp for candidates beyond the logits width.
- block = tl.where(start + block * BLOCK_SIZE >= width, nblocks, block)
- tl.debug_barrier()
- tl.store(flags + row * (nblocks + 1) + block, 1, (cols < K) & (block >= 0))
- @triton.jit(do_not_specialize=["width", "nblocks"])
- def _mask_candidates_kernel(
- logits,
- starts,
- ends,
- flags,
- stride_row,
- stride_col,
- stride_start,
- stride_end,
- width,
- nblocks,
- BLOCK_SIZE: tl.constexpr,
- HAS_STARTS: tl.constexpr,
- ROW_REPEAT: tl.constexpr,
- TILE: tl.constexpr,
- ):
- row = tl.program_id(0).to(tl.int64)
- cols = tl.program_id(1) * TILE + tl.arange(0, TILE)
- start = tl.load(starts + row // ROW_REPEAT * stride_start) if HAS_STARTS else 0
- end = tl.load(ends + row // ROW_REPEAT * stride_end)
- valid = (cols >= start) & (cols < end) & (cols < width)
- block = (cols - start) // BLOCK_SIZE
- keep = tl.load(flags + row * (nblocks + 1) + block, valid, other=0)
- edge = tl.load(flags + row * (nblocks + 1) + nblocks)
- keep = (keep != 0) | ((cols == width - 1) & (edge != 0))
- tl.store(
- logits + row * stride_row + cols * stride_col,
- -float("inf"),
- (cols < width) & ~(valid & keep),
- )
- def select_candidate_blocks(
- logits: torch.Tensor,
- row_ks: torch.Tensor | None,
- row_ke: torch.Tensor,
- topk_blocks: int,
- block_size: int,
- out: torch.Tensor,
- row_repeat: int = 1,
- ) -> None:
- """Select local block IDs by maximum score, pinning each row's newest block.
- Row bounds are in packed column space; absent starts mean zero.
- Decode rows share bounds in groups of ``row_repeat``. Output is -1 padded.
- """
- assert logits.is_cuda
- rows, width = logits.shape
- if not rows:
- return
- if not width:
- out.fill_(-1)
- return
- nblocks = triton.cdiv(width, block_size)
- scores = logits.new_empty((rows, nblocks))
- _block_scores_kernel[(rows, triton.cdiv(nblocks, 128))](
- logits,
- row_ks,
- row_ke,
- scores,
- *logits.stride(),
- row_ks.stride(0) if row_ks is not None else 0,
- row_ke.stride(0),
- width,
- nblocks,
- block_size,
- row_ks is not None,
- row_repeat,
- 128,
- )
- # Keep the existing top-k tie behavior.
- top = scores.topk(min(topk_blocks, nblocks), dim=-1)
- _store_candidates_kernel[(rows, triton.cdiv(topk_blocks, 256))](
- top.values,
- top.indices,
- out,
- *out.stride(),
- top.values.shape[1],
- topk_blocks,
- 256,
- )
- def apply_candidate_mask(
- logits: torch.Tensor,
- row_ks: torch.Tensor | None,
- row_ke: torch.Tensor,
- candidate_blocks: torch.Tensor,
- block_size: int,
- row_repeat: int = 1,
- ) -> None:
- """Mask packed logits outside causal bounds and request-local candidates."""
- assert logits.is_cuda
- rows, width = logits.shape
- if not rows or not width:
- return
- nblocks = triton.cdiv(width, block_size)
- flags = torch.empty((rows, nblocks + 1), device=logits.device, dtype=torch.uint8)
- start_stride = row_ks.stride(0) if row_ks is not None else 0
- _candidate_flags_kernel[(rows,)](
- candidate_blocks,
- row_ks,
- flags,
- *candidate_blocks.stride(),
- start_stride,
- width,
- nblocks,
- block_size,
- candidate_blocks.shape[1],
- row_ks is not None,
- row_repeat,
- )
- _mask_candidates_kernel[(rows, triton.cdiv(width, 1024))](
- logits,
- row_ks,
- row_ke,
- flags,
- *logits.stride(),
- start_stride,
- row_ke.stride(0),
- width,
- nblocks,
- block_size,
- row_ks is not None,
- row_repeat,
- 1024,
- )
|