use ferrox_core::cache::KvCache;
use ferrox_core::kv_swa::KvWindow;
use super::Decoder;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct KvWindowPolicy {
enabled: bool,
}
pub const KV_WINDOW_ENV: &str = "FERROX_KV_WINDOW";
impl KvWindowPolicy {
pub const fn off() -> Self {
KvWindowPolicy { enabled: false }
}
pub const fn on() -> Self {
KvWindowPolicy { enabled: true }
}
pub fn from_env() -> Self {
let on = matches!(
std::env::var(KV_WINDOW_ENV).ok().as_deref(),
Some("1") | Some("on") | Some("true") | Some("yes")
);
#[cfg(feature = "metal")]
let on = on && !ferrox_metal::attn::metal_attn_enabled();
KvWindowPolicy { enabled: on }
}
pub fn enabled(&self) -> bool {
self.enabled
}
pub fn window_for(&self, attention_window: Option<usize>) -> Option<KvWindow> {
if !self.enabled {
return None;
}
KvWindow::with_default_slack(attention_window?)
}
pub fn layer_window(
&self,
config: &crate::config::ModelConfig,
layer_idx: usize,
) -> Option<KvWindow> {
self.window_for(config.layer_sliding_window(layer_idx))
}
}
impl Default for KvWindowPolicy {
fn default() -> Self {
Self::off()
}
}
impl Decoder {
pub fn kv_window_for_layer(&self, layer_idx: usize) -> Option<KvWindow> {
self.kv_window.layer_window(&self.config, layer_idx)
}
pub(crate) fn evict_layer_kv(&self, layer_idx: usize, cache: &mut KvCache) {
let Some(window) = self.kv_window_for_layer(layer_idx) else {
return;
};
if cache.window() != Some(window) {
cache.arm_window(window);
}
cache.evict_behind_window();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_default_policy_evicts_nothing() {
let off = KvWindowPolicy::off();
assert!(!off.enabled());
assert_eq!(off.window_for(Some(1024)), None);
assert_eq!(KvWindowPolicy::default(), off);
}
#[test]
fn the_eviction_window_equals_the_window_attention_reads() {
let on = KvWindowPolicy::on();
let w = on.window_for(Some(1024)).expect("a windowed layer");
assert_eq!(w.window(), 1024);
assert!(w.max_rows() >= 1024);
}
#[test]
fn a_full_attention_layer_never_evicts() {
assert_eq!(KvWindowPolicy::on().window_for(None), None);
assert_eq!(KvWindowPolicy::off().window_for(None), None);
}
#[test]
fn a_zero_window_does_not_become_an_evicting_window() {
assert_eq!(KvWindowPolicy::on().window_for(Some(0)), None);
}
}