Skip to main content

scirs2_core/profiling/
comprehensive.rs

1//! Comprehensive profiling integration that combines application profiling with system monitoring
2
3use crate::profiling::advanced::{
4    BottleneckConfig, BottleneckDetector, BottleneckReport, FlameGraphGenerator,
5};
6use crate::profiling::flame_graph_svg::{
7    EnhancedFlameGraph, SvgFlameGraphConfig, SvgFlameGraphGenerator,
8};
9use crate::profiling::profiler::Profiler;
10use crate::profiling::system_monitor::{
11    AlertConfig, SystemAlert, SystemAlerter, SystemMonitor, SystemMonitorConfig,
12};
13use crate::profiling::timer::Timer;
14use std::sync::{Arc, Mutex};
15use std::time::{Duration, Instant};
16
17/// Comprehensive profiling session that combines multiple profiling techniques
18pub struct ComprehensiveProfiler {
19    /// Application profiler
20    app_profiler: Arc<Mutex<Profiler>>,
21    /// System resource monitor
22    systemmonitor: SystemMonitor,
23    /// System alerter
24    system_alerter: SystemAlerter,
25    /// Flame graph generator
26    flame_graph_generator: FlameGraphGenerator,
27    /// Session start time
28    session_start: Instant,
29    /// Session configuration
30    config: ComprehensiveConfig,
31}
32
33/// Configuration for comprehensive profiling
34#[derive(Debug, Clone)]
35pub struct ComprehensiveConfig {
36    /// System monitoring configuration
37    pub systemconfig: SystemMonitorConfig,
38    /// Alert configuration
39    pub alertconfig: AlertConfig,
40    /// SVG flame graph configuration
41    pub svgconfig: SvgFlameGraphConfig,
42    /// Enable automatic bottleneck detection
43    pub enable_bottleneck_detection: bool,
44    /// Enable automatic alert notifications
45    pub enable_alerts: bool,
46    /// Enable flame graph generation
47    pub enable_flame_graphs: bool,
48    /// Session name for reports
49    pub session_name: String,
50}
51
52impl Default for ComprehensiveConfig {
53    fn default() -> Self {
54        Self {
55            systemconfig: SystemMonitorConfig::default(),
56            alertconfig: AlertConfig::default(),
57            svgconfig: SvgFlameGraphConfig::default(),
58            enable_bottleneck_detection: true,
59            enable_alerts: true,
60            enable_flame_graphs: true,
61            session_name: "Profiling Session".to_string(),
62        }
63    }
64}
65
66impl ComprehensiveProfiler {
67    /// Create a new comprehensive profiler
68    pub fn new(config: ComprehensiveConfig) -> Self {
69        Self {
70            app_profiler: Arc::new(Mutex::new(Profiler::new())),
71            systemmonitor: SystemMonitor::new(config.systemconfig.clone()),
72            system_alerter: SystemAlerter::new(config.alertconfig.clone()),
73            flame_graph_generator: FlameGraphGenerator::new(),
74            session_start: Instant::now(),
75            config,
76        }
77    }
78
79    /// Start comprehensive profiling
80    pub fn start(&mut self) -> Result<(), crate::profiling::system_monitor::SystemMonitorError> {
81        // Start application profiler
82        self.app_profiler.lock().expect("Operation failed").start();
83
84        // Start system monitor
85        self.systemmonitor.start()?;
86
87        self.session_start = Instant::now();
88        Ok(())
89    }
90
91    /// Stop comprehensive profiling
92    pub fn stop(&mut self) {
93        self.app_profiler.lock().expect("Operation failed").stop();
94        self.systemmonitor.stop();
95    }
96
97    /// Time a function with comprehensive profiling
98    pub fn time_function<F, R>(&mut self, name: &str, f: F) -> R
99    where
100        F: FnOnce() -> R,
101    {
102        // Start flame graph tracking
103        self.flame_graph_generator.start_call(name);
104
105        // Execute with application profiling
106        let result = Timer::time_function(name, f);
107
108        // End flame graph tracking
109        self.flame_graph_generator.end_call();
110
111        // Check for alerts if enabled
112        if self.config.enable_alerts {
113            if let Ok(current_metrics) = self.systemmonitor.get_current_metrics() {
114                let alerts = self.system_alerter.check_alerts(&current_metrics);
115                for alert in alerts {
116                    self.handle_alert(&alert);
117                }
118            }
119        }
120
121        result
122    }
123
124    /// Generate comprehensive profiling report
125    pub fn generate_report(&mut self) -> ComprehensiveReport {
126        let app_report = self
127            .app_profiler
128            .lock()
129            .expect("Operation failed")
130            .get_report();
131        let system_metrics = self.systemmonitor.get_metrics_history();
132        let alerts = self.system_alerter.get_alert_history();
133
134        let mut bottleneck_reports = Vec::new();
135        if self.config.enable_bottleneck_detection {
136            let mut detector = BottleneckDetector::new(BottleneckConfig::default());
137            bottleneck_reports =
138                detector.analyze(&self.app_profiler.lock().expect("Operation failed"));
139        }
140
141        let flame_graph = if self.config.enable_flame_graphs {
142            Some(self.flame_graph_generator.generate())
143        } else {
144            None
145        };
146
147        ComprehensiveReport {
148            session_name: self.config.session_name.clone(),
149            session_duration: self.session_start.elapsed(),
150            application_report: app_report,
151            system_metrics,
152            alerts,
153            bottleneck_reports,
154            flame_graph,
155            generated_at: Instant::now(),
156        }
157    }
158
159    /// Export comprehensive report to multiple formats
160    pub fn export_report(&mut self, basepath: &str) -> Result<(), std::io::Error> {
161        let report = self.generate_report();
162
163        // Export text report
164        std::fs::write(format!("{basepath}_report.txt"), report.totext_format())?;
165
166        // Export JSON report
167        std::fs::write(format!("{basepath}_report.json"), report.to_json_format())?;
168
169        // Export flame graph if available
170        if let Some(ref flame_graph) = report.flame_graph {
171            let svg_generator = SvgFlameGraphGenerator::new(self.config.svgconfig.clone());
172            svg_generator.export_to_file(flame_graph, &format!("{basepath}_flamegraph.svg"))?;
173
174            // Export enhanced flame graph with system metrics
175            let enhanced = EnhancedFlameGraph {
176                performance: flame_graph.clone(),
177                memory: None,
178                cpu_usage: report
179                    .system_metrics
180                    .iter()
181                    .map(|m| (m.timestamp.duration_since(self.session_start), m.cpu_usage))
182                    .collect(),
183                memory_usage: report
184                    .system_metrics
185                    .iter()
186                    .map(|m| {
187                        (
188                            m.timestamp.duration_since(self.session_start),
189                            m.memory_usage,
190                        )
191                    })
192                    .collect(),
193                total_duration: self.session_start.elapsed(),
194            };
195            enhanced.export_enhanced_svg(&format!("{basepath}_enhanced_flamegraph.svg"))?;
196        }
197
198        Ok(())
199    }
200
201    /// Handle system alerts
202    fn handle_alert(&self, alert: &SystemAlert) {
203        // In a real implementation, this could send notifications, log to files, etc.
204        println!("ALERT: {}", alert.message);
205    }
206
207    /// Get application profiler reference
208    pub fn app_profiler(&self) -> Arc<Mutex<Profiler>> {
209        Arc::clone(&self.app_profiler)
210    }
211
212    /// Get current system metrics
213    pub fn get_current_system_metrics(
214        &self,
215    ) -> Result<
216        crate::profiling::system_monitor::SystemMetrics,
217        crate::profiling::system_monitor::SystemMonitorError,
218    > {
219        self.systemmonitor.get_current_metrics()
220    }
221
222    /// Get recent alerts
223    pub fn get_recent_alerts(&self, duration: Duration) -> Vec<SystemAlert> {
224        self.system_alerter.get_recent_alerts(duration)
225    }
226}
227
228impl Drop for ComprehensiveProfiler {
229    fn drop(&mut self) {
230        self.stop();
231    }
232}
233
234/// Comprehensive profiling report
235#[derive(Debug)]
236pub struct ComprehensiveReport {
237    /// Session name
238    pub session_name: String,
239    /// Total session duration
240    pub session_duration: Duration,
241    /// Application profiling report
242    pub application_report: String,
243    /// System metrics collected during session
244    pub system_metrics: Vec<crate::profiling::system_monitor::SystemMetrics>,
245    /// System alerts triggered during session
246    pub alerts: Vec<SystemAlert>,
247    /// Bottleneck analysis results
248    pub bottleneck_reports: Vec<BottleneckReport>,
249    /// Flame graph data
250    pub flame_graph: Option<crate::profiling::advanced::FlameGraphNode>,
251    /// Report generation timestamp
252    pub generated_at: Instant,
253}
254
255impl ComprehensiveReport {
256    /// Convert report to text format
257    pub fn totext_format(&self) -> String {
258        use std::fmt::Write;
259        let mut report = String::new();
260
261        writeln!(report, "=== {} ===", self.session_name).expect("Operation failed");
262        writeln!(
263            report,
264            "Session Duration: {:.2} seconds",
265            self.session_duration.as_secs_f64()
266        )
267        .expect("Test: operation failed");
268        writeln!(report, "Generated At: {:?}", self.generated_at).expect("Operation failed");
269        writeln!(report).expect("Operation failed");
270
271        // Application profiling
272        writeln!(report, "=== Application Performance ===").expect("Operation failed");
273        writeln!(report, "{}", self.application_report).expect("Operation failed");
274
275        // System metrics summary
276        if !self.system_metrics.is_empty() {
277            writeln!(report, "=== System Resource Summary ===").expect("Operation failed");
278            let avg_cpu = self.system_metrics.iter().map(|m| m.cpu_usage).sum::<f64>()
279                / self.system_metrics.len() as f64;
280            let avg_memory = self
281                .system_metrics
282                .iter()
283                .map(|m| m.memory_usage)
284                .sum::<usize>()
285                / self.system_metrics.len();
286            let max_cpu = self
287                .system_metrics
288                .iter()
289                .map(|m| m.cpu_usage)
290                .fold(0.0, f64::max);
291            let max_memory = self
292                .system_metrics
293                .iter()
294                .map(|m| m.memory_usage)
295                .max()
296                .unwrap_or(0);
297
298            writeln!(report, "Average CPU Usage: {avg_cpu:.1}%").expect("Operation failed");
299            writeln!(report, "Maximum CPU Usage: {max_cpu:.1}%").expect("Operation failed");
300            writeln!(
301                report,
302                "Average Memory Usage: {:.1} MB",
303                avg_memory as f64 / (1024.0 * 1024.0)
304            )
305            .expect("Test: operation failed");
306            writeln!(
307                report,
308                "Maximum Memory Usage: {:.1} MB",
309                max_memory as f64 / (1024.0 * 1024.0)
310            )
311            .expect("Test: operation failed");
312            writeln!(report).expect("Operation failed");
313        }
314
315        // Alerts
316        if !self.alerts.is_empty() {
317            writeln!(report, "=== System Alerts ({}) ===", self.alerts.len())
318                .expect("Operation failed");
319            for alert in &self.alerts {
320                writeln!(report, "[{:?}] {}", alert.severity, alert.message)
321                    .expect("Operation failed");
322            }
323            writeln!(report).expect("Operation failed");
324        }
325
326        // Bottlenecks
327        if !self.bottleneck_reports.is_empty() {
328            writeln!(
329                report,
330                "=== Performance Bottlenecks ({}) ===",
331                self.bottleneck_reports.len()
332            )
333            .expect("Test: operation failed");
334            for bottleneck in &self.bottleneck_reports {
335                writeln!(report, "Operation: {}", bottleneck.operation).expect("Operation failed");
336                writeln!(report, "Type: {:?}", bottleneck.bottleneck_type)
337                    .expect("Operation failed");
338                writeln!(report, "Severity: {:.2}", bottleneck.severity).expect("Operation failed");
339                writeln!(report, "Description: {}", bottleneck.description)
340                    .expect("Operation failed");
341                if !bottleneck.suggestions.is_empty() {
342                    writeln!(report, "Suggestions:").expect("Operation failed");
343                    for suggestion in &bottleneck.suggestions {
344                        writeln!(report, "  - {suggestion}").expect("Operation failed");
345                    }
346                }
347                writeln!(report).expect("Operation failed");
348            }
349        }
350
351        report
352    }
353
354    /// Convert report to JSON format
355    pub fn to_json_format(&self) -> String {
356        // Simplified JSON generation - in a real implementation would use serde
357        use std::fmt::Write;
358        let mut json = String::new();
359
360        writeln!(json, "{{").expect("Operation failed");
361        writeln!(json, "  \"session_name\": \"{}\",", self.session_name).expect("Operation failed");
362        writeln!(
363            json,
364            "  \"session_duration_seconds\": {},",
365            self.session_duration.as_secs_f64()
366        )
367        .expect("Test: operation failed");
368        writeln!(json, "  \"alert_count\": {},", self.alerts.len()).expect("Operation failed");
369        writeln!(
370            json,
371            "  \"bottleneck_count\": {},",
372            self.bottleneck_reports.len()
373        )
374        .expect("Test: operation failed");
375        writeln!(
376            json,
377            "  \"system_sample_count\": {}",
378            self.system_metrics.len()
379        )
380        .expect("Test: operation failed");
381
382        if !self.system_metrics.is_empty() {
383            let avg_cpu = self.system_metrics.iter().map(|m| m.cpu_usage).sum::<f64>()
384                / self.system_metrics.len() as f64;
385            let max_cpu = self
386                .system_metrics
387                .iter()
388                .map(|m| m.cpu_usage)
389                .fold(0.0, f64::max);
390            writeln!(json, "  \"average_cpu_usage\": {avg_cpu},").expect("Operation failed");
391            writeln!(json, "  \"maximum_cpu_usage\": {max_cpu}").expect("Operation failed");
392        }
393
394        writeln!(json, "}}").expect("Operation failed");
395        json
396    }
397
398    /// Print comprehensive report to console
399    pub fn print(&self) {
400        println!("{}", self.totext_format());
401    }
402}
403
404/// Convenience macro for comprehensive profiling
405#[macro_export]
406macro_rules! comprehensive_profile {
407    ($profiler:expr, $name:expr, $body:block) => {{
408        $profiler.time_function($name, || $body)
409    }};
410}
411
412#[cfg(test)]
413mod tests {
414    use super::*;
415    use std::thread;
416
417    #[test]
418    fn test_comprehensive_profiler() {
419        let config = ComprehensiveConfig {
420            session_name: "Test Session".to_string(),
421            ..Default::default()
422        };
423
424        let mut profiler = ComprehensiveProfiler::new(config);
425        profiler.start().expect("Operation failed");
426
427        // Profile some work
428        let result = profiler.time_function("test_work", || {
429            thread::sleep(Duration::from_millis(10));
430            42
431        });
432
433        assert_eq!(result, 42);
434
435        // Generate report
436        let report = profiler.generate_report();
437        assert_eq!(report.session_name, "Test Session");
438        assert!(report.session_duration > Duration::from_millis(5));
439
440        profiler.stop();
441    }
442
443    #[test]
444    fn test_comprehensive_report() {
445        let report = ComprehensiveReport {
446            session_name: "Test".to_string(),
447            session_duration: Duration::from_secs(1),
448            application_report: "Test report".to_string(),
449            system_metrics: Vec::new(),
450            alerts: Vec::new(),
451            bottleneck_reports: Vec::new(),
452            flame_graph: None,
453            generated_at: Instant::now(),
454        };
455
456        let text = report.totext_format();
457        assert!(text.contains("Test"));
458
459        let json = report.to_json_format();
460        assert!(json.contains("session_name"));
461    }
462}