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