Skip to main content

scirs2_core/benchmarking/cross_module/
mod.rs

1// Copyright 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::benchmarking::current_process_memory_bytes;
5use crate::error::{CoreError, CoreResult, ErrorContext};
6#[cfg(feature = "parallel")]
7use crate::parallel_ops::*;
8#[cfg(feature = "serialization")]
9use chrono;
10use std::collections::HashMap;
11use std::fmt;
12use std::sync::{Arc, Mutex};
13use std::time::{Duration, Instant};
14/// Cross-module performance benchmarking configuration
15#[derive(Debug, Clone)]
16pub struct CrossModuleBenchConfig {
17    /// Number of benchmark iterations
18    pub iterations: usize,
19    /// Warmup iterations before measurement
20    pub warmup_iterations: usize,
21    /// Data sizes to test
22    pub datasizes: Vec<usize>,
23    /// Thread counts to test (for parallel operations)
24    pub ns: Vec<usize>,
25    /// Memory limits for testing
26    pub memory_limits: Vec<usize>,
27    /// Enable detailed profiling
28    pub enable_profiling: bool,
29    /// Enable regression detection
30    pub enable_regression_detection: bool,
31    /// Baseline performance file path
32    pub baseline_file: Option<String>,
33    /// Maximum acceptable regression percentage
34    pub max_regression_percent: f64,
35    /// Benchmark timeout per test
36    pub timeout: Duration,
37}
38impl Default for CrossModuleBenchConfig {
39    fn default() -> Self {
40        Self {
41            iterations: 100,
42            warmup_iterations: 10,
43            datasizes: vec![1024, 1024 * 16, 1024 * 1024, 1024 * 1024 * 16],
44            ns: vec![1, 2, 4, 8],
45            memory_limits: vec![64 * 1024 * 1024, 256 * 1024 * 1024, 1024 * 1024 * 1024],
46            enable_profiling: true,
47            enable_regression_detection: true,
48            baseline_file: None,
49            max_regression_percent: 10.0,
50            timeout: Duration::from_secs(60),
51        }
52    }
53}
54/// Performance measurement result
55#[derive(Debug, Clone)]
56pub struct PerformanceMeasurement {
57    /// Operation name
58    pub name: String,
59    /// Module combination involved
60    pub modules: Vec<String>,
61    /// Data size used
62    pub datasize: usize,
63    /// Thread count used
64    pub n: usize,
65    /// Average execution time
66    pub avg_duration: Duration,
67    /// Minimum execution time
68    pub min_duration: Duration,
69    /// Maximum execution time
70    pub max_duration: Duration,
71    /// Standard deviation
72    pub std_deviation: Duration,
73    /// Throughput (operations per second)
74    pub throughput: f64,
75    /// Memory usage (bytes)
76    pub memory_usage: usize,
77    /// Peak memory usage (bytes)
78    pub peak_memory: usize,
79    /// CPU utilization percentage
80    pub cpu_utilization: f64,
81    /// Operations count
82    pub operations_count: usize,
83    /// Detailed timing breakdown
84    pub timing_breakdown: HashMap<String, Duration>,
85}
86impl PerformanceMeasurement {
87    /// Create a new performance measurement
88    pub fn new(name: String, modules: Vec<String>) -> Self {
89        Self {
90            name,
91            modules,
92            datasize: 0,
93            n: 1,
94            avg_duration: Duration::from_nanos(0),
95            min_duration: Duration::from_nanos(u64::MAX),
96            max_duration: Duration::from_nanos(0),
97            std_deviation: Duration::from_nanos(0),
98            throughput: 0.0,
99            memory_usage: 0,
100            peak_memory: 0,
101            cpu_utilization: 0.0,
102            operations_count: 0,
103            timing_breakdown: HashMap::new(),
104        }
105    }
106    /// Calculate efficiency score (0-100)
107    pub fn efficiency_score(&self) -> f64 {
108        if self.avg_duration.as_nanos() == 0 {
109            return 0.0;
110        }
111        let time_efficiency = 1.0 / (self.avg_duration.as_secs_f64() + 1e-9);
112        let memory_efficiency = if self.memory_usage > 0 {
113            self.throughput / (self.memory_usage as f64 / 1024.0 / 1024.0)
114        } else {
115            self.throughput
116        };
117        ((time_efficiency + memory_efficiency) / 2.0 * 100.0).min(100.0)
118    }
119}
120/// Benchmark suite result
121#[derive(Debug, Clone)]
122pub struct BenchmarkSuiteResult {
123    /// Suite name
124    pub name: String,
125    /// Individual measurements
126    pub measurements: Vec<PerformanceMeasurement>,
127    /// Overall suite duration
128    pub total_duration: Duration,
129    /// Average efficiency score
130    pub avg_efficiency: f64,
131    /// Regression analysis results
132    pub regression_analysis: Option<RegressionAnalysis>,
133    /// Scalability analysis
134    pub scalability_analysis: ScalabilityAnalysis,
135    /// Memory efficiency analysis
136    pub memory_analysis: MemoryEfficiencyAnalysis,
137}
138/// Regression analysis results
139#[derive(Debug, Clone)]
140pub struct RegressionAnalysis {
141    /// Whether regression was detected
142    pub regression_detected: bool,
143    /// Regressed benchmarks
144    pub regressions: Vec<RegressionResult>,
145    /// Improved benchmarks
146    pub improvements: Vec<RegressionResult>,
147    /// Overall performance change percentage
148    pub overall_change_percent: f64,
149}
150/// Individual regression result
151#[derive(Debug, Clone)]
152pub struct RegressionResult {
153    /// Benchmark name
154    pub benchmark_name: String,
155    /// Baseline performance
156    pub baseline_duration: Duration,
157    /// Current performance
158    pub current_duration: Duration,
159    /// Change percentage (positive = regression, negative = improvement)
160    pub change_percent: f64,
161    /// Significance of change
162    pub significance: RegressionSignificance,
163}
164/// Significance levels for performance changes
165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166pub enum RegressionSignificance {
167    /// Negligible change (< 5%)
168    Negligible,
169    /// Minor change (5-15%)
170    Minor,
171    /// Moderate change (15-30%)
172    Moderate,
173    /// Major change (30-50%)
174    Major,
175    /// Critical change (> 50%)
176    Critical,
177}
178/// Scalability analysis results
179#[derive(Debug, Clone)]
180pub struct ScalabilityAnalysis {
181    /// Thread scalability efficiency (0.saturating_sub(1))
182    pub thread_scalability: f64,
183    /// Data size scalability efficiency (0.saturating_sub(1))
184    pub data_scalability: f64,
185    /// Memory scalability efficiency (0.saturating_sub(1))
186    pub memory_scalability: f64,
187    /// Scalability breakdown by data size
188    pub datasize_breakdown: HashMap<usize, f64>,
189    /// Scalability breakdown by thread count
190    pub n_breakdown: HashMap<usize, f64>,
191}
192/// Memory efficiency analysis
193#[derive(Debug, Clone)]
194pub struct MemoryEfficiencyAnalysis {
195    /// Average memory usage per operation (bytes)
196    pub avg_memory_per_op: f64,
197    /// Peak to average memory ratio
198    pub peak_to_avg_ratio: f64,
199    /// Memory fragmentation score (0.saturating_sub(1), lower is better)
200    pub fragmentation_score: f64,
201    /// Zero-copy efficiency score (0.saturating_sub(1))
202    pub zero_copy_efficiency: f64,
203    /// Memory bandwidth utilization (0.saturating_sub(1))
204    pub bandwidth_utilization: f64,
205}
206/// Cross-module benchmark runner
207pub struct CrossModuleBenchmarkRunner {
208    config: CrossModuleBenchConfig,
209    results: Arc<Mutex<Vec<BenchmarkSuiteResult>>>,
210}
211impl CrossModuleBenchmarkRunner {
212    /// Create a new benchmark runner
213    pub fn new(config: CrossModuleBenchConfig) -> Self {
214        Self {
215            config,
216            results: Arc::new(Mutex::new(Vec::new())),
217        }
218    }
219    /// Run comprehensive cross-module benchmarks
220    pub fn run_benchmarks(&self) -> CoreResult<BenchmarkSuiteResult> {
221        let start_time = Instant::now();
222        let mut measurements = Vec::new();
223        println!("🚀 Running Cross-Module Performance Benchmarks");
224        println!("==============================================");
225        measurements.extend(self.run_data_pipeline_benchmarks()?);
226        measurements.extend(self.run_memory_efficiency_benchmarks()?);
227        measurements.extend(self.run_scalability_benchmarks()?);
228        measurements.extend(self.run_real_world_benchmarks()?);
229        let total_duration = start_time.elapsed();
230        let avg_efficiency = if measurements.is_empty() {
231            0.0
232        } else {
233            measurements
234                .iter()
235                .map(|m| m.efficiency_score())
236                .sum::<f64>()
237                / measurements.len() as f64
238        };
239        let regression_analysis = if self.config.enable_regression_detection {
240            Some(self.analyze_regressions(&measurements)?)
241        } else {
242            None
243        };
244        let scalability_analysis = self.analyze_scalability(&measurements)?;
245        let memory_analysis = self.analyze_memory_efficiency(&measurements)?;
246        let suite_result = BenchmarkSuiteResult {
247            name: "Cross-Module Performance Suite".to_string(),
248            measurements,
249            total_duration,
250            avg_efficiency,
251            regression_analysis,
252            scalability_analysis,
253            memory_analysis,
254        };
255        {
256            let mut results = self.results.lock().map_err(|_| {
257                CoreError::ComputationError(ErrorContext::new("Failed to lock results".to_string()))
258            })?;
259            results.push(suite_result.clone());
260        }
261        Ok(suite_result)
262    }
263    /// Run data pipeline benchmarks
264    fn run_data_pipeline_benchmarks(&self) -> CoreResult<Vec<PerformanceMeasurement>> {
265        let mut measurements = Vec::new();
266        println!("📊 Running Data Pipeline Benchmarks...");
267        measurements.push(self.benchmark_linalg_stats_pipeline()?);
268        measurements.push(self.benchmark_signal_fft_pipeline()?);
269        measurements.push(self.benchmark_io_processing_pipeline()?);
270        measurements.push(self.benchmark_ml_pipeline()?);
271        Ok(measurements)
272    }
273    /// Benchmark linear algebra + statistics pipeline
274    fn benchmark_linalg_stats_pipeline(&self) -> CoreResult<PerformanceMeasurement> {
275        let mut measurement = PerformanceMeasurement::new(
276            "linalg_stats_pipeline".to_string(),
277            vec!["scirs2-linalg".to_string(), "scirs2-stats".to_string()],
278        );
279        for &datasize in &self.config.datasizes {
280            let timing_data = self.time_operation(&format!("{datasize}"), || {
281                self.simulate_linalg_stats_workflow(datasize)
282            })?;
283            if datasize == *self.config.datasizes.last().expect("Operation failed") {
284                measurement.datasize = datasize;
285                measurement.avg_duration = timing_data.avg_duration;
286                measurement.min_duration = timing_data.min_duration;
287                measurement.max_duration = timing_data.max_duration;
288                measurement.throughput = timing_data.throughput;
289                measurement.memory_usage = timing_data.memory_usage;
290                measurement.peak_memory = timing_data.peak_memory;
291                measurement.operations_count = timing_data.operations_count;
292            }
293        }
294        Ok(measurement)
295    }
296    /// Simulate linear algebra + statistics workflow
297    fn simulate_linalg_stats_workflow(&self, datasize: usize) -> CoreResult<()> {
298        let matrix_size = (datasize as f64).sqrt() as usize;
299        let matrix_elements = matrix_size * matrix_size;
300        let operations = matrix_size.pow(3);
301        for _ in 0..operations.min(1000000) {
302            let result = 1.23456 * 7.89012 + 3.45678;
303        }
304        let stats_operations = datasize;
305        for _ in 0..stats_operations.min(1000000) {
306            let result = 1.23456_f64.sin() + 7.89012_f64.cos();
307        }
308        Ok(())
309    }
310    /// Benchmark signal processing + FFT pipeline
311    fn benchmark_signal_fft_pipeline(&self) -> CoreResult<PerformanceMeasurement> {
312        let mut measurement = PerformanceMeasurement::new(
313            "signal_fft_pipeline".to_string(),
314            vec!["scirs2-signal".to_string(), "scirs2-fft".to_string()],
315        );
316        for &datasize in &self.config.datasizes {
317            let timing_data = self.time_operation(&format!("{datasize}"), || {
318                self.simulate_signal_fft_workflow(datasize)
319            })?;
320            if datasize == *self.config.datasizes.last().expect("Operation failed") {
321                measurement.datasize = datasize;
322                measurement.avg_duration = timing_data.avg_duration;
323                measurement.throughput = timing_data.throughput;
324                measurement.memory_usage = timing_data.memory_usage;
325                measurement.peak_memory = timing_data.peak_memory;
326                measurement.operations_count = timing_data.operations_count;
327            }
328        }
329        Ok(measurement)
330    }
331    /// Simulate signal processing + FFT workflow
332    fn simulate_signal_fft_workflow(&self, datasize: usize) -> CoreResult<()> {
333        let signal_length = datasize / std::mem::size_of::<f64>();
334        let filter_operations = signal_length.min(1000000);
335        for _ in 0..filter_operations {
336            let result = 1.23456_f64.sin() * 0.78901 + 2.34567_f64.cos();
337        }
338        let fft_operations = (signal_length as f64 * (signal_length as f64).log2()) as usize;
339        for _ in 0..fft_operations.min(1000000) {
340            let result = std::f64::consts::PI * std::f64::consts::E.exp();
341        }
342        Ok(())
343    }
344    /// Benchmark data I/O + processing pipeline
345    fn benchmark_io_processing_pipeline(&self) -> CoreResult<PerformanceMeasurement> {
346        let mut measurement = PerformanceMeasurement::new(
347            "io_processing_pipeline".to_string(),
348            vec!["scirs2-io".to_string(), "scirs2-core".to_string()],
349        );
350        for &datasize in &self.config.datasizes {
351            let timing_data = self.time_operation(&format!("{datasize}"), || {
352                self.simulate_io_processing_workflow(datasize)
353            })?;
354            if datasize == *self.config.datasizes.last().expect("Operation failed") {
355                measurement.datasize = datasize;
356                measurement.avg_duration = timing_data.avg_duration;
357                measurement.throughput = timing_data.throughput;
358                measurement.memory_usage = timing_data.memory_usage;
359                measurement.peak_memory = timing_data.peak_memory;
360                measurement.operations_count = timing_data.operations_count;
361            }
362        }
363        Ok(measurement)
364    }
365    /// Simulate data I/O + processing workflow
366    fn simulate_io_processing_workflow(&self, datasize: usize) -> CoreResult<()> {
367        let buffer = vec![0u8; datasize];
368        let mut checksum = 0u64;
369        for &byte in &buffer {
370            checksum = checksum.wrapping_add(byte as u64);
371        }
372        for i in 0..datasize.min(100000) {
373            let value = (0 as f64) / datasize as f64;
374            if !value.is_finite() {
375                return Err(CoreError::ValidationError(ErrorContext::new(
376                    "Invalid value".to_string(),
377                )));
378            }
379        }
380        if checksum == u64::MAX {
381            return Err(CoreError::ComputationError(ErrorContext::new(
382                "Unlikely checksum".to_string(),
383            )));
384        }
385        Ok(())
386    }
387    /// Benchmark machine learning pipeline
388    fn benchmark_ml_pipeline(&self) -> CoreResult<PerformanceMeasurement> {
389        let mut measurement = PerformanceMeasurement::new(
390            "ml_pipeline".to_string(),
391            vec!["scirs2-neural".to_string(), "scirs2-optimize".to_string()],
392        );
393        for &datasize in &self.config.datasizes {
394            let timing_data = self.time_operation(&format!("{datasize}"), || {
395                self.simulate_ml_workflow(datasize)
396            })?;
397            if datasize == *self.config.datasizes.last().expect("Operation failed") {
398                measurement.datasize = datasize;
399                measurement.avg_duration = timing_data.avg_duration;
400                measurement.throughput = timing_data.throughput;
401                measurement.memory_usage = timing_data.memory_usage;
402                measurement.peak_memory = timing_data.peak_memory;
403                measurement.operations_count = timing_data.operations_count;
404            }
405        }
406        Ok(measurement)
407    }
408    /// Simulate machine learning workflow
409    fn simulate_ml_workflow(&self, datasize: usize) -> CoreResult<()> {
410        let feature_count = (datasize / 1000).max(10);
411        let sample_count = datasize / feature_count;
412        for _ in 0..sample_count.min(10000) {
413            for _ in 0..feature_count.min(1000) {
414                let activation = 1.0 / (1.0 + (-0.5_f64).exp());
415            }
416        }
417        for _ in 0..(feature_count * sample_count).min(100000) {
418            let gradient = 0.01 * 1.23456;
419        }
420        Ok(())
421    }
422    /// Run memory efficiency benchmarks
423    fn run_memory_efficiency_benchmarks(&self) -> CoreResult<Vec<PerformanceMeasurement>> {
424        let mut measurements = Vec::new();
425        println!("🧠 Running Memory Efficiency Benchmarks...");
426        measurements.push(self.benchmark_zero_copy_operations()?);
427        measurements.push(self.benchmark_memory_mapped_operations()?);
428        measurements.push(self.benchmark_out_of_core_operations()?);
429        Ok(measurements)
430    }
431    /// Benchmark zero-copy operations
432    fn benchmark_zero_copy_operations(&self) -> CoreResult<PerformanceMeasurement> {
433        let mut measurement = PerformanceMeasurement::new(
434            "zero_copy_operations".to_string(),
435            vec!["scirs2-core".to_string()],
436        );
437        for &datasize in &self.config.datasizes {
438            let timing_data = self.time_operation(&format!("{datasize}"), || {
439                self.simulate_zero_copy_workflow(datasize)
440            })?;
441            if datasize == *self.config.datasizes.last().expect("Operation failed") {
442                measurement.datasize = datasize;
443                measurement.avg_duration = timing_data.avg_duration;
444                measurement.throughput = timing_data.throughput;
445                measurement.memory_usage = timing_data.memory_usage;
446                measurement.peak_memory = timing_data.peak_memory;
447                measurement.operations_count = timing_data.operations_count;
448            }
449        }
450        Ok(measurement)
451    }
452    /// Simulate zero-copy operations
453    fn simulate_zero_copy_workflow(&self, datasize: usize) -> CoreResult<()> {
454        let buffer = vec![1.0f64; datasize / std::mem::size_of::<f64>()];
455        let chunk_size = buffer.len() / 4;
456        for i in 0..4 {
457            let start = i * chunk_size;
458            let end = ((i + 1) * chunk_size).min(buffer.len());
459            let slice = &buffer[start..end];
460            let mut sum = 0.0;
461            for &value in slice {
462                sum += value;
463            }
464            if sum < 0.0 {
465                return Err(CoreError::ComputationError(ErrorContext::new(
466                    "Invalid sum".to_string(),
467                )));
468            }
469        }
470        Ok(())
471    }
472    /// Benchmark memory-mapped operations
473    fn benchmark_memory_mapped_operations(&self) -> CoreResult<PerformanceMeasurement> {
474        let mut measurement = PerformanceMeasurement::new(
475            "memory_mapped_operations".to_string(),
476            vec!["scirs2-core".to_string(), "scirs2-io".to_string()],
477        );
478        println!("   Simulating memory-mapped operations...");
479        for &datasize in &self.config.datasizes {
480            let timing_data = self.time_operation(&format!("{datasize}"), || {
481                self.simulate_mmap_workflow(datasize)
482            })?;
483            if datasize == *self.config.datasizes.last().expect("Operation failed") {
484                measurement.datasize = datasize;
485                measurement.avg_duration = timing_data.avg_duration;
486                measurement.throughput = timing_data.throughput;
487                measurement.memory_usage = timing_data.memory_usage;
488                measurement.peak_memory = timing_data.peak_memory;
489                measurement.operations_count = timing_data.operations_count;
490            }
491        }
492        Ok(measurement)
493    }
494    /// Simulate memory-mapped workflow
495    fn simulate_mmap_workflow(&self, datasize: usize) -> CoreResult<()> {
496        let element_count = datasize / std::mem::size_of::<f64>();
497        let chunk_size = element_count / 16;
498        for chunk_id in 0..16 {
499            let start_idx = chunk_id * chunk_size;
500            let end_idx = ((chunk_id + 1) * chunk_size).min(element_count);
501            for idx in start_idx..end_idx {
502                let value = (idx as f64).sin();
503                if !value.is_finite() {
504                    return Err(CoreError::ComputationError(ErrorContext::new(
505                        "Invalid computation".to_string(),
506                    )));
507                }
508            }
509        }
510        Ok(())
511    }
512    /// Benchmark out-of-core operations
513    fn benchmark_out_of_core_operations(&self) -> CoreResult<PerformanceMeasurement> {
514        let mut measurement = PerformanceMeasurement::new(
515            "out_of_core_operations".to_string(),
516            vec!["scirs2-core".to_string()],
517        );
518        println!("   Simulating out-of-core operations...");
519        for &datasize in &self.config.datasizes {
520            let timing_data = self.time_operation(&format!("{datasize}"), || {
521                self.simulate_out_of_core_workflow(datasize)
522            })?;
523            if datasize == *self.config.datasizes.last().expect("Operation failed") {
524                measurement.datasize = datasize;
525                measurement.avg_duration = timing_data.avg_duration;
526                measurement.throughput = timing_data.throughput;
527                measurement.memory_usage = timing_data.memory_usage;
528                measurement.peak_memory = timing_data.peak_memory;
529                measurement.operations_count = timing_data.operations_count;
530            }
531        }
532        Ok(measurement)
533    }
534    /// Simulate out-of-core workflow
535    fn simulate_out_of_core_workflow(&self, datasize: usize) -> CoreResult<()> {
536        let total_elements = datasize / std::mem::size_of::<f64>();
537        let chunk_size = 1024;
538        let num_chunks = total_elements.div_ceil(chunk_size);
539        for chunk_idx in 0..num_chunks {
540            let start = chunk_idx * chunk_size;
541            let end = (start + chunk_size).min(total_elements);
542            let chunk_len = end - start;
543            let chunk_data = vec![1.0f64; chunk_len];
544            let mut sum = 0.0;
545            for &value in &chunk_data {
546                sum += value * value;
547            }
548            if sum < 0.0 {
549                return Err(CoreError::ComputationError(ErrorContext::new(
550                    "Invalid computation result".to_string(),
551                )));
552            }
553        }
554        Ok(())
555    }
556    /// Run scalability benchmarks
557    fn run_scalability_benchmarks(&self) -> CoreResult<Vec<PerformanceMeasurement>> {
558        let mut measurements = Vec::new();
559        println!("📈 Running Scalability Benchmarks...");
560        measurements.push(self.benchmark_thread_scalability()?);
561        measurements.push(self.benchmark_datasize_scalability()?);
562        measurements.push(self.benchmark_memory_scalability()?);
563        Ok(measurements)
564    }
565    /// Benchmark thread scalability
566    fn benchmark_thread_scalability(&self) -> CoreResult<PerformanceMeasurement> {
567        let mut measurement = PerformanceMeasurement::new(
568            "thread_scalability".to_string(),
569            vec!["scirs2-core".to_string()],
570        );
571        #[cfg(feature = "parallel")]
572        {
573            for &n in &self.config.ns {
574                let timing_data = self.time_operation(&format!("{n}"), || {
575                    self.simulate_scalable_operation(n * 1024)
576                })?;
577                if n == *self.config.ns.last().expect("Operation failed") {
578                    measurement.n = n;
579                    measurement.avg_duration = timing_data.avg_duration;
580                    measurement.throughput = timing_data.throughput;
581                    measurement.operations_count = timing_data.operations_count;
582                }
583            }
584        }
585        #[cfg(not(feature = "parallel"))]
586        {
587            measurement.n = 1;
588            measurement.avg_duration = Duration::from_millis(100);
589            measurement.throughput = 1000.0;
590            measurement.operations_count = 1000;
591        }
592        Ok(measurement)
593    }
594    /// Simulate parallel operations
595    #[cfg(feature = "parallel")]
596    fn count(n: usize) -> CoreResult<()> {
597        let work_items = 100000;
598        let items_per_thread = work_items / n;
599        crate::parallel_ops::ThreadPoolBuilder::new()
600            .num_threads(n)
601            .build()
602            .map_err(|e| CoreError::ComputationError(ErrorContext::new(format!("{e}"))))?
603            .install(|| {
604                (0..n).into_par_iter().try_for_each(|_| {
605                    for _ in 0..items_per_thread {
606                        let result = 1.23456_f64.sin() + 7.89012_f64.cos();
607                    }
608                    Ok::<(), CoreError>(())
609                })
610            })?;
611        Ok(())
612    }
613    /// Simulate parallel operations (fallback)
614    #[cfg(not(feature = "parallel"))]
615    fn count(n: usize) -> CoreResult<()> {
616        for _ in 0..100000 {
617            let result = 1.23456_f64.sin() + 7.89012_f64.cos();
618        }
619        Ok(())
620    }
621    /// Benchmark data size scalability
622    fn benchmark_datasize_scalability(&self) -> CoreResult<PerformanceMeasurement> {
623        let mut measurement = PerformanceMeasurement::new(
624            "datasize_scalability".to_string(),
625            vec!["scirs2-core".to_string()],
626        );
627        println!("   Testing data size scalability...");
628        let mut scalability_scores = Vec::new();
629        for &datasize in &self.config.datasizes {
630            let timing_data = self.time_operation(&format!("{datasize}"), || {
631                self.simulate_scalable_operation(datasize)
632            })?;
633            let ops_per_byte = timing_data.throughput / datasize as f64;
634            scalability_scores.push(ops_per_byte);
635            if datasize == *self.config.datasizes.last().expect("Operation failed") {
636                measurement.datasize = datasize;
637                measurement.avg_duration = timing_data.avg_duration;
638                measurement.throughput = timing_data.throughput;
639                measurement.memory_usage = timing_data.memory_usage;
640                measurement.peak_memory = timing_data.peak_memory;
641                measurement.operations_count = timing_data.operations_count;
642            }
643        }
644        Ok(measurement)
645    }
646    /// Simulate scalable operation for data size testing
647    fn simulate_scalable_operation(&self, datasize: usize) -> CoreResult<()> {
648        let elements = datasize / std::mem::size_of::<f64>();
649        for i in 0..elements.min(1000000) {
650            let value = (0 as f64) / elements as f64;
651            let result = value.sin() + value.cos();
652        }
653        Ok(())
654    }
655    /// Benchmark memory scalability
656    fn benchmark_memory_scalability(&self) -> CoreResult<PerformanceMeasurement> {
657        let mut measurement = PerformanceMeasurement::new(
658            "memory_scalability".to_string(),
659            vec!["scirs2-core".to_string()],
660        );
661        println!("   Testing memory scalability...");
662        for &memory_limit in &self.config.memory_limits {
663            let timing_data = self.time_operation(&format!("{memory_limit}"), || {
664                self.simulate_scalable_operation(memory_limit)
665            })?;
666            if memory_limit == *self.config.memory_limits.last().expect("Operation failed") {
667                measurement.memory_usage = memory_limit;
668                measurement.avg_duration = timing_data.avg_duration;
669                measurement.throughput = timing_data.throughput;
670                measurement.operations_count = timing_data.operations_count;
671            }
672        }
673        Ok(measurement)
674    }
675    /// Simulate memory-constrained operation
676    fn limit(n: usize) -> CoreResult<()> {
677        let element_count = (n / std::mem::size_of::<f64>()).min(1000000);
678        let buffer = vec![1.0f64; element_count];
679        let mut result = 0.0;
680        for (i, &value) in buffer.iter().enumerate() {
681            result += value * (i as f64).sqrt();
682        }
683        if result < 0.0 {
684            return Err(CoreError::ComputationError(ErrorContext::new(
685                "Invalid result".to_string(),
686            )));
687        }
688        Ok(())
689    }
690    /// Run real-world scenario benchmarks
691    fn run_real_world_benchmarks(&self) -> CoreResult<Vec<PerformanceMeasurement>> {
692        let mut measurements = Vec::new();
693        println!("🌍 Running Real-World Scenario Benchmarks...");
694        measurements.push(self.benchmark_scientific_simulation()?);
695        measurements.push(self.benchmark_data_analysis_pipeline()?);
696        measurements.push(self.benchmark_machine_learning_training()?);
697        Ok(measurements)
698    }
699    /// Benchmark scientific simulation scenario
700    fn benchmark_scientific_simulation(&self) -> CoreResult<PerformanceMeasurement> {
701        let mut measurement = PerformanceMeasurement::new(
702            "scientific_simulation".to_string(),
703            vec!["scirs2-linalg".to_string(), "scirs2-integrate".to_string()],
704        );
705        println!("   Running scientific simulation benchmark...");
706        for &datasize in &self.config.datasizes {
707            let timing_data = self.time_operation(&format!("{datasize}"), || {
708                self.simulate_scientific_workflow(datasize)
709            })?;
710            if datasize == *self.config.datasizes.last().expect("Operation failed") {
711                measurement.datasize = datasize;
712                measurement.avg_duration = timing_data.avg_duration;
713                measurement.throughput = timing_data.throughput;
714                measurement.memory_usage = timing_data.memory_usage;
715                measurement.peak_memory = timing_data.peak_memory;
716                measurement.operations_count = timing_data.operations_count;
717            }
718        }
719        Ok(measurement)
720    }
721    /// Simulate scientific simulation workflow
722    fn simulate_scientific_workflow(&self, datasize: usize) -> CoreResult<()> {
723        let grid_size = (datasize as f64).sqrt() as usize;
724        let time_steps = 100;
725        for i in 0..grid_size {
726            for j in 0..grid_size {
727                let x = 0 as f64 / grid_size as f64;
728                let y = j as f64 / grid_size as f64;
729                let initial_value = (x * x + y * y).exp() * (-x * y).sin();
730            }
731        }
732        for _step in 0..time_steps {
733            for i in 1..(grid_size - 1) {
734                for _j in 1..(grid_size - 1) {
735                    let dt = 0.01;
736                    let dx = 1.0 / grid_size as f64;
737                    let laplacian = dt / (dx * dx);
738                }
739            }
740            let matrix_ops = grid_size * grid_size / 100;
741            for _ in 0..matrix_ops {
742                let result = 1.23456_f64.sin() + 0.78901_f64.cos();
743            }
744        }
745        Ok(())
746    }
747    /// Benchmark data analysis pipeline scenario
748    fn benchmark_data_analysis_pipeline(&self) -> CoreResult<PerformanceMeasurement> {
749        let mut measurement = PerformanceMeasurement::new(
750            "data_analysis_pipeline".to_string(),
751            vec![
752                "scirs2-io".to_string(),
753                "scirs2-stats".to_string(),
754                "scirs2-signal".to_string(),
755            ],
756        );
757        println!("   Running data analysis pipeline benchmark...");
758        for &datasize in &self.config.datasizes {
759            let timing_data = self.time_operation(&format!("{datasize}"), || {
760                self.simulate_data_analysis_workflow(datasize)
761            })?;
762            if datasize == *self.config.datasizes.last().expect("Operation failed") {
763                measurement.datasize = datasize;
764                measurement.avg_duration = timing_data.avg_duration;
765                measurement.throughput = timing_data.throughput;
766                measurement.memory_usage = timing_data.memory_usage;
767                measurement.peak_memory = timing_data.peak_memory;
768                measurement.operations_count = timing_data.operations_count;
769            }
770        }
771        Ok(measurement)
772    }
773    /// Simulate data analysis workflow
774    fn simulate_data_analysis_workflow(&self, datasize: usize) -> CoreResult<()> {
775        let sample_count = datasize / std::mem::size_of::<f64>();
776        let raw_data = vec![0.0f64; sample_count];
777        let mut processed_data = Vec::with_capacity(sample_count);
778        for (i, &value) in raw_data.iter().enumerate() {
779            let cleaned_value = value + (i as f64 * 0.01).sin();
780            processed_data.push(cleaned_value);
781        }
782        let mut sum = 0.0;
783        let mut sum_squares = 0.0;
784        for &value in &processed_data {
785            sum += value;
786            sum_squares += value * value;
787        }
788        let mean = sum / processed_data.len() as f64;
789        let variance = (sum_squares / processed_data.len() as f64) - (mean * mean);
790        for (i, &value) in processed_data.iter().enumerate() {
791            let freq = 2.0 * std::f64::consts::PI * (i as f64) / sample_count as f64;
792            let filtered = value * freq.cos();
793        }
794        if variance < 0.0 {
795            return Err(CoreError::ComputationError(ErrorContext::new(
796                "Invalid variance".to_string(),
797            )));
798        }
799        Ok(())
800    }
801    /// Benchmark machine learning training scenario
802    fn benchmark_machine_learning_training(&self) -> CoreResult<PerformanceMeasurement> {
803        let mut measurement = PerformanceMeasurement::new(
804            "ml_training".to_string(),
805            vec![
806                "scirs2-neural".to_string(),
807                "scirs2-optimize".to_string(),
808                "scirs2-linalg".to_string(),
809            ],
810        );
811        println!("   Running ML training benchmark...");
812        for &datasize in &self.config.datasizes {
813            let timing_data = self.time_operation(&format!("{datasize}"), || {
814                self.simulate_ml_training_workflow(datasize)
815            })?;
816            if datasize == *self.config.datasizes.last().expect("Operation failed") {
817                measurement.datasize = datasize;
818                measurement.avg_duration = timing_data.avg_duration;
819                measurement.throughput = timing_data.throughput;
820                measurement.memory_usage = timing_data.memory_usage;
821                measurement.peak_memory = timing_data.peak_memory;
822                measurement.operations_count = timing_data.operations_count;
823            }
824        }
825        Ok(measurement)
826    }
827    /// Simulate machine learning training workflow
828    fn simulate_ml_training_workflow(&self, datasize: usize) -> CoreResult<()> {
829        let batch_size = 32;
830        let feature_dim = 128;
831        let hidden_dim = 256;
832        let numbatches = (datasize / (batch_size * feature_dim)).max(1);
833        let epochs = 10;
834        for _epoch in 0..epochs {
835            for _batch in 0..numbatches {
836                for i in 0..batch_size {
837                    for j in 0..hidden_dim {
838                        let mut activation = 0.0;
839                        for k in 0..feature_dim {
840                            let weight = ((i + j + k) as f64) * 0.01;
841                            let input = ((i * k) as f64) * 0.001;
842                            activation += weight * input;
843                        }
844                        let output = 1.0 / (1.0 + (-activation).exp());
845                    }
846                }
847                for i in 0..hidden_dim {
848                    for j in 0..feature_dim {
849                        let gradient = ((i + j) as f64) * 0.001;
850                        let weight_update = gradient * 0.01;
851                    }
852                }
853                let param_count = hidden_dim * feature_dim;
854                for _ in 0..param_count / 1000 {
855                    let momentum_update = 0.9 * 0.01 + 0.1 * 0.001;
856                }
857            }
858        }
859        Ok(())
860    }
861    /// Time an operation with multiple iterations, measuring real
862    /// wall-clock duration and real resident-memory usage (`VmRSS` deltas
863    /// on Linux; `0` — "not measured" — elsewhere, never a fabricated
864    /// constant) per iteration.
865    fn time_operation<F>(&self, name: &str, mut operation: F) -> CoreResult<TimingData>
866    where
867        F: FnMut() -> CoreResult<()>,
868    {
869        let mut durations = Vec::new();
870        let mut memory_deltas = Vec::new();
871        for _ in 0..self.config.warmup_iterations {
872            operation()?;
873        }
874        for _ in 0..self.config.iterations {
875            let memory_before = current_process_memory_bytes();
876            let start = Instant::now();
877            operation()?;
878            let duration = start.elapsed();
879            let memory_after = current_process_memory_bytes();
880            durations.push(duration);
881            memory_deltas.push(memory_after.saturating_sub(memory_before));
882        }
883        let total_duration: Duration = durations.iter().sum();
884        let avg_duration = total_duration / durations.len() as u32;
885        let min_duration = *durations.iter().min().expect("Operation failed");
886        let max_duration = *durations.iter().max().expect("Operation failed");
887        let variance = durations
888            .iter()
889            .map(|d| {
890                let diff = d.as_nanos() as i128 - avg_duration.as_nanos() as i128;
891                (diff * diff) as u128
892            })
893            .sum::<u128>()
894            / durations.len() as u128;
895        let std_deviation = Duration::from_nanos((variance as f64).sqrt() as u64);
896        let throughput = if avg_duration.as_secs_f64() > 0.0 {
897            self.config.iterations as f64 / avg_duration.as_secs_f64()
898        } else {
899            0.0
900        };
901        let memory_usage = memory_deltas.iter().sum::<usize>() / memory_deltas.len().max(1);
902        let peak_memory = memory_deltas.iter().copied().max().unwrap_or(0);
903        Ok(TimingData {
904            name: name.to_string(),
905            avg_duration,
906            min_duration,
907            max_duration,
908            std_deviation,
909            throughput,
910            memory_usage,
911            peak_memory,
912            operations_count: self.config.iterations,
913        })
914    }
915    /// Analyze performance regressions against a statistical baseline derived from
916    /// the current measurement set. Each benchmark's timing is compared to the
917    /// fleet-wide mean; an entry is a regression when its duration exceeds
918    /// `mean + 2 * std_dev` (simplified z-score outlier) or when the
919    /// configured `max_regression_percent` threshold is crossed relative to a
920    /// stored external baseline (if `baseline_file` is set).
921    ///
922    /// When no external baseline is available the method uses intra-suite
923    /// statistics so regressions can still be detected from a single run
924    /// (e.g. one benchmark taking abnormally longer than all others).
925    fn analyze_regressions(
926        &self,
927        measurements: &[PerformanceMeasurement],
928    ) -> CoreResult<RegressionAnalysis> {
929        if measurements.is_empty() {
930            return Ok(RegressionAnalysis {
931                regression_detected: false,
932                regressions: Vec::new(),
933                improvements: Vec::new(),
934                overall_change_percent: 0.0,
935            });
936        }
937        let durations_ns: Vec<f64> = measurements
938            .iter()
939            .map(|m| m.avg_duration.as_nanos() as f64)
940            .collect();
941        let n = durations_ns.len() as f64;
942        let mean_ns = durations_ns.iter().sum::<f64>() / n;
943        let variance_ns = durations_ns
944            .iter()
945            .map(|&d| {
946                let diff = d - mean_ns;
947                diff * diff
948            })
949            .sum::<f64>()
950            / n;
951        let std_ns = variance_ns.sqrt();
952        let mut baseline_map: HashMap<String, f64> = HashMap::new();
953        if let Some(ref path) = self.config.baseline_file {
954            if let Ok(contents) = std::fs::read_to_string(path) {
955                for line in contents.lines() {
956                    let parts: Vec<&str> = line.splitn(2, ' ').collect();
957                    if parts.len() == 2 {
958                        if let Ok(nanos) = parts[1].trim().parse::<f64>() {
959                            baseline_map.insert(parts[0].trim().to_string(), nanos);
960                        }
961                    }
962                }
963            }
964        }
965        let mut regressions: Vec<RegressionResult> = Vec::new();
966        let mut improvements: Vec<RegressionResult> = Vec::new();
967        let mut total_change_sum = 0.0_f64;
968        let threshold_factor = self.config.max_regression_percent / 100.0;
969        for m in measurements {
970            let current_ns = m.avg_duration.as_nanos() as f64;
971            let baseline_ns = baseline_map.get(&m.name).copied().unwrap_or(mean_ns);
972            let change_percent = if baseline_ns > 0.0 {
973                (current_ns - baseline_ns) / baseline_ns * 100.0
974            } else {
975                0.0
976            };
977            let z_score = if std_ns > 0.0 {
978                (current_ns - mean_ns) / std_ns
979            } else {
980                0.0
981            };
982            let is_regression = change_percent > threshold_factor * 100.0 || z_score > 2.0;
983            let is_improvement = change_percent < -(threshold_factor * 100.0) || z_score < -2.0;
984            let significance = {
985                let abs_change = change_percent.abs();
986                if abs_change < 5.0 {
987                    RegressionSignificance::Negligible
988                } else if abs_change < 15.0 {
989                    RegressionSignificance::Minor
990                } else if abs_change < 30.0 {
991                    RegressionSignificance::Moderate
992                } else if abs_change < 50.0 {
993                    RegressionSignificance::Major
994                } else {
995                    RegressionSignificance::Critical
996                }
997            };
998            let result = RegressionResult {
999                benchmark_name: m.name.clone(),
1000                baseline_duration: Duration::from_nanos(baseline_ns.max(0.0) as u64),
1001                current_duration: m.avg_duration,
1002                change_percent,
1003                significance,
1004            };
1005            if is_regression {
1006                regressions.push(result);
1007            } else if is_improvement {
1008                improvements.push(result);
1009            }
1010            total_change_sum += change_percent;
1011        }
1012        let overall_change_percent = total_change_sum / measurements.len() as f64;
1013        let regression_detected = !regressions.is_empty();
1014        Ok(RegressionAnalysis {
1015            regression_detected,
1016            regressions,
1017            improvements,
1018            overall_change_percent,
1019        })
1020    }
1021    /// Analyze scalability characteristics
1022    fn analyze_scalability(
1023        &self,
1024        measurements: &[PerformanceMeasurement],
1025    ) -> CoreResult<ScalabilityAnalysis> {
1026        let mut datasize_breakdown = HashMap::new();
1027        let mut n_breakdown = HashMap::new();
1028        for measurement in measurements {
1029            if measurement.datasize > 0 {
1030                datasize_breakdown
1031                    .insert(measurement.datasize, measurement.efficiency_score() / 100.0);
1032            }
1033            if measurement.n > 0 {
1034                n_breakdown.insert(measurement.n, measurement.efficiency_score() / 100.0);
1035            }
1036        }
1037        let scalability_analysis = ScalabilityAnalysis {
1038            thread_scalability: Self::retained_efficiency_score(&n_breakdown),
1039            data_scalability: Self::retained_efficiency_score(&datasize_breakdown),
1040            memory_scalability: Self::memory_scalability_score(measurements),
1041            datasize_breakdown,
1042            n_breakdown,
1043        };
1044        Ok(scalability_analysis)
1045    }
1046    /// How well efficiency is retained as a breakdown key (thread count or
1047    /// data size) grows from its smallest to largest value observed in this
1048    /// run: `efficiency(largest) / efficiency(smallest)`, clamped to
1049    /// `[0, 1]`. A single observed key has nothing to compare against and
1050    /// conservatively scores `1.0` (no evidence of degradation), rather
1051    /// than a fabricated constant regardless of the data.
1052    fn retained_efficiency_score(breakdown: &HashMap<usize, f64>) -> f64 {
1053        let mut keys: Vec<usize> = breakdown.keys().copied().collect();
1054        keys.sort_unstable();
1055        let (Some(&smallest), Some(&largest)) = (keys.first(), keys.last()) else {
1056            return 1.0;
1057        };
1058        if smallest == largest {
1059            return 1.0;
1060        }
1061        let eff_small = breakdown[&smallest];
1062        let eff_large = breakdown[&largest];
1063        if eff_small <= 0.0 {
1064            return if eff_large > 0.0 { 1.0 } else { 0.0 };
1065        }
1066        (eff_large / eff_small).clamp(0.0, 1.0)
1067    }
1068    /// How well memory usage scales with data size: ideally memory grows no
1069    /// faster than the data being processed (linear or better). Computed as
1070    /// `(data_growth / memory_growth)` between the smallest- and
1071    /// largest-`datasize` measurements, clamped to `[0, 1]` (a ratio `< 1`
1072    /// means memory grew faster than the data size, i.e. worse-than-linear
1073    /// scaling).
1074    fn memory_scalability_score(measurements: &[PerformanceMeasurement]) -> f64 {
1075        let mut by_size: Vec<(usize, usize)> = measurements
1076            .iter()
1077            .filter(|m| m.datasize > 0)
1078            .map(|m| (m.datasize, m.memory_usage))
1079            .collect();
1080        by_size.sort_unstable_by_key(|&(size, _)| size);
1081        let (Some(&(small_size, small_mem)), Some(&(large_size, large_mem))) =
1082            (by_size.first(), by_size.last())
1083        else {
1084            return 1.0;
1085        };
1086        if small_size == large_size || small_mem == 0 {
1087            return 1.0;
1088        }
1089        let data_growth = large_size as f64 / small_size as f64;
1090        let mem_growth = large_mem as f64 / small_mem as f64;
1091        if mem_growth <= 0.0 {
1092            return 1.0;
1093        }
1094        (data_growth / mem_growth).clamp(0.0, 1.0)
1095    }
1096    /// Analyze memory efficiency
1097    fn analyze_memory_efficiency(
1098        &self,
1099        measurements: &[PerformanceMeasurement],
1100    ) -> CoreResult<MemoryEfficiencyAnalysis> {
1101        let total_operations: usize = measurements.iter().map(|m| m.operations_count).sum();
1102        let total_memory: usize = measurements.iter().map(|m| m.memory_usage).sum();
1103        let avg_memory_per_op = if total_operations > 0 {
1104            total_memory as f64 / total_operations as f64
1105        } else {
1106            0.0
1107        };
1108        let avg_memory_usage = if measurements.is_empty() {
1109            0.0
1110        } else {
1111            total_memory as f64 / measurements.len() as f64
1112        };
1113        let overall_peak_memory = measurements
1114            .iter()
1115            .map(|m| m.peak_memory)
1116            .max()
1117            .unwrap_or(0);
1118        let peak_to_avg_ratio = if avg_memory_usage > 0.0 {
1119            overall_peak_memory as f64 / avg_memory_usage
1120        } else {
1121            1.0
1122        };
1123        let per_benchmark_peak_ratios: Vec<f64> = measurements
1124            .iter()
1125            .filter(|m| m.memory_usage > 0)
1126            .map(|m| (m.peak_memory as f64 / m.memory_usage as f64 - 1.0).max(0.0))
1127            .collect();
1128        let fragmentation_score = if per_benchmark_peak_ratios.is_empty() {
1129            0.0
1130        } else {
1131            (per_benchmark_peak_ratios.iter().sum::<f64>() / per_benchmark_peak_ratios.len() as f64)
1132                .min(1.0)
1133        };
1134        let cross_module: Vec<&PerformanceMeasurement> = measurements
1135            .iter()
1136            .filter(|m| m.modules.len() > 1)
1137            .collect();
1138        let zero_copy_efficiency = if cross_module.is_empty() {
1139            1.0
1140        } else {
1141            let efficient = cross_module
1142                .iter()
1143                .filter(|m| (m.memory_usage as f64) <= avg_memory_usage.max(1.0))
1144                .count();
1145            efficient as f64 / cross_module.len() as f64
1146        };
1147        let max_throughput = measurements
1148            .iter()
1149            .map(|m| m.throughput)
1150            .fold(0.0_f64, f64::max);
1151        let avg_throughput = if measurements.is_empty() {
1152            0.0
1153        } else {
1154            measurements.iter().map(|m| m.throughput).sum::<f64>() / measurements.len() as f64
1155        };
1156        let bandwidth_utilization = if max_throughput > 0.0 {
1157            (avg_throughput / max_throughput).clamp(0.0, 1.0)
1158        } else {
1159            0.0
1160        };
1161        let memory_analysis = MemoryEfficiencyAnalysis {
1162            avg_memory_per_op,
1163            peak_to_avg_ratio,
1164            fragmentation_score,
1165            zero_copy_efficiency,
1166            bandwidth_utilization,
1167        };
1168        Ok(memory_analysis)
1169    }
1170    /// Generate comprehensive benchmark report
1171    pub fn generate_benchmark_report(&self) -> CoreResult<String> {
1172        let results = self.results.lock().map_err(|_| {
1173            CoreError::ComputationError(ErrorContext::new("Failed to lock results".to_string()))
1174        })?;
1175        if results.is_empty() {
1176            return Ok("No benchmark results available.".to_string());
1177        }
1178        let latest = &results[results.len() - 1];
1179        let mut report = String::new();
1180        report.push_str("# SciRS2 Cross-Module Performance Benchmark Report\n\n");
1181        #[cfg(feature = "serialization")]
1182        {
1183            report.push_str(&format!(
1184                "**Generated**: {}\n",
1185                chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC")
1186            ));
1187        }
1188        #[cfg(not(feature = "serialization"))]
1189        {
1190            report.push_str("**Generated**: [timestamp unavailable]\n");
1191        }
1192        report.push_str(&format!("**Suite**: {}\n", latest.name));
1193        report.push_str(&format!(
1194            "**Total Duration**: {:?}\n",
1195            latest.total_duration
1196        ));
1197        report.push_str(&format!(
1198            "**Average Efficiency**: {:.1}%\n\n",
1199            latest.avg_efficiency
1200        ));
1201        report.push_str("## Executive Summary\n\n");
1202        report.push_str(&format!(
1203            "- **Benchmarks Executed**: {}\n",
1204            latest.measurements.len()
1205        ));
1206        report.push_str(&format!(
1207            "- **Overall Efficiency**: {:.1}%\n",
1208            latest.avg_efficiency
1209        ));
1210        report.push_str(&format!(
1211            "- **Thread Scalability**: {:.1}%\n",
1212            latest.scalability_analysis.thread_scalability * 100.0
1213        ));
1214        report.push_str(&format!(
1215            "- **Memory Efficiency**: {:.1}%\n",
1216            (1.0 - latest.memory_analysis.fragmentation_score) * 100.0
1217        ));
1218        report.push_str("\n## Benchmark Results\n\n");
1219        for measurement in &latest.measurements {
1220            report.push_str(&format!(
1221                "### {} ({})\n",
1222                measurement.name,
1223                measurement.modules.join(" + ")
1224            ));
1225            report.push_str(&format!(
1226                "- **Data Size**: {} bytes\n",
1227                measurement.datasize
1228            ));
1229            report.push_str(&format!(
1230                "- **Average Time**: {:?}\n",
1231                measurement.avg_duration
1232            ));
1233            report.push_str(&format!(
1234                "- **Throughput**: {:.2} ops/sec\n",
1235                measurement.throughput
1236            ));
1237            report.push_str(&format!(
1238                "- **Memory Usage**: {} MB\n",
1239                measurement.memory_usage / (1024 * 1024)
1240            ));
1241            report.push_str(&format!(
1242                "- **Efficiency Score**: {:.1}%\n",
1243                measurement.efficiency_score()
1244            ));
1245            report.push('\n');
1246        }
1247        report.push_str("## Scalability Analysis\n\n");
1248        report.push_str(&format!(
1249            "- **Thread Scalability**: {:.1}%\n",
1250            latest.scalability_analysis.thread_scalability * 100.0
1251        ));
1252        report.push_str(&format!(
1253            "- **Data Size Scalability**: {:.1}%\n",
1254            latest.scalability_analysis.data_scalability * 100.0
1255        ));
1256        report.push_str(&format!(
1257            "- **Memory Scalability**: {:.1}%\n",
1258            latest.scalability_analysis.memory_scalability * 100.0
1259        ));
1260        report.push_str("\n## Memory Efficiency Analysis\n\n");
1261        report.push_str(&format!(
1262            "- **Average Memory per Operation**: {:.2} bytes\n",
1263            latest.memory_analysis.avg_memory_per_op
1264        ));
1265        report.push_str(&format!(
1266            "- **Peak to Average Ratio**: {:.2}\n",
1267            latest.memory_analysis.peak_to_avg_ratio
1268        ));
1269        report.push_str(&format!(
1270            "- **Fragmentation Score**: {:.3} (lower is better)\n",
1271            latest.memory_analysis.fragmentation_score
1272        ));
1273        report.push_str(&format!(
1274            "- **Zero-Copy Efficiency**: {:.1}%\n",
1275            latest.memory_analysis.zero_copy_efficiency * 100.0
1276        ));
1277        if let Some(regression) = &latest.regression_analysis {
1278            report.push_str("\n## Regression Analysis\n\n");
1279            if regression.regression_detected {
1280                report.push_str("⚠️ **Performance regressions detected**\n\n");
1281                for reg in &regression.regressions {
1282                    report.push_str(&format!(
1283                        "- **{}**: {:.2}% regression\n",
1284                        reg.benchmark_name, reg.change_percent
1285                    ));
1286                }
1287            } else {
1288                report.push_str("✅ **No significant regressions detected**\n");
1289            }
1290        }
1291        report.push_str("\n## Recommendations\n\n");
1292        if latest.avg_efficiency >= 80.0 {
1293            report.push_str(
1294                "✅ **Excellent Performance**: The cross-module performance is very good.\n",
1295            );
1296        } else if latest.avg_efficiency >= 60.0 {
1297            report.push_str(
1298                "⚠️ **Good Performance**: Consider optimizing bottlenecks identified above.\n",
1299            );
1300        } else {
1301            report
1302                .push_str(
1303                    "❌ **Performance Issues**: Significant optimization work needed before 1.0 release.\n",
1304                );
1305        }
1306        Ok(report)
1307    }
1308}
1309/// Internal timing data structure
1310#[derive(Debug)]
1311struct TimingData {
1312    name: String,
1313    avg_duration: Duration,
1314    min_duration: Duration,
1315    max_duration: Duration,
1316    std_deviation: Duration,
1317    throughput: f64,
1318    memory_usage: usize,
1319    peak_memory: usize,
1320    operations_count: usize,
1321}
1322impl fmt::Display for RegressionSignificance {
1323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1324        match self {
1325            RegressionSignificance::Negligible => write!(f, "Negligible"),
1326            RegressionSignificance::Minor => write!(f, "Minor"),
1327            RegressionSignificance::Moderate => write!(f, "Moderate"),
1328            RegressionSignificance::Major => write!(f, "Major"),
1329            RegressionSignificance::Critical => write!(f, "Critical"),
1330        }
1331    }
1332}
1333/// Convenience function to create a default benchmark suite
1334#[allow(dead_code)]
1335pub fn create_default_benchmark_suite() -> CoreResult<CrossModuleBenchmarkRunner> {
1336    let config = CrossModuleBenchConfig::default();
1337    Ok(CrossModuleBenchmarkRunner::new(config))
1338}
1339/// Convenience function to run quick benchmarks for CI/CD
1340#[allow(dead_code)]
1341pub fn run_quick_benchmarks() -> CoreResult<BenchmarkSuiteResult> {
1342    let config = CrossModuleBenchConfig {
1343        iterations: 2,
1344        warmup_iterations: 1,
1345        datasizes: vec![1024],
1346        ns: vec![1],
1347        memory_limits: vec![64 * 1024 * 1024],
1348        enable_profiling: false,
1349        enable_regression_detection: false,
1350        timeout: Duration::from_secs(30),
1351        ..Default::default()
1352    };
1353    let runner = CrossModuleBenchmarkRunner::new(config);
1354    runner.run_benchmarks()
1355}
1356
1357#[cfg(test)]
1358mod tests;