test_naive_block.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. from typing import List, Optional
  2. import pytest
  3. from aphrodite.processing.block.interfaces import Block, BlockAllocator
  4. from aphrodite.processing.block.naive_block import (NaiveBlock,
  5. NaiveBlockAllocator)
  6. class TestNaiveBlockAllocator:
  7. @staticmethod
  8. def create_allocate_lambda(allocate_type: str,
  9. allocator: NaiveBlockAllocator,
  10. prev_block: Optional[Block],
  11. token_ids: List[int]):
  12. if allocate_type == "immutable":
  13. allocate_block = lambda: allocator.allocate_immutable_block(
  14. prev_block=prev_block, token_ids=token_ids)
  15. elif allocate_type == "mutable":
  16. allocate_block = lambda: allocator.allocate_mutable_block(
  17. prev_block=prev_block)
  18. else:
  19. raise ValueError()
  20. return allocate_block
  21. @staticmethod
  22. @pytest.mark.parametrize("allocate_type", ["immutable", "mutable"])
  23. @pytest.mark.parametrize("num_blocks", [1, 1024])
  24. @pytest.mark.parametrize("block_size", [1, 16])
  25. def test_allocate_ooms(allocate_type: str, num_blocks: int,
  26. block_size: int):
  27. allocator = NaiveBlockAllocator(create_block=NaiveBlock,
  28. num_blocks=num_blocks,
  29. block_size=block_size)
  30. allocate_block = TestNaiveBlockAllocator.create_allocate_lambda(
  31. allocate_type,
  32. allocator,
  33. prev_block=None,
  34. token_ids=list(range(block_size)))
  35. [allocate_block() for _ in range(num_blocks)]
  36. with pytest.raises(BlockAllocator.NoFreeBlocksError):
  37. allocate_block()
  38. @staticmethod
  39. @pytest.mark.parametrize("allocate_type", ["immutable", "mutable"])
  40. @pytest.mark.parametrize("num_blocks", [1, 1024])
  41. @pytest.mark.parametrize("block_size", [1, 16])
  42. def test_free_prevents_oom(allocate_type: str, num_blocks: int,
  43. block_size: int):
  44. allocator = NaiveBlockAllocator(create_block=NaiveBlock,
  45. num_blocks=num_blocks,
  46. block_size=block_size)
  47. allocate_block = TestNaiveBlockAllocator.create_allocate_lambda(
  48. allocate_type,
  49. allocator,
  50. prev_block=None,
  51. token_ids=list(range(block_size)))
  52. blocks = [allocate_block() for _ in range(num_blocks)]
  53. with pytest.raises(BlockAllocator.NoFreeBlocksError):
  54. allocate_block()
  55. block_to_free = blocks.pop()
  56. for _ in range(100):
  57. block_id = block_to_free.block_id
  58. allocator.free(block_to_free)
  59. assert block_to_free.block_id is None
  60. new_block = allocate_block()
  61. assert new_block.block_id == block_id
  62. with pytest.raises(BlockAllocator.NoFreeBlocksError):
  63. allocate_block()
  64. block_to_free = new_block
  65. @staticmethod
  66. @pytest.mark.parametrize("allocate_type", ["immutable", "mutable"])
  67. @pytest.mark.parametrize("num_blocks", [1024])
  68. @pytest.mark.parametrize("block_size", [16])
  69. def test_get_num_free_blocks(allocate_type: str, num_blocks: int,
  70. block_size: int):
  71. allocator = NaiveBlockAllocator(create_block=NaiveBlock,
  72. num_blocks=num_blocks,
  73. block_size=block_size)
  74. allocate_block = TestNaiveBlockAllocator.create_allocate_lambda(
  75. allocate_type,
  76. allocator,
  77. prev_block=None,
  78. token_ids=list(range(block_size)))
  79. assert allocator.get_num_free_blocks() == num_blocks
  80. blocks = [allocate_block() for _ in range(num_blocks)]
  81. for i, block in enumerate(blocks):
  82. assert allocator.get_num_free_blocks() == i
  83. allocator.free(block)
  84. @staticmethod
  85. @pytest.mark.parametrize("num_blocks", [4])
  86. @pytest.mark.parametrize("block_size", [8])
  87. def test_naive_block_get_num_blocks_touched(num_blocks, block_size):
  88. """ Verify the allocator can correctly return the number of
  89. blocks touched, with different lookahead slots.
  90. """
  91. allocator_src = NaiveBlockAllocator(create_block=NaiveBlock,
  92. num_blocks=num_blocks,
  93. block_size=block_size)
  94. allocator_dst = NaiveBlockAllocator(create_block=NaiveBlock,
  95. num_blocks=num_blocks,
  96. block_size=block_size)
  97. # Create a chain of cacheable blocks in the dst
  98. allocate_block = TestNaiveBlockAllocator.create_allocate_lambda(
  99. "immutable",
  100. allocator_src,
  101. prev_block=None,
  102. token_ids=list(range(block_size)))
  103. src_blocks = [allocate_block() for _ in range(num_blocks - 1)]
  104. # All blocks are cached
  105. assert allocator_dst.get_num_blocks_touched(
  106. src_blocks) == num_blocks - 1
  107. # Insert one non-full block in the src
  108. allocate_non_full_block = \
  109. TestNaiveBlockAllocator.create_allocate_lambda(
  110. "mutable", allocator_src,
  111. prev_block=src_blocks[-1],token_ids=[]
  112. )
  113. src_blocks.append(allocate_non_full_block())
  114. src_blocks[-1].append_token_ids([0])
  115. assert allocator_dst.get_num_blocks_touched(
  116. src_blocks, num_lookahead_slots=1) == num_blocks
  117. assert allocator_dst.get_num_blocks_touched(
  118. src_blocks, num_lookahead_slots=block_size - 1) == num_blocks
  119. assert allocator_dst.get_num_blocks_touched(
  120. src_blocks, num_lookahead_slots=block_size) == (num_blocks + 1)