Skip to main content

rez_next_cache/
benchmarks.rs

1//! Intelligent Cache Benchmarks
2//!
3//! Comprehensive benchmarking suite for the intelligent cache system.
4
5use crate::{
6    BenchmarkResult, IntelligentCacheManager, PerformanceMonitor, UnifiedCache, UnifiedCacheConfig,
7};
8use rand::Rng;
9use std::{sync::Arc, time::Duration};
10use tokio::time::sleep;
11
12/// Benchmark configuration
13#[derive(Debug, Clone)]
14pub struct BenchmarkConfig {
15    /// Number of operations per benchmark
16    pub operations_count: usize,
17    /// Number of concurrent workers
18    pub worker_count: usize,
19    /// Key space size (number of unique keys)
20    pub key_space_size: usize,
21    /// Value size in bytes
22    pub value_size: usize,
23    /// Read/write ratio (0.0 = all writes, 1.0 = all reads)
24    pub read_write_ratio: f64,
25    /// Benchmark duration limit
26    pub max_duration: Duration,
27}
28
29impl Default for BenchmarkConfig {
30    fn default() -> Self {
31        Self {
32            operations_count: 100_000,
33            worker_count: 4,
34            key_space_size: 10_000,
35            value_size: 1024,
36            read_write_ratio: 0.8, // 80% reads, 20% writes
37            max_duration: Duration::from_secs(60),
38        }
39    }
40}
41
42/// Benchmark suite for intelligent cache
43pub struct CacheBenchmarkSuite {
44    /// Cache manager under test
45    cache: Arc<IntelligentCacheManager<String, Vec<u8>>>,
46    /// Performance monitor
47    monitor: Arc<PerformanceMonitor>,
48    /// Benchmark configuration
49    config: BenchmarkConfig,
50}
51
52impl CacheBenchmarkSuite {
53    /// Create a new benchmark suite
54    pub fn new(cache_config: UnifiedCacheConfig, bench_config: BenchmarkConfig) -> Self {
55        let cache = Arc::new(IntelligentCacheManager::new(cache_config));
56        let monitor = cache.monitor();
57
58        Self {
59            cache,
60            monitor,
61            config: bench_config,
62        }
63    }
64
65    /// Run all benchmarks
66    pub async fn run_all_benchmarks(&self) -> Vec<BenchmarkResult> {
67        let mut results = Vec::new();
68
69        // Basic performance benchmarks
70        results.push(self.benchmark_sequential_operations().await);
71        results.push(self.benchmark_concurrent_operations().await);
72        results.push(self.benchmark_mixed_workload().await);
73
74        // Cache-specific benchmarks
75        results.push(self.benchmark_hit_rate_optimization().await);
76        results.push(self.benchmark_memory_efficiency().await);
77        results.push(self.benchmark_predictive_preheating().await);
78        results.push(self.benchmark_adaptive_tuning().await);
79
80        // Stress tests
81        results.push(self.benchmark_high_contention().await);
82        results.push(self.benchmark_large_dataset().await);
83
84        results
85    }
86
87    /// Benchmark sequential operations
88    pub async fn benchmark_sequential_operations(&self) -> BenchmarkResult {
89        self.monitor
90            .run_benchmark("sequential_operations", || async {
91                let test_data = self.generate_test_data();
92
93                // Sequential writes
94                for (key, value) in &test_data {
95                    let _ = self.cache.put(key.clone(), value.clone()).await;
96                }
97
98                // Sequential reads
99                for (key, _) in &test_data {
100                    let _ = self.cache.get(key).await;
101                }
102            })
103            .await
104    }
105
106    /// Benchmark concurrent operations
107    pub async fn benchmark_concurrent_operations(&self) -> BenchmarkResult {
108        self.monitor
109            .run_benchmark("concurrent_operations", || async {
110                let test_data = Arc::new(self.generate_test_data());
111                let cache = Arc::clone(&self.cache);
112
113                let mut handles = Vec::new();
114
115                for worker_id in 0..self.config.worker_count {
116                    let cache = Arc::clone(&cache);
117                    let test_data = Arc::clone(&test_data);
118                    let ops_per_worker = self.config.operations_count / self.config.worker_count;
119
120                    let handle = tokio::spawn(async move {
121                        for i in 0..ops_per_worker {
122                            let key_index = (worker_id * ops_per_worker + i) % test_data.len();
123                            let (key, value) = &test_data[key_index];
124
125                            if i % 5 == 0 {
126                                // Write operation
127                                let _ = cache.put(key.clone(), value.clone()).await;
128                            } else {
129                                // Read operation
130                                let _ = cache.get(key).await;
131                            }
132                        }
133                    });
134
135                    handles.push(handle);
136                }
137
138                // Wait for all workers to complete
139                for handle in handles {
140                    let _ = handle.await;
141                }
142            })
143            .await
144    }
145
146    /// Benchmark mixed workload (reads and writes)
147    pub async fn benchmark_mixed_workload(&self) -> BenchmarkResult {
148        self.monitor
149            .run_benchmark("mixed_workload", || async {
150                let test_data = self.generate_test_data();
151
152                for (i, (key, value)) in test_data.iter().enumerate() {
153                    let operation_ratio = i as f64 / test_data.len() as f64;
154
155                    if operation_ratio < self.config.read_write_ratio {
156                        // Read operation
157                        let _ = self.cache.get(key).await;
158                    } else {
159                        // Write operation
160                        let _ = self.cache.put(key.clone(), value.clone()).await;
161                    }
162                }
163            })
164            .await
165    }
166
167    /// Benchmark hit rate optimization
168    pub async fn benchmark_hit_rate_optimization(&self) -> BenchmarkResult {
169        self.monitor
170            .run_benchmark("hit_rate_optimization", || async {
171                let test_data = self.generate_test_data();
172
173                // Phase 1: Populate cache with hot data
174                let hot_data_size = test_data.len() / 4; // 25% hot data
175                for (key, value) in test_data.iter().take(hot_data_size) {
176                    let _ = self.cache.put(key.clone(), value.clone()).await;
177                }
178
179                // Phase 2: Access pattern simulation (80/20 rule)
180                for _ in 0..self.config.operations_count {
181                    let mut rng = rand::rng();
182                    let key_index = if rng.random::<f64>() < 0.8 {
183                        // 80% access to hot data
184                        rng.random_range(0..hot_data_size)
185                    } else {
186                        // 20% access to cold data
187                        hot_data_size + rng.random_range(0..(test_data.len() - hot_data_size))
188                    };
189
190                    let (key, value) = &test_data[key_index];
191
192                    if self.cache.get(key).await.is_none() {
193                        // Cache miss - populate
194                        let _ = self.cache.put(key.clone(), value.clone()).await;
195                    }
196                }
197            })
198            .await
199    }
200
201    /// Benchmark memory efficiency
202    pub async fn benchmark_memory_efficiency(&self) -> BenchmarkResult {
203        self.monitor
204            .run_benchmark("memory_efficiency", || async {
205                let large_value = vec![0u8; self.config.value_size * 10]; // 10x larger values
206
207                // Fill cache to capacity
208                for i in 0..self.config.key_space_size {
209                    let key = format!("large_key_{}", i);
210                    let _ = self.cache.put(key, large_value.clone()).await;
211                }
212
213                // Trigger evictions with new data
214                for i in 0..self.config.key_space_size / 2 {
215                    let key = format!("new_key_{}", i);
216                    let _ = self.cache.put(key, large_value.clone()).await;
217                }
218            })
219            .await
220    }
221
222    /// Benchmark predictive preheating
223    pub async fn benchmark_predictive_preheating(&self) -> BenchmarkResult {
224        self.monitor
225            .run_benchmark("predictive_preheating", || async {
226                let test_data = self.generate_test_data();
227
228                // Create predictable access patterns
229                for cycle in 0..10 {
230                    for (i, (key, value)) in test_data.iter().enumerate() {
231                        if i % 10 == cycle % 10 {
232                            // Access pattern: every 10th item in rotation
233                            if self.cache.get(key).await.is_none() {
234                                let _ = self.cache.put(key.clone(), value.clone()).await;
235                            }
236                        }
237                    }
238
239                    // Wait for pattern learning
240                    sleep(Duration::from_millis(100)).await;
241                }
242
243                // Test prediction accuracy
244                for (i, (key, _)) in test_data.iter().enumerate() {
245                    if i % 10 == 0 {
246                        // These should be preheated
247                        let _ = self.cache.get(key).await;
248                    }
249                }
250            })
251            .await
252    }
253
254    /// Benchmark adaptive tuning
255    pub async fn benchmark_adaptive_tuning(&self) -> BenchmarkResult {
256        self.monitor
257            .run_benchmark("adaptive_tuning", || async {
258                let test_data = self.generate_test_data();
259
260                // Phase 1: Low hit rate workload
261                for _ in 0..1000 {
262                    let mut rng = rand::rng();
263                    let key_index = rng.random_range(0..test_data.len());
264                    let (key, value) = &test_data[key_index];
265
266                    if self.cache.get(key).await.is_none() {
267                        let _ = self.cache.put(key.clone(), value.clone()).await;
268                    }
269                }
270
271                // Wait for tuning
272                sleep(Duration::from_secs(1)).await;
273
274                // Phase 2: High hit rate workload
275                let hot_keys: Vec<_> = test_data.iter().take(100).collect();
276                for _ in 0..1000 {
277                    let mut rng = rand::rng();
278                    let (key, value) = hot_keys[rng.random_range(0..hot_keys.len())];
279
280                    if self.cache.get(key).await.is_none() {
281                        let _ = self.cache.put(key.clone(), value.clone()).await;
282                    }
283                }
284            })
285            .await
286    }
287
288    /// Benchmark high contention scenarios
289    pub async fn benchmark_high_contention(&self) -> BenchmarkResult {
290        self.monitor
291            .run_benchmark("high_contention", || async {
292                let hot_keys = vec!["hot_key_1", "hot_key_2", "hot_key_3"];
293                let test_value = vec![0u8; self.config.value_size];
294
295                let cache = Arc::clone(&self.cache);
296                let mut handles = Vec::new();
297
298                // Multiple workers accessing the same hot keys
299                for _ in 0..self.config.worker_count * 2 {
300                    let cache = Arc::clone(&cache);
301                    let hot_keys = hot_keys.clone();
302                    let test_value = test_value.clone();
303
304                    let handle = tokio::spawn(async move {
305                        for _ in 0..1000 {
306                            let key_index = {
307                                let mut rng = rand::rng();
308                                rng.random_range(0..hot_keys.len())
309                            };
310                            let key = &hot_keys[key_index];
311
312                            let is_read = {
313                                let mut rng = rand::rng();
314                                rng.random::<bool>()
315                            };
316
317                            if is_read {
318                                let _ = cache.get(&key.to_string()).await;
319                            } else {
320                                let _ = cache.put(key.to_string(), test_value.clone()).await;
321                            }
322                        }
323                    });
324
325                    handles.push(handle);
326                }
327
328                for handle in handles {
329                    let _ = handle.await;
330                }
331            })
332            .await
333    }
334
335    /// Benchmark large dataset handling
336    pub async fn benchmark_large_dataset(&self) -> BenchmarkResult {
337        self.monitor
338            .run_benchmark("large_dataset", || async {
339                let large_dataset_size = self.config.key_space_size * 10;
340                let test_value = vec![0u8; self.config.value_size];
341
342                // Populate with large dataset
343                for i in 0..large_dataset_size {
344                    let key = format!("large_dataset_key_{}", i);
345                    let _ = self.cache.put(key, test_value.clone()).await;
346
347                    // Periodic reads to test cache behavior under load
348                    if i % 1000 == 0 {
349                        for j in 0..100 {
350                            let read_key = format!("large_dataset_key_{}", j);
351                            let _ = self.cache.get(&read_key).await;
352                        }
353                    }
354                }
355            })
356            .await
357    }
358
359    /// Generate test data for benchmarks
360    fn generate_test_data(&self) -> Vec<(String, Vec<u8>)> {
361        (0..self.config.key_space_size)
362            .map(|i| {
363                let key = format!("test_key_{}", i);
364                let value = vec![i as u8; self.config.value_size];
365                (key, value)
366            })
367            .collect()
368    }
369
370    /// Get cache statistics
371    pub async fn get_cache_stats(&self) -> crate::UnifiedCacheStats {
372        self.cache.get_stats().await
373    }
374
375    /// Get performance metrics
376    pub async fn get_performance_metrics(&self) -> crate::PerformanceMetrics {
377        self.monitor.get_performance_metrics().await
378    }
379}
380
381/// Run a comprehensive benchmark suite
382pub async fn run_comprehensive_benchmarks() -> Vec<BenchmarkResult> {
383    println!("šŸš€ Starting Intelligent Cache Comprehensive Benchmarks");
384
385    // Test different configurations
386    let configs = vec![
387        ("High Performance", UnifiedCacheConfig::high_performance()),
388        ("Low Memory", UnifiedCacheConfig::low_memory()),
389        ("Default", UnifiedCacheConfig::default()),
390    ];
391
392    let mut all_results = Vec::new();
393
394    for (config_name, cache_config) in configs {
395        println!("\nšŸ“Š Testing configuration: {}", config_name);
396
397        let bench_config = BenchmarkConfig::default();
398        let suite = CacheBenchmarkSuite::new(cache_config, bench_config);
399
400        let results = suite.run_all_benchmarks().await;
401
402        println!(
403            "āœ… Completed {} benchmarks for {}",
404            results.len(),
405            config_name
406        );
407        for result in &results {
408            println!(
409                "  {} - {:.2} ops/sec, {:.2}μs avg latency",
410                result.name, result.ops_per_second, result.avg_latency_us
411            );
412        }
413
414        all_results.extend(results);
415    }
416
417    println!("\nšŸŽÆ Benchmark Summary:");
418    println!("Total benchmarks completed: {}", all_results.len());
419
420    all_results
421}