scirs2_core/profiling/
mod.rs

1//! # Profiling (Beta 2 Enhanced)
2//!
3//! This module provides comprehensive utilities for profiling computational performance in scientific applications
4//! with advanced features for detailed performance analysis and optimization.
5//!
6//! ## Enhanced Features (Beta 2)
7//!
8//! * Function-level timing instrumentation
9//! * Memory allocation tracking
10//! * Hierarchical profiling for nested operations
11//! * Easy-to-use macros for profiling sections of code
12//! * **Flame graph generation** for visualizing call hierarchies
13//! * **Automated bottleneck detection** with performance thresholds
14//! * **System-level resource monitoring** (CPU, memory, network)
15//! * **Hardware performance counter integration**
16//! * **Differential profiling** to compare performance between runs
17//! * **Continuous performance monitoring** for long-running processes
18//! * **Export capabilities** to various formats (JSON, CSV, flamegraph)
19//!
20//! ## Usage
21//!
22//! ```rust,no_run
23//! use scirs2_core::profiling::{Profiler, Timer, MemoryTracker};
24//!
25//! // Start the global profiler
26//! Profiler::global().lock().expect("Operation failed").start();
27//!
28//! // Time a function call
29//! let result = Timer::time_function("matrix_multiplication", || {
30//!     // Perform matrix multiplication
31//!     // ...
32//!     42 // Return some result
33//! });
34//!
35//! // Time a code block with more control
36//! let timer = Timer::start("data_processing");
37//! // Perform data processing
38//! // ...
39//! timer.stop();
40//!
41//! // Track memory allocations
42//! let tracker = MemoryTracker::start("large_array_operation");
43//! let large_array = vec![0; 1_000_000];
44//! // ...
45//! tracker.stop();
46//!
47//! // Print profiling report
48//! Profiler::global().lock().expect("Operation failed").print_report();
49//!
50//! // Stop profiling
51//! Profiler::global().lock().expect("Operation failed").stop();
52//! ```
53
54// Module declarations
55pub mod advanced;
56pub mod comprehensive;
57pub mod entries;
58pub mod memory;
59pub mod profiler;
60pub mod timer;
61
62// External modules that were already in the profiling directory
63pub mod adaptive;
64pub mod continuousmonitoring;
65pub mod coverage;
66pub mod dashboards;
67pub mod flame_graph_svg;
68pub mod hardware_counters;
69pub mod performance_hints;
70pub mod production;
71pub mod system_monitor;
72
73// Re-exports for backward compatibility and convenient access
74pub use entries::{MemoryEntry, TimingEntry};
75pub use memory::{profiling_memory_tracker, MemoryTracker};
76pub use profiler::Profiler;
77pub use timer::Timer;
78
79// Advanced profiling re-exports
80pub use advanced::{
81    BottleneckConfig, BottleneckDetector, BottleneckReport, BottleneckType, DifferentialProfiler,
82    DifferentialReport, ExportableProfiler, FlameGraphGenerator, FlameGraphNode, MemoryDiff,
83    PerformanceChange, PerformanceStats, ProfileSnapshot, ResourceStats, SystemResourceMonitor,
84    TimingDiff,
85};
86
87// Comprehensive profiling re-exports
88pub use comprehensive::{ComprehensiveConfig, ComprehensiveProfiler, ComprehensiveReport};
89
90/// Macro for timing a block of code
91#[macro_export]
92macro_rules! profile_time {
93    ($name:expr, $body:block) => {{
94        let timer = $crate::profiling::Timer::start($name);
95        let result = $body;
96        timer.stop();
97        result
98    }};
99}
100
101/// Macro for tracking memory usage in a block of code
102#[macro_export]
103macro_rules! profile_memory {
104    ($name:expr, $body:block) => {{
105        let tracker = $crate::profiling::MemoryTracker::start($name);
106        let result = $body;
107        tracker.stop();
108        result
109    }};
110}
111
112/// Macro for timing a block of code with a parent operation
113#[macro_export]
114macro_rules! profile_time_with_parent {
115    ($name:expr, $parent:expr, $body:block) => {{
116        let timer = $crate::profiling::Timer::start_with_parent($name, $parent);
117        let result = $body;
118        timer.stop();
119        result
120    }};
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use std::thread;
127    use std::time::Duration;
128
129    #[test]
130    fn test_timer_basic() {
131        let timer = Timer::start("test_operation");
132        thread::sleep(Duration::from_millis(10));
133        timer.stop();
134
135        let elapsed = timer.elapsed();
136        assert!(elapsed >= Duration::from_millis(10));
137    }
138
139    #[test]
140    fn test_memory_tracker_basic() {
141        let tracker = MemoryTracker::start("test_memory");
142        tracker.stop();
143        // Memory tracking is a placeholder, so we just test that it doesn't panic
144    }
145
146    #[test]
147    fn test_profiler_integration() {
148        // Use global profiler
149        Profiler::global().lock().expect("Operation failed").start();
150
151        let timer = Timer::start("integration_test");
152        thread::sleep(Duration::from_millis(5));
153        timer.stop();
154
155        let stats = Profiler::global()
156            .lock()
157            .expect("Operation failed")
158            .get_timing_stats("integration_test");
159        assert!(stats.is_some());
160
161        let (calls, total, avg, max) = stats.expect("Operation failed");
162        assert_eq!(calls, 1);
163        assert!(total >= Duration::from_millis(5));
164        assert!(avg >= Duration::from_millis(5));
165        assert!(max >= Duration::from_millis(5));
166    }
167
168    #[test]
169    fn test_flame_graph_generator() {
170        let mut generator = advanced::FlameGraphGenerator::new();
171
172        generator.start_call("function_a");
173        generator.start_call("function_b");
174        thread::sleep(Duration::from_millis(1));
175        generator.end_call();
176        generator.end_call();
177
178        let flame_graph = generator.generate();
179        assert!(!flame_graph.children.is_empty());
180    }
181
182    #[test]
183    fn test_bottleneck_detector() {
184        // Use global profiler
185        Profiler::global().lock().expect("Operation failed").start();
186
187        // Simulate a slow operation
188        let timer = Timer::start("slow_operation");
189        thread::sleep(Duration::from_millis(200));
190        timer.stop();
191
192        let config = advanced::BottleneckConfig {
193            min_execution_threshold: Duration::from_millis(100),
194            min_calls: 1, // Allow single calls to be detected
195            ..Default::default()
196        };
197
198        let mut detector = advanced::BottleneckDetector::new(config);
199        let reports = detector.analyze(&Profiler::global().lock().expect("Operation failed"));
200
201        assert!(!reports.is_empty());
202        assert_eq!(
203            reports[0].bottleneck_type,
204            advanced::BottleneckType::SlowExecution
205        );
206    }
207
208    #[test]
209    fn test_differential_profiler() {
210        // Use global profiler
211        Profiler::global().lock().expect("Operation failed").start();
212
213        // Baseline run
214        let timer = Timer::start("diff_test_operation");
215        thread::sleep(Duration::from_millis(10));
216        timer.stop();
217
218        let mut diff_profiler = advanced::DifferentialProfiler::new();
219        diff_profiler.setbaseline(
220            &Profiler::global().lock().expect("Operation failed"),
221            Some("baseline".to_string()),
222        );
223
224        // Current run (slower) - use same operation name for comparison
225        let timer = Timer::start("diff_test_operation");
226        thread::sleep(Duration::from_millis(20));
227        timer.stop();
228
229        diff_profiler.set_current(
230            &Profiler::global().lock().expect("Operation failed"),
231            Some("current".to_string()),
232        );
233
234        let report = diff_profiler.generate_diff_report();
235        assert!(report.is_some());
236
237        let report = report.expect("Operation failed");
238        assert!(!report.timing_diffs.is_empty() || !report.memory_diffs.is_empty());
239        // Allow either timing or memory diffs
240    }
241
242    #[test]
243    fn test_system_resourcemonitor() {
244        let monitor = advanced::SystemResourceMonitor::new(Duration::from_millis(10));
245        monitor.start();
246
247        thread::sleep(Duration::from_millis(50));
248        monitor.stop();
249
250        let stats = monitor.get_stats();
251        assert!(stats.sample_count > 0);
252    }
253
254    #[test]
255    fn test_exportable_profiler() {
256        let mut profiler = advanced::ExportableProfiler::new();
257        profiler.add_metadata("test_run".to_string(), "beta2".to_string());
258
259        profiler.profiler().start();
260
261        let timer = Timer::start("export_test");
262        thread::sleep(Duration::from_millis(5));
263        timer.stop();
264
265        // Test CSV export (to a temporary file path that we won't actually create)
266        // In a real test, you'd use tempfile crate
267        let csv_result = profiler.export_to_csv("/tmp/test_profile.csv");
268        // We expect this to work or fail gracefully
269        drop(csv_result);
270    }
271}