568 lines
22 KiB
Python
568 lines
22 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
"""Unit tests for the fold / unfold prefix-cache hit logic."""
|
|
|
|
# Third Party
|
|
import pytest
|
|
|
|
# First Party
|
|
from lmcache.native_storage_ops import Bitmap
|
|
from lmcache.v1.distributed.api import TrimPolicy
|
|
from lmcache.v1.distributed.bitmap_ops import (
|
|
FULL_ATTENTION_WINDOW,
|
|
fold,
|
|
fold_unfold,
|
|
fold_unfold_ranked,
|
|
highest_set_bit,
|
|
merge_bitmaps,
|
|
select_retained,
|
|
unfold,
|
|
unfold_range,
|
|
)
|
|
from lmcache.v1.distributed.bitmap_ops.fold import _fold_python, _unfold_python
|
|
|
|
|
|
def _make_presence(num_chunks: int, present_per_group: list[list[int]]) -> Bitmap:
|
|
"""Build a group-major presence bitmap.
|
|
|
|
Args:
|
|
num_chunks: chunks per group.
|
|
present_per_group: present_per_group[g] is the list of chunk indices
|
|
available for object group g.
|
|
|
|
Returns:
|
|
A group-major Bitmap of length ``len(present_per_group) * num_chunks``.
|
|
"""
|
|
bm = Bitmap(len(present_per_group) * num_chunks)
|
|
for group_idx, chunks in enumerate(present_per_group):
|
|
base = group_idx * num_chunks
|
|
for j in chunks:
|
|
bm.set(base + j)
|
|
return bm
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# unfold_range #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
def test_unfold_full_attention_needs_whole_prefix():
|
|
assert unfold_range(4, FULL_ATTENTION_WINDOW) == (0, 4)
|
|
assert unfold_range(4, 0) == (0, 4)
|
|
|
|
|
|
def test_unfold_window_needs_only_last_w():
|
|
assert unfold_range(4, 2) == (2, 4)
|
|
assert unfold_range(1, 2) == (0, 1) # window larger than prefix
|
|
assert unfold_range(5, 1) == (4, 5) # mamba: last chunk only
|
|
|
|
|
|
def test_unfold_empty_prefix():
|
|
assert unfold_range(0, FULL_ATTENTION_WINDOW) == (0, 0)
|
|
assert unfold_range(0, 2) == (0, 0)
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# fold_unfold — single group reduces to leading-ones #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"present,expected_hit",
|
|
[
|
|
([0, 1, 2], 3), # full contiguous prefix
|
|
([0, 1, 3], 2), # gap at 2 caps the prefix
|
|
([], 0), # nothing present
|
|
([1, 2], 0), # missing chunk 0 -> empty prefix
|
|
],
|
|
)
|
|
def test_single_full_group_equals_leading_ones(present, expected_hit):
|
|
num_chunks = 4
|
|
found = _make_presence(num_chunks, [present])
|
|
hit, mask = fold_unfold(found, num_chunks, [FULL_ATTENTION_WINDOW])
|
|
assert hit == expected_hit
|
|
# equals the plain PREFIX leading-ones count on the same bitmap
|
|
assert hit == found.count_leading_ones()
|
|
# retained mask is exactly the first `hit` chunks
|
|
assert mask.get_indices_list() == list(range(expected_hit))
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# fold_unfold — worked full + sliding-window example #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
def test_full_plus_sliding_window_worked_example():
|
|
# N=5; group A full present {0,1,2,3}; group B sliding-window w=2 {2,3,4}.
|
|
# A blocks length 5 (chunk 4 missing); B's last-2 window at L=4 is {2,3} (present).
|
|
num_chunks = 5
|
|
found = _make_presence(num_chunks, [[0, 1, 2, 3], [2, 3, 4]])
|
|
hit, mask = fold_unfold(found, num_chunks, [FULL_ATTENTION_WINDOW, 2])
|
|
assert hit == 4
|
|
# A (full) needs chunks 0..3 -> flat 0,1,2,3 ; B (w=2) needs 2..3 -> flat 7,8
|
|
assert mask.get_indices_list() == [0, 1, 2, 3, 7, 8]
|
|
|
|
|
|
def test_sliding_window_does_not_block_long_prefix_when_tail_present():
|
|
# SW group missing early chunks but holding the tail still serves a long hit.
|
|
num_chunks = 6
|
|
found = _make_presence(num_chunks, [[0, 1, 2, 3, 4, 5], [4, 5]])
|
|
hit, mask = fold_unfold(found, num_chunks, [FULL_ATTENTION_WINDOW, 2])
|
|
assert hit == 6
|
|
# full needs 0..5 ; window-2 needs 4..5 -> flat 6*1 + {4,5} = {10,11}
|
|
assert mask.get_indices_list() == [0, 1, 2, 3, 4, 5, 10, 11]
|
|
|
|
|
|
def test_mamba_window_one():
|
|
# mamba == window 1: only the last chunk of the prefix is needed.
|
|
num_chunks = 4
|
|
found = _make_presence(num_chunks, [[0, 1, 2, 3], [3]])
|
|
hit, mask = fold_unfold(found, num_chunks, [FULL_ATTENTION_WINDOW, 1])
|
|
assert hit == 4
|
|
assert mask.get_indices_list() == [0, 1, 2, 3, 7] # full 0..3 + mamba {3}
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# fold_unfold — all-full reduces to require-all intersection #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"group_a,group_b,expected_hit",
|
|
[
|
|
([0, 1, 2, 3], [0, 1, 2, 3], 4), # both full -> full
|
|
([0, 1, 2, 3], [0, 1], 2), # B caps at 2
|
|
([0, 1], [0, 1, 2, 3], 2), # A caps at 2
|
|
([0, 2, 3], [0, 1, 2, 3], 1), # A gap at 1 caps at 1
|
|
],
|
|
)
|
|
def test_all_full_is_require_all_intersection(group_a, group_b, expected_hit):
|
|
num_chunks = 4
|
|
found = _make_presence(num_chunks, [group_a, group_b])
|
|
windows = [FULL_ATTENTION_WINDOW, FULL_ATTENTION_WINDOW]
|
|
hit, mask = fold_unfold(found, num_chunks, windows)
|
|
assert hit == expected_hit
|
|
# both groups retain the same first `hit` chunks
|
|
expected = list(range(expected_hit)) + [num_chunks + j for j in range(expected_hit)]
|
|
assert mask.get_indices_list() == expected
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# fold_unfold — edges #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
def test_zero_chunks():
|
|
found = Bitmap(0)
|
|
hit, mask = fold_unfold(found, 0, [FULL_ATTENTION_WINDOW, 2])
|
|
assert hit == 0
|
|
assert mask.get_indices_list() == []
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# fold_unfold_ranked — group x chunk x kv_rank layout #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
def _make_ranked(
|
|
num_chunks: int,
|
|
num_ranks: int,
|
|
present_per_group: list[list[tuple[int, int]]],
|
|
) -> Bitmap:
|
|
"""Build a group-major / chunk-major / rank-minor presence bitmap.
|
|
|
|
present_per_group[g] is the list of ``(chunk, rank)`` present for group g.
|
|
"""
|
|
num_groups = len(present_per_group)
|
|
stride = num_chunks * num_ranks
|
|
bm = Bitmap(num_groups * stride)
|
|
for group_idx, cells in enumerate(present_per_group):
|
|
gbase = group_idx * stride
|
|
for chunk, rank in cells:
|
|
bm.set(gbase + chunk * num_ranks + rank)
|
|
return bm
|
|
|
|
|
|
def test_ranked_chunk_present_only_if_all_ranks_present():
|
|
# 1 full group, 2 ranks, 3 chunks. chunk1 is missing rank 1 -> not present.
|
|
present = [[(0, 0), (0, 1), (1, 0), (2, 0), (2, 1)]]
|
|
found = _make_ranked(3, 2, present)
|
|
hit, mask = fold_unfold_ranked(found, 3, 2, [FULL_ATTENTION_WINDOW])
|
|
assert hit == 1 # only chunk 0 has both ranks; chunk1 gap caps the prefix
|
|
assert mask.get_indices_list() == [0, 1] # both ranks of chunk 0
|
|
|
|
|
|
def test_ranked_reduces_to_unranked_when_one_rank():
|
|
# num_ranks == 1 must match fold_unfold exactly.
|
|
found_unranked = _make_presence(5, [[0, 1, 2, 3], [2, 3, 4]])
|
|
found_ranked = _make_ranked(
|
|
5, 1, [[(c, 0) for c in [0, 1, 2, 3]], [(c, 0) for c in [2, 3, 4]]]
|
|
)
|
|
hit_u, mask_u = fold_unfold(found_unranked, 5, [FULL_ATTENTION_WINDOW, 2])
|
|
hit_r, mask_r = fold_unfold_ranked(found_ranked, 5, 1, [FULL_ATTENTION_WINDOW, 2])
|
|
assert hit_u == hit_r == 4
|
|
assert mask_u.get_indices_list() == mask_r.get_indices_list()
|
|
|
|
|
|
def test_ranked_full_plus_sw_expands_all_ranks():
|
|
# 2 groups, 2 ranks, 4 chunks. group0 full all present; group1 SW w=1 all present.
|
|
g0 = [(c, r) for c in range(4) for r in range(2)]
|
|
g1 = [(c, r) for c in range(4) for r in range(2)]
|
|
found = _make_ranked(4, 2, [g0, g1])
|
|
hit, mask = fold_unfold_ranked(found, 4, 2, [FULL_ATTENTION_WINDOW, 1])
|
|
assert hit == 4
|
|
# group0 full -> chunks 0..3 (ranks 0,1): flat 0..7
|
|
# group1 w=1 -> chunk 3 only (ranks 0,1): group base = 4*2 = 8, chunk3 -> 8+6,8+7
|
|
assert mask.get_indices_list() == [0, 1, 2, 3, 4, 5, 6, 7, 14, 15]
|
|
|
|
|
|
def test_ranked_invalid_num_ranks_raises():
|
|
with pytest.raises(ValueError):
|
|
fold_unfold_ranked(Bitmap(0), 0, 0, [FULL_ATTENTION_WINDOW])
|
|
|
|
|
|
def test_empty_group_windows_raises():
|
|
with pytest.raises(ValueError):
|
|
fold_unfold(Bitmap(0), 0, [])
|
|
|
|
|
|
def test_negative_num_chunks_raises():
|
|
with pytest.raises(ValueError):
|
|
fold_unfold(Bitmap(0), -1, [FULL_ATTENTION_WINDOW])
|
|
|
|
|
|
def _bm(num_keys: int, set_indices: list[int]) -> Bitmap:
|
|
bm = Bitmap(num_keys)
|
|
for i in set_indices:
|
|
bm.set(i)
|
|
return bm
|
|
|
|
|
|
class TestSelectRetained:
|
|
"""select_retained picks the retained subset per policy: PREFIX trims at the
|
|
first gap; any other policy keeps every set bit (gaps and all)."""
|
|
|
|
def test_prefix_trims_at_first_gap(self):
|
|
found = _bm(5, [0, 1, 3, 4]) # gap at index 2
|
|
assert select_retained(found, 5, TrimPolicy.PREFIX).get_indices_list() == [0, 1]
|
|
|
|
def test_sparse_keeps_all_found(self):
|
|
found = _bm(5, [0, 2, 4])
|
|
result = select_retained(found, 5, TrimPolicy.SPARSE).get_indices_list()
|
|
assert result == [0, 2, 4]
|
|
|
|
def test_segmented_prefix_keeps_all_found(self):
|
|
found = _bm(5, [0, 1, 3, 4]) # gap at index 2
|
|
result = select_retained(
|
|
found, 5, TrimPolicy.SEGMENTED_PREFIX
|
|
).get_indices_list()
|
|
assert result == [0, 1, 3, 4]
|
|
|
|
|
|
class TestMergeBitmaps:
|
|
"""merge_bitmaps always returns a num_keys-sized bitmap."""
|
|
|
|
def test_empty_input_returns_sized_bitmap(self):
|
|
"""Empty input -> num_keys-sized all-zeros bitmap (not Bitmap(0)), so a
|
|
downstream ``&`` with a same-sized mask never hits a size mismatch."""
|
|
merged = merge_bitmaps([], 5)
|
|
assert merged.popcount() == 0
|
|
mask = Bitmap(5)
|
|
mask.set(2)
|
|
assert (merged & mask).popcount() == 0 # would raise on size mismatch
|
|
|
|
def test_empty_generator_returns_sized_bitmap(self):
|
|
"""A generator is truthy even when empty; the result is still size-5."""
|
|
merged = merge_bitmaps((b for b in []), 5)
|
|
assert merged.popcount() == 0
|
|
assert (merged & Bitmap(5)).popcount() == 0
|
|
|
|
def test_union_of_bitmaps(self):
|
|
"""Non-empty inputs are OR-merged into one num_keys-sized bitmap."""
|
|
a, b = Bitmap(5), Bitmap(5)
|
|
a.set(0)
|
|
b.set(3)
|
|
assert merge_bitmaps([a, b], 5).get_indices_list() == [0, 3]
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# Separated operators: fold / highest_set_bit / unfold #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
class TestFoldOperator:
|
|
"""``fold`` produces the servable bitmap (bit ``j`` = every group can serve
|
|
a length-``j + 1`` prefix)."""
|
|
|
|
def test_full_attention_servable_is_downward_closed(self):
|
|
# full group present {0,1,2} of 4 -> servable lengths {1,2,3} -> bits
|
|
# {0,1,2} (bit j == length j+1).
|
|
found = _make_ranked(4, 1, [[(0, 0), (1, 0), (2, 0)]])
|
|
servable = fold(found, 4, 1, [FULL_ATTENTION_WINDOW])
|
|
assert servable.get_indices_list() == [0, 1, 2]
|
|
|
|
def test_sliding_window_servable_is_gappy(self):
|
|
# window-2 group present chunks {0,1,3,4} of 5. A length L is servable
|
|
# iff chunks [L-2, L) present: L=1 ok(0), 2 ok(0,1), 3 no(1,2),
|
|
# 4 no(2,3), 5 ok(3,4) -> lengths {1,2,5} -> bits {0,1,4}.
|
|
found = _make_ranked(5, 1, [[(0, 0), (1, 0), (3, 0), (4, 0)]])
|
|
servable = fold(found, 5, 1, [2])
|
|
assert servable.get_indices_list() == [0, 1, 4]
|
|
|
|
def test_nothing_present_is_empty(self):
|
|
# No chunk present -> no length servable -> empty bitmap (highest_set_bit
|
|
# returns -1, so the pipeline reports hit length 0).
|
|
found = _make_ranked(3, 2, [[]]) # nothing present
|
|
servable = fold(found, 3, 2, [FULL_ATTENTION_WINDOW])
|
|
assert servable.get_indices_list() == []
|
|
|
|
|
|
class TestHighestSetBit:
|
|
"""``highest_set_bit`` returns the highest set bit, -1 if none."""
|
|
|
|
def test_basic(self):
|
|
bm = Bitmap(10)
|
|
for i in (1, 4, 7):
|
|
bm.set(i)
|
|
assert highest_set_bit(bm) == 7
|
|
|
|
def test_empty_returns_minus_one(self):
|
|
assert highest_set_bit(Bitmap(10)) == -1
|
|
assert highest_set_bit(Bitmap(0)) == -1
|
|
|
|
def test_single_and_last_bit(self):
|
|
bm = Bitmap(9)
|
|
bm.set(8)
|
|
assert highest_set_bit(bm) == 8
|
|
|
|
|
|
class TestUnfoldOperator:
|
|
"""``unfold`` expands a hit length into the ranked retain mask."""
|
|
|
|
def test_full_plus_sliding_window(self):
|
|
# hit=4, full group keeps [0,4), window-2 group keeps [2,4); 2 ranks.
|
|
mask = unfold(4, 5, 2, [FULL_ATTENTION_WINDOW, 2])
|
|
stride = 5 * 2
|
|
expected = [0, 1, 2, 3, 4, 5, 6, 7] # full: chunks 0..3 x 2 ranks
|
|
expected += [stride + 4, stride + 5, stride + 6, stride + 7] # win: c2,c3
|
|
assert mask.get_indices_list() == expected
|
|
|
|
def test_zero_hit_is_empty(self):
|
|
assert unfold(0, 5, 2, [FULL_ATTENTION_WINDOW, 2]).get_indices_list() == []
|
|
|
|
def test_hit_clamped_to_num_chunks(self):
|
|
# hit beyond num_chunks is clamped; full group keeps every chunk.
|
|
mask = unfold(99, 3, 1, [FULL_ATTENTION_WINDOW])
|
|
assert mask.get_indices_list() == [0, 1, 2]
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# Native ops must match the pure-Python reference (_fold_python/_unfold_python) #
|
|
# bit-for-bit, on deterministic constructed inputs. #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
class TestNativeMatchesReference:
|
|
# (num_chunks, num_ranks, group_windows) shapes, small to large.
|
|
CASES = [
|
|
(64, 1, [FULL_ATTENTION_WINDOW]),
|
|
(64, 4, [FULL_ATTENTION_WINDOW, FULL_ATTENTION_WINDOW]),
|
|
(100, 3, [FULL_ATTENTION_WINDOW, 2, 5, 1]),
|
|
(300, 4, [FULL_ATTENTION_WINDOW, FULL_ATTENTION_WINDOW, 8, 32, 1]),
|
|
]
|
|
|
|
def test_fold_matches_reference(self):
|
|
for num_chunks, num_ranks, gw in self.CASES:
|
|
nk = len(gw) * num_chunks * num_ranks
|
|
bm = Bitmap(nk)
|
|
# Deterministic irregular gap pattern (no RNG): drop ~1/7 of bits on
|
|
# an irregular stride so windows and rank-reduction are exercised.
|
|
bm.batched_set([i for i in range(nk) if (i * 5 + i // num_ranks) % 7 != 0])
|
|
assert (
|
|
fold(bm, num_chunks, num_ranks, gw).get_indices_list()
|
|
== _fold_python(bm, num_chunks, num_ranks, gw).get_indices_list()
|
|
), f"fold mismatch C={num_chunks} R={num_ranks} gw={gw}"
|
|
|
|
def test_unfold_matches_reference_at_boundaries(self):
|
|
for num_chunks, num_ranks, gw in self.CASES:
|
|
# Cover empty, both ends, and interior hit lengths.
|
|
for hit in (0, 1, num_chunks // 3, num_chunks - 1, num_chunks):
|
|
assert (
|
|
unfold(hit, num_chunks, num_ranks, gw).get_indices_list()
|
|
== _unfold_python(hit, num_chunks, num_ranks, gw).get_indices_list()
|
|
), f"unfold mismatch hit={hit} C={num_chunks} R={num_ranks} gw={gw}"
|
|
|
|
|
|
# --------------------------------------------------------------------------- #
|
|
# End-to-end: full fold -> highest_set_bit -> unfold pipeline against an #
|
|
# independent reference modeling vLLM's hybrid prefix-cache hit logic. #
|
|
# --------------------------------------------------------------------------- #
|
|
|
|
|
|
def _reference_longest_hit(num_chunks, group_present, group_windows):
|
|
"""Longest model-wide prefix hit, mirroring vLLM's per-group
|
|
``find_longest_cache_hit`` combined across a hybrid model (independent
|
|
brute force; no vLLM import).
|
|
|
|
A length-``L`` prefix is a model-wide hit iff every object group can serve
|
|
it under its rule:
|
|
|
|
* full attention (``window <= 0``): chunks ``[0, L)`` all present
|
|
(vLLM ``FullAttentionManager``);
|
|
* sliding window ``w``: chunks ``[max(0, L - w), L)`` all present
|
|
(vLLM ``SlidingWindowManager``).
|
|
|
|
Args:
|
|
num_chunks: number of chunks.
|
|
group_present: ``group_present[g]`` = set of chunk indices present for
|
|
object group ``g`` (after requiring every kv_rank present).
|
|
group_windows: per-group window size; ``<= 0`` means full attention.
|
|
|
|
Returns:
|
|
The largest ``L`` in ``[0, num_chunks]`` servable by all groups.
|
|
"""
|
|
best = 0
|
|
for length in range(num_chunks + 1):
|
|
servable_by_all = True
|
|
for present, window in zip(group_present, group_windows, strict=True):
|
|
lo = 0 if window <= 0 else max(0, length - window)
|
|
if not all(j in present for j in range(lo, length)):
|
|
servable_by_all = False
|
|
break
|
|
if servable_by_all:
|
|
best = length
|
|
return best
|
|
|
|
|
|
def _expected_retained_indices(hit, num_chunks, num_ranks, group_windows):
|
|
"""The ranked retain-mask indices the pipeline should produce for ``hit``."""
|
|
indices = []
|
|
stride = num_chunks * num_ranks
|
|
for g, window in enumerate(group_windows):
|
|
lo, hi = unfold_range(hit, window)
|
|
for j in range(lo, hi):
|
|
base = g * stride + j * num_ranks
|
|
indices.extend(range(base, base + num_ranks))
|
|
return sorted(indices)
|
|
|
|
|
|
class TestEndToEndAgainstVllmStyleReference:
|
|
"""Drive the full fold/highest_set_bit/unfold pipeline and compare the
|
|
hit length and retain mask against an independent vLLM-style oracle."""
|
|
|
|
def _run(
|
|
self, num_chunks, num_ranks, group_windows, present_cells, expected_hit=None
|
|
):
|
|
# present_cells[g] = set of (chunk, rank) present for group g.
|
|
stride = num_chunks * num_ranks
|
|
bm = Bitmap(len(group_windows) * stride)
|
|
for g, cells in enumerate(present_cells):
|
|
for chunk, rank in cells:
|
|
bm.set(g * stride + chunk * num_ranks + rank)
|
|
hit, mask = fold_unfold_ranked(bm, num_chunks, num_ranks, group_windows)
|
|
|
|
# Reference: a chunk is present for a group only if all ranks present.
|
|
group_present = [
|
|
{
|
|
chunk
|
|
for chunk in range(num_chunks)
|
|
if all((chunk, r) in cells for r in range(num_ranks))
|
|
}
|
|
for cells in present_cells
|
|
]
|
|
ref_hit = _reference_longest_hit(num_chunks, group_present, group_windows)
|
|
assert hit == ref_hit, (
|
|
f"hit {hit} != reference {ref_hit} "
|
|
f"(windows={group_windows}, present={group_present})"
|
|
)
|
|
if expected_hit is not None:
|
|
assert hit == expected_hit, f"hit {hit} != hand-derived {expected_hit}"
|
|
assert mask.get_indices_list() == _expected_retained_indices(
|
|
hit, num_chunks, num_ranks, group_windows
|
|
)
|
|
|
|
def test_full_attention_only_is_contiguous_prefix(self):
|
|
# Two full-attention groups; hit is the shortest contiguous prefix.
|
|
self._run(
|
|
num_chunks=6,
|
|
num_ranks=2,
|
|
group_windows=[FULL_ATTENTION_WINDOW, FULL_ATTENTION_WINDOW],
|
|
present_cells=[
|
|
{(j, r) for j in range(5) for r in range(2)}, # chunks 0..4
|
|
{(j, r) for j in range(3) for r in range(2)}, # chunks 0..2
|
|
],
|
|
) # -> hit 3
|
|
|
|
def test_sliding_window_tail_extends_hit(self):
|
|
# Full group has 0..5; window-2 group only has the tail {4,5} -> hit 6.
|
|
self._run(
|
|
num_chunks=6,
|
|
num_ranks=1,
|
|
group_windows=[FULL_ATTENTION_WINDOW, 2],
|
|
present_cells=[
|
|
{(j, 0) for j in range(6)},
|
|
{(4, 0), (5, 0)},
|
|
],
|
|
)
|
|
|
|
def test_mamba_window_one(self):
|
|
self._run(
|
|
num_chunks=4,
|
|
num_ranks=1,
|
|
group_windows=[FULL_ATTENTION_WINDOW, 1],
|
|
present_cells=[{(j, 0) for j in range(4)}, {(3, 0)}],
|
|
) # -> hit 4
|
|
|
|
def test_missing_rank_breaks_chunk(self):
|
|
# chunk 2 missing one rank -> not present -> caps the full-attn prefix.
|
|
self._run(
|
|
num_chunks=5,
|
|
num_ranks=2,
|
|
group_windows=[FULL_ATTENTION_WINDOW],
|
|
present_cells=[
|
|
{(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (3, 0), (3, 1)},
|
|
],
|
|
) # -> hit 2
|
|
|
|
def test_large_adversarial_hybrid(self):
|
|
# A large, deterministic scenario engineered so the hit is decided by a
|
|
# mid-window sliding-window gap, with decoy later gaps a wrong algorithm
|
|
# might trip on. 300 chunks x 4 ranks x 5 groups.
|
|
#
|
|
# windows: [full, full, SW8, SW32, mamba]
|
|
# - g0 full: gap at chunk 150 -> full prefix capped at 150
|
|
# - g1 full: one rank of chunk 220 gone -> chunk 220 absent (rank test)
|
|
# - g2 SW8: gaps at 10,11,12 (old) -> must NOT affect a hit > 20
|
|
# - g3 SW32: gap at chunk 130 -> lengths 131..162 unservable
|
|
# - g4 mamba: fully present
|
|
# The only length servable by all groups and <= 150 is 130 (g3's gap at
|
|
# 130 blocks 131..162; g3 is servable again only at >= 163, beyond g0's
|
|
# 150 cap). So the model-wide hit is exactly 130.
|
|
num_chunks, num_ranks = 300, 4
|
|
group_windows = [FULL_ATTENTION_WINDOW, FULL_ATTENTION_WINDOW, 8, 32, 1]
|
|
cells = [
|
|
{(j, r) for j in range(num_chunks) for r in range(num_ranks)}
|
|
for _ in group_windows
|
|
]
|
|
cells[0] -= {(150, r) for r in range(num_ranks)}
|
|
cells[1].discard((220, 2))
|
|
cells[2] -= {(j, r) for j in (10, 11, 12) for r in range(num_ranks)}
|
|
cells[3] -= {(130, r) for r in range(num_ranks)}
|
|
self._run(num_chunks, num_ranks, group_windows, cells, expected_hit=130)
|
|
|
|
def test_dense_deterministic_pattern(self):
|
|
# Wide grid with a deterministic irregular gap pattern (no RNG): drops
|
|
# ~1/9 of cells on an irregular stride so many window/intersection
|
|
# boundaries are exercised. Validated against the reference oracle.
|
|
num_chunks, num_ranks = 128, 3
|
|
group_windows = [FULL_ATTENTION_WINDOW, 2, 5, 1]
|
|
cells = []
|
|
for g in range(len(group_windows)):
|
|
present = {
|
|
(j, r)
|
|
for j in range(num_chunks)
|
|
for r in range(num_ranks)
|
|
if (j * 7 + r * 3 + g * 5) % 9 != 0
|
|
}
|
|
cells.append(present)
|
|
self._run(num_chunks, num_ranks, group_windows, cells)
|