| 1 | # SPDX-License-Identifier: Apache-2.0 |
| 2 | # SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | """A KV cache group may hold both windowed and global layers — e.g. Gemma-3 with |
| 4 | the hybrid KV cache manager disabled, where the sliding-window layers are |
| 5 | promoted to full-attention *storage* and merged into one group whose spec still |
| 6 | records the window. Backends must take the window from the layers, never from |
| 7 | that group spec, or the global layers get windowed too and silently lose access |
| 8 | to everything older than the window. |
| 9 | """ |
| 10 | |
| 11 | from types import SimpleNamespace |
| 12 | from unittest.mock import MagicMock, patch |
| 13 | |
| 14 | import pytest |
| 15 | |
| 16 | from vllm.v1.attention.backends.cpu_attn import ( |
| 17 | CPUAttentionBackendImpl, |
| 18 | CPUAttentionMetadataBuilder, |
| 19 | ) |
| 20 | |
| 21 | |
| 22 | def _layers(layer_windows: list[int]): |
| 23 | """Stand-in attention layers, one per window, as one KV cache group.""" |
| 24 | return { |
| 25 | f"layer_{i}": SimpleNamespace( |
| 26 | impl=MagicMock(spec=CPUAttentionBackendImpl, sliding_window=window) |
| 27 | ) |
| 28 | for i, window in enumerate(layer_windows) |
| 29 | } |
| 30 | |
| 31 | |
| 32 | @pytest.mark.parametrize( |
| 33 | "layer_windows,expected", |
| 34 | [ |
| 35 | ([512, 512], 512), # uniform sliding window -> shared by the group |
| 36 | ([-1, -1], -1), # all global -> no window |
| 37 | ([512, -1], -1), # mixed -> the group cannot assume either window |
| 38 | ], |
| 39 | ) |
| 40 | def test_cpu_group_sliding_window(layer_windows, expected): |
| 41 | layers = _layers(layer_windows) |
| 42 | builder = SimpleNamespace(vllm_config=None, layer_names=list(layers)) |
| 43 | with patch( |
| 44 | "vllm.v1.attention.backends.cpu_attn.get_layers_from_vllm_config", |
| 45 | return_value=layers, |
| 46 | ): |
| 47 | window = CPUAttentionMetadataBuilder._group_sliding_window(builder) |
| 48 | assert window == expected |