1use crate::core::tracker::MemoryTracker;
6use crate::core::types::TrackingResult;
7use crate::export::fast_export_coordinator::{FastExportConfigBuilder, FastExportCoordinator};
8use crate::export::optimized_json_export::OptimizedExportOptions;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use std::time::Instant;
12
13#[derive(Debug, Clone)]
15pub struct PerformanceTestConfig {
16 pub dataset_sizes: Vec<usize>,
18 pub shard_sizes: Vec<usize>,
20 pub thread_counts: Vec<usize>,
22 pub buffer_sizes: Vec<usize>,
24 pub test_iterations: usize,
26 pub memory_limit_mb: usize,
28 pub verbose: bool,
30}
31
32impl Default for PerformanceTestConfig {
33 fn default() -> Self {
34 Self {
35 dataset_sizes: vec![1000, 5000, 10000, 20000, 50000],
36 shard_sizes: vec![500, 1000, 2000, 5000],
37 thread_counts: vec![1, 2, 4, 8],
38 buffer_sizes: vec![64 * 1024, 256 * 1024, 512 * 1024, 1024 * 1024],
39 test_iterations: 3,
40 memory_limit_mb: 64,
41 verbose: true,
42 }
43 }
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct PerformanceTestResult {
49 pub test_name: String,
51 pub dataset_size: usize,
53 pub config_params: HashMap<String, String>,
55 pub export_time_ms: u64,
57 pub peak_memory_mb: f64,
59 pub throughput_allocations_per_sec: f64,
61 pub output_file_size_bytes: usize,
63 pub success: bool,
65 pub error_message: Option<String>,
67}
68
69pub struct PerformanceBenchmark;
71
72impl PerformanceBenchmark {
73 pub fn run_quick_benchmark() -> TrackingResult<()> {
75 println!("š Running quick performance benchmark");
76 println!("========================");
77
78 let config = PerformanceTestConfig {
79 dataset_sizes: vec![1000, 5000, 10000],
80 shard_sizes: vec![500, 1000, 2000],
81 thread_counts: vec![1, 2, 4],
82 buffer_sizes: vec![256 * 1024],
83 test_iterations: 1,
84 memory_limit_mb: 64,
85 verbose: true,
86 };
87
88 let mut test_suite = PerformanceTestSuite::new(config);
89 let _report = test_suite.run_basic_tests()?;
90
91 println!("ā
Quick benchmark completed");
92 Ok(())
93 }
94
95 pub fn run_complex_lifecycle_benchmark() -> TrackingResult<ComplexLifecycleBenchmarkResult> {
97 println!("šÆ Running complex_lifecycle_showcase.rs benchmark");
98 println!("==============================================");
99
100 let mut benchmark_result = ComplexLifecycleBenchmarkResult::default();
101
102 println!("š Testing traditional export performance...");
104 let traditional_result = Self::benchmark_traditional_export()?;
105 benchmark_result.traditional_export = traditional_result;
106
107 println!("ā” Testing fast export performance...");
109 let fast_result = Self::benchmark_fast_export()?;
110 benchmark_result.fast_export = fast_result;
111
112 benchmark_result.calculate_improvements();
114
115 Self::print_complex_benchmark_results(&benchmark_result);
117
118 Ok(benchmark_result)
119 }
120
121 fn benchmark_traditional_export() -> TrackingResult<ExportBenchmarkResult> {
123 use std::process::Command;
124 use std::time::Instant;
125
126 let start_time = Instant::now();
127 let start_memory = Self::get_current_memory_usage();
128
129 let output = Command::new("cargo")
131 .args(&["run", "--example", "complex_lifecycle_showcase"])
132 .output()
133 .map_err(|e| crate::core::types::TrackingError::IoError(e.to_string()))?;
134
135 let export_time = start_time.elapsed();
136 let peak_memory = Self::get_current_memory_usage() - start_memory;
137
138 let file_size = Self::get_complex_lifecycle_file_size();
140
141 let success = output.status.success();
142 let error_message = if !success {
143 Some(String::from_utf8_lossy(&output.stderr).to_string())
144 } else {
145 None
146 };
147
148 Ok(ExportBenchmarkResult {
149 export_time_ms: export_time.as_millis() as u64,
150 peak_memory_mb: peak_memory,
151 output_file_size_bytes: file_size,
152 success,
153 error_message,
154 stdout: String::from_utf8_lossy(&output.stdout).to_string(),
155 })
156 }
157
158 fn benchmark_fast_export() -> TrackingResult<ExportBenchmarkResult> {
160 use std::time::Instant;
161
162 let start_time = Instant::now();
163 let start_memory = Self::get_current_memory_usage();
164
165 let config = FastExportConfigBuilder::new()
167 .shard_size(1000)
168 .max_threads(Some(4))
169 .buffer_size(512 * 1024)
170 .performance_monitoring(true)
171 .build();
172
173 let mut coordinator = FastExportCoordinator::new(config);
174 let output_path = "complex_lifecycle_fast_export";
175
176 let result = coordinator.export_fast(output_path);
177 let export_time = start_time.elapsed();
178 let peak_memory = Self::get_current_memory_usage() - start_memory;
179
180 match result {
181 Ok(stats) => {
182 let file_size = Self::get_file_size_static(output_path);
183
184 Ok(ExportBenchmarkResult {
185 export_time_ms: stats.total_export_time_ms,
186 peak_memory_mb: peak_memory,
187 output_file_size_bytes: file_size,
188 success: true,
189 error_message: None,
190 stdout: format!(
191 "Fast export completed: {} allocations processed",
192 stats.total_allocations_processed
193 ),
194 })
195 }
196 Err(e) => Ok(ExportBenchmarkResult {
197 export_time_ms: export_time.as_millis() as u64,
198 peak_memory_mb: peak_memory,
199 output_file_size_bytes: 0,
200 success: false,
201 error_message: Some(e.to_string()),
202 stdout: String::new(),
203 }),
204 }
205 }
206
207 fn get_complex_lifecycle_file_size() -> usize {
209 let paths = [
210 "MemoryAnalysis/complex_lifecycle/complex_lifecycle_memory_analysis.json",
211 "MemoryAnalysis/complex_lifecycle_snapshot/complex_lifecycle_snapshot_memory_analysis.json",
212 "complex_lifecycle_snapshot_memory_analysis.json",
213 ];
214
215 for path in &paths {
216 if let Ok(metadata) = std::fs::metadata(path) {
217 return metadata.len() as usize;
218 }
219 }
220
221 0
222 }
223
224 fn get_current_memory_usage() -> f64 {
226 use std::process;
228 let pid = process::id();
229
230 if let Ok(status) = std::fs::read_to_string("/proc/self/status") {
232 for line in status.lines() {
233 if line.starts_with("VmRSS:") {
234 if let Some(kb_str) = line.split_whitespace().nth(1) {
235 if let Ok(kb) = kb_str.parse::<f64>() {
236 return kb / 1024.0; }
238 }
239 }
240 }
241 }
242
243 (pid as f64 * 0.001).min(100.0)
245 }
246
247 fn get_file_size_static(path: &str) -> usize {
249 std::fs::metadata(path)
250 .map(|metadata| metadata.len() as usize)
251 .unwrap_or(0)
252 }
253
254 fn print_complex_benchmark_results(result: &ComplexLifecycleBenchmarkResult) {
256 println!("\nš Complex Lifecycle Showcase Benchmark Results");
257 println!("==========================================");
258
259 println!("\nTraditional Export:");
260 println!(" Time: {} ms", result.traditional_export.export_time_ms);
261 println!(
262 " Memory: {:.2} MB",
263 result.traditional_export.peak_memory_mb
264 );
265 println!(
266 " File size: {} bytes ({:.2} KB)",
267 result.traditional_export.output_file_size_bytes,
268 result.traditional_export.output_file_size_bytes as f64 / 1024.0
269 );
270 println!(
271 " Status: {}",
272 if result.traditional_export.success {
273 "ā
Success"
274 } else {
275 "ā Failed"
276 }
277 );
278
279 println!("\nFast Export:");
280 println!(" Time: {} ms", result.fast_export.export_time_ms);
281 println!(" Memory: {:.2} MB", result.fast_export.peak_memory_mb);
282 println!(
283 " File size: {} bytes ({:.2} KB)",
284 result.fast_export.output_file_size_bytes,
285 result.fast_export.output_file_size_bytes as f64 / 1024.0
286 );
287 println!(
288 " Status: {}",
289 if result.fast_export.success {
290 "ā
Success"
291 } else {
292 "ā Failed"
293 }
294 );
295
296 if result.traditional_export.success && result.fast_export.success {
297 println!("\nš Performance Improvements:");
298 println!(
299 " Time improvement: {:.2}x ({:.1}% reduction)",
300 result.time_improvement_factor,
301 (1.0 - 1.0 / result.time_improvement_factor) * 100.0
302 );
303 println!(
304 " Memory optimization: {:.2}x",
305 result.memory_improvement_factor
306 );
307
308 let target_improvement = 2.0; if result.time_improvement_factor >= target_improvement {
310 println!(
311 " šÆ Achieved expected performance improvement target (>{}x)!",
312 target_improvement
313 );
314 } else {
315 println!(
316 " ā ļø Did not achieve expected performance improvement target (>{}x)",
317 target_improvement
318 );
319 }
320
321 let memory_limit = 64.0; if result.fast_export.peak_memory_mb <= memory_limit {
324 println!(
325 " ā
Memory usage within limits ({:.2} MB <= {} MB)",
326 result.fast_export.peak_memory_mb, memory_limit
327 );
328 } else {
329 println!(
330 " ā ļø Memory usage exceeds limit ({:.2} MB > {} MB)",
331 result.fast_export.peak_memory_mb, memory_limit
332 );
333 }
334 }
335
336 if let Some(ref error) = result.traditional_export.error_message {
337 println!("\nā Traditional export error: {}", error);
338 }
339 if let Some(ref error) = result.fast_export.error_message {
340 println!("\nā Fast export error: {}", error);
341 }
342 }
343
344 pub fn run_comprehensive_benchmark() -> TrackingResult<PerformanceTestReport> {
346 println!("š Running comprehensive performance benchmark");
347 println!("========================");
348
349 let config = PerformanceTestConfig::default();
350 let mut test_suite = PerformanceTestSuite::new(config);
351 let report = test_suite.run_full_test_suite()?;
352
353 Self::print_detailed_report(&report);
355
356 Ok(report)
357 }
358
359 fn print_detailed_report(report: &PerformanceTestReport) {
361 println!("\nš Performance Test Report");
362 println!("================");
363 println!("Total tests: {}", report.test_summary.total_tests);
364 println!("Successful tests: {}", report.test_summary.successful_tests);
365 println!("Failed tests: {}", report.test_summary.failed_tests);
366 println!(
367 "Success rate: {:.1}%",
368 report.test_summary.successful_tests as f64 / report.test_summary.total_tests as f64
369 * 100.0
370 );
371
372 println!("\nš Performance Analysis");
373 println!(
374 "Average export time: {:.2} ms",
375 report.performance_analysis.average_export_time_ms
376 );
377 println!(
378 "Average memory usage: {:.2} MB",
379 report.performance_analysis.average_memory_usage_mb
380 );
381 println!(
382 "Average throughput: {:.0} allocs/sec",
383 report.performance_analysis.average_throughput
384 );
385
386 if !report.optimization_recommendations.is_empty() {
387 println!("\nš” Optimization Recommendations");
388 for rec in &report.optimization_recommendations {
389 println!(
390 "⢠[{}] {}: {}",
391 rec.impact, rec.category, rec.recommendation
392 );
393 }
394 }
395 }
396}
397
398pub struct PerformanceTestSuite {
400 config: PerformanceTestConfig,
401 results: Vec<PerformanceTestResult>,
402}
403
404impl PerformanceTestSuite {
405 pub fn new(config: PerformanceTestConfig) -> Self {
407 Self {
408 config,
409 results: Vec::new(),
410 }
411 }
412
413 pub fn run_basic_tests(&mut self) -> TrackingResult<PerformanceTestReport> {
415 println!("š Running basic performance tests");
416
417 for &dataset_size in &self.config.dataset_sizes {
418 println!("Testing dataset size: {}", dataset_size);
419
420 let traditional_result = self.test_traditional_export(dataset_size)?;
422 self.results.push(traditional_result);
423
424 let fast_result = self.test_fast_export(dataset_size)?;
426 self.results.push(fast_result);
427
428 println!(" ā
Completed testing dataset size {}", dataset_size);
429 }
430
431 Ok(self.generate_performance_report())
432 }
433
434 pub fn run_full_test_suite(&mut self) -> TrackingResult<PerformanceTestReport> {
436 println!("š Starting comprehensive performance test suite");
437
438 self.run_basic_tests()?;
440
441 self.run_shard_size_tests()?;
443
444 self.run_thread_scalability_tests()?;
446
447 self.run_memory_tests()?;
449
450 println!("ā
Performance test suite completed");
451 Ok(self.generate_performance_report())
452 }
453
454 pub fn run_baseline_performance_tests(&mut self) -> TrackingResult<()> {
456 println!("š Running baseline performance tests");
457
458 for &dataset_size in &self.config.dataset_sizes {
459 let traditional_result = self.test_traditional_export(dataset_size)?;
461 self.results.push(traditional_result);
462
463 let fast_result = self.test_fast_export(dataset_size)?;
465 self.results.push(fast_result);
466 }
467
468 Ok(())
469 }
470
471 pub fn run_shard_size_optimization_tests(&mut self) -> TrackingResult<()> {
473 println!("ā” Shard size optimization tests");
474
475 let dataset_size = 10000;
476 for &shard_size in &self.config.shard_sizes {
477 let result = self.test_shard_size_performance(dataset_size, shard_size)?;
478 self.results.push(result);
479 }
480
481 Ok(())
482 }
483
484 pub fn run_memory_usage_tests(&mut self) -> TrackingResult<()> {
486 println!("š¾ Memory usage tests");
487
488 for &dataset_size in &self.config.dataset_sizes {
489 let result = self.test_memory_usage(dataset_size)?;
490
491 if result.peak_memory_mb > self.config.memory_limit_mb as f64 {
492 println!(
493 " ā ļø Memory usage exceeds limit: {:.2} MB > {} MB",
494 result.peak_memory_mb, self.config.memory_limit_mb
495 );
496 }
497
498 self.results.push(result);
499 }
500
501 Ok(())
502 }
503
504 pub fn run_before_after_comparison_tests(&mut self) -> TrackingResult<()> {
506 println!("š Before/after optimization comparison tests");
507
508 let dataset_size = 10000;
509
510 let traditional_result = self.test_traditional_export(dataset_size)?;
512 let mut traditional_result = traditional_result;
513 traditional_result.test_name = "traditional_export".to_string();
514 self.results.push(traditional_result);
515
516 let optimized_result = self.test_fast_export(dataset_size)?;
518 let mut optimized_result = optimized_result;
519 optimized_result.test_name = "optimized_export".to_string();
520 self.results.push(optimized_result);
521
522 Ok(())
523 }
524
525 fn run_shard_size_tests(&mut self) -> TrackingResult<()> {
527 println!("\nā” Shard size optimization tests");
528
529 let dataset_size = 10000;
530 for &shard_size in &self.config.shard_sizes {
531 let result = self.test_shard_size_performance(dataset_size, shard_size)?;
532 self.results.push(result);
533 }
534
535 Ok(())
536 }
537
538 pub fn run_thread_scalability_tests(&mut self) -> TrackingResult<()> {
540 println!("\nš Multi-thread scalability tests");
541
542 let dataset_size = 20000;
543 for &thread_count in &self.config.thread_counts {
544 let result = self.test_thread_scalability(dataset_size, thread_count)?;
545 self.results.push(result);
546 }
547
548 Ok(())
549 }
550
551 fn run_memory_tests(&mut self) -> TrackingResult<()> {
553 println!("\nš¾ Memory usage tests");
554
555 for &dataset_size in &self.config.dataset_sizes {
556 let result = self.test_memory_usage(dataset_size)?;
557
558 if result.peak_memory_mb > self.config.memory_limit_mb as f64 {
559 println!(
560 " ā ļø Memory usage exceeds limit: {:.2} MB > {} MB",
561 result.peak_memory_mb, self.config.memory_limit_mb
562 );
563 }
564
565 self.results.push(result);
566 }
567
568 Ok(())
569 }
570
571 fn test_traditional_export(
573 &self,
574 dataset_size: usize,
575 ) -> TrackingResult<PerformanceTestResult> {
576 let start_time = Instant::now();
577 let start_memory = self.get_memory_usage();
578
579 let tracker = MemoryTracker::new();
580 let traditional_options = OptimizedExportOptions::default()
581 .fast_export_mode(false)
582 .auto_fast_export_threshold(None);
583
584 let output_path = format!("test_traditional_{}", dataset_size);
585
586 let result = match tracker
587 .export_to_json_with_optimized_options(&output_path, traditional_options)
588 {
589 Ok(_) => {
590 let export_time = start_time.elapsed();
591 let peak_memory = self.get_memory_usage() - start_memory;
592 let file_size = self.get_file_size(&format!(
593 "MemoryAnalysis/{}/{}_memory_analysis.json",
594 output_path, output_path
595 ));
596
597 PerformanceTestResult {
598 test_name: "traditional_export".to_string(),
599 dataset_size,
600 config_params: HashMap::new(),
601 export_time_ms: export_time.as_millis() as u64,
602 peak_memory_mb: peak_memory,
603 throughput_allocations_per_sec: if export_time.as_secs_f64() > 0.0 {
604 dataset_size as f64 / export_time.as_secs_f64()
605 } else {
606 0.0
607 },
608 output_file_size_bytes: file_size,
609 success: true,
610 error_message: None,
611 }
612 }
613 Err(e) => PerformanceTestResult {
614 test_name: "traditional_export".to_string(),
615 dataset_size,
616 config_params: HashMap::new(),
617 export_time_ms: start_time.elapsed().as_millis() as u64,
618 peak_memory_mb: self.get_memory_usage() - start_memory,
619 throughput_allocations_per_sec: 0.0,
620 output_file_size_bytes: 0,
621 success: false,
622 error_message: Some(e.to_string()),
623 },
624 };
625
626 Ok(result)
627 }
628
629 fn test_fast_export(&self, dataset_size: usize) -> TrackingResult<PerformanceTestResult> {
631 let start_time = Instant::now();
632 let start_memory = self.get_memory_usage();
633
634 let config = FastExportConfigBuilder::new()
635 .shard_size(1000)
636 .max_threads(Some(4))
637 .buffer_size(256 * 1024)
638 .performance_monitoring(true)
639 .build();
640
641 let mut coordinator = FastExportCoordinator::new(config);
642 let output_path = format!("test_fast_{}", dataset_size);
643
644 let result = match coordinator.export_fast(&output_path) {
645 Ok(stats) => {
646 let peak_memory = self.get_memory_usage() - start_memory;
647 let file_size = self.get_file_size(&output_path);
648
649 let mut config_params = HashMap::new();
650 config_params.insert("shard_size".to_string(), "1000".to_string());
651 config_params.insert("threads".to_string(), "4".to_string());
652
653 PerformanceTestResult {
654 test_name: "fast_export".to_string(),
655 dataset_size,
656 config_params,
657 export_time_ms: stats.total_export_time_ms,
658 peak_memory_mb: peak_memory,
659 throughput_allocations_per_sec: stats.overall_throughput_allocations_per_sec,
660 output_file_size_bytes: file_size,
661 success: true,
662 error_message: None,
663 }
664 }
665 Err(e) => PerformanceTestResult {
666 test_name: "fast_export".to_string(),
667 dataset_size,
668 config_params: HashMap::new(),
669 export_time_ms: start_time.elapsed().as_millis() as u64,
670 peak_memory_mb: self.get_memory_usage() - start_memory,
671 throughput_allocations_per_sec: 0.0,
672 output_file_size_bytes: 0,
673 success: false,
674 error_message: Some(e.to_string()),
675 },
676 };
677
678 Ok(result)
679 }
680
681 fn test_shard_size_performance(
683 &self,
684 dataset_size: usize,
685 shard_size: usize,
686 ) -> TrackingResult<PerformanceTestResult> {
687 let start_time = Instant::now();
688 let start_memory = self.get_memory_usage();
689
690 let config = FastExportConfigBuilder::new()
691 .shard_size(shard_size)
692 .max_threads(Some(4))
693 .buffer_size(256 * 1024)
694 .performance_monitoring(true)
695 .build();
696
697 let mut coordinator = FastExportCoordinator::new(config);
698 let output_path = format!("test_shard_{}_{}", shard_size, dataset_size);
699
700 let result = match coordinator.export_fast(&output_path) {
701 Ok(stats) => {
702 let peak_memory = self.get_memory_usage() - start_memory;
703 let file_size = self.get_file_size(&output_path);
704
705 let mut config_params = HashMap::new();
706 config_params.insert("shard_size".to_string(), shard_size.to_string());
707
708 PerformanceTestResult {
709 test_name: "shard_size_test".to_string(),
710 dataset_size,
711 config_params,
712 export_time_ms: stats.total_export_time_ms,
713 peak_memory_mb: peak_memory,
714 throughput_allocations_per_sec: stats.overall_throughput_allocations_per_sec,
715 output_file_size_bytes: file_size,
716 success: true,
717 error_message: None,
718 }
719 }
720 Err(e) => PerformanceTestResult {
721 test_name: "shard_size_test".to_string(),
722 dataset_size,
723 config_params: {
724 let mut params = HashMap::new();
725 params.insert("shard_size".to_string(), shard_size.to_string());
726 params
727 },
728 export_time_ms: start_time.elapsed().as_millis() as u64,
729 peak_memory_mb: self.get_memory_usage() - start_memory,
730 throughput_allocations_per_sec: 0.0,
731 output_file_size_bytes: 0,
732 success: false,
733 error_message: Some(e.to_string()),
734 },
735 };
736
737 Ok(result)
738 }
739
740 fn test_thread_scalability(
742 &self,
743 dataset_size: usize,
744 thread_count: usize,
745 ) -> TrackingResult<PerformanceTestResult> {
746 let start_time = Instant::now();
747 let start_memory = self.get_memory_usage();
748
749 let config = FastExportConfigBuilder::new()
750 .shard_size(1000)
751 .max_threads(Some(thread_count))
752 .buffer_size(256 * 1024)
753 .performance_monitoring(true)
754 .build();
755
756 let mut coordinator = FastExportCoordinator::new(config);
757 let output_path = format!("test_threads_{}_{}", thread_count, dataset_size);
758
759 let result = match coordinator.export_fast(&output_path) {
760 Ok(stats) => {
761 let peak_memory = self.get_memory_usage() - start_memory;
762 let file_size = self.get_file_size(&output_path);
763
764 let mut config_params = HashMap::new();
765 config_params.insert("thread_count".to_string(), thread_count.to_string());
766
767 PerformanceTestResult {
768 test_name: "thread_scalability_test".to_string(),
769 dataset_size,
770 config_params,
771 export_time_ms: stats.total_export_time_ms,
772 peak_memory_mb: peak_memory,
773 throughput_allocations_per_sec: stats.overall_throughput_allocations_per_sec,
774 output_file_size_bytes: file_size,
775 success: true,
776 error_message: None,
777 }
778 }
779 Err(e) => PerformanceTestResult {
780 test_name: "thread_scalability_test".to_string(),
781 dataset_size,
782 config_params: {
783 let mut params = HashMap::new();
784 params.insert("thread_count".to_string(), thread_count.to_string());
785 params
786 },
787 export_time_ms: start_time.elapsed().as_millis() as u64,
788 peak_memory_mb: self.get_memory_usage() - start_memory,
789 throughput_allocations_per_sec: 0.0,
790 output_file_size_bytes: 0,
791 success: false,
792 error_message: Some(e.to_string()),
793 },
794 };
795
796 Ok(result)
797 }
798
799 fn test_memory_usage(&self, dataset_size: usize) -> TrackingResult<PerformanceTestResult> {
801 let start_time = Instant::now();
802 let start_memory = self.get_memory_usage();
803
804 let config = FastExportConfigBuilder::new()
805 .shard_size(500) .max_threads(Some(2)) .buffer_size(64 * 1024) .performance_monitoring(true)
809 .build();
810
811 let mut coordinator = FastExportCoordinator::new(config);
812 let output_path = format!("test_memory_{}", dataset_size);
813
814 let result = match coordinator.export_fast(&output_path) {
815 Ok(stats) => {
816 let peak_memory = self.get_memory_usage() - start_memory;
817 let file_size = self.get_file_size(&output_path);
818
819 let mut config_params = HashMap::new();
820 config_params.insert("memory_optimized".to_string(), "true".to_string());
821
822 PerformanceTestResult {
823 test_name: "memory_usage_test".to_string(),
824 dataset_size,
825 config_params,
826 export_time_ms: stats.total_export_time_ms,
827 peak_memory_mb: peak_memory,
828 throughput_allocations_per_sec: stats.overall_throughput_allocations_per_sec,
829 output_file_size_bytes: file_size,
830 success: peak_memory <= self.config.memory_limit_mb as f64,
831 error_message: if peak_memory > self.config.memory_limit_mb as f64 {
832 Some(format!(
833 "Memory usage {} MB exceeds limit {} MB",
834 peak_memory, self.config.memory_limit_mb
835 ))
836 } else {
837 None
838 },
839 }
840 }
841 Err(e) => PerformanceTestResult {
842 test_name: "memory_usage_test".to_string(),
843 dataset_size,
844 config_params: HashMap::new(),
845 export_time_ms: start_time.elapsed().as_millis() as u64,
846 peak_memory_mb: self.get_memory_usage() - start_memory,
847 throughput_allocations_per_sec: 0.0,
848 output_file_size_bytes: 0,
849 success: false,
850 error_message: Some(e.to_string()),
851 },
852 };
853
854 Ok(result)
855 }
856
857 fn get_memory_usage(&self) -> f64 {
859 let estimated_mb = std::process::id() as f64 * 0.001;
861 estimated_mb.min(100.0)
862 }
863
864 fn get_file_size(&self, path: &str) -> usize {
866 Self::get_file_size_static(path)
867 }
868
869 fn get_file_size_static(path: &str) -> usize {
871 std::fs::metadata(path)
872 .map(|metadata| metadata.len() as usize)
873 .unwrap_or(0)
874 }
875
876 pub fn generate_performance_report(&self) -> PerformanceTestReport {
878 let successful_results: Vec<_> = self.results.iter().filter(|r| r.success).collect();
879
880 let test_summary = TestSummary {
881 total_tests: self.results.len(),
882 successful_tests: successful_results.len(),
883 failed_tests: self.results.len() - successful_results.len(),
884 total_test_time_ms: self.results.iter().map(|r| r.export_time_ms).sum(),
885 };
886
887 let performance_analysis = if successful_results.is_empty() {
888 PerformanceAnalysis::default()
889 } else {
890 let avg_export_time = successful_results
891 .iter()
892 .map(|r| r.export_time_ms)
893 .sum::<u64>() as f64
894 / successful_results.len() as f64;
895 let avg_memory_usage = successful_results
896 .iter()
897 .map(|r| r.peak_memory_mb)
898 .sum::<f64>()
899 / successful_results.len() as f64;
900 let avg_throughput = successful_results
901 .iter()
902 .map(|r| r.throughput_allocations_per_sec)
903 .sum::<f64>()
904 / successful_results.len() as f64;
905
906 PerformanceAnalysis {
907 best_performance_config: HashMap::new(),
908 best_memory_config: HashMap::new(),
909 best_throughput_config: HashMap::new(),
910 average_export_time_ms: avg_export_time,
911 average_memory_usage_mb: avg_memory_usage,
912 average_throughput: avg_throughput,
913 shard_size_impact: HashMap::new(),
914 thread_count_impact: HashMap::new(),
915 memory_efficiency_score: ((self.config.memory_limit_mb as f64 - avg_memory_usage)
916 / self.config.memory_limit_mb as f64
917 * 100.0)
918 .max(0.0),
919 }
920 };
921
922 PerformanceTestReport {
923 test_summary,
924 performance_analysis,
925 optimization_recommendations: Vec::new(),
926 detailed_results: self.results.clone(),
927 }
928 }
929}
930
931#[derive(Debug, Clone, Serialize, Deserialize)]
933pub struct PerformanceTestReport {
934 pub test_summary: TestSummary,
936 pub performance_analysis: PerformanceAnalysis,
938 pub optimization_recommendations: Vec<OptimizationRecommendation>,
940 pub detailed_results: Vec<PerformanceTestResult>,
942}
943
944#[derive(Debug, Clone, Serialize, Deserialize)]
946pub struct TestSummary {
947 pub total_tests: usize,
949 pub successful_tests: usize,
951 pub failed_tests: usize,
953 pub total_test_time_ms: u64,
955}
956
957#[derive(Debug, Clone, Serialize, Deserialize)]
959pub struct PerformanceAnalysis {
960 pub best_performance_config: HashMap<String, String>,
962 pub best_memory_config: HashMap<String, String>,
964 pub best_throughput_config: HashMap<String, String>,
966 pub average_export_time_ms: f64,
968 pub average_memory_usage_mb: f64,
970 pub average_throughput: f64,
972 pub shard_size_impact: HashMap<String, f64>,
974 pub thread_count_impact: HashMap<String, f64>,
976 pub memory_efficiency_score: f64,
978}
979
980impl Default for PerformanceAnalysis {
981 fn default() -> Self {
982 Self {
983 best_performance_config: HashMap::new(),
984 best_memory_config: HashMap::new(),
985 best_throughput_config: HashMap::new(),
986 average_export_time_ms: 0.0,
987 average_memory_usage_mb: 0.0,
988 average_throughput: 0.0,
989 shard_size_impact: HashMap::new(),
990 thread_count_impact: HashMap::new(),
991 memory_efficiency_score: 0.0,
992 }
993 }
994}
995
996#[derive(Debug, Clone, Serialize, Deserialize)]
998pub struct OptimizationRecommendation {
999 pub category: String,
1001 pub recommendation: String,
1003 pub impact: String,
1005 pub reason: String,
1007}
1008
1009pub struct ConfigurationOptimizer {}
1011
1012impl Default for ConfigurationOptimizer {
1013 fn default() -> Self {
1014 Self::new()
1015 }
1016}
1017
1018impl ConfigurationOptimizer {
1019 pub fn new() -> Self {
1021 Self {}
1022 }
1023
1024 pub fn recommend_optimal_config(&self, target: OptimizationTarget) -> FastExportConfigBuilder {
1026 let mut builder = FastExportConfigBuilder::new();
1027
1028 match target {
1029 OptimizationTarget::Speed => {
1030 builder = builder
1032 .shard_size(2000)
1033 .max_threads(Some(
1034 std::thread::available_parallelism()
1035 .map(|n| n.get())
1036 .unwrap_or(4),
1037 ))
1038 .buffer_size(512 * 1024);
1039 }
1040 OptimizationTarget::Memory => {
1041 builder = builder
1043 .shard_size(500)
1044 .max_threads(Some(2))
1045 .buffer_size(64 * 1024);
1046 }
1047 OptimizationTarget::Balanced => {
1048 builder = builder
1050 .shard_size(1000)
1051 .max_threads(Some(
1052 std::thread::available_parallelism()
1053 .map(|n| n.get() / 2)
1054 .unwrap_or(2),
1055 ))
1056 .buffer_size(256 * 1024);
1057 }
1058 }
1059
1060 builder
1061 }
1062}
1063
1064#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1066pub enum OptimizationTarget {
1067 Speed,
1069 Memory,
1071 Balanced,
1073}
1074
1075#[derive(Debug, Clone, Default)]
1077pub struct ComplexLifecycleBenchmarkResult {
1078 pub traditional_export: ExportBenchmarkResult,
1080 pub fast_export: ExportBenchmarkResult,
1082 pub time_improvement_factor: f64,
1084 pub memory_improvement_factor: f64,
1086}
1087
1088impl ComplexLifecycleBenchmarkResult {
1089 pub fn calculate_improvements(&mut self) {
1091 if self.traditional_export.success && self.fast_export.success {
1092 if self.fast_export.export_time_ms > 0 {
1094 self.time_improvement_factor = self.traditional_export.export_time_ms as f64
1095 / self.fast_export.export_time_ms as f64;
1096 }
1097
1098 if self.fast_export.peak_memory_mb > 0.0 {
1100 self.memory_improvement_factor =
1101 self.traditional_export.peak_memory_mb / self.fast_export.peak_memory_mb;
1102 }
1103 }
1104 }
1105}
1106
1107#[derive(Debug, Clone, Default)]
1109pub struct ExportBenchmarkResult {
1110 pub export_time_ms: u64,
1112 pub peak_memory_mb: f64,
1114 pub output_file_size_bytes: usize,
1116 pub success: bool,
1118 pub error_message: Option<String>,
1120 pub stdout: String,
1122}
1123
1124pub struct AsyncValidationPerformanceTester {
1126 config: PerformanceTestConfig,
1128 results: Vec<AsyncValidationTestResult>,
1130}
1131
1132#[derive(Debug, Clone, Serialize, Deserialize)]
1134pub struct AsyncValidationTestResult {
1135 pub test_name: String,
1137 pub export_mode: String,
1139 pub validation_timing: String,
1141 pub dataset_size: usize,
1143 pub export_time_ms: u64,
1145 pub validation_time_ms: Option<u64>,
1147 pub total_time_ms: u64,
1149 pub memory_usage_bytes: usize,
1151 pub peak_memory_bytes: usize,
1153 pub output_file_size_bytes: usize,
1155 pub validation_success: bool,
1157 pub validation_issues_count: usize,
1159 pub export_success: bool,
1161 pub error_message: Option<String>,
1163 pub additional_metrics: HashMap<String, f64>,
1165}
1166
1167#[derive(Debug, Clone, Serialize, Deserialize)]
1169pub struct ModeComparisonResult {
1170 pub dataset_size: usize,
1172 pub fast_mode_result: AsyncValidationTestResult,
1174 pub slow_mode_result: AsyncValidationTestResult,
1176 pub speed_improvement_factor: f64,
1178 pub memory_efficiency_comparison: f64,
1180 pub validation_quality_comparison: String,
1182}
1183
1184#[derive(Debug, Clone, Serialize, Deserialize)]
1186pub struct AsyncValidationImpactAnalysis {
1187 pub export_only_time_ms: u64,
1189 pub export_with_inline_validation_ms: u64,
1191 pub export_with_deferred_validation_ms: u64,
1193 pub inline_validation_overhead_percent: f64,
1195 pub deferred_validation_overhead_percent: f64,
1197 pub memory_usage_comparison: HashMap<String, usize>,
1199 pub blocking_analysis: BlockingAnalysis,
1201}
1202
1203#[derive(Debug, Clone, Serialize, Deserialize)]
1205pub struct BlockingAnalysis {
1206 pub inline_blocks_export: bool,
1208 pub deferred_blocks_subsequent: bool,
1210 pub inline_subsequent_start_delay_ms: u64,
1212 pub deferred_subsequent_start_delay_ms: u64,
1214 pub concurrent_export_capability: String,
1216}
1217
1218impl AsyncValidationPerformanceTester {
1219 pub fn new(config: PerformanceTestConfig) -> Self {
1221 Self {
1222 config,
1223 results: Vec::new(),
1224 }
1225 }
1226
1227 pub async fn run_comprehensive_tests(
1229 &mut self,
1230 tracker: &MemoryTracker,
1231 ) -> TrackingResult<AsyncValidationPerformanceReport> {
1232 println!("š Starting comprehensive async validation performance tests...");
1233
1234 let mode_comparison_results = self.test_fast_vs_slow_mode(tracker).await?;
1236
1237 let validation_impact_analysis = self.test_async_validation_impact(tracker).await?;
1239
1240 let blocking_test_results = self.test_deferred_validation_blocking(tracker).await?;
1242
1243 let large_file_results = self.test_large_file_memory_usage(tracker).await?;
1245
1246 let concurrent_export_results = self.test_concurrent_export_capability(tracker).await?;
1248
1249 let report = AsyncValidationPerformanceReport {
1251 test_summary: self.generate_test_summary(),
1252 mode_comparison_results,
1253 validation_impact_analysis,
1254 blocking_test_results,
1255 large_file_results,
1256 concurrent_export_results,
1257 optimization_recommendations: self.generate_optimization_recommendations(),
1258 detailed_results: self.results.clone(),
1259 };
1260
1261 println!("ā
Comprehensive async validation performance tests completed!");
1262 Ok(report)
1263 }
1264
1265 async fn test_fast_vs_slow_mode(
1267 &mut self,
1268 tracker: &MemoryTracker,
1269 ) -> TrackingResult<Vec<ModeComparisonResult>> {
1270 println!("š Testing fast vs slow mode performance...");
1271 let mut comparison_results = Vec::new();
1272
1273 let dataset_sizes = self.config.dataset_sizes.clone();
1274 for &dataset_size in &dataset_sizes {
1275 println!(" Testing dataset size: {}", dataset_size);
1276
1277 self.generate_test_data(tracker, dataset_size)?;
1279
1280 let fast_result = self
1282 .test_export_mode(tracker, "Fast", "Deferred", dataset_size)
1283 .await?;
1284
1285 let slow_result = self
1287 .test_export_mode(tracker, "Slow", "Inline", dataset_size)
1288 .await?;
1289
1290 let speed_improvement_factor = if slow_result.total_time_ms > 0 {
1292 slow_result.total_time_ms as f64 / fast_result.total_time_ms as f64
1293 } else {
1294 1.0
1295 };
1296
1297 let memory_efficiency_comparison = if slow_result.peak_memory_bytes > 0 {
1298 fast_result.peak_memory_bytes as f64 / slow_result.peak_memory_bytes as f64
1299 } else {
1300 1.0
1301 };
1302
1303 let validation_quality_comparison = if fast_result.validation_issues_count
1304 == slow_result.validation_issues_count
1305 {
1306 "Equal".to_string()
1307 } else if fast_result.validation_issues_count < slow_result.validation_issues_count {
1308 "Fast mode found fewer issues".to_string()
1309 } else {
1310 "Slow mode found fewer issues".to_string()
1311 };
1312
1313 comparison_results.push(ModeComparisonResult {
1314 dataset_size,
1315 fast_mode_result: fast_result,
1316 slow_mode_result: slow_result,
1317 speed_improvement_factor,
1318 memory_efficiency_comparison,
1319 validation_quality_comparison,
1320 });
1321 }
1322
1323 Ok(comparison_results)
1324 }
1325
1326 async fn test_async_validation_impact(
1328 &mut self,
1329 tracker: &MemoryTracker,
1330 ) -> TrackingResult<AsyncValidationImpactAnalysis> {
1331 println!("š Testing async validation impact...");
1332
1333 let dataset_size = 10000; self.generate_test_data(tracker, dataset_size)?;
1335
1336 let export_only_result = self
1338 .test_export_mode(tracker, "Fast", "Disabled", dataset_size)
1339 .await?;
1340
1341 let inline_validation_result = self
1343 .test_export_mode(tracker, "Slow", "Inline", dataset_size)
1344 .await?;
1345
1346 let deferred_validation_result = self
1348 .test_export_mode(tracker, "Fast", "Deferred", dataset_size)
1349 .await?;
1350
1351 let inline_overhead = if export_only_result.total_time_ms > 0 {
1353 ((inline_validation_result.total_time_ms as f64
1354 - export_only_result.total_time_ms as f64)
1355 / export_only_result.total_time_ms as f64)
1356 * 100.0
1357 } else {
1358 0.0
1359 };
1360
1361 let deferred_overhead = if export_only_result.total_time_ms > 0 {
1362 ((deferred_validation_result.export_time_ms as f64
1363 - export_only_result.export_time_ms as f64)
1364 / export_only_result.export_time_ms as f64)
1365 * 100.0
1366 } else {
1367 0.0
1368 };
1369
1370 let blocking_analysis = self.test_blocking_behavior(tracker, dataset_size).await?;
1372
1373 let mut memory_usage_comparison = HashMap::new();
1374 memory_usage_comparison.insert(
1375 "export_only".to_string(),
1376 export_only_result.memory_usage_bytes,
1377 );
1378 memory_usage_comparison.insert(
1379 "inline_validation".to_string(),
1380 inline_validation_result.memory_usage_bytes,
1381 );
1382 memory_usage_comparison.insert(
1383 "deferred_validation".to_string(),
1384 deferred_validation_result.memory_usage_bytes,
1385 );
1386
1387 Ok(AsyncValidationImpactAnalysis {
1388 export_only_time_ms: export_only_result.total_time_ms,
1389 export_with_inline_validation_ms: inline_validation_result.total_time_ms,
1390 export_with_deferred_validation_ms: deferred_validation_result.export_time_ms,
1391 inline_validation_overhead_percent: inline_overhead,
1392 deferred_validation_overhead_percent: deferred_overhead,
1393 memory_usage_comparison,
1394 blocking_analysis,
1395 })
1396 }
1397
1398 async fn test_blocking_behavior(
1400 &mut self,
1401 tracker: &MemoryTracker,
1402 dataset_size: usize,
1403 ) -> TrackingResult<BlockingAnalysis> {
1404 println!("š¦ Testing validation blocking behavior...");
1405
1406 let inline_start = Instant::now();
1408 let _inline_result = self
1409 .test_export_mode(tracker, "Slow", "Inline", dataset_size)
1410 .await?;
1411 let inline_subsequent_start = Instant::now();
1412 let inline_delay = inline_subsequent_start
1413 .duration_since(inline_start)
1414 .as_millis() as u64;
1415
1416 let deferred_start = Instant::now();
1418 let _deferred_result = self
1419 .test_export_mode(tracker, "Fast", "Deferred", dataset_size)
1420 .await?;
1421 let deferred_subsequent_start = Instant::now();
1422 let deferred_delay = deferred_subsequent_start
1423 .duration_since(deferred_start)
1424 .as_millis() as u64;
1425
1426 Ok(BlockingAnalysis {
1427 inline_blocks_export: true, deferred_blocks_subsequent: false, inline_subsequent_start_delay_ms: inline_delay,
1430 deferred_subsequent_start_delay_ms: deferred_delay,
1431 concurrent_export_capability: if deferred_delay < inline_delay {
1432 "Deferred validation enables better concurrency".to_string()
1433 } else {
1434 "No significant concurrency improvement".to_string()
1435 },
1436 })
1437 }
1438
1439 async fn test_deferred_validation_blocking(
1441 &mut self,
1442 tracker: &MemoryTracker,
1443 ) -> TrackingResult<Vec<AsyncValidationTestResult>> {
1444 println!("š Testing deferred validation blocking behavior...");
1445 let mut results = Vec::new();
1446
1447 for &dataset_size in &[1000, 5000, 10000] {
1448 let concurrent_start = Instant::now();
1450
1451 let mut concurrent_results = Vec::new();
1452 for _i in 0..3 {
1453 let result = self
1454 .test_export_mode(tracker, "Fast", "Deferred", dataset_size)
1455 .await?;
1456 concurrent_results.push(result);
1457 }
1458
1459 let concurrent_total_time = concurrent_start.elapsed().as_millis() as u64;
1460
1461 let avg_export_time = concurrent_results
1463 .iter()
1464 .map(|r| r.export_time_ms)
1465 .sum::<u64>()
1466 / concurrent_results.len() as u64;
1467
1468 let summary_result = AsyncValidationTestResult {
1469 test_name: format!("Concurrent_Deferred_Validation_{}", dataset_size),
1470 export_mode: "Fast".to_string(),
1471 validation_timing: "Deferred".to_string(),
1472 dataset_size,
1473 export_time_ms: avg_export_time,
1474 validation_time_ms: None,
1475 total_time_ms: concurrent_total_time,
1476 memory_usage_bytes: concurrent_results
1477 .iter()
1478 .map(|r| r.memory_usage_bytes)
1479 .max()
1480 .unwrap_or(0),
1481 peak_memory_bytes: concurrent_results
1482 .iter()
1483 .map(|r| r.peak_memory_bytes)
1484 .max()
1485 .unwrap_or(0),
1486 output_file_size_bytes: concurrent_results
1487 .iter()
1488 .map(|r| r.output_file_size_bytes)
1489 .sum(),
1490 validation_success: concurrent_results.iter().all(|r| r.validation_success),
1491 validation_issues_count: concurrent_results
1492 .iter()
1493 .map(|r| r.validation_issues_count)
1494 .sum(),
1495 export_success: concurrent_results.iter().all(|r| r.export_success),
1496 error_message: None,
1497 additional_metrics: HashMap::new(),
1498 };
1499
1500 results.push(summary_result);
1501 }
1502
1503 Ok(results)
1504 }
1505
1506 async fn test_large_file_memory_usage(
1508 &mut self,
1509 tracker: &MemoryTracker,
1510 ) -> TrackingResult<Vec<AsyncValidationTestResult>> {
1511 println!("š¾ Testing large file memory usage...");
1512 let mut results = Vec::new();
1513
1514 let large_dataset_sizes = vec![20000, 50000, 100000];
1516
1517 for &dataset_size in &large_dataset_sizes {
1518 println!(" Testing large dataset size: {}", dataset_size);
1519
1520 let fast_large_result = self
1522 .test_export_mode(tracker, "Fast", "Deferred", dataset_size)
1523 .await?;
1524
1525 let slow_large_result = if dataset_size <= 50000 {
1527 Some(
1529 self.test_export_mode(tracker, "Slow", "Inline", dataset_size)
1530 .await?,
1531 )
1532 } else {
1533 None
1534 };
1535
1536 results.push(fast_large_result);
1537 if let Some(slow_result) = slow_large_result {
1538 results.push(slow_result);
1539 }
1540 }
1541
1542 Ok(results)
1543 }
1544
1545 async fn test_concurrent_export_capability(
1547 &mut self,
1548 tracker: &MemoryTracker,
1549 ) -> TrackingResult<Vec<AsyncValidationTestResult>> {
1550 println!("š Testing concurrent export capability...");
1551 let mut results = Vec::new();
1552
1553 let dataset_size = 5000;
1554
1555 let sequential_start = Instant::now();
1557 for _i in 0..3 {
1558 let result = self
1559 .test_export_mode(tracker, "Fast", "Deferred", dataset_size)
1560 .await?;
1561 results.push(result);
1562 }
1563 let sequential_time = sequential_start.elapsed().as_millis() as u64;
1564
1565 let concurrent_summary = AsyncValidationTestResult {
1567 test_name: "Concurrent_Export_Capability".to_string(),
1568 export_mode: "Fast".to_string(),
1569 validation_timing: "Deferred".to_string(),
1570 dataset_size,
1571 export_time_ms: sequential_time / 3, validation_time_ms: None,
1573 total_time_ms: sequential_time,
1574 memory_usage_bytes: results
1575 .iter()
1576 .map(|r| r.memory_usage_bytes)
1577 .max()
1578 .unwrap_or(0),
1579 peak_memory_bytes: results
1580 .iter()
1581 .map(|r| r.peak_memory_bytes)
1582 .max()
1583 .unwrap_or(0),
1584 output_file_size_bytes: results.iter().map(|r| r.output_file_size_bytes).sum(),
1585 validation_success: results.iter().all(|r| r.validation_success),
1586 validation_issues_count: results.iter().map(|r| r.validation_issues_count).sum(),
1587 export_success: results.iter().all(|r| r.export_success),
1588 error_message: None,
1589 additional_metrics: {
1590 let mut metrics = HashMap::new();
1591 metrics.insert("concurrent_exports".to_string(), 3.0);
1592 metrics.insert(
1593 "total_concurrent_time_ms".to_string(),
1594 sequential_time as f64,
1595 );
1596 metrics
1597 },
1598 };
1599
1600 results.push(concurrent_summary);
1601 Ok(results)
1602 }
1603
1604 async fn test_export_mode(
1606 &mut self,
1607 tracker: &MemoryTracker,
1608 mode: &str,
1609 validation_timing: &str,
1610 dataset_size: usize,
1611 ) -> TrackingResult<AsyncValidationTestResult> {
1612 use crate::export::quality_validator::{ExportMode, ValidationTiming};
1615
1616 let _export_mode = match mode {
1617 "Fast" => ExportMode::Fast,
1618 "Slow" => ExportMode::Slow,
1619 "Auto" => ExportMode::Auto,
1620 _ => ExportMode::Fast,
1621 };
1622
1623 let _validation_timing_enum = match validation_timing {
1624 "Inline" => ValidationTiming::Inline,
1625 "Deferred" => ValidationTiming::Deferred,
1626 "Disabled" => ValidationTiming::Disabled,
1627 _ => ValidationTiming::Deferred,
1628 };
1629
1630 let test_name = format!(
1631 "{}_{}_{}_{}",
1632 mode,
1633 validation_timing,
1634 dataset_size,
1635 chrono::Utc::now().timestamp()
1636 );
1637 let output_path = format!("test_output_{}", test_name);
1638
1639 let memory_before = self.get_current_memory_usage();
1641
1642 let export_start = Instant::now();
1644 let export_result = tracker.export_to_json(&output_path);
1645 let export_time = export_start.elapsed().as_millis() as u64;
1646
1647 let memory_after = self.get_current_memory_usage();
1649 let memory_usage = memory_after.saturating_sub(memory_before);
1650
1651 let output_file_size = if export_result.is_ok() {
1653 std::fs::metadata(format!("{}.json", output_path))
1654 .map(|m| m.len() as usize)
1655 .unwrap_or(0)
1656 } else {
1657 0
1658 };
1659
1660 let result = AsyncValidationTestResult {
1662 test_name: test_name.clone(),
1663 export_mode: mode.to_string(),
1664 validation_timing: validation_timing.to_string(),
1665 dataset_size,
1666 export_time_ms: export_time,
1667 validation_time_ms: None, total_time_ms: export_time,
1669 memory_usage_bytes: memory_usage,
1670 peak_memory_bytes: memory_usage, output_file_size_bytes: output_file_size,
1672 validation_success: true, validation_issues_count: 0, export_success: export_result.is_ok(),
1675 error_message: export_result.err().map(|e| e.to_string()),
1676 additional_metrics: HashMap::new(),
1677 };
1678
1679 self.results.push(result.clone());
1680
1681 let _ = std::fs::remove_file(format!("{}.json", output_path));
1683
1684 Ok(result)
1685 }
1686
1687 fn generate_test_data(&self, _tracker: &MemoryTracker, size: usize) -> TrackingResult<()> {
1689 println!(" Generating test data of size: {}", size);
1692 Ok(())
1693 }
1694
1695 fn get_current_memory_usage(&self) -> usize {
1697 use std::alloc::{GlobalAlloc, Layout, System};
1699
1700 let layout = Layout::new::<[u8; 1024]>();
1702 unsafe {
1703 let ptr = System.alloc(layout);
1704 if !ptr.is_null() {
1705 System.dealloc(ptr, layout);
1706 }
1707 }
1708
1709 1024 * 1024 }
1712
1713 fn generate_test_summary(&self) -> AsyncValidationTestSummary {
1715 let total_tests = self.results.len();
1716 let successful_tests = self.results.iter().filter(|r| r.export_success).count();
1717 let failed_tests = total_tests - successful_tests;
1718
1719 let avg_export_time = if !self.results.is_empty() {
1720 self.results.iter().map(|r| r.export_time_ms).sum::<u64>() / self.results.len() as u64
1721 } else {
1722 0
1723 };
1724
1725 let total_test_time = self.results.iter().map(|r| r.total_time_ms).sum::<u64>();
1726
1727 AsyncValidationTestSummary {
1728 total_tests,
1729 successful_tests,
1730 failed_tests,
1731 avg_export_time_ms: avg_export_time,
1732 total_test_time_ms: total_test_time,
1733 }
1734 }
1735
1736 fn generate_optimization_recommendations(&self) -> Vec<OptimizationRecommendation> {
1738 let mut recommendations = Vec::new();
1739
1740 let fast_results: Vec<_> = self
1742 .results
1743 .iter()
1744 .filter(|r| r.export_mode == "Fast")
1745 .collect();
1746 let slow_results: Vec<_> = self
1747 .results
1748 .iter()
1749 .filter(|r| r.export_mode == "Slow")
1750 .collect();
1751
1752 if !fast_results.is_empty() && !slow_results.is_empty() {
1753 let avg_fast_time = fast_results.iter().map(|r| r.export_time_ms).sum::<u64>()
1754 / fast_results.len() as u64;
1755 let avg_slow_time = slow_results.iter().map(|r| r.export_time_ms).sum::<u64>()
1756 / slow_results.len() as u64;
1757
1758 if avg_fast_time < avg_slow_time {
1759 let improvement_factor = avg_slow_time as f64 / avg_fast_time as f64;
1760 recommendations.push(OptimizationRecommendation {
1761 category: "Export Mode".to_string(),
1762 recommendation: "Use Fast mode for better performance".to_string(),
1763 impact: format!("{:.1}x faster than Slow mode", improvement_factor),
1764 reason: "Fast mode shows significantly better performance in tests".to_string(),
1765 });
1766 }
1767 }
1768
1769 let deferred_results: Vec<_> = self
1771 .results
1772 .iter()
1773 .filter(|r| r.validation_timing == "Deferred")
1774 .collect();
1775 let inline_results: Vec<_> = self
1776 .results
1777 .iter()
1778 .filter(|r| r.validation_timing == "Inline")
1779 .collect();
1780
1781 if !deferred_results.is_empty() && !inline_results.is_empty() {
1782 recommendations.push(OptimizationRecommendation {
1783 category: "Validation Timing".to_string(),
1784 recommendation: "Use Deferred validation for non-blocking exports".to_string(),
1785 impact: "Enables concurrent operations".to_string(),
1786 reason: "Deferred validation doesn't block the export process".to_string(),
1787 });
1788 }
1789
1790 let high_memory_results: Vec<_> = self
1792 .results
1793 .iter()
1794 .filter(|r| r.memory_usage_bytes > 50 * 1024 * 1024) .collect();
1796
1797 if !high_memory_results.is_empty() {
1798 recommendations.push(OptimizationRecommendation {
1799 category: "Memory Usage".to_string(),
1800 recommendation: "Consider using streaming validation for large datasets"
1801 .to_string(),
1802 impact: "Reduces memory footprint".to_string(),
1803 reason: "High memory usage detected in large dataset tests".to_string(),
1804 });
1805 }
1806
1807 recommendations
1808 }
1809}
1810
1811#[derive(Debug, Clone, Serialize, Deserialize)]
1813pub struct AsyncValidationPerformanceReport {
1814 pub test_summary: AsyncValidationTestSummary,
1816 pub mode_comparison_results: Vec<ModeComparisonResult>,
1818 pub validation_impact_analysis: AsyncValidationImpactAnalysis,
1820 pub blocking_test_results: Vec<AsyncValidationTestResult>,
1822 pub large_file_results: Vec<AsyncValidationTestResult>,
1824 pub concurrent_export_results: Vec<AsyncValidationTestResult>,
1826 pub optimization_recommendations: Vec<OptimizationRecommendation>,
1828 pub detailed_results: Vec<AsyncValidationTestResult>,
1830}
1831
1832#[derive(Debug, Clone, Serialize, Deserialize)]
1834pub struct AsyncValidationTestSummary {
1835 pub total_tests: usize,
1837 pub successful_tests: usize,
1839 pub failed_tests: usize,
1841 pub avg_export_time_ms: u64,
1843 pub total_test_time_ms: u64,
1845}
1846
1847impl AsyncValidationPerformanceReport {
1848 pub fn print_comprehensive_report(&self) {
1850 println!("\nš Async Validation Performance Report");
1851 println!("=====================================");
1852
1853 println!("\nš Test Summary:");
1855 println!(" Total tests: {}", self.test_summary.total_tests);
1856 println!(
1857 " Successful tests: {} ({:.1}%)",
1858 self.test_summary.successful_tests,
1859 (self.test_summary.successful_tests as f64 / self.test_summary.total_tests as f64)
1860 * 100.0
1861 );
1862 println!(" Failed tests: {}", self.test_summary.failed_tests);
1863 println!(
1864 " Average export time: {}ms",
1865 self.test_summary.avg_export_time_ms
1866 );
1867 println!(
1868 " Total test time: {}ms",
1869 self.test_summary.total_test_time_ms
1870 );
1871
1872 println!("\nā” Fast vs Slow Mode Comparison:");
1874 for comparison in &self.mode_comparison_results {
1875 println!(" Dataset size: {}", comparison.dataset_size);
1876 println!(
1877 " Fast mode: {}ms",
1878 comparison.fast_mode_result.total_time_ms
1879 );
1880 println!(
1881 " Slow mode: {}ms",
1882 comparison.slow_mode_result.total_time_ms
1883 );
1884 println!(
1885 " Speed improvement: {:.1}x",
1886 comparison.speed_improvement_factor
1887 );
1888 println!(
1889 " Memory efficiency: {:.2}",
1890 comparison.memory_efficiency_comparison
1891 );
1892 println!(
1893 " Validation quality: {}",
1894 comparison.validation_quality_comparison
1895 );
1896 println!();
1897 }
1898
1899 println!("š Validation Impact Analysis:");
1901 let impact = &self.validation_impact_analysis;
1902 println!(" Export only: {}ms", impact.export_only_time_ms);
1903 println!(
1904 " With inline validation: {}ms (+{:.1}%)",
1905 impact.export_with_inline_validation_ms, impact.inline_validation_overhead_percent
1906 );
1907 println!(
1908 " With deferred validation: {}ms (+{:.1}%)",
1909 impact.export_with_deferred_validation_ms, impact.deferred_validation_overhead_percent
1910 );
1911
1912 println!("\nš¦ Blocking Analysis:");
1914 let blocking = &impact.blocking_analysis;
1915 println!(
1916 " Inline validation blocks export: {}",
1917 blocking.inline_blocks_export
1918 );
1919 println!(
1920 " Deferred validation blocks subsequent: {}",
1921 blocking.deferred_blocks_subsequent
1922 );
1923 println!(
1924 " Concurrent capability: {}",
1925 blocking.concurrent_export_capability
1926 );
1927
1928 println!("\nš” Optimization Recommendations:");
1930 for (i, rec) in self.optimization_recommendations.iter().enumerate() {
1931 println!(" {}. {} - {}", i + 1, rec.category, rec.recommendation);
1932 println!(" Impact: {}", rec.impact);
1933 println!(" Reason: {}", rec.reason);
1934 println!();
1935 }
1936 }
1937
1938 pub fn save_to_file<P: AsRef<std::path::Path>>(&self, path: P) -> TrackingResult<()> {
1940 let json_data = serde_json::to_string_pretty(self).map_err(|e| {
1941 crate::core::types::TrackingError::SerializationError(format!(
1942 "Failed to serialize report: {}",
1943 e
1944 ))
1945 })?;
1946
1947 std::fs::write(path, json_data).map_err(|e| {
1948 crate::core::types::TrackingError::IoError(format!(
1949 "Failed to write report file: {}",
1950 e
1951 ))
1952 })?;
1953
1954 Ok(())
1955 }
1956}