use crate::core::Expression;
use std::collections::HashMap;
use std::sync::{Arc, OnceLock, RwLock};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BindingContext {
Native,
Python,
NodeJs,
WebAssembly,
Custom,
}
#[derive(Debug, Clone)]
pub struct PerformanceConfig {
pub simd_enabled: bool,
pub simd_threshold: usize,
pub memoization_enabled: bool,
pub cache_size_limit: usize,
pub parallel_enabled: bool,
pub parallel_threshold: usize,
}
impl Default for PerformanceConfig {
fn default() -> Self {
Self {
simd_enabled: true,
simd_threshold: 50, memoization_enabled: true,
cache_size_limit: 10000, parallel_enabled: false, parallel_threshold: 1000, }
}
}
impl PerformanceConfig {
pub fn python_optimized() -> Self {
Self {
simd_enabled: true,
simd_threshold: 50,
memoization_enabled: true,
cache_size_limit: 50000, parallel_enabled: false, parallel_threshold: usize::MAX, }
}
pub fn nodejs_optimized() -> Self {
Self {
simd_enabled: true,
simd_threshold: 50,
memoization_enabled: true,
cache_size_limit: 20000, parallel_enabled: true, parallel_threshold: 500, }
}
pub fn native_optimized() -> Self {
Self {
simd_enabled: true,
simd_threshold: 20, memoization_enabled: true,
cache_size_limit: 100000, parallel_enabled: true,
parallel_threshold: 100, }
}
pub fn wasm_optimized() -> Self {
Self {
simd_enabled: true, simd_threshold: 100, memoization_enabled: true,
cache_size_limit: 1000, parallel_enabled: false, parallel_threshold: usize::MAX,
}
}
pub fn for_binding(context: BindingContext) -> Self {
match context {
BindingContext::Native => Self::native_optimized(),
BindingContext::Python => Self::python_optimized(),
BindingContext::NodeJs => Self::nodejs_optimized(),
BindingContext::WebAssembly => Self::wasm_optimized(),
BindingContext::Custom => Self::default(),
}
}
}
pub struct PerformanceOptimizer {
pub config: PerformanceConfig,
simplify_cache: Arc<RwLock<HashMap<u64, Expression>>>,
derivative_cache: Arc<RwLock<HashMap<u64, Expression>>>,
}
impl PerformanceOptimizer {
pub fn new(config: PerformanceConfig) -> Self {
Self {
config,
simplify_cache: Arc::new(RwLock::new(HashMap::new())),
derivative_cache: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn should_use_simd(&self, operation_size: usize) -> bool {
self.config.simd_enabled && operation_size >= self.config.simd_threshold
}
pub fn should_use_parallel(&self, operation_size: usize) -> bool {
self.config.parallel_enabled && operation_size >= self.config.parallel_threshold
}
pub fn get_cached_simplify(&self, expr_hash: u64) -> Option<Expression> {
if !self.config.memoization_enabled {
return None;
}
self.simplify_cache.read().ok()?.get(&expr_hash).cloned()
}
pub fn cache_simplify(&self, expr_hash: u64, result: Expression) {
if !self.config.memoization_enabled {
return;
}
if let Ok(mut cache) = self.simplify_cache.write() {
if cache.len() >= self.config.cache_size_limit {
if let Some(oldest_key) = cache.keys().next().copied() {
cache.remove(&oldest_key);
}
}
cache.insert(expr_hash, result);
}
}
pub fn cache_stats(&self) -> CacheStats {
let simplify_size = self.simplify_cache.read().map(|c| c.len()).unwrap_or(0);
let derivative_size = self.derivative_cache.read().map(|c| c.len()).unwrap_or(0);
CacheStats {
simplify_cache_size: simplify_size,
derivative_cache_size: derivative_size,
total_memory_estimate: (simplify_size + derivative_size) * 1024, }
}
}
#[derive(Debug, Clone)]
pub struct CacheStats {
pub simplify_cache_size: usize,
pub derivative_cache_size: usize,
pub total_memory_estimate: usize, }
static GLOBAL_OPTIMIZER: OnceLock<PerformanceOptimizer> = OnceLock::new();
pub fn init_performance_optimizer(config: PerformanceConfig) {
let _ = GLOBAL_OPTIMIZER.get_or_init(|| PerformanceOptimizer::new(config));
}
pub fn get_performance_optimizer() -> Option<&'static PerformanceOptimizer> {
GLOBAL_OPTIMIZER.get()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_performance_config_defaults() {
let config = PerformanceConfig::default();
assert!(config.simd_enabled);
assert_eq!(config.simd_threshold, 50);
assert!(config.memoization_enabled);
}
#[test]
fn test_python_optimized_config() {
let config = PerformanceConfig::python_optimized();
assert!(config.simd_enabled);
assert!(!config.parallel_enabled); assert!(config.memoization_enabled);
assert_eq!(config.cache_size_limit, 50000);
}
#[test]
fn test_performance_optimizer_simd_threshold() {
let config = PerformanceConfig::default();
let optimizer = PerformanceOptimizer::new(config);
assert!(!optimizer.should_use_simd(10)); assert!(optimizer.should_use_simd(100)); }
#[test]
fn test_memoization_cache() {
let config = PerformanceConfig::default();
let optimizer = PerformanceOptimizer::new(config);
let expr = Expression::integer(42);
let hash = 12345u64;
assert!(optimizer.get_cached_simplify(hash).is_none());
optimizer.cache_simplify(hash, expr.clone());
assert_eq!(optimizer.get_cached_simplify(hash), Some(expr));
}
}