#[derive(Debug, Clone)]
pub struct AdaptiveTieringConfig {
pub vram_budget: u64,
pub ram_budget: u64,
pub quality_target: f32,
pub max_swap_latency_ms: u32,
pub enable_adaptation: bool,
pub prefetch_depth: usize,
pub enable_mixed_precision: bool,
pub vram_importance_threshold: f32,
pub kv_cache_headroom: u64,
}
impl Default for AdaptiveTieringConfig {
fn default() -> Self {
Self {
vram_budget: 0, ram_budget: 0, quality_target: 0.95,
max_swap_latency_ms: 100,
enable_adaptation: true,
prefetch_depth: 2,
enable_mixed_precision: true,
vram_importance_threshold: 0.7,
kv_cache_headroom: 2 * 1024 * 1024 * 1024, }
}
}
impl AdaptiveTieringConfig {
pub fn high_quality() -> Self {
Self {
quality_target: 0.99,
enable_mixed_precision: false,
..Default::default()
}
}
pub fn memory_optimized() -> Self {
Self {
quality_target: 0.90,
enable_mixed_precision: true,
vram_importance_threshold: 0.5,
..Default::default()
}
}
pub fn with_budgets(vram_gb: f64, ram_gb: f64) -> Self {
Self {
vram_budget: (vram_gb * 1024.0 * 1024.0 * 1024.0) as u64,
ram_budget: (ram_gb * 1024.0 * 1024.0 * 1024.0) as u64,
..Default::default()
}
}
pub fn effective_vram_budget(&self, detected_vram: u64) -> u64 {
if self.vram_budget > 0 {
self.vram_budget
} else {
detected_vram.saturating_sub(self.kv_cache_headroom)
}
}
pub fn effective_ram_budget(&self, detected_ram: u64) -> u64 {
if self.ram_budget > 0 {
self.ram_budget
} else {
let headroom = 4 * 1024 * 1024 * 1024; detected_ram.saturating_sub(headroom)
}
}
pub fn validate(&self) -> Result<(), ConfigError> {
if self.quality_target < 0.0 || self.quality_target > 1.0 {
return Err(ConfigError::InvalidQualityTarget(self.quality_target));
}
if self.vram_importance_threshold < 0.0 || self.vram_importance_threshold > 1.0 {
return Err(ConfigError::InvalidImportanceThreshold(
self.vram_importance_threshold,
));
}
Ok(())
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum ConfigError {
#[error("quality_target must be in [0.0, 1.0], got {0}")]
InvalidQualityTarget(f32),
#[error("vram_importance_threshold must be in [0.0, 1.0], got {0}")]
InvalidImportanceThreshold(f32),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = AdaptiveTieringConfig::default();
assert!((config.quality_target - 0.95).abs() < f32::EPSILON);
assert!(config.enable_mixed_precision);
assert!(config.enable_adaptation);
}
#[test]
fn test_effective_vram_budget_auto() {
let config = AdaptiveTieringConfig::default();
let detected_vram = 24 * 1024 * 1024 * 1024u64; let effective = config.effective_vram_budget(detected_vram);
assert_eq!(effective, 22 * 1024 * 1024 * 1024);
}
#[test]
fn test_effective_vram_budget_explicit() {
let config = AdaptiveTieringConfig::with_budgets(20.0, 60.0);
let detected_vram = 24 * 1024 * 1024 * 1024u64;
let effective = config.effective_vram_budget(detected_vram);
assert_eq!(effective, 20 * 1024 * 1024 * 1024);
}
#[test]
fn test_validation() {
let mut config = AdaptiveTieringConfig::default();
assert!(config.validate().is_ok());
config.quality_target = 1.5;
assert!(config.validate().is_err());
config.quality_target = 0.95;
config.vram_importance_threshold = -0.1;
assert!(config.validate().is_err());
}
}