use lambdust::benchmarks::{PerformanceTester, SchemeBenchmarkSuite, PerformanceTestConfig};
use lambdust::cli::{LightweightCli, ArgDef, ArgType, CliError};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceSnapshot {
pub timestamp: u64,
pub system_info: SystemInfo,
pub performance_metrics: PerformanceMetrics,
pub memory_usage: MemoryUsage,
pub execution_profile: ExecutionProfile,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemInfo {
pub cpu_cores: usize,
pub memory_total_mb: u64,
pub platform: String,
pub load_average: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceMetrics {
pub arithmetic_ops_per_sec: f64,
pub list_ops_per_sec: f64,
pub memory_allocation_ops_per_sec: f64,
pub function_call_overhead_ns: f64,
pub gc_collections_per_sec: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryUsage {
pub heap_size_mb: f64,
pub allocated_objects: usize,
pub gc_pressure: f64,
pub memory_fragmentation: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionProfile {
pub hot_functions: Vec<HotFunction>,
pub bottlenecks: Vec<String>,
pub optimization_opportunities: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HotFunction {
pub name: String,
pub call_count: u64,
pub total_time_ms: f64,
pub avg_time_per_call_ns: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceTrend {
pub metric_name: String,
pub snapshots: Vec<(u64, f64)>, pub trend_direction: TrendDirection,
pub regression_detected: bool,
pub improvement_percentage: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TrendDirection {
Improving,
Stable,
Degrading,
Unknown,
}
pub struct PerformanceMonitor {
snapshot_history: Vec<PerformanceSnapshot>,
#[allow(dead_code)]
performance_tester: PerformanceTester,
#[allow(dead_code)]
benchmark_suite: SchemeBenchmarkSuite,
monitoring_config: MonitoringConfig,
}
#[derive(Debug, Clone)]
pub struct MonitoringConfig {
pub snapshot_interval: Duration,
pub history_retention_days: u32,
pub regression_threshold: f64,
pub output_file: PathBuf,
pub enable_real_time_alerts: bool,
}
impl PerformanceMonitor {
pub fn new(config: MonitoringConfig) -> Self {
Self {
snapshot_history: Vec::new(),
performance_tester: PerformanceTester::new(PerformanceTestConfig::default()),
benchmark_suite: SchemeBenchmarkSuite::new(),
monitoring_config: config,
}
}
pub fn take_snapshot(&mut self) -> PerformanceSnapshot {
println!("📸 Taking performance snapshot...");
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let system_info = self.collect_system_info();
let performance_metrics = self.collect_performance_metrics();
let memory_usage = self.collect_memory_usage();
let execution_profile = self.collect_execution_profile();
let snapshot = PerformanceSnapshot {
timestamp,
system_info,
performance_metrics,
memory_usage,
execution_profile,
};
self.snapshot_history.push(snapshot.clone());
self.cleanup_old_snapshots();
println!("✅ Performance snapshot completed");
snapshot
}
fn collect_system_info(&self) -> SystemInfo {
SystemInfo {
cpu_cores: num_cpus::get(),
memory_total_mb: 8192, platform: std::env::consts::OS.to_string(),
load_average: self.get_load_average(),
}
}
fn collect_performance_metrics(&mut self) -> PerformanceMetrics {
println!(" 🔢 Collecting performance metrics...");
let test_config = lambdust::benchmarks::PerformanceTestConfig {
micro_bench_iterations: 1000,
macro_bench_iterations: 100,
test_duration: Duration::from_millis(500),
warmup_duration: Duration::from_millis(100),
..Default::default()
};
let tester = lambdust::benchmarks::PerformanceTester::new(test_config);
let results = tester.run_comprehensive_tests();
PerformanceMetrics {
arithmetic_ops_per_sec: results.micro_benchmark_results.arithmetic_ops_per_sec,
list_ops_per_sec: results.micro_benchmark_results.list_ops_per_sec,
memory_allocation_ops_per_sec: results.macro_benchmark_results.allocation_ops_per_sec,
function_call_overhead_ns: 1_000_000.0 / results.micro_benchmark_results.env_lookup_ops_per_sec * 1000.0,
gc_collections_per_sec: 0.0, }
}
fn collect_memory_usage(&self) -> MemoryUsage {
println!(" 🧠 Collecting memory usage...");
MemoryUsage {
heap_size_mb: self.estimate_heap_size(),
allocated_objects: self.count_allocated_objects(),
gc_pressure: self.calculate_gc_pressure(),
memory_fragmentation: self.calculate_memory_fragmentation(),
}
}
fn collect_execution_profile(&self) -> ExecutionProfile {
println!(" 📊 Collecting execution profile...");
let hot_functions = vec![
HotFunction {
name: "arithmetic_operations".to_string(),
call_count: 1000000,
total_time_ms: 50.0,
avg_time_per_call_ns: 50.0,
},
HotFunction {
name: "list_operations".to_string(),
call_count: 500000,
total_time_ms: 75.0,
avg_time_per_call_ns: 150.0,
},
];
let bottlenecks = vec![
"Memory allocation overhead".to_string(),
"Symbol interning contention".to_string(),
];
let optimization_opportunities = vec![
"Consider SIMD optimizations for numeric operations".to_string(),
"Implement memory pooling for small objects".to_string(),
];
ExecutionProfile {
hot_functions,
bottlenecks,
optimization_opportunities,
}
}
pub fn analyze_performance_trends(&self) -> Vec<PerformanceTrend> {
let mut trends = Vec::new();
if self.snapshot_history.len() < 2 {
return trends;
}
let arithmetic_values: Vec<_> = self.snapshot_history.iter()
.map(|s| (s.timestamp, s.performance_metrics.arithmetic_ops_per_sec))
.collect();
trends.push(self.calculate_trend(
"Arithmetic Operations/sec".to_string(),
arithmetic_values,
));
let memory_values: Vec<_> = self.snapshot_history.iter()
.map(|s| (s.timestamp, s.memory_usage.heap_size_mb))
.collect();
trends.push(self.calculate_trend(
"Heap Size (MB)".to_string(),
memory_values,
));
let list_values: Vec<_> = self.snapshot_history.iter()
.map(|s| (s.timestamp, s.performance_metrics.list_ops_per_sec))
.collect();
trends.push(self.calculate_trend(
"List Operations/sec".to_string(),
list_values,
));
trends
}
fn calculate_trend(&self, metric_name: String, snapshots: Vec<(u64, f64)>) -> PerformanceTrend {
if snapshots.len() < 2 {
return PerformanceTrend {
metric_name,
snapshots,
trend_direction: TrendDirection::Unknown,
regression_detected: false,
improvement_percentage: 0.0,
};
}
let first_value = snapshots[0].1;
let last_value = snapshots[snapshots.len() - 1].1;
let percentage_change = ((last_value - first_value) / first_value) * 100.0;
let trend_direction = if percentage_change > 5.0 {
TrendDirection::Improving
} else if percentage_change < -5.0 {
TrendDirection::Degrading
} else {
TrendDirection::Stable
};
let regression_detected = match trend_direction {
TrendDirection::Degrading => percentage_change.abs() > self.monitoring_config.regression_threshold,
_ => false,
};
PerformanceTrend {
metric_name,
snapshots,
trend_direction,
regression_detected,
improvement_percentage: percentage_change,
}
}
pub fn detect_regressions(&self) -> Vec<String> {
let mut regressions = Vec::new();
let trends = self.analyze_performance_trends();
for trend in trends {
if trend.regression_detected {
regressions.push(format!(
"Regression detected in {}: {:.1}% decrease",
trend.metric_name,
trend.improvement_percentage.abs()
));
}
}
regressions
}
pub fn generate_monitoring_report(&self) -> String {
let mut report = String::new();
report.push_str("=== Lambdust Performance Monitoring Report ===\n\n");
if let Some(latest) = self.snapshot_history.last() {
report.push_str("📊 Latest Performance Snapshot:\n");
report.push_str(&format!(" • Timestamp: {}\n", latest.timestamp));
report.push_str(&format!(" • Arithmetic Operations: {:.0} ops/sec\n",
latest.performance_metrics.arithmetic_ops_per_sec));
report.push_str(&format!(" • List Operations: {:.0} ops/sec\n",
latest.performance_metrics.list_ops_per_sec));
report.push_str(&format!(" • Memory Usage: {:.1} MB\n",
latest.memory_usage.heap_size_mb));
report.push_str(&format!(" • GC Pressure: {:.2}\n",
latest.memory_usage.gc_pressure));
report.push('\n');
}
let trends = self.analyze_performance_trends();
if !trends.is_empty() {
report.push_str("📈 Performance Trends:\n");
for trend in trends {
let trend_symbol = match trend.trend_direction {
TrendDirection::Improving => "📈",
TrendDirection::Degrading => "📉",
TrendDirection::Stable => "➡️",
TrendDirection::Unknown => "❓",
};
report.push_str(&format!(" {} {}: {:.1}% change\n",
trend_symbol, trend.metric_name, trend.improvement_percentage));
if trend.regression_detected {
report.push_str(" ⚠️ REGRESSION DETECTED!\n");
}
}
report.push('\n');
}
let regressions = self.detect_regressions();
if !regressions.is_empty() {
report.push_str("🚨 Performance Regressions Detected:\n");
for regression in regressions {
report.push_str(&format!(" • {regression}\n"));
}
report.push('\n');
}
if let Some(latest) = self.snapshot_history.last() {
report.push_str("💻 System Information:\n");
report.push_str(&format!(" • CPU Cores: {}\n", latest.system_info.cpu_cores));
report.push_str(&format!(" • Memory: {} MB\n", latest.system_info.memory_total_mb));
report.push_str(&format!(" • Platform: {}\n", latest.system_info.platform));
report.push_str(&format!(" • Load Average: {:.2}\n", latest.system_info.load_average));
report.push('\n');
}
if let Some(latest) = self.snapshot_history.last() {
report.push_str("🔧 Optimization Recommendations:\n");
for rec in &latest.execution_profile.optimization_opportunities {
report.push_str(&format!(" • {rec}\n"));
}
}
report
}
pub fn save_monitoring_data(&self) -> Result<(), std::io::Error> {
let data = serde_json::to_string_pretty(&self.snapshot_history)?;
std::fs::write(&self.monitoring_config.output_file, data)?;
Ok(())
}
pub fn load_monitoring_data(&mut self) -> Result<(), Box<dyn std::error::Error>> {
if self.monitoring_config.output_file.exists() {
let data = std::fs::read_to_string(&self.monitoring_config.output_file)?;
self.snapshot_history = serde_json::from_str(&data)?;
}
Ok(())
}
fn cleanup_old_snapshots(&mut self) {
let retention_seconds = self.monitoring_config.history_retention_days as u64 * 24 * 60 * 60;
let cutoff_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() - retention_seconds;
self.snapshot_history.retain(|snapshot| snapshot.timestamp >= cutoff_time);
}
fn get_load_average(&self) -> f64 {
1.0
}
fn estimate_heap_size(&self) -> f64 {
64.0
}
fn count_allocated_objects(&self) -> usize {
10000
}
fn calculate_gc_pressure(&self) -> f64 {
0.3
}
fn calculate_memory_fragmentation(&self) -> f64 {
0.15
}
pub fn run_continuous_monitoring(&mut self) {
println!("🔄 Starting continuous performance monitoring...");
println!("Press Ctrl+C to stop monitoring\n");
loop {
let _snapshot = self.take_snapshot();
let regressions = self.detect_regressions();
if !regressions.is_empty() && self.monitoring_config.enable_real_time_alerts {
println!("🚨 PERFORMANCE REGRESSION ALERT:");
for regression in regressions {
println!(" • {regression}");
}
println!();
}
if let Err(e) = self.save_monitoring_data() {
eprintln!("⚠️ Failed to save monitoring data: {e}");
}
std::thread::sleep(self.monitoring_config.snapshot_interval);
}
}
}
fn main() {
let cli = LightweightCli {
name: "Performance Monitor".to_string(),
version: "1.0.0".to_string(),
author: "Lambdust Team".to_string(),
about: "Real-time performance monitoring and analysis for Lambdust".to_string(),
args: vec![
ArgDef {
name: "continuous".to_string(),
short: Some('c'),
long: Some("continuous".to_string()),
help: "Run continuous monitoring".to_string(),
value_name: None,
arg_type: ArgType::Flag,
positional: false,
index: None,
allowed_values: None,
},
ArgDef {
name: "interval".to_string(),
short: Some('i'),
long: Some("interval".to_string()),
help: "Snapshot interval in seconds".to_string(),
value_name: Some("SECONDS".to_string()),
arg_type: ArgType::Value,
positional: false,
index: None,
allowed_values: None,
},
ArgDef {
name: "output".to_string(),
short: Some('o'),
long: Some("output".to_string()),
help: "Output file for monitoring data".to_string(),
value_name: Some("FILE".to_string()),
arg_type: ArgType::Value,
positional: false,
index: None,
allowed_values: None,
},
ArgDef {
name: "retention".to_string(),
short: Some('r'),
long: Some("retention".to_string()),
help: "Data retention period in days".to_string(),
value_name: Some("DAYS".to_string()),
arg_type: ArgType::Value,
positional: false,
index: None,
allowed_values: None,
},
ArgDef {
name: "threshold".to_string(),
short: Some('t'),
long: Some("threshold".to_string()),
help: "Regression detection threshold (percentage)".to_string(),
value_name: Some("PERCENTAGE".to_string()),
arg_type: ArgType::Value,
positional: false,
index: None,
allowed_values: None,
},
ArgDef {
name: "report".to_string(),
short: None,
long: Some("report".to_string()),
help: "Generate monitoring report from existing data".to_string(),
value_name: None,
arg_type: ArgType::Flag,
positional: false,
index: None,
allowed_values: None,
},
],
};
let args: Vec<String> = std::env::args().collect();
let parsed_args = match cli.parse(&args[1..]) {
Ok(args) => args,
Err(CliError::HelpRequested) => {
cli.print_help();
return;
}
Err(CliError::VersionRequested) => {
println!("{} {}", cli.name, cli.version);
return;
}
Err(e) => {
eprintln!("Error: {e}");
std::process::exit(1);
}
};
let interval_secs: u64 = parsed_args.values.get("interval")
.unwrap_or(&"60".to_string())
.parse()
.expect("Invalid interval value");
let retention_days: u32 = parsed_args.values.get("retention")
.unwrap_or(&"30".to_string())
.parse()
.expect("Invalid retention value");
let threshold: f64 = parsed_args.values.get("threshold")
.unwrap_or(&"10.0".to_string())
.parse()
.expect("Invalid threshold value");
let output_file = PathBuf::from(
parsed_args.values.get("output")
.unwrap_or(&"performance_monitoring.json".to_string())
);
let config = MonitoringConfig {
snapshot_interval: Duration::from_secs(interval_secs),
history_retention_days: retention_days,
regression_threshold: threshold,
output_file,
enable_real_time_alerts: true,
};
let mut monitor = PerformanceMonitor::new(config);
if let Err(e) = monitor.load_monitoring_data() {
eprintln!("⚠️ Could not load existing monitoring data: {e}");
}
if *parsed_args.flags.get("report").unwrap_or(&false) {
println!("{}", monitor.generate_monitoring_report());
} else if *parsed_args.flags.get("continuous").unwrap_or(&false) {
monitor.run_continuous_monitoring();
} else {
let _snapshot = monitor.take_snapshot();
println!("{}", monitor.generate_monitoring_report());
if let Err(e) = monitor.save_monitoring_data() {
eprintln!("⚠️ Failed to save monitoring data: {e}");
} else {
println!("✅ Monitoring data saved successfully");
}
}
}