mathhook_core/core/performance/
strategy.rs1use crate::core::Expression;
7use std::collections::HashMap;
8use std::sync::{Arc, OnceLock, RwLock};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum BindingContext {
13 Native,
15 Python,
17 NodeJs,
19 WebAssembly,
21 Custom,
23}
24
25#[derive(Debug, Clone)]
27pub struct PerformanceConfig {
28 pub simd_enabled: bool,
30 pub simd_threshold: usize,
32 pub memoization_enabled: bool,
34 pub cache_size_limit: usize,
36 pub parallel_enabled: bool,
38 pub parallel_threshold: usize,
40}
41
42impl Default for PerformanceConfig {
43 fn default() -> Self {
44 Self {
45 simd_enabled: true,
46 simd_threshold: 50, memoization_enabled: true,
48 cache_size_limit: 10000, parallel_enabled: false, parallel_threshold: 1000, }
52 }
53}
54
55impl PerformanceConfig {
56 pub fn python_optimized() -> Self {
58 Self {
59 simd_enabled: true,
60 simd_threshold: 50,
61 memoization_enabled: true,
62 cache_size_limit: 50000, parallel_enabled: false, parallel_threshold: usize::MAX, }
66 }
67
68 pub fn nodejs_optimized() -> Self {
70 Self {
71 simd_enabled: true,
72 simd_threshold: 50,
73 memoization_enabled: true,
74 cache_size_limit: 20000, parallel_enabled: true, parallel_threshold: 500, }
78 }
79
80 pub fn native_optimized() -> Self {
82 Self {
83 simd_enabled: true,
84 simd_threshold: 20, memoization_enabled: true,
86 cache_size_limit: 100000, parallel_enabled: true,
88 parallel_threshold: 100, }
90 }
91
92 pub fn wasm_optimized() -> Self {
94 Self {
95 simd_enabled: true, simd_threshold: 100, memoization_enabled: true,
98 cache_size_limit: 1000, parallel_enabled: false, parallel_threshold: usize::MAX,
101 }
102 }
103
104 pub fn for_binding(context: BindingContext) -> Self {
106 match context {
107 BindingContext::Native => Self::native_optimized(),
108 BindingContext::Python => Self::python_optimized(),
109 BindingContext::NodeJs => Self::nodejs_optimized(),
110 BindingContext::WebAssembly => Self::wasm_optimized(),
111 BindingContext::Custom => Self::default(),
112 }
113 }
114}
115
116pub struct PerformanceOptimizer {
118 pub config: PerformanceConfig,
119 simplify_cache: Arc<RwLock<HashMap<u64, Expression>>>,
120 derivative_cache: Arc<RwLock<HashMap<u64, Expression>>>,
121}
122
123impl PerformanceOptimizer {
124 pub fn new(config: PerformanceConfig) -> Self {
125 Self {
126 config,
127 simplify_cache: Arc::new(RwLock::new(HashMap::new())),
128 derivative_cache: Arc::new(RwLock::new(HashMap::new())),
129 }
130 }
131
132 pub fn should_use_simd(&self, operation_size: usize) -> bool {
134 self.config.simd_enabled && operation_size >= self.config.simd_threshold
135 }
136
137 pub fn should_use_parallel(&self, operation_size: usize) -> bool {
139 self.config.parallel_enabled && operation_size >= self.config.parallel_threshold
140 }
141
142 pub fn get_cached_simplify(&self, expr_hash: u64) -> Option<Expression> {
144 if !self.config.memoization_enabled {
145 return None;
146 }
147
148 self.simplify_cache.read().ok()?.get(&expr_hash).cloned()
149 }
150
151 pub fn cache_simplify(&self, expr_hash: u64, result: Expression) {
153 if !self.config.memoization_enabled {
154 return;
155 }
156
157 if let Ok(mut cache) = self.simplify_cache.write() {
158 if cache.len() >= self.config.cache_size_limit {
160 if let Some(oldest_key) = cache.keys().next().copied() {
162 cache.remove(&oldest_key);
163 }
164 }
165 cache.insert(expr_hash, result);
166 }
167 }
168
169 pub fn cache_stats(&self) -> CacheStats {
171 let simplify_size = self.simplify_cache.read().map(|c| c.len()).unwrap_or(0);
172 let derivative_size = self.derivative_cache.read().map(|c| c.len()).unwrap_or(0);
173
174 CacheStats {
175 simplify_cache_size: simplify_size,
176 derivative_cache_size: derivative_size,
177 total_memory_estimate: (simplify_size + derivative_size) * 1024, }
179 }
180}
181
182#[derive(Debug, Clone)]
183pub struct CacheStats {
184 pub simplify_cache_size: usize,
185 pub derivative_cache_size: usize,
186 pub total_memory_estimate: usize, }
188
189static GLOBAL_OPTIMIZER: OnceLock<PerformanceOptimizer> = OnceLock::new();
191
192pub fn init_performance_optimizer(config: PerformanceConfig) {
194 let _ = GLOBAL_OPTIMIZER.get_or_init(|| PerformanceOptimizer::new(config));
195}
196
197pub fn get_performance_optimizer() -> Option<&'static PerformanceOptimizer> {
199 GLOBAL_OPTIMIZER.get()
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_performance_config_defaults() {
208 let config = PerformanceConfig::default();
209 assert!(config.simd_enabled);
210 assert_eq!(config.simd_threshold, 50);
211 assert!(config.memoization_enabled);
212 }
213
214 #[test]
215 fn test_python_optimized_config() {
216 let config = PerformanceConfig::python_optimized();
217 assert!(config.simd_enabled);
218 assert!(!config.parallel_enabled); assert!(config.memoization_enabled);
220 assert_eq!(config.cache_size_limit, 50000);
221 }
222
223 #[test]
224 fn test_performance_optimizer_simd_threshold() {
225 let config = PerformanceConfig::default();
226 let optimizer = PerformanceOptimizer::new(config);
227
228 assert!(!optimizer.should_use_simd(10)); assert!(optimizer.should_use_simd(100)); }
231
232 #[test]
233 fn test_memoization_cache() {
234 let config = PerformanceConfig::default();
235 let optimizer = PerformanceOptimizer::new(config);
236
237 let expr = Expression::integer(42);
238 let hash = 12345u64;
239
240 assert!(optimizer.get_cached_simplify(hash).is_none());
242
243 optimizer.cache_simplify(hash, expr.clone());
245
246 assert_eq!(optimizer.get_cached_simplify(hash), Some(expr));
248 }
249}