use analyzer::hotspot::{MemoryStats, TimeStats};
use analyzer::{CallStackAnalyzer, Hotspot, HotspotAnalyzer, StackFrame};
use collector::{FunctionStats, FunctionTraceHandle, FunctionTracker, TrackerStats};
use report::{
Difficulty, OptimizationRecommendation, PerformanceSummary, Priority, RecommendationType,
};
use std::collections::{BTreeMap, HashMap};
use std::time::SystemTime;
use std::time::{Duration, Instant};
pub mod analyzer;
pub mod collector;
pub mod report;
pub mod storage;
pub use analyzer::{Bottleneck, BottleneckType, CallStackAnalysis, DepthStats, RecursionInfo};
#[derive(Debug, Clone)]
pub struct AdvancedProfilerConfig {
pub event_buffer_capacity: usize,
pub sampling_config: SamplingConfig,
pub max_call_depth: usize,
pub enable_hotspot_analysis: bool,
pub enable_stack_analysis: bool,
pub report_config: ReportConfig,
}
#[derive(Debug, Clone)]
pub struct ReportConfig {
pub generate_json: bool,
pub generate_text: bool,
pub generate_html: bool,
pub output_dir: Option<String>,
}
impl Default for AdvancedProfilerConfig {
fn default() -> Self {
Self {
event_buffer_capacity: 10000,
sampling_config: SamplingConfig::default(),
max_call_depth: 100,
enable_hotspot_analysis: true,
enable_stack_analysis: true,
report_config: ReportConfig {
generate_json: true,
generate_text: true,
generate_html: false,
output_dir: None,
},
}
}
}
#[derive(Debug)]
pub struct AdvancedProfiler {
function_tracker: FunctionTracker,
stack_analyzer: Option<CallStackAnalyzer>,
hotspot_analyzer: Option<HotspotAnalyzer>,
config: AdvancedProfilerConfig,
is_running: bool,
start_time: Option<std::time::Instant>,
}
impl AdvancedProfiler {
pub fn new(config: AdvancedProfilerConfig) -> Self {
let function_tracker: _ =
FunctionTracker::new(config.event_buffer_capacity, config.sampling_config.clone());
let stack_analyzer: _ = if config.enable_stack_analysis {
Some(CallStackAnalyzer::new(config.max_call_depth))
} else {
None
};
let hotspot_analyzer: _ = if config.enable_hotspot_analysis {
Some(HotspotAnalyzer::with_default_config())
} else {
None
};
Self {
function_tracker,
stack_analyzer,
hotspot_analyzer,
config,
is_running: false,
start_time: None,
}
}
pub fn with_default_config() -> Self {
Self::new(AdvancedProfilerConfig::default())
}
pub fn start(&mut self) {
self.is_running = true;
self.start_time = Some(std::time::Instant::now());
}
pub fn stop(&mut self) {
self.is_running = false;
}
pub fn is_active(&self) -> bool {
self.is_running
}
pub fn track_function(
&mut self,
function_name: &str,
file: Option<String>,
line: Option<u32>,
column: Option<u32>,
) -> FunctionTraceHandle {
let start_memory: _ = 0; let call_depth: _ = self
.stack_analyzer
.as_ref()
.map(|a| a.get_current_stack().len())
.unwrap_or(0);
let handle: _ =
self.function_tracker
.track_function(function_name, start_memory, call_depth);
if let Some(stack_analyzer) = &mut self.stack_analyzer {
let timestamp: _ = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
stack_analyzer.enter_function(function_name, file, line, column, timestamp);
}
handle
}
pub fn record_return(
&mut self,
handle: FunctionTraceHandle,
end_memory: usize,
) -> Option<FunctionStats> {
let stats: _ = self
.function_tracker
.record_return(handle.clone(), end_memory);
if let Some(stack_analyzer) = &mut self.stack_analyzer {
let timestamp: _ = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
stack_analyzer.exit_function(&handle.function_name, timestamp, end_memory);
}
if let Some(hotspot_analyzer) = &mut self.hotspot_analyzer {
if let Some(ref function_stats) = stats {
let execution_time: _ = Duration::from_nanos(
function_stats.total_time.as_nanos() as u64 / function_stats.call_count.max(1),
);
let avg_memory: _ = function_stats.avg_memory as usize;
hotspot_analyzer.record_execution(
&handle.function_name,
execution_time,
avg_memory,
);
}
}
stats
}
pub fn analyze(&mut self) -> PerformanceSummary {
let mut summary = PerformanceSummary::new();
if let Some(start_time) = self.start_time {
summary.total_execution_time = start_time.elapsed();
}
let function_stats: _ = self.function_tracker.get_all_function_stats();
summary.function_count = function_stats.len();
summary.total_calls = function_stats.values().map(|s| s.call_count).sum();
if let Some(hotspot_analyzer) = &mut self.hotspot_analyzer {
summary.hotspots = hotspot_analyzer.identify_hotspots();
}
if let Some(stack_analyzer) = &mut self.stack_analyzer {
let stack_analysis: _ = stack_analyzer.analyze_stack();
summary.bottlenecks = stack_analysis.bottlenecks.clone();
summary.call_stack_analysis = Some(stack_analysis);
}
summary.optimization_recommendations = self.generate_recommendations(&summary);
summary
}
fn generate_recommendations(
&self,
summary: &PerformanceSummary,
) -> Vec<OptimizationRecommendation> {
let mut recommendations = Vec::new();
for hotspot in &summary.hotspots {
for suggestion in &hotspot.optimization_suggestions {
recommendations.push(OptimizationRecommendation {
recommendation_type: match hotspot.hotspot_type {
analyzer::hotspot::HotspotType::TimeHotspot => {
RecommendationType::AlgorithmOptimization
}
analyzer::hotspot::HotspotType::MemoryHotspot => {
RecommendationType::MemoryOptimization
}
analyzer::hotspot::HotspotType::FrequencyHotspot => {
RecommendationType::CodeRefactoring
}
_ => RecommendationType::AlgorithmOptimization,
},
priority: if hotspot.heat_score > 0.8 {
Priority::Critical
} else if hotspot.heat_score > 0.6 {
Priority::High
} else {
Priority::Medium
},
title: format!("优化函数: {}", hotspot.function_name),
description: suggestion.clone(),
expected_impact: format!(
"可减少 {:.1}% 的执行时间",
hotspot.heat_score * 100.0
),
difficulty: Difficulty::Medium,
});
}
}
for bottleneck in &summary.bottlenecks {
recommendations.push(OptimizationRecommendation {
recommendation_type: RecommendationType::AlgorithmOptimization,
priority: if bottleneck.impact > 0.7 {
Priority::Critical
} else {
Priority::High
},
title: format!("解决瓶颈: {}", bottleneck.function),
description: bottleneck.description.clone(),
expected_impact: format!("可提升 {:.1}% 性能", bottleneck.impact * 100.0),
difficulty: Difficulty::Hard,
});
}
recommendations
}
pub fn generate_report(&mut self) -> Result<String, String> {
let summary: _ = self.analyze();
let mut output = String::new();
if self.config.report_config.generate_text {
output.push_str(&summary.to_text());
output.push('\n');
}
if self.config.report_config.generate_json {
output.push_str("\n=== JSON 格式报告 ===\n");
output.push_str(&summary.to_json());
output.push('\n');
}
if self.config.report_config.generate_html {
let html: _ = summary.to_html();
if let Some(ref output_dir) = self.config.report_config.output_dir {
let filename: _ = format!(
"{}/performance_report_{}.html",
output_dir,
chrono::Utc::now().timestamp()
);
fs::write(&filename, &html)
.map_err(|e| format!("Failed to write HTML report: {}", e))?;
output.push_str(&format!("\nHTML 报告已保存到: {}\n", filename));
}
}
Ok(output)
}
pub fn get_realtime_snapshot(&self) -> RealtimeSnapshot {
RealtimeSnapshot {
is_running: self.is_running,
uptime: self.start_time.map(|t| t.elapsed()),
active_traces: self.function_tracker.get_active_trace_count(),
sampled_events: self.function_tracker.get_sampling_stats().sampled_events,
total_traces: self.function_tracker.get_tracker_stats().total_traces,
}
}
pub fn clear(&mut self) {
self.function_tracker.clear();
if let Some(stack_analyzer) = &mut self.stack_analyzer {
stack_analyzer.clear();
}
if let Some(hotspot_analyzer) = &mut self.hotspot_analyzer {
hotspot_analyzer.clear();
}
}
pub fn get_function_stats(&self, function_name: &str) -> Option<&FunctionStats> {
self.function_tracker.get_function_stats(function_name)
}
pub fn get_all_function_stats(&self) -> Vec<FunctionStats> {
self.function_tracker
.get_all_function_stats()
.into_values()
.collect()
}
}
#[derive(Debug, Clone)]
pub struct RealtimeSnapshot {
pub is_running: bool,
pub uptime: Option<std::time::Duration>,
pub active_traces: usize,
pub sampled_events: u64,
pub total_traces: u64,
}
impl RealtimeSnapshot {
pub fn get_uptime_seconds(&self) -> f64 {
self.uptime.map(|d| d.as_secs_f64()).unwrap_or(0.0)
}
pub fn get_traces_per_second(&self) -> f64 {
let uptime: _ = self.get_uptime_seconds();
if uptime > 0.0 {
self.total_traces as f64 / uptime
} else {
0.0
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_advanced_profiler_creation() {
let profiler: _ = AdvancedProfiler::with_default_config();
assert!(!profiler.is_active());
}
#[test]
fn test_start_and_stop() {
let mut profiler = AdvancedProfiler::with_default_config();
profiler.start();
assert!(profiler.is_active());
profiler.stop();
assert!(!profiler.is_active());
}
#[test]
fn test_track_and_record() {
let mut profiler = AdvancedProfiler::with_default_config();
profiler.start();
let handle: _ = profiler.track_function("test_function", None, None, None);
std::thread::sleep(std::time::Duration::from_millis(10));
let stats: _ = profiler.record_return(handle, 1024);
assert!(stats.is_some());
let stats: _ = stats.unwrap();
assert_eq!(stats.function_name, "test_function");
assert!(stats.call_count >= 1);
}
#[test]
fn test_generate_report() {
let mut profiler = AdvancedProfiler::with_default_config();
profiler.start();
for _ in 0..10 {
let handle: _ = profiler.track_function("test_func", None, None, None);
std::thread::sleep(std::time::Duration::from_millis(1));
profiler.record_return(handle, 1024);
}
let report: _ = profiler.generate_report();
assert!(report.is_ok());
assert!(report.unwrap().contains("性能分析摘要报告"));
}
#[test]
fn test_realtime_snapshot() {
let profiler: _ = AdvancedProfiler::with_default_config();
let snapshot: _ = profiler.get_realtime_snapshot();
assert!(!snapshot.is_running);
assert_eq!(snapshot.active_traces, 0);
}
#[test]
fn test_clear() {
let mut profiler = AdvancedProfiler::with_default_config();
profiler.start();
profiler.track_function("test_func", None, None, None);
profiler.clear();
assert_eq!(profiler.get_all_function_stats().len(), 0);
}
}