1use crate::{JitCompiler, JitError, JitResult};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::sync::{Arc, Mutex};
11use std::time::{Duration, Instant, SystemTime};
12
13pub struct BenchmarkSuite {
15 config: BenchmarkConfig,
16 benchmarks: Vec<Box<dyn Benchmark>>,
17 results: Arc<Mutex<BenchmarkResults>>,
18 profiler: BenchmarkProfiler,
19}
20
21#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
23pub struct BenchmarkConfig {
24 pub warmup_iterations: usize,
26
27 pub measurement_iterations: usize,
29
30 pub max_execution_time: Duration,
32
33 pub min_execution_time: Duration,
35
36 pub confidence_level: f64,
38
39 pub enable_profiling: bool,
41
42 pub enable_memory_tracking: bool,
44
45 pub enable_energy_measurement: bool,
47
48 pub output_format: OutputFormat,
50
51 pub suite_name: String,
53
54 pub parallel_execution: ParallelExecution,
56}
57
58impl Default for BenchmarkConfig {
59 fn default() -> Self {
60 Self {
61 warmup_iterations: 10,
62 measurement_iterations: 100,
63 max_execution_time: Duration::from_secs(300), min_execution_time: Duration::from_millis(1),
65 confidence_level: 0.95,
66 enable_profiling: true,
67 enable_memory_tracking: true,
68 enable_energy_measurement: false, output_format: OutputFormat::Json,
70 suite_name: "ToRSh JIT Benchmark Suite".to_string(),
71 parallel_execution: ParallelExecution::Sequential,
72 }
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
78pub enum OutputFormat {
79 Json,
80 Csv,
81 Html,
82 Markdown,
83 Binary,
84}
85
86#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
88pub enum ParallelExecution {
89 Sequential,
90 Parallel { max_threads: usize },
91 Adaptive,
92}
93
94pub trait Benchmark: Send + Sync {
96 fn name(&self) -> &str;
98
99 fn description(&self) -> &str;
101
102 fn setup(&mut self) -> JitResult<()>;
104
105 fn execute(&self, compiler: &mut JitCompiler) -> JitResult<BenchmarkMeasurement>;
107
108 fn teardown(&mut self) -> JitResult<()>;
110
111 fn metadata(&self) -> BenchmarkMetadata;
113
114 fn validate(&self, measurement: &BenchmarkMeasurement) -> JitResult<ValidationResult>;
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct BenchmarkMeasurement {
121 pub execution_time: Duration,
123
124 pub compilation_time: Duration,
126
127 pub memory_stats: MemoryStatistics,
129
130 pub cpu_utilization: f64,
132
133 pub throughput: f64,
135
136 pub energy_consumption: Option<f64>,
138
139 pub custom_metrics: HashMap<String, f64>,
141
142 pub timestamp: SystemTime,
144
145 pub config_hash: u64,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct MemoryStatistics {
152 pub peak_usage: usize,
154
155 pub average_usage: usize,
157
158 pub allocations: usize,
160
161 pub deallocations: usize,
163
164 pub leaks: usize,
166
167 pub cache_stats: CacheStatistics,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct CacheStatistics {
174 pub l1_hit_rate: f64,
176
177 pub l2_hit_rate: f64,
179
180 pub l3_hit_rate: f64,
182
183 pub cache_misses: u64,
185
186 pub bandwidth_utilization: f64,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct BenchmarkMetadata {
193 pub category: BenchmarkCategory,
195
196 pub workload: WorkloadCharacteristics,
198
199 pub expected_performance: PerformanceRange,
201
202 pub resource_requirements: ResourceRequirements,
204
205 pub tags: Vec<String>,
207
208 pub author: String,
210
211 pub version: String,
213}
214
215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
217pub enum BenchmarkCategory {
218 Compilation,
220
221 Execution,
223
224 Memory,
226
227 Optimization,
229
230 Stress,
232
233 Regression,
235
236 Comparative,
238
239 Application,
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
245pub struct WorkloadCharacteristics {
246 pub complexity: ComputationalComplexity,
248
249 pub data_size: DataSize,
251
252 pub memory_pattern: MemoryAccessPattern,
254
255 pub parallelism: ParallelismDegree,
257
258 pub io_characteristics: IoCharacteristics,
260}
261
262#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
264pub enum ComputationalComplexity {
265 Low,
266 Medium,
267 High,
268 VeryHigh,
269 Custom { flops: u64 },
270}
271
272#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
274pub enum DataSize {
275 Small, Medium, Large, VeryLarge, Custom { bytes: usize },
280}
281
282#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
284pub enum MemoryAccessPattern {
285 Sequential,
286 Random,
287 Strided { stride: usize },
288 Irregular,
289 Clustered,
290}
291
292#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
294pub enum ParallelismDegree {
295 Serial,
296 LowParallel, MediumParallel, HighParallel, Custom { threads: usize },
300}
301
302#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
304pub enum IoCharacteristics {
305 None,
306 Read,
307 Write,
308 ReadWrite,
309 Network,
310 Custom { pattern: String },
311}
312
313#[derive(Debug, Clone, Serialize, Deserialize)]
315pub struct PerformanceRange {
316 pub min_execution_time: Duration,
318
319 pub max_execution_time: Duration,
321
322 pub throughput_range: (f64, f64),
324
325 pub memory_range: (usize, usize),
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize)]
331pub struct ResourceRequirements {
332 pub min_cpu_cores: usize,
334
335 pub min_memory: usize,
337
338 pub cpu_features: Vec<String>,
340
341 pub gpu_requirements: Option<GpuRequirements>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct GpuRequirements {
348 pub min_compute_capability: f64,
350
351 pub min_memory: usize,
353
354 pub features: Vec<String>,
356}
357
358#[derive(Debug, Clone)]
360pub struct ValidationResult {
361 pub is_valid: bool,
362 pub errors: Vec<String>,
363 pub warnings: Vec<String>,
364 pub correctness_score: f64,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct BenchmarkResults {
370 pub results: HashMap<String, BenchmarkResult>,
372
373 pub suite_statistics: SuiteStatistics,
375
376 pub system_info: SystemInfo,
378
379 pub config: BenchmarkConfig,
381
382 pub timestamp: SystemTime,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct BenchmarkResult {
389 pub name: String,
391
392 pub measurements: Vec<BenchmarkMeasurement>,
394
395 pub statistics: BenchmarkStatistics,
397
398 pub validation: ValidationSummary,
400
401 pub comparisons: Vec<BenchmarkComparison>,
403
404 pub regression_analysis: Option<RegressionAnalysis>,
406}
407
408#[derive(Debug, Clone, Serialize, Deserialize)]
410pub struct BenchmarkStatistics {
411 pub mean_execution_time: Duration,
413
414 pub median_execution_time: Duration,
416
417 pub std_deviation: Duration,
419
420 pub min_execution_time: Duration,
422
423 pub max_execution_time: Duration,
425
426 pub p95_execution_time: Duration,
428
429 pub p99_execution_time: Duration,
431
432 pub coefficient_variation: f64,
434
435 pub confidence_interval: (Duration, Duration),
437
438 pub throughput_stats: ThroughputStatistics,
440
441 pub memory_stats: MemoryStatisticsSummary,
443}
444
445#[derive(Debug, Clone, Serialize, Deserialize)]
447pub struct ThroughputStatistics {
448 pub mean_throughput: f64,
449 pub max_throughput: f64,
450 pub min_throughput: f64,
451 pub std_deviation: f64,
452}
453
454#[derive(Debug, Clone, Serialize, Deserialize)]
456pub struct MemoryStatisticsSummary {
457 pub mean_peak_usage: usize,
458 pub max_peak_usage: usize,
459 pub mean_allocations: usize,
460 pub total_leaks: usize,
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct ValidationSummary {
466 pub success_rate: f64,
467 pub error_count: usize,
468 pub warning_count: usize,
469 pub avg_correctness_score: f64,
470}
471
472#[derive(Debug, Clone, Serialize, Deserialize)]
474pub struct BenchmarkComparison {
475 pub baseline_name: String,
477
478 pub performance_improvement: f64,
480
481 pub significance: StatisticalSignificance,
483
484 pub detailed_metrics: HashMap<String, f64>,
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize)]
490pub struct StatisticalSignificance {
491 pub p_value: f64,
492 pub is_significant: bool,
493 pub confidence_level: f64,
494 pub effect_size: f64,
495}
496
497#[derive(Debug, Clone, Serialize, Deserialize)]
499pub struct RegressionAnalysis {
500 pub trend: RegressionTrend,
502
503 pub regressions: Vec<PerformanceRegression>,
505
506 pub correlations: HashMap<String, f64>,
508}
509
510#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
512pub enum RegressionTrend {
513 Improving,
514 Stable,
515 Degrading,
516 Fluctuating,
517}
518
519#[derive(Debug, Clone, Serialize, Deserialize)]
521pub struct PerformanceRegression {
522 pub regression_type: RegressionType,
523 pub severity: RegressionSeverity,
524 pub detected_at: SystemTime,
525 pub performance_delta: f64,
526 pub description: String,
527}
528
529#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
531pub enum RegressionType {
532 ExecutionTime,
533 CompilationTime,
534 MemoryUsage,
535 Throughput,
536 EnergyConsumption,
537}
538
539#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
541pub enum RegressionSeverity {
542 Low,
543 Medium,
544 High,
545 Critical,
546}
547
548#[derive(Debug, Clone, Serialize, Deserialize)]
550pub struct SuiteStatistics {
551 pub total_benchmarks: usize,
553
554 pub successful_benchmarks: usize,
556
557 pub failed_benchmarks: usize,
559
560 pub total_execution_time: Duration,
562
563 pub avg_performance_improvement: f64,
565
566 pub performance_distribution: HashMap<String, usize>,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
572pub struct SystemInfo {
573 pub cpu_info: CpuInfo,
575
576 pub memory_info: MemoryInfo,
578
579 pub os_info: String,
581
582 pub rust_version: String,
584
585 pub compiler_version: String,
587
588 pub environment: HashMap<String, String>,
590}
591
592#[derive(Debug, Clone, Serialize, Deserialize)]
594pub struct CpuInfo {
595 pub model: String,
596 pub cores: usize,
597 pub frequency: f64,
598 pub cache_sizes: Vec<usize>,
599 pub features: Vec<String>,
600}
601
602#[derive(Debug, Clone, Serialize, Deserialize)]
604pub struct MemoryInfo {
605 pub total: usize,
606 pub available: usize,
607 pub page_size: usize,
608}
609
610pub struct BenchmarkProfiler {
612 profiling_enabled: bool,
613 memory_tracker: MemoryTracker,
614 cpu_profiler: CpuProfiler,
615 energy_meter: Option<EnergyMeter>,
616}
617
618struct MemoryTracker {
620 peak_usage: usize,
621 current_usage: usize,
622 allocations: usize,
623 deallocations: usize,
624}
625
626struct CpuProfiler {
628 sampling_rate: u64,
629 profiles: Vec<CpuProfile>,
630}
631
632#[derive(Debug, Clone)]
634struct CpuProfile {
635 timestamp: Instant,
636 cpu_usage: f64,
637 instruction_count: u64,
638 cache_misses: u64,
639}
640
641struct EnergyMeter {
643 baseline_power: f64,
644 current_power: f64,
645 total_energy: f64,
646}
647
648impl BenchmarkSuite {
649 pub fn new(config: BenchmarkConfig) -> Self {
651 Self {
652 config: config.clone(),
653 benchmarks: Vec::new(),
654 results: Arc::new(Mutex::new(BenchmarkResults {
655 results: HashMap::new(),
656 suite_statistics: SuiteStatistics {
657 total_benchmarks: 0,
658 successful_benchmarks: 0,
659 failed_benchmarks: 0,
660 total_execution_time: Duration::ZERO,
661 avg_performance_improvement: 0.0,
662 performance_distribution: HashMap::new(),
663 },
664 system_info: SystemInfo::collect(),
665 config: config.clone(),
666 timestamp: SystemTime::now(),
667 })),
668 profiler: BenchmarkProfiler::new(config.enable_profiling),
669 }
670 }
671
672 pub fn add_benchmark(&mut self, benchmark: Box<dyn Benchmark>) {
674 self.benchmarks.push(benchmark);
675 }
676
677 pub fn run_all(&mut self, compiler: &mut JitCompiler) -> JitResult<BenchmarkResults> {
679 let start_time = Instant::now();
680 let mut successful = 0;
681 let mut failed = 0;
682
683 let total_benchmarks = self.benchmarks.len();
684 println!("Running {} benchmarks...", total_benchmarks);
685
686 for (index, benchmark) in self.benchmarks.iter_mut().enumerate() {
687 println!(
688 "Running benchmark {}/{}: {}",
689 index + 1,
690 total_benchmarks,
691 benchmark.name()
692 );
693
694 match benchmark.execute(compiler) {
696 Ok(measurement) => {
697 let benchmark_result = BenchmarkResult {
699 name: benchmark.name().to_string(),
700 measurements: vec![measurement.clone()],
701 statistics: BenchmarkStatistics {
702 mean_execution_time: measurement.execution_time,
703 median_execution_time: measurement.execution_time,
704 std_deviation: Duration::ZERO,
705 min_execution_time: measurement.execution_time,
706 max_execution_time: measurement.execution_time,
707 p95_execution_time: measurement.execution_time,
708 p99_execution_time: measurement.execution_time,
709 coefficient_variation: 0.0,
710 confidence_interval: (
711 measurement.execution_time,
712 measurement.execution_time,
713 ),
714 throughput_stats: ThroughputStatistics {
715 mean_throughput: 1000.0,
716 max_throughput: 1000.0,
717 min_throughput: 1000.0,
718 std_deviation: 0.0,
719 },
720 memory_stats: MemoryStatisticsSummary {
721 mean_peak_usage: 1024 * 1024, max_peak_usage: 1024 * 1024,
723 mean_allocations: 100,
724 total_leaks: 0,
725 },
726 },
727 validation: ValidationSummary {
728 success_rate: 1.0,
729 error_count: 0,
730 warning_count: 0,
731 avg_correctness_score: 1.0,
732 },
733 comparisons: Vec::new(),
734 regression_analysis: None,
735 };
736
737 if let Ok(mut results) = self.results.lock() {
738 results
739 .results
740 .insert(benchmark.name().to_string(), benchmark_result);
741 }
742 successful += 1;
743 }
744 Err(e) => {
745 eprintln!("Benchmark {} failed: {}", benchmark.name(), e);
746 failed += 1;
747 }
748 }
749 }
750
751 let total_time = start_time.elapsed();
752
753 if let Ok(mut results) = self.results.lock() {
755 results.suite_statistics.total_benchmarks = self.benchmarks.len();
756 results.suite_statistics.successful_benchmarks = successful;
757 results.suite_statistics.failed_benchmarks = failed;
758 results.suite_statistics.total_execution_time = total_time;
759
760 let total_improvement: f64 = results
762 .results
763 .values()
764 .flat_map(|r| r.comparisons.iter())
765 .map(|c| c.performance_improvement)
766 .sum();
767 let comparison_count = results
768 .results
769 .values()
770 .flat_map(|r| r.comparisons.iter())
771 .count();
772
773 if comparison_count > 0 {
774 results.suite_statistics.avg_performance_improvement =
775 total_improvement / comparison_count as f64;
776 }
777
778 return Ok(results.clone());
779 }
780
781 Err(JitError::RuntimeError(
782 "Failed to access results".to_string(),
783 ))
784 }
785
786 fn run_single_benchmark(
788 &mut self,
789 benchmark: &mut Box<dyn Benchmark>,
790 compiler: &mut JitCompiler,
791 ) -> JitResult<BenchmarkResult> {
792 benchmark.setup()?;
794
795 let mut measurements = Vec::new();
796 let mut validation_results = Vec::new();
797
798 for _ in 0..self.config.warmup_iterations {
800 let _ = benchmark.execute(compiler)?;
801 }
802
803 for _ in 0..self.config.measurement_iterations {
805 let measurement = benchmark.execute(compiler)?;
806 let validation = benchmark.validate(&measurement)?;
807
808 measurements.push(measurement);
809 validation_results.push(validation);
810 }
811
812 let statistics = self.calculate_statistics(&measurements);
814
815 let validation_summary = self.calculate_validation_summary(&validation_results);
817
818 let comparisons = Vec::new();
820
821 let regression_analysis = None;
823
824 benchmark.teardown()?;
826
827 Ok(BenchmarkResult {
828 name: benchmark.name().to_string(),
829 measurements,
830 statistics,
831 validation: validation_summary,
832 comparisons,
833 regression_analysis,
834 })
835 }
836
837 fn calculate_statistics(&self, measurements: &[BenchmarkMeasurement]) -> BenchmarkStatistics {
839 if measurements.is_empty() {
840 return BenchmarkStatistics {
841 mean_execution_time: Duration::ZERO,
842 median_execution_time: Duration::ZERO,
843 std_deviation: Duration::ZERO,
844 min_execution_time: Duration::ZERO,
845 max_execution_time: Duration::ZERO,
846 p95_execution_time: Duration::ZERO,
847 p99_execution_time: Duration::ZERO,
848 coefficient_variation: 0.0,
849 confidence_interval: (Duration::ZERO, Duration::ZERO),
850 throughput_stats: ThroughputStatistics {
851 mean_throughput: 0.0,
852 max_throughput: 0.0,
853 min_throughput: 0.0,
854 std_deviation: 0.0,
855 },
856 memory_stats: MemoryStatisticsSummary {
857 mean_peak_usage: 0,
858 max_peak_usage: 0,
859 mean_allocations: 0,
860 total_leaks: 0,
861 },
862 };
863 }
864
865 let execution_times: Vec<Duration> =
866 measurements.iter().map(|m| m.execution_time).collect();
867
868 let mean_time = Duration::from_nanos(
869 execution_times
870 .iter()
871 .map(|d| d.as_nanos() as u64)
872 .sum::<u64>()
873 / measurements.len() as u64,
874 );
875
876 let mut sorted_times = execution_times.clone();
877 sorted_times.sort();
878
879 let median_time = sorted_times[sorted_times.len() / 2];
880 let min_time = *sorted_times
881 .first()
882 .expect("sorted_times should not be empty");
883 let max_time = *sorted_times
884 .last()
885 .expect("sorted_times should not be empty");
886
887 let p95_index = (sorted_times.len() as f64 * 0.95) as usize;
889 let p99_index = (sorted_times.len() as f64 * 0.99) as usize;
890 let p95_time = sorted_times.get(p95_index).copied().unwrap_or(max_time);
891 let p99_time = sorted_times.get(p99_index).copied().unwrap_or(max_time);
892
893 let variance = execution_times
895 .iter()
896 .map(|t| {
897 let diff = t.as_nanos() as f64 - mean_time.as_nanos() as f64;
898 diff * diff
899 })
900 .sum::<f64>()
901 / measurements.len() as f64;
902
903 let std_dev = Duration::from_nanos(variance.sqrt() as u64);
904
905 let cv = if mean_time.as_nanos() > 0 {
907 std_dev.as_nanos() as f64 / mean_time.as_nanos() as f64
908 } else {
909 0.0
910 };
911
912 let t_value = 1.96; let margin_of_error = t_value * (variance.sqrt() / (measurements.len() as f64).sqrt());
915 let ci_lower =
916 Duration::from_nanos((mean_time.as_nanos() as f64 - margin_of_error).max(0.0) as u64);
917 let ci_upper = Duration::from_nanos((mean_time.as_nanos() as f64 + margin_of_error) as u64);
918
919 let throughputs: Vec<f64> = measurements.iter().map(|m| m.throughput).collect();
921 let mean_throughput = throughputs.iter().sum::<f64>() / throughputs.len() as f64;
922 let max_throughput = throughputs.iter().copied().fold(0.0, f64::max);
923 let min_throughput = throughputs.iter().copied().fold(f64::INFINITY, f64::min);
924 let throughput_variance = throughputs
925 .iter()
926 .map(|&t| (t - mean_throughput).powi(2))
927 .sum::<f64>()
928 / throughputs.len() as f64;
929 let throughput_std_dev = throughput_variance.sqrt();
930
931 let peak_usages: Vec<usize> = measurements
933 .iter()
934 .map(|m| m.memory_stats.peak_usage)
935 .collect();
936 let mean_peak_usage = peak_usages.iter().sum::<usize>() / peak_usages.len();
937 let max_peak_usage = *peak_usages.iter().max().unwrap_or(&0);
938
939 let allocations: Vec<usize> = measurements
940 .iter()
941 .map(|m| m.memory_stats.allocations)
942 .collect();
943 let mean_allocations = allocations.iter().sum::<usize>() / allocations.len();
944
945 let total_leaks = measurements.iter().map(|m| m.memory_stats.leaks).sum();
946
947 BenchmarkStatistics {
948 mean_execution_time: mean_time,
949 median_execution_time: median_time,
950 std_deviation: std_dev,
951 min_execution_time: min_time,
952 max_execution_time: max_time,
953 p95_execution_time: p95_time,
954 p99_execution_time: p99_time,
955 coefficient_variation: cv,
956 confidence_interval: (ci_lower, ci_upper),
957 throughput_stats: ThroughputStatistics {
958 mean_throughput,
959 max_throughput,
960 min_throughput,
961 std_deviation: throughput_std_dev,
962 },
963 memory_stats: MemoryStatisticsSummary {
964 mean_peak_usage,
965 max_peak_usage,
966 mean_allocations,
967 total_leaks,
968 },
969 }
970 }
971
972 fn calculate_validation_summary(&self, validations: &[ValidationResult]) -> ValidationSummary {
974 if validations.is_empty() {
975 return ValidationSummary {
976 success_rate: 0.0,
977 error_count: 0,
978 warning_count: 0,
979 avg_correctness_score: 0.0,
980 };
981 }
982
983 let successful = validations.iter().filter(|v| v.is_valid).count();
984 let success_rate = successful as f64 / validations.len() as f64;
985
986 let error_count = validations.iter().map(|v| v.errors.len()).sum();
987 let warning_count = validations.iter().map(|v| v.warnings.len()).sum();
988
989 let avg_correctness_score =
990 validations.iter().map(|v| v.correctness_score).sum::<f64>() / validations.len() as f64;
991
992 ValidationSummary {
993 success_rate,
994 error_count,
995 warning_count,
996 avg_correctness_score,
997 }
998 }
999
1000 pub fn export_results(&self, file_path: &str) -> JitResult<()> {
1002 if let Ok(results) = self.results.lock() {
1003 match self.config.output_format {
1004 OutputFormat::Json => {
1005 let json = serde_json::to_string_pretty(&*results).map_err(|e| {
1006 JitError::RuntimeError(format!("JSON serialization failed: {}", e))
1007 })?;
1008 std::fs::write(file_path, json)
1009 .map_err(|e| JitError::RuntimeError(format!("File write failed: {}", e)))?;
1010 }
1011 OutputFormat::Csv => {
1012 let csv = self.generate_csv_report(&results);
1013 std::fs::write(file_path, csv)
1014 .map_err(|e| JitError::RuntimeError(format!("File write failed: {}", e)))?;
1015 }
1016 OutputFormat::Html => {
1017 let html = self.generate_html_report(&results);
1018 std::fs::write(file_path, html)
1019 .map_err(|e| JitError::RuntimeError(format!("File write failed: {}", e)))?;
1020 }
1021 OutputFormat::Markdown => {
1022 let markdown = self.generate_markdown_report(&results);
1023 std::fs::write(file_path, markdown)
1024 .map_err(|e| JitError::RuntimeError(format!("File write failed: {}", e)))?;
1025 }
1026 OutputFormat::Binary => {
1027 let binary =
1029 oxicode::serde::encode_to_vec(&*results, oxicode::config::standard())
1030 .map_err(|e| {
1031 JitError::RuntimeError(format!(
1032 "Binary serialization failed: {}",
1033 e
1034 ))
1035 })?;
1036 std::fs::write(file_path, binary)
1037 .map_err(|e| JitError::RuntimeError(format!("File write failed: {}", e)))?;
1038 }
1039 }
1040 }
1041
1042 Ok(())
1043 }
1044
1045 fn generate_csv_report(&self, results: &BenchmarkResults) -> String {
1046 let mut csv = String::new();
1047 csv.push_str("Benchmark,Mean Time (μs),Median Time (μs),Min Time (μs),Max Time (μs),Std Dev (μs),Throughput (ops/s),Memory (MB)\n");
1048
1049 for (name, result) in &results.results {
1050 csv.push_str(&format!(
1051 "{},{},{},{},{},{},{},{}\n",
1052 name,
1053 result.statistics.mean_execution_time.as_micros(),
1054 result.statistics.median_execution_time.as_micros(),
1055 result.statistics.min_execution_time.as_micros(),
1056 result.statistics.max_execution_time.as_micros(),
1057 result.statistics.std_deviation.as_micros(),
1058 result.statistics.throughput_stats.mean_throughput,
1059 result.statistics.memory_stats.mean_peak_usage / 1024 / 1024
1060 ));
1061 }
1062
1063 csv
1064 }
1065
1066 fn generate_html_report(&self, results: &BenchmarkResults) -> String {
1067 format!(
1068 r#"<!DOCTYPE html>
1069<html>
1070<head>
1071 <title>{} - Benchmark Results</title>
1072 <style>
1073 body {{ font-family: Arial, sans-serif; margin: 20px; }}
1074 table {{ border-collapse: collapse; width: 100%; }}
1075 th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
1076 th {{ background-color: #f2f2f2; }}
1077 .summary {{ background-color: #f9f9f9; padding: 15px; margin-bottom: 20px; }}
1078 </style>
1079</head>
1080<body>
1081 <h1>{} - Benchmark Results</h1>
1082 <div class="summary">
1083 <h2>Summary</h2>
1084 <p>Total Benchmarks: {}</p>
1085 <p>Successful: {}</p>
1086 <p>Failed: {}</p>
1087 <p>Total Execution Time: {:.2?}</p>
1088 </div>
1089 <h2>Detailed Results</h2>
1090 <table>
1091 <tr>
1092 <th>Benchmark</th>
1093 <th>Mean Time (μs)</th>
1094 <th>Throughput (ops/s)</th>
1095 <th>Memory (MB)</th>
1096 <th>Success Rate</th>
1097 </tr>
1098 {}
1099 </table>
1100</body>
1101</html>"#,
1102 results.config.suite_name,
1103 results.config.suite_name,
1104 results.suite_statistics.total_benchmarks,
1105 results.suite_statistics.successful_benchmarks,
1106 results.suite_statistics.failed_benchmarks,
1107 results.suite_statistics.total_execution_time,
1108 results
1109 .results
1110 .iter()
1111 .map(|(name, result)| format!(
1112 "<tr><td>{}</td><td>{}</td><td>{:.2}</td><td>{}</td><td>{:.1}%</td></tr>",
1113 name,
1114 result.statistics.mean_execution_time.as_micros(),
1115 result.statistics.throughput_stats.mean_throughput,
1116 result.statistics.memory_stats.mean_peak_usage / 1024 / 1024,
1117 result.validation.success_rate * 100.0
1118 ))
1119 .collect::<Vec<_>>()
1120 .join("\n")
1121 )
1122 }
1123
1124 fn generate_markdown_report(&self, results: &BenchmarkResults) -> String {
1125 let mut markdown = format!("# {} - Benchmark Results\n\n", results.config.suite_name);
1126
1127 markdown.push_str("## Summary\n\n");
1128 markdown.push_str(&format!(
1129 "- **Total Benchmarks**: {}\n",
1130 results.suite_statistics.total_benchmarks
1131 ));
1132 markdown.push_str(&format!(
1133 "- **Successful**: {}\n",
1134 results.suite_statistics.successful_benchmarks
1135 ));
1136 markdown.push_str(&format!(
1137 "- **Failed**: {}\n",
1138 results.suite_statistics.failed_benchmarks
1139 ));
1140 markdown.push_str(&format!(
1141 "- **Total Execution Time**: {:.2?}\n\n",
1142 results.suite_statistics.total_execution_time
1143 ));
1144
1145 markdown.push_str("## Detailed Results\n\n");
1146 markdown.push_str(
1147 "| Benchmark | Mean Time (μs) | Throughput (ops/s) | Memory (MB) | Success Rate |\n",
1148 );
1149 markdown.push_str(
1150 "|-----------|----------------|--------------------|--------------|--------------|\n",
1151 );
1152
1153 for (name, result) in &results.results {
1154 markdown.push_str(&format!(
1155 "| {} | {} | {:.2} | {} | {:.1}% |\n",
1156 name,
1157 result.statistics.mean_execution_time.as_micros(),
1158 result.statistics.throughput_stats.mean_throughput,
1159 result.statistics.memory_stats.mean_peak_usage / 1024 / 1024,
1160 result.validation.success_rate * 100.0
1161 ));
1162 }
1163
1164 markdown
1165 }
1166}
1167
1168impl BenchmarkProfiler {
1169 pub fn new(enabled: bool) -> Self {
1170 Self {
1171 profiling_enabled: enabled,
1172 memory_tracker: MemoryTracker::new(),
1173 cpu_profiler: CpuProfiler::new(),
1174 energy_meter: None,
1175 }
1176 }
1177
1178 pub fn start_profiling(&mut self) {
1179 if self.profiling_enabled {
1180 self.memory_tracker.reset();
1181 self.cpu_profiler.start();
1182 if let Some(ref mut meter) = self.energy_meter {
1183 meter.start();
1184 }
1185 }
1186 }
1187
1188 pub fn stop_profiling(&mut self) -> ProfileData {
1189 ProfileData {
1190 memory_stats: self.memory_tracker.get_stats(),
1191 cpu_stats: self.cpu_profiler.get_stats(),
1192 energy_stats: self.energy_meter.as_ref().map(|m| m.get_stats()),
1193 }
1194 }
1195}
1196
1197impl MemoryTracker {
1198 pub fn new() -> Self {
1199 Self {
1200 peak_usage: 0,
1201 current_usage: 0,
1202 allocations: 0,
1203 deallocations: 0,
1204 }
1205 }
1206
1207 pub fn reset(&mut self) {
1208 self.peak_usage = 0;
1209 self.current_usage = 0;
1210 self.allocations = 0;
1211 self.deallocations = 0;
1212 }
1213
1214 pub fn get_stats(&self) -> MemoryStatistics {
1215 MemoryStatistics {
1216 peak_usage: self.peak_usage,
1217 average_usage: self.current_usage,
1218 allocations: self.allocations,
1219 deallocations: self.deallocations,
1220 leaks: if self.allocations > self.deallocations {
1221 self.allocations - self.deallocations
1222 } else {
1223 0
1224 },
1225 cache_stats: CacheStatistics {
1226 l1_hit_rate: 0.95, l2_hit_rate: 0.80, l3_hit_rate: 0.60, cache_misses: 1000, bandwidth_utilization: 0.70, },
1232 }
1233 }
1234}
1235
1236impl CpuProfiler {
1237 pub fn new() -> Self {
1238 Self {
1239 sampling_rate: 1000, profiles: Vec::new(),
1241 }
1242 }
1243
1244 pub fn start(&mut self) {
1245 self.profiles.clear();
1246 }
1247
1248 pub fn get_stats(&self) -> CpuStatistics {
1249 CpuStatistics {
1250 avg_usage: 0.75, instruction_count: 1000000, cache_misses: 5000, }
1254 }
1255}
1256
1257impl EnergyMeter {
1258 pub fn start(&mut self) {
1259 self.baseline_power = self.current_power;
1260 self.total_energy = 0.0;
1261 }
1262
1263 pub fn get_stats(&self) -> EnergyStatistics {
1264 EnergyStatistics {
1265 total_energy: self.total_energy,
1266 avg_power: self.current_power,
1267 peak_power: self.current_power * 1.2, }
1269 }
1270}
1271
1272impl SystemInfo {
1273 pub fn collect() -> Self {
1274 Self {
1275 cpu_info: CpuInfo {
1276 model: "Unknown CPU".to_string(),
1277 cores: num_cpus::get(),
1278 frequency: 2400.0, cache_sizes: vec![32768, 262144, 8388608], features: vec!["SSE".to_string(), "AVX".to_string()],
1281 },
1282 memory_info: MemoryInfo {
1283 total: 8 * 1024 * 1024 * 1024, available: 6 * 1024 * 1024 * 1024, page_size: 4096,
1286 },
1287 os_info: std::env::consts::OS.to_string(),
1288 rust_version: env!("CARGO_PKG_RUST_VERSION").to_string(),
1289 compiler_version: "1.0.0".to_string(),
1290 environment: std::env::vars().collect(),
1291 }
1292 }
1293}
1294
1295#[derive(Debug, Clone)]
1297pub struct ProfileData {
1298 pub memory_stats: MemoryStatistics,
1299 pub cpu_stats: CpuStatistics,
1300 pub energy_stats: Option<EnergyStatistics>,
1301}
1302
1303#[derive(Debug, Clone)]
1305pub struct CpuStatistics {
1306 pub avg_usage: f64,
1307 pub instruction_count: u64,
1308 pub cache_misses: u64,
1309}
1310
1311#[derive(Debug, Clone)]
1313pub struct EnergyStatistics {
1314 pub total_energy: f64,
1315 pub avg_power: f64,
1316 pub peak_power: f64,
1317}
1318
1319#[cfg(test)]
1320mod tests {
1321 use super::*;
1322
1323 #[test]
1324 fn test_benchmark_suite_creation() {
1325 let config = BenchmarkConfig::default();
1326 let suite = BenchmarkSuite::new(config);
1327 assert_eq!(suite.benchmarks.len(), 0);
1328 }
1329
1330 #[test]
1331 fn test_statistics_calculation() {
1332 let suite = BenchmarkSuite::new(BenchmarkConfig::default());
1333
1334 let measurements = vec![
1335 BenchmarkMeasurement {
1336 execution_time: Duration::from_millis(100),
1337 compilation_time: Duration::from_millis(10),
1338 memory_stats: MemoryStatistics {
1339 peak_usage: 1024,
1340 average_usage: 512,
1341 allocations: 10,
1342 deallocations: 8,
1343 leaks: 2,
1344 cache_stats: CacheStatistics {
1345 l1_hit_rate: 0.95,
1346 l2_hit_rate: 0.80,
1347 l3_hit_rate: 0.60,
1348 cache_misses: 100,
1349 bandwidth_utilization: 0.70,
1350 },
1351 },
1352 cpu_utilization: 0.8,
1353 throughput: 1000.0,
1354 energy_consumption: Some(10.0),
1355 custom_metrics: HashMap::new(),
1356 timestamp: SystemTime::now(),
1357 config_hash: 12345,
1358 },
1359 BenchmarkMeasurement {
1360 execution_time: Duration::from_millis(110),
1361 compilation_time: Duration::from_millis(12),
1362 memory_stats: MemoryStatistics {
1363 peak_usage: 1100,
1364 average_usage: 550,
1365 allocations: 12,
1366 deallocations: 10,
1367 leaks: 2,
1368 cache_stats: CacheStatistics {
1369 l1_hit_rate: 0.96,
1370 l2_hit_rate: 0.82,
1371 l3_hit_rate: 0.62,
1372 cache_misses: 95,
1373 bandwidth_utilization: 0.72,
1374 },
1375 },
1376 cpu_utilization: 0.85,
1377 throughput: 950.0,
1378 energy_consumption: Some(11.0),
1379 custom_metrics: HashMap::new(),
1380 timestamp: SystemTime::now(),
1381 config_hash: 12345,
1382 },
1383 ];
1384
1385 let stats = suite.calculate_statistics(&measurements);
1386 assert_eq!(stats.mean_execution_time, Duration::from_millis(105));
1387 assert_eq!(stats.min_execution_time, Duration::from_millis(100));
1388 assert_eq!(stats.max_execution_time, Duration::from_millis(110));
1389 }
1390
1391 #[test]
1392 fn test_system_info_collection() {
1393 let info = SystemInfo::collect();
1394 assert!(info.cpu_info.cores > 0);
1395 assert!(!info.os_info.is_empty());
1396 }
1397}