interfaces.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. from abc import ABC, abstractmethod
  2. from typing import Dict, FrozenSet, List, Optional, Protocol, Tuple
  3. from aphrodite.common.utils import Device
  4. BlockId = int
  5. class Block(ABC):
  6. @abstractmethod
  7. def append_token_ids(self, token_ids: List[int]) -> None:
  8. pass
  9. @property
  10. @abstractmethod
  11. def block_id(self) -> Optional[int]:
  12. pass
  13. @block_id.setter
  14. @abstractmethod
  15. def block_id(self, value: Optional[int]) -> None:
  16. """NOTE: Do not use this API outside Block."""
  17. self._block_id = value
  18. @property
  19. @abstractmethod
  20. def token_ids(self) -> List[int]:
  21. pass
  22. @property
  23. @abstractmethod
  24. def num_tokens_total(self) -> int:
  25. """The number of tokens till the current block (inclusive)
  26. """
  27. pass
  28. @property
  29. @abstractmethod
  30. def num_empty_slots(self) -> int:
  31. pass
  32. @property
  33. @abstractmethod
  34. def is_full(self) -> bool:
  35. pass
  36. @property
  37. @abstractmethod
  38. def prev_block(self) -> Optional["Block"]:
  39. pass
  40. @property
  41. @abstractmethod
  42. def computed(self) -> bool:
  43. raise NotImplementedError
  44. @computed.setter
  45. @abstractmethod
  46. def computed(self, value) -> bool:
  47. """Should be only used by PrefixCacingAllocator"""
  48. raise NotImplementedError
  49. @property
  50. @abstractmethod
  51. def last_accessed(self) -> float:
  52. raise NotImplementedError
  53. @last_accessed.setter
  54. @abstractmethod
  55. def last_accessed(self, last_accessed_ts: float):
  56. raise NotImplementedError
  57. class Factory(Protocol):
  58. @abstractmethod
  59. def __call__(
  60. self,
  61. prev_block: Optional["Block"],
  62. token_ids: List[int],
  63. block_size: int,
  64. allocator: "BlockAllocator",
  65. block_id: Optional[int] = None,
  66. ) -> "Block":
  67. pass
  68. @property
  69. @abstractmethod
  70. def content_hash(self) -> Optional[int]:
  71. """Return the content-based hash of the current block, or None if it is
  72. not yet defined or not supported.
  73. For the content-based hash to be defined, the current block must be
  74. full.
  75. """
  76. return None
  77. class BlockAllocator(ABC):
  78. @abstractmethod
  79. def allocate_mutable_block(self, prev_block: Optional[Block]) -> Block:
  80. pass
  81. @abstractmethod
  82. def allocate_immutable_block(self, prev_block: Optional[Block],
  83. token_ids: List[int]) -> Block:
  84. pass
  85. @abstractmethod
  86. def allocate_immutable_blocks(
  87. self, prev_block: Optional[Block],
  88. block_token_ids: List[List[int]]) -> List[Block]:
  89. pass
  90. @abstractmethod
  91. def free(self, block: Block) -> None:
  92. pass
  93. @abstractmethod
  94. def fork(self, last_block: Block) -> List[Block]:
  95. pass
  96. @abstractmethod
  97. def get_num_total_blocks(self) -> int:
  98. pass
  99. @abstractmethod
  100. def get_num_free_blocks(self) -> int:
  101. pass
  102. @abstractmethod
  103. def get_physical_block_id(self, absolute_id: int) -> int:
  104. pass
  105. @abstractmethod
  106. def swap_out(self, blocks: List[Block]) -> None:
  107. pass
  108. @abstractmethod
  109. def swap_in(self, blocks: List[Block]) -> None:
  110. pass
  111. @property
  112. @abstractmethod
  113. def all_block_ids(self) -> FrozenSet[int]:
  114. pass
  115. @abstractmethod
  116. def clear_copy_on_writes(self) -> List[Tuple[int, int]]:
  117. pass
  118. @abstractmethod
  119. def mark_blocks_as_accessed(self, block_ids: List[int],
  120. now: float) -> None:
  121. pass
  122. @abstractmethod
  123. def mark_blocks_as_computed(self, block_ids: List[int]) -> None:
  124. pass
  125. @abstractmethod
  126. def get_computed_block_ids(self, prev_computed_block_ids: List[int],
  127. block_ids: List[int],
  128. skip_last_block_id: bool) -> List[int]:
  129. pass
  130. @abstractmethod
  131. def get_common_computed_block_ids(
  132. self, computed_seq_block_ids: List[List[int]]) -> List[int]:
  133. pass
  134. @abstractmethod
  135. def cow_block_if_not_appendable(self, block: Block) -> BlockId:
  136. """NOTE: This should not be used besides Block"""
  137. pass
  138. @abstractmethod
  139. def promote_to_immutable_block(self, block: Block) -> BlockId:
  140. """NOTE: This should not be used besides Block"""
  141. pass
  142. @abstractmethod
  143. def get_num_blocks_touched(self,
  144. blocks: List[Block],
  145. num_lookahead_slots: int = 0) -> int:
  146. pass
  147. class NoFreeBlocksError(ValueError):
  148. pass
  149. class DeviceAwareBlockAllocator(ABC):
  150. @abstractmethod
  151. def allocate_mutable_block(self, prev_block: Optional[Block],
  152. device: Device) -> Block:
  153. pass
  154. @abstractmethod
  155. def allocate_immutable_block(self, prev_block: Optional[Block],
  156. token_ids: List[int],
  157. device: Device) -> Block:
  158. pass
  159. @abstractmethod
  160. def allocate_immutable_blocks(self, prev_block: Optional[Block],
  161. block_token_ids: List[List[int]],
  162. device: Device) -> List[Block]:
  163. pass
  164. @abstractmethod
  165. def get_num_free_blocks(self, device: Device) -> int:
  166. pass
  167. @abstractmethod
  168. def get_num_total_blocks(self, device: Device) -> int:
  169. pass
  170. @abstractmethod
  171. def free(self, block: Block) -> None:
  172. pass
  173. @abstractmethod
  174. def fork(self, last_block: Block) -> List[Block]:
  175. pass
  176. @property
  177. @abstractmethod
  178. def all_block_ids(self) -> FrozenSet[int]:
  179. pass
  180. @abstractmethod
  181. def clear_copy_on_writes(self) -> List[Tuple[int, int]]:
  182. pass
  183. @abstractmethod
  184. def mark_blocks_as_accessed(self, block_ids: List[int],
  185. now: float) -> None:
  186. pass
  187. @abstractmethod
  188. def mark_blocks_as_computed(self, block_ids: List[int]) -> None:
  189. pass
  190. @abstractmethod
  191. def get_computed_block_ids(self, prev_computed_block_ids: List[int],
  192. block_ids: List[int],
  193. skip_last_block_id: bool) -> List[int]:
  194. pass
  195. @abstractmethod
  196. def get_common_computed_block_ids(
  197. self, computed_seq_block_ids: List[List[int]]) -> List[int]:
  198. pass
  199. @abstractmethod
  200. def get_num_blocks_touched(self,
  201. blocks: List[Block],
  202. device: Device,
  203. num_lookahead_slots: int = 0) -> int:
  204. pass
  205. @abstractmethod
  206. def swap(self, blocks: List[Block], src_device: Device,
  207. dst_device: Device) -> Dict[int, int]:
  208. pass
  209. @abstractmethod
  210. def get_physical_block_id(self, device: Device, absolute_id: int) -> int:
  211. pass
  212. @abstractmethod
  213. def allocate_or_get_null_block(self) -> Block:
  214. """
  215. Null blocks are used as a placeholders for KV cache blocks that have
  216. been dropped due to sliding window.
  217. There is at most one null block per allocator.
  218. """
  219. pass