1pub mod cross_module;
13pub mod performance;
14pub mod regression;
15
16pub use cross_module::{
18 create_default_benchmark_suite, run_quick_benchmarks,
19 BenchmarkSuiteResult as CrossModuleBenchmarkSuiteResult, CrossModuleBenchConfig,
20 CrossModuleBenchmarkRunner, PerformanceMeasurement as CrossModulePerformanceMeasurement,
21};
22
23use crate::error::{CoreError, CoreResult, ErrorContext};
24use crate::performance_optimization::OptimizationStrategy;
25use std::collections::{HashMap, HashSet};
26use std::time::{Duration, Instant};
27
28pub(crate) fn current_process_memory_bytes() -> usize {
38 #[cfg(target_os = "linux")]
39 {
40 if let Ok(status) = std::fs::read_to_string("/proc/self/status") {
41 for line in status.lines() {
42 if let Some(rest) = line.strip_prefix("VmRSS:") {
43 if let Some(kb_str) = rest.split_whitespace().next() {
44 if let Ok(kb) = kb_str.parse::<usize>() {
45 return kb * 1024;
46 }
47 }
48 }
49 }
50 }
51 }
52
53 0
54}
55
56#[derive(Debug, Clone)]
58pub struct BenchmarkConfig {
59 pub strategies: HashSet<OptimizationStrategy>,
61 pub sample_sizes: Vec<usize>,
63 pub warmup_iterations: usize,
65 pub measurement_iterations: usize,
67 pub measurement_time: Duration,
69 pub min_duration: Duration,
71 pub max_duration: Duration,
73 pub confidence_level: f64,
75 pub max_cv: f64,
77 pub enable_profiling: bool,
79 pub enable_memory_tracking: bool,
81 pub tags: Vec<String>,
83}
84
85impl Default for BenchmarkConfig {
86 fn default() -> Self {
87 let mut strategies = HashSet::new();
88 strategies.insert(OptimizationStrategy::Scalar);
89
90 Self {
91 strategies,
92 sample_sizes: vec![1000, 10000, 100000],
93 warmup_iterations: 10,
94 measurement_iterations: 100,
95 measurement_time: Duration::from_secs(5),
96 min_duration: Duration::from_millis(1),
97 max_duration: Duration::from_secs(30),
98 confidence_level: 0.95,
99 max_cv: 0.1, enable_profiling: false,
101 enable_memory_tracking: true,
102 tags: Vec::new(),
103 }
104 }
105}
106
107impl BenchmarkConfig {
108 pub fn new() -> Self {
110 Self::default()
111 }
112
113 pub fn with_warmup_iterations(mut self, iterations: usize) -> Self {
115 self.warmup_iterations = iterations;
116 self
117 }
118
119 pub fn with_measurement_iterations(mut self, iterations: usize) -> Self {
121 self.measurement_iterations = iterations;
122 self
123 }
124
125 pub fn with_measurement_time(mut self, time: Duration) -> Self {
127 self.measurement_time = time;
128 self
129 }
130
131 pub fn with_min_duration(mut self, duration: Duration) -> Self {
133 self.min_duration = std::time::Duration::from_secs(1);
134 self
135 }
136
137 pub fn with_max_duration(mut self, duration: Duration) -> Self {
139 self.max_duration = std::time::Duration::from_secs(1);
140 self
141 }
142
143 pub fn with_confidence_level(mut self, level: f64) -> Self {
145 self.confidence_level = level;
146 self
147 }
148
149 pub fn with_max_cv(mut self, cv: f64) -> Self {
151 self.max_cv = cv;
152 self
153 }
154
155 pub fn with_profiling(mut self, enabled: bool) -> Self {
157 self.enable_profiling = enabled;
158 self
159 }
160
161 pub fn with_memory_tracking(mut self, enabled: bool) -> Self {
163 self.enable_memory_tracking = enabled;
164 self
165 }
166
167 pub fn with_tags(mut self, tags: Vec<String>) -> Self {
169 self.tags = tags;
170 self
171 }
172
173 pub fn with_tag(mut self, tag: String) -> Self {
175 self.tags.push(tag);
176 self
177 }
178
179 pub fn with_strategies(mut self, strategies: HashSet<OptimizationStrategy>) -> Self {
181 self.strategies = strategies;
182 self
183 }
184
185 pub fn with_strategy(mut self, strategy: OptimizationStrategy) -> Self {
187 self.strategies.insert(strategy);
188 self
189 }
190
191 pub fn with_sample_sizes(mut self, sample_sizes: Vec<usize>) -> Self {
193 self.sample_sizes = sample_sizes;
194 self
195 }
196}
197
198#[derive(Debug, Clone)]
200pub struct BenchmarkMeasurement {
201 pub execution_time: Duration,
203 pub duration: Duration,
205 pub strategy: OptimizationStrategy,
207 pub input_size: usize,
209 pub throughput: f64,
211 pub memory_usage: usize,
213 pub custom_metrics: HashMap<String, f64>,
215 pub timestamp: std::time::SystemTime,
217}
218
219impl BenchmarkMeasurement {
220 pub fn new(execution_time: Duration) -> Self {
222 Self {
223 execution_time,
224 duration: execution_time,
225 strategy: OptimizationStrategy::Scalar,
226 input_size: 0,
227 throughput: 0.0,
228 memory_usage: 0,
229 custom_metrics: HashMap::new(),
230 timestamp: std::time::SystemTime::now(),
231 }
232 }
233
234 pub fn with_memory_usage(mut self, memory: usize) -> Self {
236 self.memory_usage = memory;
237 self
238 }
239
240 pub fn with_custom_metric(mut self, name: String, value: f64) -> Self {
242 self.custom_metrics.insert(name, value);
243 self
244 }
245
246 pub fn with_strategy(mut self, strategy: OptimizationStrategy) -> Self {
248 self.strategy = strategy;
249 self
250 }
251
252 pub fn with_input_size(mut self, input_size: usize) -> Self {
254 self.input_size = input_size;
255 self
256 }
257
258 pub fn with_throughput(mut self, throughput: f64) -> Self {
260 self.throughput = throughput;
261 self
262 }
263
264 pub fn execution_time_nanos(&self) -> u64 {
266 self.execution_time.as_nanos() as u64
267 }
268
269 pub fn execution_time_micros(&self) -> u64 {
271 self.execution_time.as_micros() as u64
272 }
273
274 pub fn execution_time_millis(&self) -> u64 {
276 self.execution_time.as_millis() as u64
277 }
278}
279
280#[derive(Debug, Clone)]
282pub struct BenchmarkResult {
283 pub name: String,
285 pub measurements: Vec<BenchmarkMeasurement>,
287 pub statistics: BenchmarkStatistics,
289 pub config: BenchmarkConfig,
291 pub total_time: Duration,
293 pub quality_criteria_met: bool,
295 pub warnings: Vec<String>,
297}
298
299impl BenchmarkResult {
300 pub fn new(name: String, config: BenchmarkConfig) -> Self {
302 Self {
303 name,
304 measurements: Vec::new(),
305 statistics: BenchmarkStatistics::default(),
306 config,
307 total_time: Duration::from_secs(0),
308 quality_criteria_met: false,
309 warnings: Vec::new(),
310 }
311 }
312
313 pub fn add_measurement(&mut self, measurement: BenchmarkMeasurement) {
315 self.measurements.push(measurement);
316 }
317
318 pub fn finalize(&mut self) -> CoreResult<()> {
320 if self.measurements.is_empty() {
321 return Err(CoreError::ValidationError(crate::error::ErrorContext::new(
322 "No measurements collected",
323 )));
324 }
325
326 self.statistics = BenchmarkStatistics::from_measurements(&self.measurements)?;
327
328 self.quality_criteria_met = self.statistics.coefficient_of_variation <= self.config.max_cv;
330
331 if !self.quality_criteria_met {
332 self.warnings.push(format!(
333 "High coefficient of variation: {:.3} > {:.3}",
334 self.statistics.coefficient_of_variation, self.config.max_cv
335 ));
336 }
337
338 Ok(())
339 }
340
341 pub fn get_throughput(&self, operations_periteration: u64) -> f64 {
343 let avg_time_seconds = self.statistics.mean_execution_time.as_secs_f64();
344 operations_periteration as f64 / avg_time_seconds
345 }
346
347 pub fn get_memory_efficiency(&self, operations_periteration: u64) -> f64 {
349 if self.statistics.mean_memory_usage == 0 {
350 return f64::INFINITY;
351 }
352 let memory_mb = self.statistics.mean_memory_usage as f64 / (1024.0 * 1024.0);
353 operations_periteration as f64 / memory_mb
354 }
355}
356
357#[derive(Debug, Clone, Default)]
359pub struct BenchmarkStatistics {
360 pub mean_execution_time: Duration,
362 pub median_execution_time: Duration,
364 pub std_dev_execution_time: Duration,
366 pub min_execution_time: Duration,
368 pub max_execution_time: Duration,
370 pub coefficient_of_variation: f64,
372 pub confidence_interval: (Duration, Duration),
374 pub mean_memory_usage: usize,
376 pub std_dev_memory_usage: usize,
378 pub sample_count: usize,
380}
381
382impl BenchmarkStatistics {
383 pub fn from_measurements(measurements: &[BenchmarkMeasurement]) -> CoreResult<Self> {
385 if measurements.is_empty() {
386 return Err(CoreError::ValidationError(crate::error::ErrorContext::new(
387 "Cannot compute statistics from empty measurements",
388 )));
389 }
390
391 let mut execution_times: Vec<Duration> =
393 measurements.iter().map(|m| m.execution_time).collect();
394 execution_times.sort();
395
396 let mean_nanos = execution_times
398 .iter()
399 .map(|d| d.as_nanos() as f64)
400 .sum::<f64>()
401 / execution_times.len() as f64;
402 let mean_execution_time = Duration::from_nanos(mean_nanos as u64);
403
404 let median_execution_time = if execution_times.len().is_multiple_of(2) {
405 let mid = execution_times.len() / 2;
406 Duration::from_nanos(
407 ((execution_times[mid - 1].as_nanos() + execution_times[mid].as_nanos()) / 2)
408 as u64,
409 )
410 } else {
411 execution_times[execution_times.len() / 2]
412 };
413
414 let variance = execution_times
415 .iter()
416 .map(|d| {
417 let diff = d.as_nanos() as f64 - mean_nanos;
418 diff * diff
419 })
420 .sum::<f64>()
421 / execution_times.len() as f64;
422 let std_dev_execution_time = Duration::from_nanos(variance.sqrt() as u64);
423
424 let min_execution_time = execution_times[0];
425 let max_execution_time = execution_times[execution_times.len() - 1];
426
427 let coefficient_of_variation = if mean_nanos > 0.0 {
428 (variance.sqrt()) / mean_nanos
429 } else {
430 0.0
431 };
432
433 let t_value = 1.96; let standarderror = variance.sqrt() / (execution_times.len() as f64).sqrt();
436 let margin_oferror = t_value * standarderror;
437 let confidence_interval = (
438 Duration::from_nanos((mean_nanos - margin_oferror).max(0.0) as u64),
439 Duration::from_nanos((mean_nanos + margin_oferror) as u64),
440 );
441
442 let mean_memory = measurements
444 .iter()
445 .map(|m| m.memory_usage as f64)
446 .sum::<f64>()
447 / measurements.len() as f64;
448 let memory_variance = measurements
449 .iter()
450 .map(|m| {
451 let diff = m.memory_usage as f64 - mean_memory;
452 diff * diff
453 })
454 .sum::<f64>()
455 / measurements.len() as f64;
456
457 Ok(BenchmarkStatistics {
458 mean_execution_time,
459 median_execution_time,
460 std_dev_execution_time,
461 min_execution_time,
462 max_execution_time,
463 coefficient_of_variation,
464 confidence_interval,
465 mean_memory_usage: mean_memory as usize,
466 std_dev_memory_usage: memory_variance.sqrt() as usize,
467 sample_count: measurements.len(),
468 })
469 }
470
471 pub fn is_reliable(&self, max_cv: f64) -> bool {
473 self.coefficient_of_variation <= max_cv && self.sample_count >= 10
474 }
475
476 pub fn execution_time_percentile(
478 &self,
479 measurements: &[BenchmarkMeasurement],
480 percentile: f64,
481 ) -> Duration {
482 if measurements.is_empty() {
483 return Duration::from_secs(0);
484 }
485
486 let mut times: Vec<Duration> = measurements.iter().map(|m| m.execution_time).collect();
487 times.sort();
488
489 let index = (percentile / 100.0 * (times.len() - 1) as f64).round() as usize;
490 times[index.min(times.len() - 1)]
491 }
492}
493
494pub struct BenchmarkRunner {
496 config: BenchmarkConfig,
497}
498
499impl BenchmarkRunner {
500 pub fn new(config: BenchmarkConfig) -> Self {
502 Self { config }
503 }
504
505 pub fn run<F, T>(&self, name: &str, mut benchmarkfn: F) -> CoreResult<BenchmarkResult>
507 where
508 F: FnMut() -> CoreResult<T>,
509 {
510 let total_start = Instant::now();
511 let mut result = BenchmarkResult::new(name.to_string(), self.config.clone());
512
513 for _ in 0..self.config.warmup_iterations {
515 benchmarkfn()?;
516 }
517
518 let measurement_start = Instant::now();
520 let mut iteration_count = 0;
521
522 while iteration_count < self.config.measurement_iterations
523 && measurement_start.elapsed() < self.config.measurement_time
524 {
525 let memory_before = if self.config.enable_memory_tracking {
526 self.get_memory_usage().unwrap_or(0)
527 } else {
528 0
529 };
530
531 let start = Instant::now();
532 benchmarkfn()?;
533 let execution_time = start.elapsed();
534
535 let memory_after = if self.config.enable_memory_tracking {
536 self.get_memory_usage().unwrap_or(0)
537 } else {
538 0
539 };
540
541 let memory_usage = memory_after.saturating_sub(memory_before);
542
543 result.add_measurement(
544 BenchmarkMeasurement::new(execution_time).with_memory_usage(memory_usage),
545 );
546
547 iteration_count += 1;
548 }
549
550 result.total_time = total_start.elapsed();
551 result.finalize()?;
552
553 Ok(result)
554 }
555
556 pub fn run_with_setup<F, G, H, T, S>(
558 &self,
559 name: &str,
560 mut setup: F,
561 mut benchmark_fn: G,
562 mut teardown: H,
563 ) -> CoreResult<BenchmarkResult>
564 where
565 F: FnMut() -> CoreResult<S>,
566 G: FnMut(&mut S) -> CoreResult<T>,
567 H: FnMut(S) -> CoreResult<()>,
568 {
569 let total_start = Instant::now();
570 let mut result = BenchmarkResult::new(name.to_string(), self.config.clone());
571
572 for _ in 0..self.config.warmup_iterations {
574 let mut state = setup()?;
575 benchmark_fn(&mut state)?;
576 teardown(state)?;
577 }
578
579 let measurement_start = Instant::now();
581 let mut iteration_count = 0;
582
583 while iteration_count < self.config.measurement_iterations
584 && measurement_start.elapsed() < self.config.measurement_time
585 {
586 let mut state = setup()?;
587
588 let memory_before = if self.config.enable_memory_tracking {
589 self.get_memory_usage().unwrap_or(0)
590 } else {
591 0
592 };
593
594 let start = Instant::now();
595 benchmark_fn(&mut state)?;
596 let execution_time = start.elapsed();
597
598 let memory_after = if self.config.enable_memory_tracking {
599 self.get_memory_usage().unwrap_or(0)
600 } else {
601 0
602 };
603
604 teardown(state)?;
605
606 let memory_usage = memory_after.saturating_sub(memory_before);
607
608 result.add_measurement(
609 BenchmarkMeasurement::new(execution_time).with_memory_usage(memory_usage),
610 );
611
612 iteration_count += 1;
613 }
614
615 result.total_time = total_start.elapsed();
616 result.finalize()?;
617
618 Ok(result)
619 }
620
621 pub fn run_parameterized<F, T, P>(
623 &self,
624 name: &str,
625 parameters: Vec<P>,
626 mut benchmark_fn: F,
627 ) -> CoreResult<Vec<(P, BenchmarkResult)>>
628 where
629 F: FnMut(&P) -> CoreResult<T>,
630 P: Clone + std::fmt::Debug,
631 {
632 let mut results = Vec::new();
633
634 for param in parameters {
635 let param_name = format!("{name}({param:?})");
636 let param_clone = param.clone();
637
638 let result = self.run(¶m_name, || benchmark_fn(¶m_clone))?;
639 results.push((param, result));
640 }
641
642 Ok(results)
643 }
644
645 #[allow(dead_code)]
647 pub fn benchmark_operation<F, T>(
648 &self,
649 name: &str,
650 mut operation: F,
651 ) -> CoreResult<Vec<BenchmarkMeasurement>>
652 where
653 F: FnMut(&[u8], OptimizationStrategy) -> CoreResult<T>,
654 {
655 let mut measurements = Vec::new();
656
657 let data = vec![0u8; 1000];
659
660 for strategy in &self.config.strategies {
661 let start = std::time::Instant::now();
662 let _ = operation(&data, *strategy)?;
663 let elapsed = start.elapsed();
664
665 let measurement = BenchmarkMeasurement::new(elapsed)
666 .with_strategy(*strategy)
667 .with_input_size(data.len())
668 .with_throughput(data.len() as f64 / elapsed.as_secs_f64());
669
670 measurements.push(measurement);
671 }
672
673 Ok(measurements)
674 }
675
676 fn get_memory_usage(&self) -> CoreResult<usize> {
679 Ok(current_process_memory_bytes())
680 }
681}
682
683type BenchmarkFn = Box<dyn Fn(&BenchmarkRunner) -> CoreResult<BenchmarkResult> + Send + Sync>;
685
686pub struct BenchmarkSuite {
688 name: String,
689 benchmarks: Vec<BenchmarkFn>,
690 config: BenchmarkConfig,
691}
692
693impl BenchmarkSuite {
694 pub fn new(name: &str, config: BenchmarkConfig) -> Self {
696 Self {
697 name: name.to_string(),
698 benchmarks: Vec::new(),
699 config,
700 }
701 }
702
703 pub fn add_benchmark<F>(&mut self, benchmark_fn: F)
705 where
706 F: Fn(&BenchmarkRunner) -> CoreResult<BenchmarkResult> + Send + Sync + 'static,
707 {
708 self.benchmarks.push(Box::new(benchmark_fn));
709 }
710
711 pub fn run(&self) -> CoreResult<Vec<BenchmarkResult>> {
713 let runner = BenchmarkRunner::new(self.config.clone());
714 let mut results = Vec::new();
715
716 println!("Running benchmark suite: {}", self.name);
717
718 for (i, benchmark) in self.benchmarks.iter().enumerate() {
719 println!("Running benchmark {}/{}", i + 1, self.benchmarks.len());
720
721 match benchmark(&runner) {
722 Ok(result) => {
723 println!(
724 " {} completed: {:.3}ms ± {:.3}ms",
725 result.name,
726 result.statistics.mean_execution_time.as_millis(),
727 result.statistics.std_dev_execution_time.as_millis()
728 );
729 results.push(result);
730 }
731 Err(e) => {
732 println!(" Benchmark failed: {e:?}");
733 return Err(e);
734 }
735 }
736 }
737
738 self.print_summary(&results);
740
741 Ok(results)
742 }
743
744 fn print_summary(&self, results: &[BenchmarkResult]) {
746 println!("\nBenchmark Suite '{}' Summary:", self.name);
747 println!("----------------------------------------");
748
749 for result in results {
750 let quality_indicator = if result.quality_criteria_met {
751 "✓"
752 } else {
753 "⚠"
754 };
755 println!(
756 "{} {}: {:.3}ms (CV: {:.2}%)",
757 quality_indicator,
758 result.name,
759 result.statistics.mean_execution_time.as_millis(),
760 result.statistics.coefficient_of_variation * 100.0
761 );
762
763 for warning in &result.warnings {
764 println!(" Warning: {warning}");
765 }
766 }
767
768 let reliable_count = results.iter().filter(|r| r.quality_criteria_met).count();
769 println!(
770 "\nReliable benchmarks: {}/{}",
771 reliable_count,
772 results.len()
773 );
774 }
775}
776
777#[derive(Debug, Clone)]
779pub struct StrategyPerformance {
780 pub strategy: OptimizationStrategy,
781 pub throughput: f64,
782 pub latency: Duration,
783 pub memory_efficiency: f64,
784 pub cache_hit_rate: f64,
785 pub avg_throughput: f64,
786 pub throughput_stddev: f64,
787 pub avg_memory_usage: f64,
788 pub optimal_size: usize,
789 pub efficiency_score: f64,
790}
791
792impl StrategyPerformance {
793 #[allow(dead_code)]
795 pub fn new(strategy: OptimizationStrategy) -> Self {
796 Self {
797 strategy,
798 throughput: 0.0,
799 latency: Duration::from_secs(0),
800 memory_efficiency: 0.0,
801 cache_hit_rate: 0.0,
802 avg_throughput: 0.0,
803 throughput_stddev: 0.0,
804 avg_memory_usage: 0.0,
805 optimal_size: 0,
806 efficiency_score: 0.0,
807 }
808 }
809}
810
811#[derive(Debug, Clone)]
813pub struct MemoryScaling {
814 pub linear_factor: f64,
815 pub logarithmic_factor: f64,
816 pub constant_overhead: usize,
817 pub linear_coefficient: f64,
818 pub constant_coefficient: f64,
819 pub r_squared: f64,
820}
821
822impl Default for MemoryScaling {
823 fn default() -> Self {
824 Self::new()
825 }
826}
827
828impl MemoryScaling {
829 #[allow(dead_code)]
831 pub fn new() -> Self {
832 Self {
833 linear_factor: 1.0,
834 logarithmic_factor: 0.0,
835 constant_overhead: 0,
836 linear_coefficient: 1.0,
837 constant_coefficient: 0.0,
838 r_squared: 1.0,
839 }
840 }
841}
842
843#[derive(Debug, Clone, PartialEq, Eq)]
845pub enum BottleneckType {
846 CpuBound,
847 MemoryBandwidth,
848 CacheMisses,
849 BranchMisprediction,
850 IoWait,
851 AlgorithmicComplexity,
852 CacheLatency,
853 ComputeBound,
854 SynchronizationOverhead,
855}
856
857#[derive(Debug, Clone)]
858pub struct PerformanceBottleneck {
859 pub bottleneck_type: BottleneckType,
860 pub severity: f64,
861 pub description: String,
862 pub mitigation_strategy: OptimizationStrategy,
863 pub size_range: (usize, usize),
864 pub impact: f64,
865 pub mitigation: String,
866}
867
868impl PerformanceBottleneck {
869 #[allow(dead_code)]
871 pub fn new(bottleneck_type: BottleneckType) -> Self {
872 Self {
873 bottleneck_type,
874 severity: 0.0,
875 description: String::new(),
876 mitigation_strategy: OptimizationStrategy::Scalar,
877 size_range: (0, 0),
878 impact: 0.0,
879 mitigation: String::new(),
880 }
881 }
882}
883
884#[derive(Debug, Clone)]
886pub struct ScalabilityAnalysis {
887 pub parallel_efficiency: HashMap<usize, f64>,
888 pub memory_scaling: MemoryScaling,
889 pub bottlenecks: Vec<PerformanceBottleneck>,
890}
891
892impl Default for ScalabilityAnalysis {
893 fn default() -> Self {
894 Self::new()
895 }
896}
897
898impl ScalabilityAnalysis {
899 #[allow(dead_code)]
901 pub fn new() -> Self {
902 Self {
903 parallel_efficiency: HashMap::new(),
904 memory_scaling: MemoryScaling::new(),
905 bottlenecks: Vec::new(),
906 }
907 }
908}
909
910#[derive(Debug, Clone)]
912pub struct BenchmarkResults {
913 pub operation_name: String,
914 pub measurements: Vec<BenchmarkMeasurement>,
915 pub strategy_summary: HashMap<OptimizationStrategy, StrategyPerformance>,
916 pub scalability_analysis: ScalabilityAnalysis,
917 pub recommendations: Vec<String>,
918 pub total_duration: Duration,
919}
920
921impl BenchmarkResults {
922 #[allow(dead_code)]
924 pub fn new(operation_name: String) -> Self {
925 Self {
926 operation_name,
927 measurements: Vec::new(),
928 strategy_summary: HashMap::new(),
929 scalability_analysis: ScalabilityAnalysis::new(),
930 recommendations: Vec::new(),
931 total_duration: Duration::from_secs(0),
932 }
933 }
934}
935
936pub mod presets {
938 use super::*;
939
940 #[allow(dead_code)]
945 pub fn advanced_comprehensive() -> BenchmarkConfig {
946 let mut strategies = HashSet::new();
947 strategies.insert(OptimizationStrategy::Scalar);
948 strategies.insert(OptimizationStrategy::Simd);
949 strategies.insert(OptimizationStrategy::Parallel);
950 strategies.insert(OptimizationStrategy::Gpu);
951 strategies.insert(OptimizationStrategy::Hybrid);
952 strategies.insert(OptimizationStrategy::CacheOptimized);
953 strategies.insert(OptimizationStrategy::MemoryBound);
954 strategies.insert(OptimizationStrategy::ComputeBound);
955 strategies.insert(OptimizationStrategy::ModernArchOptimized);
956 strategies.insert(OptimizationStrategy::VectorOptimized);
957 strategies.insert(OptimizationStrategy::EnergyEfficient);
958 strategies.insert(OptimizationStrategy::HighThroughput);
959
960 let sample_sizes = vec![
961 100, 500, 1_000, 5_000, 10_000, 50_000, 100_000, 500_000, 1_000_000, 5_000_000,
962 10_000_000,
963 ];
964
965 BenchmarkConfig {
966 strategies,
967 sample_sizes,
968 warmup_iterations: 15,
969 measurement_iterations: 50,
970 measurement_time: Duration::from_secs(10),
971 min_duration: Duration::from_millis(10),
972 max_duration: Duration::from_secs(60),
973 confidence_level: 0.95,
974 max_cv: 0.1,
975 enable_profiling: true,
976 enable_memory_tracking: true,
977 tags: vec!["Advanced".to_string(), "comprehensive".to_string()],
978 }
979 }
980
981 #[allow(dead_code)]
986 pub fn modern_architectures() -> BenchmarkConfig {
987 let mut strategies = HashSet::new();
988 strategies.insert(OptimizationStrategy::ModernArchOptimized);
989 strategies.insert(OptimizationStrategy::VectorOptimized);
990 strategies.insert(OptimizationStrategy::EnergyEfficient);
991 strategies.insert(OptimizationStrategy::HighThroughput);
992
993 let sample_sizes = vec![1_000, 10_000, 100_000, 1_000_000, 10_000_000];
994
995 BenchmarkConfig {
996 strategies,
997 sample_sizes,
998 warmup_iterations: 10,
999 measurement_iterations: 30,
1000 measurement_time: Duration::from_secs(8),
1001 min_duration: Duration::from_millis(5),
1002 max_duration: Duration::from_secs(30),
1003 confidence_level: 0.95,
1004 max_cv: 0.1,
1005 enable_profiling: true,
1006 enable_memory_tracking: true,
1007 tags: vec!["modern".to_string(), "architecture".to_string()],
1008 }
1009 }
1010
1011 #[allow(dead_code)]
1016 pub fn array_operations() -> BenchmarkConfig {
1017 let mut strategies = HashSet::new();
1018 strategies.insert(OptimizationStrategy::Scalar);
1019 strategies.insert(OptimizationStrategy::Simd);
1020 strategies.insert(OptimizationStrategy::VectorOptimized);
1021 strategies.insert(OptimizationStrategy::CacheOptimized);
1022
1023 let sample_sizes = vec![100, 1_000, 10_000, 100_000];
1024
1025 BenchmarkConfig {
1026 strategies,
1027 sample_sizes,
1028 warmup_iterations: 10,
1029 measurement_iterations: 25,
1030 measurement_time: Duration::from_secs(5),
1031 min_duration: Duration::from_millis(1),
1032 max_duration: Duration::from_secs(15),
1033 confidence_level: 0.95,
1034 max_cv: 0.15,
1035 enable_profiling: false,
1036 enable_memory_tracking: true,
1037 tags: vec!["array".to_string(), "operations".to_string()],
1038 }
1039 }
1040
1041 #[allow(dead_code)]
1046 pub fn matrix_operations() -> BenchmarkConfig {
1047 let mut strategies = HashSet::new();
1048 strategies.insert(OptimizationStrategy::Scalar);
1049 strategies.insert(OptimizationStrategy::Parallel);
1050 strategies.insert(OptimizationStrategy::CacheOptimized);
1051 strategies.insert(OptimizationStrategy::ModernArchOptimized);
1052
1053 let sample_sizes = vec![100, 500, 1_000, 5_000];
1054
1055 BenchmarkConfig {
1056 strategies,
1057 sample_sizes,
1058 warmup_iterations: 5,
1059 measurement_iterations: 20,
1060 measurement_time: Duration::from_secs(8),
1061 min_duration: Duration::from_millis(2),
1062 max_duration: Duration::from_secs(20),
1063 confidence_level: 0.95,
1064 max_cv: 0.12,
1065 enable_profiling: true,
1066 enable_memory_tracking: true,
1067 tags: vec!["matrix".to_string(), "operations".to_string()],
1068 }
1069 }
1070
1071 #[allow(dead_code)]
1076 pub fn memory_intensive() -> BenchmarkConfig {
1077 let mut strategies = HashSet::new();
1078 strategies.insert(OptimizationStrategy::MemoryBound);
1079 strategies.insert(OptimizationStrategy::CacheOptimized);
1080 strategies.insert(OptimizationStrategy::HighThroughput);
1081
1082 let sample_sizes = vec![10_000, 100_000, 1_000_000];
1083
1084 BenchmarkConfig {
1085 strategies,
1086 sample_sizes,
1087 warmup_iterations: 3,
1088 measurement_iterations: 15,
1089 measurement_time: Duration::from_secs(12),
1090 min_duration: Duration::from_millis(5),
1091 max_duration: Duration::from_secs(45),
1092 confidence_level: 0.95,
1093 max_cv: 0.2,
1094 enable_profiling: true,
1095 enable_memory_tracking: true,
1096 tags: vec!["memory".to_string(), "intensive".to_string()],
1097 }
1098 }
1099}
1100
1101#[cfg(test)]
1102mod tests {
1103 use super::*;
1104
1105 #[test]
1106 fn test_benchmark_config() {
1107 let config = BenchmarkConfig::new()
1108 .with_warmup_iterations(5)
1109 .with_measurement_iterations(50)
1110 .with_confidence_level(0.99)
1111 .with_tag("test".to_string());
1112
1113 assert_eq!(config.warmup_iterations, 5);
1114 assert_eq!(config.measurement_iterations, 50);
1115 assert_eq!(config.confidence_level, 0.99);
1116 assert_eq!(config.tags, vec!["test"]);
1117 }
1118
1119 #[test]
1120 fn test_benchmark_measurement() {
1121 let measurement = BenchmarkMeasurement::new(Duration::from_millis(100))
1122 .with_memory_usage(1024)
1123 .with_custom_metric("ops".to_string(), 1000.0);
1124
1125 assert_eq!(measurement.execution_time, Duration::from_millis(100));
1126 assert_eq!(measurement.memory_usage, 1024);
1127 assert_eq!(measurement.custom_metrics["ops"], 1000.0);
1128 }
1129
1130 #[test]
1131 fn test_benchmark_statistics() {
1132 let measurements = vec![
1133 BenchmarkMeasurement::new(Duration::from_millis(100)),
1134 BenchmarkMeasurement::new(Duration::from_millis(110)),
1135 BenchmarkMeasurement::new(Duration::from_millis(90)),
1136 BenchmarkMeasurement::new(Duration::from_millis(105)),
1137 ];
1138
1139 let stats =
1140 BenchmarkStatistics::from_measurements(&measurements).expect("Operation failed");
1141
1142 assert_eq!(stats.sample_count, 4);
1143 assert!(stats.mean_execution_time > Duration::from_millis(95));
1144 assert!(stats.mean_execution_time < Duration::from_millis(110));
1145 assert!(stats.coefficient_of_variation > 0.0);
1146 }
1147
1148 #[test]
1149 fn test_benchmark_runner() {
1150 let config = BenchmarkConfig::new()
1151 .with_warmup_iterations(1)
1152 .with_measurement_iterations(5);
1153 let runner = BenchmarkRunner::new(config);
1154
1155 let result = runner
1156 .run("test_benchmark", || {
1157 std::thread::sleep(Duration::from_micros(100));
1159 Ok(())
1160 })
1161 .expect("Operation failed");
1162
1163 assert_eq!(result.name, "test_benchmark");
1164 assert_eq!(result.measurements.len(), 5);
1165 assert!(result.statistics.mean_execution_time > Duration::from_micros(50));
1166 }
1167}