use crate::error::{StatsError, StatsResult};
use scirs2_core::ndarray::Array1;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::fs;
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CrossPlatformRegressionConfig {
pub baseline_storage_path: String,
pub regression_threshold_percent: f64,
pub significance_level: f64,
pub min_samples_: usize,
pub maxdata_retention_days: usize,
pub platform_specificbaselines: bool,
pub hardware_aware_normalization: bool,
pub compiler_optimization_detection: bool,
pub trend_analysis: bool,
pub target_platforms: Vec<PlatformInfo>,
pub monitored_functions: Vec<String>,
}
impl Default for CrossPlatformRegressionConfig {
fn default() -> Self {
Self {
baseline_storage_path: "./performancebaselines".to_string(),
regression_threshold_percent: 10.0, significance_level: 0.05,
min_samples_: 30,
maxdata_retention_days: 90,
platform_specificbaselines: true,
hardware_aware_normalization: true,
compiler_optimization_detection: true,
trend_analysis: true,
target_platforms: vec![PlatformInfo::current_platform()],
monitored_functions: vec![
"mean".to_string(),
"std".to_string(),
"variance".to_string(),
"pearsonr".to_string(),
"ttest_ind".to_string(),
"norm_pdf".to_string(),
"norm_cdf".to_string(),
],
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct PlatformInfo {
pub os: String,
pub arch: String,
pub cpu_model: String,
pub cpu_cores: usize,
pub memory_gb: usize,
pub rustc_version: String,
pub optimization_level: String,
pub simd_capabilities: Vec<String>,
}
impl PlatformInfo {
pub fn current_platform() -> Self {
Self {
os: std::env::consts::OS.to_string(),
arch: std::env::consts::ARCH.to_string(),
cpu_model: Self::detect_cpu_model(),
cpu_cores: num_cpus::get(),
memory_gb: Self::detect_memory_gb(),
rustc_version: Self::detect_rustc_version(),
optimization_level: Self::detect_optimization_level(),
simd_capabilities: Self::detect_simd_capabilities(),
}
}
fn detect_cpu_model() -> String {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx512f") {
"Intel AVX-512 Compatible".to_string()
} else if is_x86_feature_detected!("avx2") {
"Intel AVX2 Compatible".to_string()
} else if is_x86_feature_detected!("sse4.1") {
"Intel SSE4.1 Compatible".to_string()
} else {
"x86_64 Generic".to_string()
}
}
#[cfg(not(target_arch = "x86_64"))]
{
std::env::consts::ARCH.to_string()
}
}
fn detect_memory_gb() -> usize {
8 }
fn detect_rustc_version() -> String {
option_env!("RUSTC_VERSION")
.unwrap_or("unknown")
.to_string()
}
fn detect_optimization_level() -> String {
#[cfg(debug_assertions)]
{
"debug".to_string()
}
#[cfg(not(debug_assertions))]
{
"release".to_string()
}
}
fn detect_simd_capabilities() -> Vec<String> {
let mut capabilities = Vec::new();
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("sse2") {
capabilities.push("sse2".to_string());
}
if is_x86_feature_detected!("sse4.1") {
capabilities.push("sse4.1".to_string());
}
if is_x86_feature_detected!("avx") {
capabilities.push("avx".to_string());
}
if is_x86_feature_detected!("avx2") {
capabilities.push("avx2".to_string());
}
if is_x86_feature_detected!("avx512f") {
capabilities.push("avx512f".to_string());
}
if is_x86_feature_detected!("fma") {
capabilities.push("fma".to_string());
}
}
capabilities
}
pub fn platform_id(&self) -> String {
format!(
"{}-{}-{}-{}",
self.os,
self.arch,
self.optimization_level,
self.simd_capabilities.join("_")
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceBaseline {
pub platform: PlatformInfo,
pub function_name: String,
pub input_parameters: String,
pub measurements: Vec<PerformanceMeasurement>,
pub statistics: BaselineStatistics,
pub last_updated: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceMeasurement {
pub timestamp: u64,
pub execution_time_ns: f64,
pub memory_usage_bytes: usize,
pub iterations: usize,
pub hardware_context: HardwareContext,
pub compiler_context: CompilerContext,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HardwareContext {
pub cpu_utilization: f64,
pub available_memory_percent: f64,
pub cpu_frequency_mhz: f64,
pub temperature_celsius: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompilerContext {
pub rustc_version: String,
pub target_triple: String,
pub optimization_flags: Vec<String>,
pub feature_flags: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BaselineStatistics {
pub mean_time_ns: f64,
pub std_dev_time_ns: f64,
pub median_time_ns: f64,
pub p95_time_ns: f64,
pub p99_time_ns: f64,
pub coefficient_of_variation: f64,
pub confidence_interval_95: (f64, f64),
pub sample_count: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegressionAnalysisResult {
pub function_name: String,
pub platform_comparison: PlatformComparison,
pub current_measurement: PerformanceMeasurement,
pub baseline_performance: BaselineStatistics,
pub regression_detected: bool,
pub performance_change_percent: f64,
pub statistical_significance: f64,
pub confidence_level: f64,
pub trend_analysis: Option<TrendAnalysis>,
pub recommendations: Vec<PerformanceRecommendation>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlatformComparison {
pub current_platform: PlatformInfo,
pub baseline_platform: PlatformInfo,
pub hardware_normalization_factor: f64,
pub platform_similarity_score: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrendAnalysis {
pub trend_direction: TrendDirection,
pub trend_strength: f64,
pub slope_ns_per_day: f64,
pub r_squared: f64,
pub predicted_performance_30d: f64,
pub trend_significance: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TrendDirection {
Improving,
Stable,
Degrading,
Volatile,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceRecommendation {
pub category: RecommendationCategory,
pub priority: RecommendationPriority,
pub description: String,
pub expected_impact_percent: f64,
pub confidence: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RecommendationCategory {
CompilerOptimization,
AlgorithmSelection,
SIMDOptimization,
MemoryOptimization,
ParallelProcessing,
PlatformSpecific,
HardwareUpgrade,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RecommendationPriority {
Low,
Medium,
High,
Critical,
}
pub struct CrossPlatformRegressionDetector {
config: CrossPlatformRegressionConfig,
baselines: HashMap<String, PerformanceBaseline>,
historicaldata: BTreeMap<u64, Vec<PerformanceMeasurement>>,
}
impl CrossPlatformRegressionDetector {
pub fn new(config: CrossPlatformRegressionConfig) -> StatsResult<Self> {
let mut detector = Self {
config,
baselines: HashMap::new(),
historicaldata: BTreeMap::new(),
};
detector.loadbaselines()?;
Ok(detector)
}
fn loadbaselines(&mut self) -> StatsResult<()> {
if !Path::new(&self.config.baseline_storage_path).exists() {
fs::create_dir_all(&self.config.baseline_storage_path).map_err(|e| {
StatsError::InvalidInput(format!("Failed to create baseline directory: {}", e))
})?;
return Ok(());
}
let baseline_dir = Path::new(&self.config.baseline_storage_path);
if let Ok(entries) = fs::read_dir(baseline_dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.extension().is_some_and(|ext| ext == "json") {
if let Ok(content) = fs::read_to_string(&path) {
if let Ok(baseline) = serde_json::from_str::<PerformanceBaseline>(&content)
{
let key = format!(
"{}-{}",
baseline.platform.platform_id(),
baseline.function_name
);
self.baselines.insert(key, baseline);
}
}
}
}
}
Ok(())
}
fn savebaseline(&self, baseline: &PerformanceBaseline) -> StatsResult<()> {
let filename = format!(
"{}-{}.json",
baseline.platform.platform_id(),
baseline.function_name
);
let filepath = Path::new(&self.config.baseline_storage_path).join(filename);
let content = serde_json::to_string_pretty(baseline).map_err(|e| {
StatsError::InvalidInput(format!("Failed to serialize baseline: {}", e))
})?;
fs::write(filepath, content)
.map_err(|e| StatsError::InvalidInput(format!("Failed to write baseline: {}", e)))?;
Ok(())
}
pub fn record_measurement(
&mut self,
function_name: &str,
input_parameters: &str,
execution_time_ns: f64,
memory_usage_bytes: usize,
iterations: usize,
) -> StatsResult<()> {
let platform = PlatformInfo::current_platform();
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Operation failed")
.as_secs();
let measurement = PerformanceMeasurement {
timestamp,
execution_time_ns,
memory_usage_bytes,
iterations,
hardware_context: self.capture_hardware_context()?,
compiler_context: self.capture_compiler_context()?,
};
self.historicaldata
.entry(timestamp)
.or_default()
.push(measurement.clone());
let baseline_key = format!("{}-{}", platform.platform_id(), function_name);
if let Some(baseline) = self.baselines.get_mut(&baseline_key) {
baseline.measurements.push(measurement);
baseline.last_updated = timestamp;
let measurements = baseline.measurements.clone();
let _ = baseline; let stats = self.calculate_statistics(&measurements)?;
if let Some(baseline) = self.baselines.get_mut(&baseline_key) {
baseline.statistics = stats;
}
} else {
let baseline = PerformanceBaseline {
platform,
function_name: function_name.to_string(),
input_parameters: input_parameters.to_string(),
measurements: vec![measurement],
statistics: BaselineStatistics {
mean_time_ns: execution_time_ns,
std_dev_time_ns: 0.0,
median_time_ns: execution_time_ns,
p95_time_ns: execution_time_ns,
p99_time_ns: execution_time_ns,
coefficient_of_variation: 0.0,
confidence_interval_95: (execution_time_ns, execution_time_ns),
sample_count: 1,
},
last_updated: timestamp,
};
self.baselines.insert(baseline_key, baseline.clone());
self.savebaseline(&baseline)?;
}
Ok(())
}
pub fn detect_regression(
&self,
function_name: &str,
current_measurement: &PerformanceMeasurement,
) -> StatsResult<RegressionAnalysisResult> {
let platform = PlatformInfo::current_platform();
let baseline_key = format!("{}-{}", platform.platform_id(), function_name);
let baseline = self.baselines.get(&baseline_key).ok_or_else(|| {
StatsError::InvalidInput(format!(
"No baseline found for function {} on platform {}",
function_name,
platform.platform_id()
))
})?;
let performance_change_percent = ((current_measurement.execution_time_ns
- baseline.statistics.mean_time_ns)
/ baseline.statistics.mean_time_ns)
* 100.0;
let statistical_significance = self.calculate_statistical_significance(
current_measurement.execution_time_ns,
&baseline.statistics,
)?;
let regression_detected = performance_change_percent
> self.config.regression_threshold_percent
&& statistical_significance < self.config.significance_level;
let confidence_level = 1.0 - statistical_significance;
let trend_analysis = if self.config.trend_analysis {
Some(self.analyze_trend(function_name)?)
} else {
None
};
let recommendations = self.generate_recommendations(
function_name,
performance_change_percent,
&baseline.statistics,
current_measurement,
)?;
let platform_comparison = PlatformComparison {
current_platform: platform.clone(),
baseline_platform: baseline.platform.clone(),
hardware_normalization_factor: 1.0, platform_similarity_score: self
.calculate_platform_similarity(&platform, &baseline.platform),
};
Ok(RegressionAnalysisResult {
function_name: function_name.to_string(),
platform_comparison,
current_measurement: current_measurement.clone(),
baseline_performance: baseline.statistics.clone(),
regression_detected,
performance_change_percent,
statistical_significance,
confidence_level,
trend_analysis,
recommendations,
})
}
fn calculate_statistical_significance(
&self,
current_time: f64,
baseline_stats: &BaselineStatistics,
) -> StatsResult<f64> {
if baseline_stats.sample_count < 2 {
return Ok(1.0); }
let t_statistic = (current_time - baseline_stats.mean_time_ns)
/ (baseline_stats.std_dev_time_ns / (baseline_stats.sample_count as f64).sqrt());
let p_value = if t_statistic.abs() > 2.0 {
0.05 } else if t_statistic.abs() > 1.5 {
0.1 } else {
0.5 };
Ok(p_value)
}
fn calculate_statistics(
&self,
measurements: &[PerformanceMeasurement],
) -> StatsResult<BaselineStatistics> {
if measurements.is_empty() {
return Err(StatsError::InvalidInput(
"No measurements provided".to_string(),
));
}
let times: Vec<f64> = measurements.iter().map(|m| m.execution_time_ns).collect();
let _times_array = Array1::from_vec(times.clone());
let mean = times.iter().sum::<f64>() / times.len() as f64;
let variance = times.iter().map(|&x| (x - mean).powi(2)).sum::<f64>()
/ (times.len() - 1).max(1) as f64;
let std_dev = variance.sqrt();
let mut sorted_times = times.clone();
sorted_times.sort_by(|a, b| a.partial_cmp(b).expect("Operation failed"));
let median = if sorted_times.len().is_multiple_of(2) {
let mid = sorted_times.len() / 2;
(sorted_times[mid - 1] + sorted_times[mid]) / 2.0
} else {
sorted_times[sorted_times.len() / 2]
};
let p95_idx = ((sorted_times.len() as f64 * 0.95) as usize).min(sorted_times.len() - 1);
let p99_idx = ((sorted_times.len() as f64 * 0.99) as usize).min(sorted_times.len() - 1);
let p95 = sorted_times[p95_idx];
let p99 = sorted_times[p99_idx];
let coefficient_of_variation = if mean != 0.0 { std_dev / mean } else { 0.0 };
let standard_error = std_dev / (times.len() as f64).sqrt();
let margin_of_error = 1.96 * standard_error; let confidence_interval_95 = (mean - margin_of_error, mean + margin_of_error);
Ok(BaselineStatistics {
mean_time_ns: mean,
std_dev_time_ns: std_dev,
median_time_ns: median,
p95_time_ns: p95,
p99_time_ns: p99,
coefficient_of_variation,
confidence_interval_95,
sample_count: times.len(),
})
}
fn analyze_trend(&self, _functionname: &str) -> StatsResult<TrendAnalysis> {
let measurements: Vec<_> = self
.historicaldata
.values()
.flatten()
.filter(|_m| {
true
})
.collect();
if measurements.len() < 5 {
return Ok(TrendAnalysis {
trend_direction: TrendDirection::Stable,
trend_strength: 0.0,
slope_ns_per_day: 0.0,
r_squared: 0.0,
predicted_performance_30d: 0.0,
trend_significance: 1.0,
});
}
let timestamps: Vec<f64> = measurements.iter().map(|m| m.timestamp as f64).collect();
let times: Vec<f64> = measurements.iter().map(|m| m.execution_time_ns).collect();
let (slope, r_squared) = self.linear_regression(×tamps, ×)?;
let slope_ns_per_day = slope * 86400.0;
let trend_direction = if slope_ns_per_day > 100.0 {
TrendDirection::Degrading
} else if slope_ns_per_day < -100.0 {
TrendDirection::Improving
} else {
TrendDirection::Stable
};
let trend_strength = r_squared.abs();
let trend_significance = if r_squared > 0.5 { 0.01 } else { 0.5 };
let current_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Operation failed")
.as_secs() as f64;
let future_time = current_time + (30.0 * 86400.0);
let predicted_performance_30d =
slope * future_time + (times.iter().sum::<f64>() / times.len() as f64);
Ok(TrendAnalysis {
trend_direction,
trend_strength,
slope_ns_per_day,
r_squared,
predicted_performance_30d,
trend_significance,
})
}
fn linear_regression(&self, x: &[f64], y: &[f64]) -> StatsResult<(f64, f64)> {
if x.len() != y.len() || x.len() < 2 {
return Err(StatsError::InvalidInput(
"Invalid data for regression".to_string(),
));
}
let n = x.len() as f64;
let sum_x = x.iter().sum::<f64>();
let sum_y = y.iter().sum::<f64>();
let sum_xy = x.iter().zip(y.iter()).map(|(xi, yi)| xi * yi).sum::<f64>();
let sum_x2 = x.iter().map(|xi| xi * xi).sum::<f64>();
let _sum_y2 = y.iter().map(|yi| yi * yi).sum::<f64>();
let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x);
let mean_y = sum_y / n;
let ss_tot = y.iter().map(|yi| (yi - mean_y).powi(2)).sum::<f64>();
let intercept = (sum_y - slope * sum_x) / n;
let ss_res = x
.iter()
.zip(y.iter())
.map(|(xi, yi)| (yi - (slope * xi + intercept)).powi(2))
.sum::<f64>();
let r_squared = 1.0 - (ss_res / ss_tot);
Ok((slope, r_squared))
}
fn calculate_platform_similarity(
&self,
platform1: &PlatformInfo,
platform2: &PlatformInfo,
) -> f64 {
let mut score = 0.0;
let mut factors = 0.0;
if platform1.os == platform2.os {
score += 0.3;
}
factors += 0.3;
if platform1.arch == platform2.arch {
score += 0.2;
}
factors += 0.2;
let common_simd: Vec<_> = platform1
.simd_capabilities
.iter()
.filter(|cap| platform2.simd_capabilities.contains(cap))
.collect();
let total_simd = platform1
.simd_capabilities
.len()
.max(platform2.simd_capabilities.len());
if total_simd > 0 {
score += 0.3 * (common_simd.len() as f64 / total_simd as f64);
}
factors += 0.3;
if platform1.optimization_level == platform2.optimization_level {
score += 0.2;
}
factors += 0.2;
if factors > 0.0 {
score / factors
} else {
0.0
}
}
fn generate_recommendations(
&self,
_function_name: &str,
performance_change_percent: f64,
baseline_stats: &BaselineStatistics,
_measurement: &PerformanceMeasurement,
) -> StatsResult<Vec<PerformanceRecommendation>> {
let mut recommendations = Vec::new();
if performance_change_percent > 20.0 {
recommendations.push(PerformanceRecommendation {
category: RecommendationCategory::AlgorithmSelection,
priority: RecommendationPriority::High,
description: format!(
"Significant performance regression detected ({}% slower). Consider algorithm optimization.",
performance_change_percent as i32
),
expected_impact_percent: -performance_change_percent * 0.5,
confidence: 0.8,
});
}
if baseline_stats.coefficient_of_variation > 0.2 {
recommendations.push(PerformanceRecommendation {
category: RecommendationCategory::CompilerOptimization,
priority: RecommendationPriority::Medium,
description:
"High performance variability detected. Consider compiler optimization flags."
.to_string(),
expected_impact_percent: -10.0,
confidence: 0.6,
});
}
let platform = PlatformInfo::current_platform();
if platform.simd_capabilities.contains(&"avx512f".to_string()) {
recommendations.push(PerformanceRecommendation {
category: RecommendationCategory::SIMDOptimization,
priority: RecommendationPriority::Medium,
description:
"AVX-512 capabilities detected. Consider using specialized SIMD optimizations."
.to_string(),
expected_impact_percent: -25.0,
confidence: 0.7,
});
}
Ok(recommendations)
}
fn capture_hardware_context(&self) -> StatsResult<HardwareContext> {
Ok(HardwareContext {
cpu_utilization: 50.0, available_memory_percent: 75.0,
cpu_frequency_mhz: 3000.0,
temperature_celsius: None,
})
}
fn capture_compiler_context(&self) -> StatsResult<CompilerContext> {
Ok(CompilerContext {
rustc_version: option_env!("RUSTC_VERSION")
.unwrap_or("unknown")
.to_string(),
target_triple: option_env!("TARGET")
.unwrap_or("unknown-target")
.to_string(),
optimization_flags: vec![], feature_flags: vec![],
})
}
pub fn generate_report(&self) -> StatsResult<RegressionReport> {
let mut function_analyses = Vec::new();
for function_name in &self.config.monitored_functions {
if let Some(latest_measurement) = self.get_latest_measurement(function_name) {
if let Ok(analysis) = self.detect_regression(function_name, &latest_measurement) {
function_analyses.push(analysis);
}
}
}
let overall_status = if function_analyses.iter().any(|a| a.regression_detected) {
RegressionStatus::RegressionsDetected
} else {
RegressionStatus::NoRegressionsDetected
};
Ok(RegressionReport {
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Operation failed")
.as_secs(),
overall_status,
platform: PlatformInfo::current_platform(),
function_analyses,
summary_statistics: self.calculate_summary_statistics()?,
})
}
fn get_latest_measurement(&self, _functionname: &str) -> Option<PerformanceMeasurement> {
None
}
fn calculate_summary_statistics(&self) -> StatsResult<RegressionSummaryStatistics> {
Ok(RegressionSummaryStatistics {
total_functions_monitored: self.config.monitored_functions.len(),
functions_with_regressions: 0, average_performance_change: 0.0,
max_performance_change: 0.0,
total_measurements: self.historicaldata.values().map(|v| v.len()).sum(),
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegressionReport {
pub timestamp: u64,
pub overall_status: RegressionStatus,
pub platform: PlatformInfo,
pub function_analyses: Vec<RegressionAnalysisResult>,
pub summary_statistics: RegressionSummaryStatistics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RegressionStatus {
NoRegressionsDetected,
RegressionsDetected,
InsufficientData,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegressionSummaryStatistics {
pub total_functions_monitored: usize,
pub functions_with_regressions: usize,
pub average_performance_change: f64,
pub max_performance_change: f64,
pub total_measurements: usize,
}
#[allow(dead_code)]
pub fn create_regression_detector() -> StatsResult<CrossPlatformRegressionDetector> {
CrossPlatformRegressionDetector::new(CrossPlatformRegressionConfig::default())
}
#[allow(dead_code)]
pub fn create_regression_detector_with_config(
config: CrossPlatformRegressionConfig,
) -> StatsResult<CrossPlatformRegressionDetector> {
CrossPlatformRegressionDetector::new(config)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_platform_info_creation() {
let platform = PlatformInfo::current_platform();
assert!(!platform.os.is_empty());
assert!(!platform.arch.is_empty());
assert!(!platform.platform_id().is_empty());
}
#[test]
fn test_regression_detector_creation() {
let detector = create_regression_detector();
assert!(detector.is_ok());
}
#[test]
fn test_performance_measurement_recording() {
let mut detector = create_regression_detector().expect("Operation failed");
let result = detector.record_measurement(
"test_function",
"inputsize_100",
1000.0, 1024, 100, );
assert!(result.is_ok());
}
#[test]
fn testbaseline_statistics_calculation() {
let detector = create_regression_detector().expect("Operation failed");
let measurements = vec![
PerformanceMeasurement {
timestamp: 1000,
execution_time_ns: 100.0,
memory_usage_bytes: 1024,
iterations: 10,
hardware_context: HardwareContext {
cpu_utilization: 50.0,
available_memory_percent: 75.0,
cpu_frequency_mhz: 3000.0,
temperature_celsius: None,
},
compiler_context: CompilerContext {
rustc_version: "1.70.0".to_string(),
target_triple: "x86_64-unknown-linux-gnu".to_string(),
optimization_flags: vec![],
feature_flags: vec![],
},
},
PerformanceMeasurement {
timestamp: 1001,
execution_time_ns: 110.0,
memory_usage_bytes: 1024,
iterations: 10,
hardware_context: HardwareContext {
cpu_utilization: 50.0,
available_memory_percent: 75.0,
cpu_frequency_mhz: 3000.0,
temperature_celsius: None,
},
compiler_context: CompilerContext {
rustc_version: "1.70.0".to_string(),
target_triple: "x86_64-unknown-linux-gnu".to_string(),
optimization_flags: vec![],
feature_flags: vec![],
},
},
];
let stats = detector
.calculate_statistics(&measurements)
.expect("Operation failed");
assert!((stats.mean_time_ns - 105.0).abs() < 1e-10);
assert_eq!(stats.sample_count, 2);
}
#[test]
fn test_platform_similarity_calculation() {
let detector = create_regression_detector().expect("Operation failed");
let platform1 = PlatformInfo {
os: "linux".to_string(),
arch: "x86_64".to_string(),
cpu_model: "Intel Core".to_string(),
cpu_cores: 8,
memory_gb: 16,
rustc_version: "1.70.0".to_string(),
optimization_level: "release".to_string(),
simd_capabilities: vec!["avx2".to_string(), "fma".to_string()],
};
let platform2 = platform1.clone();
let similarity = detector.calculate_platform_similarity(&platform1, &platform2);
assert!((similarity - 1.0).abs() < 1e-10); }
#[test]
fn test_linear_regression() {
let detector = create_regression_detector().expect("Operation failed");
let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let y = vec![2.0, 4.0, 6.0, 8.0, 10.0];
let (slope, r_squared) = detector
.linear_regression(&x, &y)
.expect("Operation failed");
assert!((slope - 2.0).abs() < 1e-10);
assert!((r_squared - 1.0).abs() < 1e-10);
}
}