compressor_utils.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # SPDX-License-Identifier: Apache-2.0
  2. # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
  3. from dataclasses import dataclass
  4. from typing import Any
  5. import torch
  6. from vllm.model_executor.warmup.jit_warmup import zip_inputs
  7. from vllm.model_executor.warmup.jit_warmup_triton_helper import (
  8. LaunchSpec,
  9. TritonWarmupTensor,
  10. VllmTritonJitKernel,
  11. kernel_launcher,
  12. triton_scalar_specialization_rep,
  13. )
  14. from vllm.triton_utils import tl, triton
  15. from vllm.utils.math_utils import cdiv
  16. _DSPARK_SWA_INDEX_ALIGNMENT = 64
  17. def get_dspark_swa_index_width(
  18. window_size: int,
  19. num_speculative_tokens: int,
  20. ) -> int:
  21. """Return the padded width of non-causal DSpark SWA indices."""
  22. width = max(int(window_size), 0) + max(int(num_speculative_tokens), 0)
  23. return cdiv(width, _DSPARK_SWA_INDEX_ALIGNMENT) * _DSPARK_SWA_INDEX_ALIGNMENT
  24. class CompressedSlotMappingKernel(
  25. VllmTritonJitKernel["CompressedSlotMappingKernel.CompileKey"]
  26. ):
  27. TRITON_BLOCK_SIZE = 1024
  28. @dataclass(frozen=True)
  29. class CompileKey:
  30. compress_ratio: int
  31. triton_block_size: int
  32. block_size: int
  33. @staticmethod
  34. @triton.jit(do_not_specialize=["block_table_stride"])
  35. def kernel(
  36. # [num_tokens]
  37. slot_mapping_ptr,
  38. # [num_reqs + 1]
  39. query_start_loc_ptr,
  40. # [num_reqs]
  41. seq_lens_ptr,
  42. # [num_reqs, max_num_blocks]
  43. block_table_ptr,
  44. block_table_stride,
  45. block_size,
  46. COMPRESS_RATIO: tl.constexpr,
  47. PAD_ID: tl.constexpr,
  48. TRITON_BLOCK_SIZE: tl.constexpr,
  49. ):
  50. batch_idx = tl.program_id(0)
  51. query_start = tl.load(query_start_loc_ptr + batch_idx)
  52. query_end = tl.load(query_start_loc_ptr + batch_idx + 1)
  53. query_len = query_end - query_start
  54. seq_len = tl.load(seq_lens_ptr + batch_idx)
  55. start_pos = seq_len - query_len
  56. for i in range(0, query_len, TRITON_BLOCK_SIZE):
  57. offset = i + tl.arange(0, TRITON_BLOCK_SIZE)
  58. mask = offset < query_len
  59. pos = start_pos + i + tl.arange(0, TRITON_BLOCK_SIZE)
  60. is_valid = (pos + 1) % COMPRESS_RATIO == 0
  61. pos_after_compress = pos // COMPRESS_RATIO
  62. block_ids = pos_after_compress // block_size
  63. block_numbers = tl.load(
  64. block_table_ptr + batch_idx * block_table_stride + block_ids,
  65. mask=mask & is_valid,
  66. )
  67. slot_ids = block_numbers * block_size + pos_after_compress % block_size
  68. # NOTE
  69. slot_ids = tl.where(is_valid, slot_ids, PAD_ID)
  70. tl.store(slot_mapping_ptr + query_start + offset, slot_ids, mask=mask)
  71. def dispatch( # type: ignore[override]
  72. self,
  73. *,
  74. compress_ratio: int,
  75. block_size: int,
  76. ) -> CompileKey:
  77. return self.CompileKey(
  78. compress_ratio=compress_ratio,
  79. triton_block_size=self.TRITON_BLOCK_SIZE,
  80. block_size=triton_scalar_specialization_rep(block_size),
  81. )
  82. def get_warmup_keys(self, vllm_config: Any) -> list[CompileKey]:
  83. hf_config = vllm_config.model_config.hf_config
  84. configured_ratios = (
  85. *(getattr(hf_config, "compress_ratios", None) or ()),
  86. getattr(hf_config, "index_kpool", 1) or 1,
  87. )
  88. compress_ratios = tuple(
  89. dict.fromkeys(int(ratio) for ratio in configured_ratios if int(ratio) > 1)
  90. )
  91. if not compress_ratios:
  92. return []
  93. return self._trace_dispatch(self.dispatch)(
  94. zip_inputs(
  95. *(
  96. dict(
  97. compress_ratio=ratio,
  98. block_size=vllm_config.cache_config.block_size // ratio,
  99. )
  100. for ratio in compress_ratios
  101. )
  102. )
  103. )
  104. def warmup_inputs(self, compile_key: CompileKey) -> dict[str, Any]:
  105. int32_ptr = TritonWarmupTensor(torch.int32)
  106. return dict(
  107. slot_mapping=TritonWarmupTensor(torch.int64),
  108. query_start_loc=int32_ptr,
  109. seq_lens=int32_ptr,
  110. block_table=int32_ptr,
  111. block_size=compile_key.block_size,
  112. compress_ratio=compile_key.compress_ratio,
  113. )
  114. @kernel_launcher
  115. def __call__(
  116. self,
  117. slot_mapping: torch.Tensor,
  118. query_start_loc: torch.Tensor,
  119. seq_lens: torch.Tensor,
  120. block_table: torch.Tensor,
  121. block_size: int,
  122. compress_ratio: int,
  123. ) -> LaunchSpec:
  124. return (block_table.shape[0],), dict(
  125. block_table_stride=block_table.stride(0),
  126. COMPRESS_RATIO=compress_ratio,
  127. PAD_ID=-1,
  128. TRITON_BLOCK_SIZE=self.TRITON_BLOCK_SIZE,
  129. )
  130. def get_compressed_slot_mapping(
  131. num_tokens: int,
  132. query_start_loc: torch.Tensor,
  133. seq_lens: torch.Tensor,
  134. block_table: torch.Tensor,
  135. block_size: int,
  136. compress_ratio: int,
  137. out: torch.Tensor | None = None,
  138. ) -> torch.Tensor:
  139. if out is not None:
  140. # Guard: for padded / invalid sequences.
  141. # Negative positions produce bogus block indices that lead to illegal memory
  142. # accesses inside the block_table load.
  143. # NOTE: Fill -1 to the whole tensor, not just the first `num_tokens`.
  144. out.fill_(-1)
  145. slot_mapping = out[:num_tokens]
  146. else:
  147. slot_mapping = torch.full(
  148. (num_tokens,), -1, dtype=torch.int64, device=query_start_loc.device
  149. )
  150. _COMPRESSED_SLOT_MAPPING_KERNEL(
  151. slot_mapping,
  152. query_start_loc,
  153. seq_lens,
  154. block_table,
  155. block_size,
  156. compress_ratio,
  157. )
  158. return slot_mapping
  159. _COMPRESSED_SLOT_MAPPING_KERNEL = CompressedSlotMappingKernel()