Skip to main content

kore_fileformat/
realworld_benchmarking.rs

1use crate::query_optimization_engine::{
2    OptimizedQueryContext, ImprovementReport,
3};
4use std::time::Instant;
5
6/// Real-world query patterns
7#[derive(Clone, Debug, PartialEq)]
8pub enum QueryPattern {
9    /// Simple filtering with low selectivity
10    FilterSelectiveSmall,
11    /// Medium-sized JOIN operation
12    JoinMedium,
13    /// Aggregate with GROUP BY
14    AggregateGroupBy,
15    /// Complex multi-table JOIN
16    ComplexMultiJoin,
17    /// Large table scan with filter
18    LargeScanFilter,
19}
20
21impl QueryPattern {
22    pub fn description(&self) -> &str {
23        match self {
24            QueryPattern::FilterSelectiveSmall => "Small selective filter (10K rows, 10% selectivity)",
25            QueryPattern::JoinMedium => "Medium JOIN operation (100K rows, 50% selectivity)",
26            QueryPattern::AggregateGroupBy => "Aggregate with GROUP BY (50K rows, 20% selectivity)",
27            QueryPattern::ComplexMultiJoin => "Complex multi-table JOIN (1M rows, 30% selectivity)",
28            QueryPattern::LargeScanFilter => "Large table scan with filter (500K rows, 5% selectivity)",
29        }
30    }
31
32    pub fn parameters(&self) -> (usize, f64) {
33        match self {
34            QueryPattern::FilterSelectiveSmall => (10000, 0.1),
35            QueryPattern::JoinMedium => (100000, 0.5),
36            QueryPattern::AggregateGroupBy => (50000, 0.2),
37            QueryPattern::ComplexMultiJoin => (1000000, 0.3),
38            QueryPattern::LargeScanFilter => (500000, 0.05),
39        }
40    }
41}
42
43/// Benchmark configuration
44#[derive(Clone, Debug)]
45pub struct BenchmarkConfig {
46    pub iterations: usize,
47    pub warmup_iterations: usize,
48    pub enable_parallelization: bool,
49    pub enable_memory_pooling: bool,
50    pub patterns: Vec<QueryPattern>,
51}
52
53impl BenchmarkConfig {
54    pub fn new() -> Self {
55        Self {
56            iterations: 5,
57            warmup_iterations: 2,
58            enable_parallelization: true,
59            enable_memory_pooling: true,
60            patterns: vec![
61                QueryPattern::FilterSelectiveSmall,
62                QueryPattern::JoinMedium,
63                QueryPattern::AggregateGroupBy,
64                QueryPattern::ComplexMultiJoin,
65                QueryPattern::LargeScanFilter,
66            ],
67        }
68    }
69
70    pub fn with_iterations(mut self, iter: usize) -> Self {
71        self.iterations = iter;
72        self
73    }
74
75    pub fn with_warmup(mut self, warmup: usize) -> Self {
76        self.warmup_iterations = warmup;
77        self
78    }
79}
80
81impl Default for BenchmarkConfig {
82    fn default() -> Self {
83        Self::new()
84    }
85}
86
87/// Single benchmark result
88#[derive(Clone, Debug, PartialEq)]
89pub struct BenchmarkResult {
90    pub pattern: String,
91    pub description: String,
92    pub iterations: usize,
93    pub avg_sequential_ms: f64,
94    pub avg_parallel_ms: f64,
95    pub avg_speedup: f64,
96    pub memory_saved_mb: f64,
97    pub consistency_score: f64, // 0-1, higher = more consistent
98}
99
100impl BenchmarkResult {
101    pub fn improvement_percent(&self) -> f64 {
102        if self.avg_sequential_ms > 0.0 {
103            ((self.avg_sequential_ms - self.avg_parallel_ms)
104                / self.avg_sequential_ms)
105                * 100.0
106        } else {
107            0.0
108        }
109    }
110}
111
112/// Real-world benchmark suite
113pub struct RealWorldBenchmarkSuite {
114    config: BenchmarkConfig,
115    context: OptimizedQueryContext,
116    results: Vec<BenchmarkResult>,
117}
118
119impl RealWorldBenchmarkSuite {
120    pub fn new(config: BenchmarkConfig) -> Self {
121        let mut context = OptimizedQueryContext::new();
122        context.enable_parallelization = config.enable_parallelization;
123        context.enable_memory_pooling = config.enable_memory_pooling;
124
125        Self {
126            config,
127            context,
128            results: Vec::new(),
129        }
130    }
131
132    /// Run complete benchmark suite
133    pub fn run_all(&mut self) -> BenchmarkSuiteReport {
134        let start = Instant::now();
135
136        // Clone patterns to avoid borrow conflicts
137        let patterns = self.config.patterns.clone();
138
139        // Warmup phase
140        for pattern in &patterns {
141            self.warmup_pattern(pattern);
142        }
143
144        // Benchmark phase
145        for pattern in &patterns {
146            let result = self.benchmark_pattern(pattern);
147            self.results.push(result);
148        }
149
150        let total_time_ms = start.elapsed().as_millis() as f64;
151
152        BenchmarkSuiteReport {
153            config: self.config.clone(),
154            results: self.results.clone(),
155            total_time_ms,
156            generated_at: chrono_now(),
157        }
158    }
159
160    fn warmup_pattern(&mut self, pattern: &QueryPattern) {
161        for _ in 0..self.config.warmup_iterations {
162            let (rows, selectivity) = pattern.parameters();
163            let _ = self.context.execute_optimized_query(
164                &format!("warmup_{:?}", pattern),
165                rows,
166                selectivity,
167            );
168        }
169    }
170
171    fn benchmark_pattern(&mut self, pattern: &QueryPattern) -> BenchmarkResult {
172        let (rows, selectivity) = pattern.parameters();
173        let mut seq_times = Vec::new();
174        let mut par_times = Vec::new();
175        let pattern_name = format!("{:?}", pattern);
176
177        for i in 0..self.config.iterations {
178            let result = self.context.execute_optimized_query(
179                &format!("{}_iter{}", pattern_name, i),
180                rows,
181                selectivity,
182            );
183
184            seq_times.push(result.sequential_ms as f64);
185            par_times.push(result.parallel_ms as f64);
186        }
187
188        let avg_seq = seq_times.iter().sum::<f64>() / seq_times.len() as f64;
189        let avg_par = par_times.iter().sum::<f64>() / par_times.len() as f64;
190
191        // Calculate consistency score (inverse of coefficient of variation)
192        let variance = calculate_variance(&par_times, avg_par);
193        let std_dev = variance.sqrt();
194        let cv = if avg_par > 0.0 {
195            std_dev / avg_par
196        } else {
197            0.0
198        };
199        let consistency = (1.0 / (1.0 + cv)).clamp(0.0, 1.0);
200
201        BenchmarkResult {
202            pattern: pattern_name,
203            description: pattern.description().to_string(),
204            iterations: self.config.iterations,
205            avg_sequential_ms: avg_seq,
206            avg_parallel_ms: avg_par,
207            avg_speedup: if avg_par > 0.0 {
208                avg_seq / avg_par
209            } else {
210                1.0
211            },
212            memory_saved_mb: (rows as f64) * 0.05 / 1000000.0,
213            consistency_score: consistency,
214        }
215    }
216
217    pub fn get_results(&self) -> Vec<BenchmarkResult> {
218        self.results.clone()
219    }
220
221    pub fn get_improvement_summary(&self) -> ImprovementReport {
222        self.context.get_improvement_summary()
223    }
224}
225
226impl Default for RealWorldBenchmarkSuite {
227    fn default() -> Self {
228        Self::new(BenchmarkConfig::default())
229    }
230}
231
232/// Complete benchmark report
233#[derive(Clone, Debug)]
234pub struct BenchmarkSuiteReport {
235    pub config: BenchmarkConfig,
236    pub results: Vec<BenchmarkResult>,
237    pub total_time_ms: f64,
238    pub generated_at: String,
239}
240
241impl BenchmarkSuiteReport {
242    pub fn summary(&self) -> BenchmarkSummary {
243        let avg_speedup = if !self.results.is_empty() {
244            self.results.iter().map(|r| r.avg_speedup).sum::<f64>()
245                / self.results.len() as f64
246        } else {
247            1.0
248        };
249
250        let total_memory_saved = self.results.iter()
251            .map(|r| r.memory_saved_mb)
252            .sum::<f64>();
253
254        let best_speedup = self.results.iter()
255            .max_by(|a, b| {
256                a.avg_speedup.partial_cmp(&b.avg_speedup).unwrap()
257            })
258            .map(|r| r.avg_speedup)
259            .unwrap_or(1.0);
260
261        let worst_speedup = self.results.iter()
262            .min_by(|a, b| {
263                a.avg_speedup.partial_cmp(&b.avg_speedup).unwrap()
264            })
265            .map(|r| r.avg_speedup)
266            .unwrap_or(1.0);
267
268        BenchmarkSummary {
269            total_patterns: self.results.len(),
270            average_speedup: avg_speedup,
271            best_speedup,
272            worst_speedup,
273            total_memory_savings_mb: total_memory_saved,
274            avg_consistency: self.results.iter()
275                .map(|r| r.consistency_score)
276                .sum::<f64>() / self.results.len() as f64,
277        }
278    }
279
280    pub fn format_report(&self) -> String {
281        let summary = self.summary();
282        
283        format!(
284            "=== Real-World Benchmark Report ===\n\
285            Generated: {}\n\
286            Total Time: {:.2}ms\n\
287            Iterations per pattern: {}\n\
288            \n\
289            Summary:\n\
290            - Average Speedup: {:.2}x\n\
291            - Best Speedup: {:.2}x\n\
292            - Worst Speedup: {:.2}x\n\
293            - Total Memory Saved: {:.2} MB\n\
294            - Consistency Score: {:.2}\n\
295            \n\
296            Individual Results:\n{}",
297            self.generated_at,
298            self.total_time_ms,
299            self.config.iterations,
300            summary.average_speedup,
301            summary.best_speedup,
302            summary.worst_speedup,
303            summary.total_memory_savings_mb,
304            summary.avg_consistency,
305            self.results.iter()
306                .map(|r| format!(
307                    "  {} ({:.2}x speedup, {:.1}% improvement, {:.2} consistency)",
308                    r.pattern,
309                    r.avg_speedup,
310                    r.improvement_percent(),
311                    r.consistency_score
312                ))
313                .collect::<Vec<_>>()
314                .join("\n")
315        )
316    }
317}
318
319/// Benchmark summary statistics
320#[derive(Clone, Debug, PartialEq)]
321pub struct BenchmarkSummary {
322    pub total_patterns: usize,
323    pub average_speedup: f64,
324    pub best_speedup: f64,
325    pub worst_speedup: f64,
326    pub total_memory_savings_mb: f64,
327    pub avg_consistency: f64,
328}
329
330fn calculate_variance(values: &[f64], mean: f64) -> f64 {
331    if values.is_empty() {
332        return 0.0;
333    }
334    values.iter()
335        .map(|v| (v - mean).powi(2))
336        .sum::<f64>()
337        / values.len() as f64
338}
339
340fn chrono_now() -> String {
341    // Simplified - just use a timestamp format
342    let now = std::time::SystemTime::now()
343        .duration_since(std::time::UNIX_EPOCH)
344        .unwrap()
345        .as_secs();
346    format!("2026-05-10 {:02}:{:02}:{:02}",
347        (now / 3600) % 24,
348        (now / 60) % 60,
349        now % 60)
350}
351
352#[cfg(test)]
353mod tests {
354    use super::*;
355
356    #[test]
357    fn test_query_pattern_parameters() {
358        let (rows, sel) = QueryPattern::FilterSelectiveSmall.parameters();
359        assert_eq!(rows, 10000);
360        assert_eq!(sel, 0.1);
361
362        let (rows, sel) = QueryPattern::ComplexMultiJoin.parameters();
363        assert_eq!(rows, 1000000);
364        assert_eq!(sel, 0.3);
365    }
366
367    #[test]
368    fn test_benchmark_config() {
369        let config = BenchmarkConfig::new()
370            .with_iterations(10)
371            .with_warmup(3);
372
373        assert_eq!(config.iterations, 10);
374        assert_eq!(config.warmup_iterations, 3);
375    }
376
377    #[test]
378    fn test_benchmark_result_improvement() {
379        let result = BenchmarkResult {
380            pattern: "test".to_string(),
381            description: "test".to_string(),
382            iterations: 5,
383            avg_sequential_ms: 100.0,
384            avg_parallel_ms: 50.0,
385            avg_speedup: 2.0,
386            memory_saved_mb: 10.0,
387            consistency_score: 0.95,
388        };
389
390        assert_eq!(result.improvement_percent(), 50.0);
391    }
392
393    #[test]
394    fn test_real_world_benchmark_suite() {
395        let config = BenchmarkConfig::new()
396            .with_iterations(2)
397            .with_warmup(1);
398        let mut suite = RealWorldBenchmarkSuite::new(config);
399
400        let report = suite.run_all();
401        assert!(!report.results.is_empty());
402        assert!(report.total_time_ms > 0.0);
403    }
404
405    #[test]
406    fn test_benchmark_suite_report_summary() {
407        let results = vec![
408            BenchmarkResult {
409                pattern: "p1".to_string(),
410                description: "p1".to_string(),
411                iterations: 5,
412                avg_sequential_ms: 100.0,
413                avg_parallel_ms: 50.0,
414                avg_speedup: 2.0,
415                memory_saved_mb: 5.0,
416                consistency_score: 0.9,
417            },
418            BenchmarkResult {
419                pattern: "p2".to_string(),
420                description: "p2".to_string(),
421                iterations: 5,
422                avg_sequential_ms: 200.0,
423                avg_parallel_ms: 80.0,
424                avg_speedup: 2.5,
425                memory_saved_mb: 10.0,
426                consistency_score: 0.85,
427            },
428        ];
429
430        let report = BenchmarkSuiteReport {
431            config: BenchmarkConfig::default(),
432            results,
433            total_time_ms: 1000.0,
434            generated_at: "2026-05-10 12:00:00".to_string(),
435        };
436
437        let summary = report.summary();
438        assert_eq!(summary.total_patterns, 2);
439        assert!(summary.average_speedup > 2.0);
440        assert!(summary.best_speedup >= 2.0);
441    }
442
443    #[test]
444    fn test_benchmark_suite_report_format() {
445        let report = BenchmarkSuiteReport {
446            config: BenchmarkConfig::default(),
447            results: vec![],
448            total_time_ms: 500.0,
449            generated_at: "2026-05-10 12:00:00".to_string(),
450        };
451
452        let formatted = report.format_report();
453        assert!(formatted.contains("Real-World Benchmark Report"));
454        assert!(formatted.contains("Average Speedup"));
455    }
456
457    #[test]
458    fn test_variance_calculation() {
459        let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
460        let mean = 3.0;
461        let variance = calculate_variance(&values, mean);
462        assert!(variance > 0.0);
463    }
464
465    #[test]
466    fn test_benchmark_summary() {
467        let summary = BenchmarkSummary {
468            total_patterns: 5,
469            average_speedup: 2.5,
470            best_speedup: 3.5,
471            worst_speedup: 1.5,
472            total_memory_savings_mb: 100.0,
473            avg_consistency: 0.9,
474        };
475
476        assert_eq!(summary.total_patterns, 5);
477        assert!(summary.average_speedup > 1.0);
478        assert!(summary.best_speedup > summary.worst_speedup);
479    }
480}