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