Directory rename (git mv, history preserved) plus rewrite of all references: absolute imports in tests, the zero-dep runner, docstrings, comments, and the README. No behavior change. Run: python3 -m pytest v2/tests/ -q ; python3 v2/run_tests.py ; python3 -m v2.examples
61 lines
2.7 KiB
Python
61 lines
2.7 KiB
Python
"""Per-class cache pools (design_v3 §7.2): feature partition/invalidation, slab-KV window/training."""
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
from v2.cache import CacheKey, CacheManager, CachePolicy
|
|
from v2.cache.classes import FeatureCache, Slab, SlabKVCache
|
|
from v2.models.wan_causal import build_wan_causal_card
|
|
|
|
|
|
def test_feature_cache_reuse_and_adapter_partition():
|
|
fc = FeatureCache(CachePolicy("feature", max_bytes=1 << 20))
|
|
k1 = CacheKey(model_id="m", component_id="te", weights_version="v0", adapter_versions=(("l", "1"),))
|
|
v = np.ones((4,), dtype="float32")
|
|
assert fc.get(k1) is None # miss
|
|
fc.put(k1, v)
|
|
assert np.array_equal(fc.get(k1), v) # hit
|
|
k2 = CacheKey(model_id="m", component_id="te", weights_version="v0", adapter_versions=(("l", "2"),))
|
|
assert fc.get(k2) is None # different te-LoRA stack => partitioned, no stale serve
|
|
|
|
|
|
def test_feature_cache_weight_invalidation_is_wholesale():
|
|
fc = FeatureCache(CachePolicy("feature", max_bytes=1 << 20))
|
|
k = CacheKey(model_id="m", component_id="te", weights_version="v0")
|
|
fc.put(k, np.ones((2,), dtype="float32"))
|
|
fc.invalidate_weights("v1") # RL update_weights bump
|
|
assert fc.get(k) is None
|
|
|
|
|
|
def test_feature_cache_budget_eviction():
|
|
fc = FeatureCache(CachePolicy("feature", max_bytes=8)) # 8 bytes = one (2,)-float32
|
|
for i in range(5):
|
|
fc.put(CacheKey(model_id="m", component_id="c", step_index=i),
|
|
np.zeros((2,), dtype="float32"))
|
|
assert fc.used_bytes <= 8
|
|
|
|
|
|
def test_slab_kv_inference_window_vs_training_mode():
|
|
inf = SlabKVCache(CachePolicy("slab_kv", reuse_across_requests=False, per_component={"window": 2}))
|
|
for i in range(4):
|
|
inf.append("r", Slab(i, np.zeros((3,), dtype="float32"), None))
|
|
assert len(inf.get("r")) == 2 # sliding window recycles (inference)
|
|
|
|
tr = SlabKVCache(CachePolicy("slab_kv", training_mode_disables_recycle=True,
|
|
per_component={"window": 2}))
|
|
for i in range(4):
|
|
tr.append("r", Slab(i, np.zeros((3,), dtype="float32"), None))
|
|
assert len(tr.get("r")) == 4 # no mid-rollout recycle in training mode (self-forcing)
|
|
assert tr.used_bytes > 0
|
|
tr.clear_namespace("r")
|
|
assert tr.used_bytes == 0
|
|
|
|
|
|
def test_cache_manager_materializes_only_declared_classes():
|
|
cm = CacheManager.from_card(build_wan_causal_card())
|
|
assert cm.has("feature") and cm.has("slab_kv")
|
|
# a pure bidirectional card declares no KV class
|
|
from v2.models.wan21 import build_wan21_card
|
|
cm2 = CacheManager.from_card(build_wan21_card())
|
|
assert cm2.has("feature") and not cm2.has("slab_kv") # KV is the minority case
|