1use 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
17pub struct ComprehensiveProfiler {
19 app_profiler: Arc<Mutex<Profiler>>,
21 systemmonitor: SystemMonitor,
23 system_alerter: SystemAlerter,
25 flame_graph_generator: FlameGraphGenerator,
27 session_start: Instant,
29 config: ComprehensiveConfig,
31}
32
33#[derive(Debug, Clone)]
35pub struct ComprehensiveConfig {
36 pub systemconfig: SystemMonitorConfig,
38 pub alertconfig: AlertConfig,
40 pub svgconfig: SvgFlameGraphConfig,
42 pub enable_bottleneck_detection: bool,
44 pub enable_alerts: bool,
46 pub enable_flame_graphs: bool,
48 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 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 pub fn start(&mut self) -> Result<(), crate::profiling::system_monitor::SystemMonitorError> {
81 self.app_profiler.lock().expect("Operation failed").start();
83
84 self.systemmonitor.start()?;
86
87 self.session_start = Instant::now();
88 Ok(())
89 }
90
91 pub fn stop(&mut self) {
93 self.app_profiler.lock().expect("Operation failed").stop();
94 self.systemmonitor.stop();
95 }
96
97 pub fn time_function<F, R>(&mut self, name: &str, f: F) -> R
99 where
100 F: FnOnce() -> R,
101 {
102 self.flame_graph_generator.start_call(name);
104
105 let result = Timer::time_function(name, f);
107
108 self.flame_graph_generator.end_call();
110
111 if self.config.enable_alerts {
113 if let Ok(current_metrics) = self.systemmonitor.get_current_metrics() {
114 let alerts = self.system_alerter.check_alerts(¤t_metrics);
115 for alert in alerts {
116 self.handle_alert(&alert);
117 }
118 }
119 }
120
121 result
122 }
123
124 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 pub fn export_report(&mut self, basepath: &str) -> Result<(), std::io::Error> {
161 let report = self.generate_report();
162
163 std::fs::write(format!("{basepath}_report.txt"), report.totext_format())?;
165
166 std::fs::write(format!("{basepath}_report.json"), report.to_json_format())?;
168
169 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 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 fn handle_alert(&self, alert: &SystemAlert) {
203 println!("ALERT: {}", alert.message);
205 }
206
207 pub fn app_profiler(&self) -> Arc<Mutex<Profiler>> {
209 Arc::clone(&self.app_profiler)
210 }
211
212 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 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#[derive(Debug)]
236pub struct ComprehensiveReport {
237 pub session_name: String,
239 pub session_duration: Duration,
241 pub application_report: String,
243 pub system_metrics: Vec<crate::profiling::system_monitor::SystemMetrics>,
245 pub alerts: Vec<SystemAlert>,
247 pub bottleneck_reports: Vec<BottleneckReport>,
249 pub flame_graph: Option<crate::profiling::advanced::FlameGraphNode>,
251 pub generated_at: Instant,
253}
254
255impl ComprehensiveReport {
256 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 writeln!(report, "=== Application Performance ===").expect("Operation failed");
273 writeln!(report, "{}", self.application_report).expect("Operation failed");
274
275 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 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 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 pub fn to_json_format(&self) -> String {
356 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 pub fn print(&self) {
400 println!("{}", self.totext_format());
401 }
402}
403
404#[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 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 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}