Skip to main content

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// v0.2.0 Advanced profiling and instrumentation modules
74pub mod instrumentation;
75pub mod memory_profiling;
76pub mod opentelemetry_integration;
77pub mod perf_integration;
78pub mod prometheus_metrics;
79pub mod tracing_framework;
80
81// Re-exports for backward compatibility and convenient access
82pub use entries::{MemoryEntry, TimingEntry};
83pub use memory::{profiling_memory_tracker, MemoryTracker};
84pub use profiler::Profiler;
85pub use timer::Timer;
86
87// Advanced profiling re-exports
88pub use advanced::{
89    BottleneckConfig, BottleneckDetector, BottleneckReport, BottleneckType, DifferentialProfiler,
90    DifferentialReport, ExportableProfiler, FlameGraphGenerator, FlameGraphNode, MemoryDiff,
91    PerformanceChange, PerformanceStats, ProfileSnapshot, ResourceStats, SystemResourceMonitor,
92    TimingDiff,
93};
94
95// Comprehensive profiling re-exports
96pub use comprehensive::{ComprehensiveConfig, ComprehensiveProfiler, ComprehensiveReport};
97
98// v0.2.0 Advanced profiling re-exports
99pub use tracing_framework::{init_tracing, TracingConfig};
100#[cfg(feature = "profiling_advanced")]
101pub use tracing_framework::{PerfZone, SpanGuard, TracingFormat};
102
103#[cfg(feature = "profiling_opentelemetry")]
104pub use opentelemetry_integration::{get_tracer, init_opentelemetry, OtelConfig};
105
106pub use instrumentation::{clear_events, record_event};
107#[cfg(feature = "instrumentation")]
108pub use instrumentation::{
109    get_all_counters, get_counter, get_events, print_counter_summary, record_event_with_duration,
110    InstrumentationEvent, InstrumentationScope, PerformanceCounter,
111};
112pub use perf_integration::PerfCounter;
113pub use perf_integration::PerfEvent;
114#[cfg(all(target_os = "linux", feature = "profiling_perf"))]
115pub use perf_integration::{PerfCounterGroup, PerfMarker};
116pub use prometheus_metrics::MetricsRegistry;
117#[cfg(feature = "profiling_prometheus")]
118pub use prometheus_metrics::{
119    latency_buckets, register_counter, register_counter_vec, register_gauge, register_gauge_vec,
120    register_histogram, register_histogram_vec, size_buckets, PrometheusTimer, SciRS2Metrics,
121};
122
123#[cfg(feature = "profiling_memory")]
124pub use memory_profiling::{disable_profiling, AllocationAnalysis, AllocationTracker, MemoryDelta};
125pub use memory_profiling::{enable_profiling, MemoryProfiler, MemoryStats};
126
127/// Macro for timing a block of code
128#[macro_export]
129macro_rules! profile_time {
130    ($name:expr, $body:block) => {{
131        let timer = $crate::profiling::Timer::start($name);
132        let result = $body;
133        timer.stop();
134        result
135    }};
136}
137
138/// Macro for tracking memory usage in a block of code
139#[macro_export]
140macro_rules! profile_memory {
141    ($name:expr, $body:block) => {{
142        let tracker = $crate::profiling::MemoryTracker::start($name);
143        let result = $body;
144        tracker.stop();
145        result
146    }};
147}
148
149/// Macro for timing a block of code with a parent operation
150#[macro_export]
151macro_rules! profile_time_with_parent {
152    ($name:expr, $parent:expr, $body:block) => {{
153        let timer = $crate::profiling::Timer::start_with_parent($name, $parent);
154        let result = $body;
155        timer.stop();
156        result
157    }};
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163    use std::thread;
164    use std::time::Duration;
165
166    #[test]
167    fn test_timer_basic() {
168        let timer = Timer::start("test_operation");
169        thread::sleep(Duration::from_millis(10));
170        timer.stop();
171
172        let elapsed = timer.elapsed();
173        assert!(elapsed >= Duration::from_millis(10));
174    }
175
176    #[test]
177    fn test_memory_tracker_basic() {
178        let tracker = MemoryTracker::start("test_memory");
179        tracker.stop();
180        // Memory tracking is a placeholder, so we just test that it doesn't panic
181    }
182
183    #[test]
184    fn test_profiler_integration() {
185        // Use global profiler
186        Profiler::global().lock().expect("Operation failed").start();
187
188        let timer = Timer::start("integration_test");
189        thread::sleep(Duration::from_millis(5));
190        timer.stop();
191
192        let stats = Profiler::global()
193            .lock()
194            .expect("Operation failed")
195            .get_timing_stats("integration_test");
196        assert!(stats.is_some());
197
198        let (calls, total, avg, max) = stats.expect("Operation failed");
199        assert_eq!(calls, 1);
200        assert!(total >= Duration::from_millis(5));
201        assert!(avg >= Duration::from_millis(5));
202        assert!(max >= Duration::from_millis(5));
203    }
204
205    #[test]
206    fn test_flame_graph_generator() {
207        let mut generator = advanced::FlameGraphGenerator::new();
208
209        generator.start_call("function_a");
210        generator.start_call("function_b");
211        thread::sleep(Duration::from_millis(1));
212        generator.end_call();
213        generator.end_call();
214
215        let flame_graph = generator.generate();
216        assert!(!flame_graph.children.is_empty());
217    }
218
219    #[test]
220    fn test_bottleneck_detector() {
221        // Use global profiler
222        Profiler::global().lock().expect("Operation failed").start();
223
224        // Simulate a slow operation
225        let timer = Timer::start("slow_operation");
226        thread::sleep(Duration::from_millis(200));
227        timer.stop();
228
229        let config = advanced::BottleneckConfig {
230            min_execution_threshold: Duration::from_millis(100),
231            min_calls: 1, // Allow single calls to be detected
232            ..Default::default()
233        };
234
235        let mut detector = advanced::BottleneckDetector::new(config);
236        let reports = detector.analyze(&Profiler::global().lock().expect("Operation failed"));
237
238        assert!(!reports.is_empty());
239        assert_eq!(
240            reports[0].bottleneck_type,
241            advanced::BottleneckType::SlowExecution
242        );
243    }
244
245    #[test]
246    fn test_differential_profiler() {
247        // Use global profiler
248        Profiler::global().lock().expect("Operation failed").start();
249
250        // Baseline run
251        let timer = Timer::start("diff_test_operation");
252        thread::sleep(Duration::from_millis(10));
253        timer.stop();
254
255        let mut diff_profiler = advanced::DifferentialProfiler::new();
256        diff_profiler.setbaseline(
257            &Profiler::global().lock().expect("Operation failed"),
258            Some("baseline".to_string()),
259        );
260
261        // Current run (slower) - use same operation name for comparison
262        let timer = Timer::start("diff_test_operation");
263        thread::sleep(Duration::from_millis(20));
264        timer.stop();
265
266        diff_profiler.set_current(
267            &Profiler::global().lock().expect("Operation failed"),
268            Some("current".to_string()),
269        );
270
271        let report = diff_profiler.generate_diff_report();
272        assert!(report.is_some());
273
274        let report = report.expect("Operation failed");
275        assert!(!report.timing_diffs.is_empty() || !report.memory_diffs.is_empty());
276        // Allow either timing or memory diffs
277    }
278
279    #[test]
280    fn test_system_resourcemonitor() {
281        let monitor = advanced::SystemResourceMonitor::new(Duration::from_millis(10));
282        monitor.start();
283
284        thread::sleep(Duration::from_millis(50));
285        monitor.stop();
286
287        let stats = monitor.get_stats();
288        assert!(stats.sample_count > 0);
289    }
290
291    #[test]
292    fn test_exportable_profiler() {
293        let mut profiler = advanced::ExportableProfiler::new();
294        profiler.add_metadata("test_run".to_string(), "beta2".to_string());
295
296        profiler.profiler().start();
297
298        let timer = Timer::start("export_test");
299        thread::sleep(Duration::from_millis(5));
300        timer.stop();
301
302        // Test CSV export (to a temporary file path that we won't actually create)
303        // In a real test, you'd use tempfile crate
304        let csv_result = profiler.export_to_csv("/tmp/test_profile.csv");
305        // We expect this to work or fail gracefully
306        drop(csv_result);
307    }
308}