1use crate::query_optimization_engine::{
2 OptimizedQueryContext, ImprovementReport,
3};
4use std::time::Instant;
5
6#[derive(Clone, Debug, PartialEq)]
8pub enum QueryPattern {
9 FilterSelectiveSmall,
11 JoinMedium,
13 AggregateGroupBy,
15 ComplexMultiJoin,
17 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#[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#[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, }
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
112pub 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 pub fn run_all(&mut self) -> BenchmarkSuiteReport {
134 let start = Instant::now();
135
136 let patterns = self.config.patterns.clone();
138
139 for pattern in &patterns {
141 self.warmup_pattern(pattern);
142 }
143
144 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 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#[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#[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 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}