quantrs2_core/optimizations/
profiling_integration.rs

1//! Quantum Computing Profiling Integration with SciRS2 Beta.1
2//!
3//! This module provides comprehensive profiling capabilities for quantum
4//! computations using the advanced profiling features in scirs2-core beta.1.
5
6use crate::error::QuantRS2Result;
7use scirs2_core::profiling::{MemoryTracker, Profiler, Timer};
8use std::collections::HashMap;
9use std::sync::{Arc, Mutex, OnceLock};
10use std::time::{Duration, Instant};
11
12/// Quantum operation profiling data
13#[derive(Debug, Clone, serde::Serialize)]
14pub struct QuantumOperationProfile {
15    pub operation_name: String,
16    pub execution_count: u64,
17    pub total_time: Duration,
18    pub average_time: Duration,
19    pub min_time: Duration,
20    pub max_time: Duration,
21    pub memory_usage: u64,
22    pub gate_count: u64,
23}
24
25/// Comprehensive quantum profiler
26pub struct QuantumProfiler {
27    /// Operation profiles
28    profiles: Arc<Mutex<HashMap<String, QuantumOperationProfile>>>,
29    /// Active timers
30    active_timers: Arc<Mutex<HashMap<String, Instant>>>,
31    /// Global profiling enabled flag
32    enabled: Arc<Mutex<bool>>,
33    /// Memory tracking
34    memory_tracker: Arc<Mutex<Option<MemoryTracker>>>,
35}
36
37impl Default for QuantumProfiler {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl QuantumProfiler {
44    /// Create a new quantum profiler
45    pub fn new() -> Self {
46        Self {
47            profiles: Arc::new(Mutex::new(HashMap::new())),
48            active_timers: Arc::new(Mutex::new(HashMap::new())),
49            enabled: Arc::new(Mutex::new(false)),
50            memory_tracker: Arc::new(Mutex::new(None)),
51        }
52    }
53
54    /// Enable profiling
55    pub fn enable(&self) {
56        *self.enabled.lock().unwrap() = true;
57
58        // Start global profiler
59        if let Ok(mut profiler) = Profiler::global().lock() {
60            profiler.start();
61        }
62    }
63
64    /// Disable profiling
65    pub fn disable(&self) {
66        *self.enabled.lock().unwrap() = false;
67
68        // Stop global profiler
69        if let Ok(mut profiler) = Profiler::global().lock() {
70            profiler.stop();
71        }
72    }
73
74    /// Check if profiling is enabled
75    pub fn is_enabled(&self) -> bool {
76        *self.enabled.lock().unwrap()
77    }
78
79    /// Start profiling a quantum operation
80    pub fn start_operation(&self, operation_name: &str) {
81        if !self.is_enabled() {
82            return;
83        }
84
85        let mut timers = self.active_timers.lock().unwrap();
86        timers.insert(operation_name.to_string(), Instant::now());
87
88        // Start memory tracking
89        let mut tracker = self.memory_tracker.lock().unwrap();
90        *tracker = Some(MemoryTracker::start(operation_name));
91    }
92
93    /// End profiling a quantum operation
94    pub fn end_operation(&self, operation_name: &str, gate_count: u64) {
95        if !self.is_enabled() {
96            return;
97        }
98
99        let start_time = {
100            let mut timers = self.active_timers.lock().unwrap();
101            timers.remove(operation_name)
102        };
103
104        if let Some(start) = start_time {
105            let execution_time = start.elapsed();
106
107            // Stop memory tracking
108            let memory_usage = {
109                let mut tracker = self.memory_tracker.lock().unwrap();
110                if let Some(mem_tracker) = tracker.take() {
111                    mem_tracker.stop();
112                    // In a real implementation, this would return actual memory usage
113                    0 // Placeholder
114                } else {
115                    0
116                }
117            };
118
119            // Update profile
120            let mut profiles = self.profiles.lock().unwrap();
121            let profile = profiles
122                .entry(operation_name.to_string())
123                .or_insert_with(|| QuantumOperationProfile {
124                    operation_name: operation_name.to_string(),
125                    execution_count: 0,
126                    total_time: Duration::ZERO,
127                    average_time: Duration::ZERO,
128                    min_time: Duration::MAX,
129                    max_time: Duration::ZERO,
130                    memory_usage: 0,
131                    gate_count: 0,
132                });
133
134            profile.execution_count += 1;
135            profile.total_time += execution_time;
136            profile.average_time = profile.total_time / profile.execution_count as u32;
137            profile.min_time = profile.min_time.min(execution_time);
138            profile.max_time = profile.max_time.max(execution_time);
139            profile.memory_usage += memory_usage;
140            profile.gate_count += gate_count;
141        }
142    }
143
144    /// Profile a quantum operation with automatic timing
145    pub fn profile_operation<F, R>(&self, operation_name: &str, gate_count: u64, operation: F) -> R
146    where
147        F: FnOnce() -> R,
148    {
149        if !self.is_enabled() {
150            return operation();
151        }
152
153        self.start_operation(operation_name);
154        let result = operation();
155        self.end_operation(operation_name, gate_count);
156        result
157    }
158
159    /// Get profiling results for all operations
160    pub fn get_profiles(&self) -> HashMap<String, QuantumOperationProfile> {
161        self.profiles.lock().unwrap().clone()
162    }
163
164    /// Get profiling results for a specific operation
165    pub fn get_operation_profile(&self, operation_name: &str) -> Option<QuantumOperationProfile> {
166        self.profiles.lock().unwrap().get(operation_name).cloned()
167    }
168
169    /// Generate a comprehensive profiling report
170    pub fn generate_report(&self) -> String {
171        let profiles = self.get_profiles();
172        let mut report = String::new();
173
174        report.push_str("=== QuantRS2 Performance Profiling Report ===\n\n");
175
176        if profiles.is_empty() {
177            report.push_str("No profiling data available.\n");
178            return report;
179        }
180
181        // Sort by total execution time
182        let mut sorted_profiles: Vec<_> = profiles.values().collect();
183        sorted_profiles.sort_by(|a, b| b.total_time.cmp(&a.total_time));
184
185        report.push_str(&format!(
186            "{:<30} {:<10} {:<12} {:<12} {:<12} {:<12} {:<10}\n",
187            "Operation", "Count", "Total (ms)", "Avg (ms)", "Min (ms)", "Max (ms)", "Gates"
188        ));
189        report.push_str(&"-".repeat(110));
190        report.push('\n');
191
192        for profile in &sorted_profiles {
193            report.push_str(&format!(
194                "{:<30} {:<10} {:<12.3} {:<12.3} {:<12.3} {:<12.3} {:<10}\n",
195                profile.operation_name,
196                profile.execution_count,
197                profile.total_time.as_secs_f64() * 1000.0,
198                profile.average_time.as_secs_f64() * 1000.0,
199                profile.min_time.as_secs_f64() * 1000.0,
200                profile.max_time.as_secs_f64() * 1000.0,
201                profile.gate_count,
202            ));
203        }
204
205        report.push_str("\n=== Performance Insights ===\n");
206
207        // Find the most time-consuming operation
208        if let Some(slowest) = sorted_profiles.first() {
209            report.push_str(&format!(
210                "Most time-consuming operation: {} ({:.3}ms total)\n",
211                slowest.operation_name,
212                slowest.total_time.as_secs_f64() * 1000.0
213            ));
214        }
215
216        // Find the most frequent operation
217        let most_frequent = sorted_profiles.iter().max_by_key(|p| p.execution_count);
218        if let Some(frequent) = most_frequent {
219            report.push_str(&format!(
220                "Most frequent operation: {} ({} executions)\n",
221                frequent.operation_name, frequent.execution_count
222            ));
223        }
224
225        // Calculate total gate throughput
226        let total_gates: u64 = profiles.values().map(|p| p.gate_count).sum();
227        let total_time: Duration = profiles.values().map(|p| p.total_time).sum();
228        if total_time.as_secs_f64() > 0.0 {
229            let gate_throughput = total_gates as f64 / total_time.as_secs_f64();
230            report.push_str(&format!(
231                "Total gate throughput: {:.0} gates/second\n",
232                gate_throughput
233            ));
234        }
235
236        report
237    }
238
239    /// Clear all profiling data
240    pub fn clear(&self) {
241        self.profiles.lock().unwrap().clear();
242        self.active_timers.lock().unwrap().clear();
243    }
244
245    /// Export profiling data to JSON
246    pub fn export_json(&self) -> QuantRS2Result<String> {
247        let profiles = self.get_profiles();
248        serde_json::to_string_pretty(&profiles).map_err(|e| e.into()) // Use the existing From<serde_json::Error> implementation
249    }
250}
251
252/// Global quantum profiler instance
253static GLOBAL_QUANTUM_PROFILER: OnceLock<QuantumProfiler> = OnceLock::new();
254
255/// Get the global quantum profiler
256pub fn global_quantum_profiler() -> &'static QuantumProfiler {
257    GLOBAL_QUANTUM_PROFILER.get_or_init(QuantumProfiler::new)
258}
259
260/// Enable quantum profiling globally
261pub fn enable_quantum_profiling() {
262    global_quantum_profiler().enable();
263}
264
265/// Disable quantum profiling globally
266pub fn disable_quantum_profiling() {
267    global_quantum_profiler().disable();
268}
269
270/// Check if quantum profiling is active
271pub fn is_profiling_active() -> bool {
272    global_quantum_profiler().is_enabled()
273}
274
275/// Macro for easy profiling of quantum operations
276#[macro_export]
277macro_rules! profile_quantum_operation {
278    ($operation_name:expr, $gate_count:expr, $operation:expr) => {{
279        $crate::optimizations::profiling_integration::global_quantum_profiler().profile_operation(
280            $operation_name,
281            $gate_count,
282            || $operation,
283        )
284    }};
285}
286
287/// Macro for easy profiling with automatic gate counting
288#[macro_export]
289macro_rules! profile_gate_operation {
290    ($gate_name:expr, $operation:expr) => {{
291        $crate::optimizations::profiling_integration::global_quantum_profiler().profile_operation(
292            $gate_name,
293            1,
294            || $operation,
295        )
296    }};
297}
298
299#[cfg(test)]
300mod tests {
301    use super::*;
302    use std::thread;
303
304    #[test]
305    fn test_basic_profiling() {
306        let profiler = QuantumProfiler::new();
307        profiler.enable();
308
309        // Profile a simple operation
310        let result = profiler.profile_operation("test_gate", 1, || {
311            thread::sleep(Duration::from_millis(10));
312            42
313        });
314
315        assert_eq!(result, 42);
316
317        let profiles = profiler.get_profiles();
318        assert!(profiles.contains_key("test_gate"));
319
320        let test_profile = &profiles["test_gate"];
321        assert_eq!(test_profile.execution_count, 1);
322        assert_eq!(test_profile.gate_count, 1);
323        assert!(test_profile.total_time >= Duration::from_millis(10));
324    }
325
326    #[test]
327    fn test_multiple_operations() {
328        let profiler = QuantumProfiler::new();
329        profiler.enable();
330
331        // Profile multiple operations
332        for i in 0..5 {
333            profiler.profile_operation("hadamard", 1, || {
334                thread::sleep(Duration::from_millis(1));
335            });
336        }
337
338        for i in 0..3 {
339            profiler.profile_operation("cnot", 2, || {
340                thread::sleep(Duration::from_millis(2));
341            });
342        }
343
344        let profiles = profiler.get_profiles();
345
346        let hadamard_profile = &profiles["hadamard"];
347        assert_eq!(hadamard_profile.execution_count, 5);
348        assert_eq!(hadamard_profile.gate_count, 5);
349
350        let cnot_profile = &profiles["cnot"];
351        assert_eq!(cnot_profile.execution_count, 3);
352        assert_eq!(cnot_profile.gate_count, 6); // 2 gates * 3 executions
353    }
354
355    #[test]
356    fn test_profiling_disabled() {
357        let profiler = QuantumProfiler::new();
358        // Don't enable profiling
359
360        let result = profiler.profile_operation("test_gate", 1, || 42);
361
362        assert_eq!(result, 42);
363
364        let profiles = profiler.get_profiles();
365        assert!(profiles.is_empty()); // No profiling data should be collected
366    }
367
368    #[test]
369    fn test_report_generation() {
370        let profiler = QuantumProfiler::new();
371        profiler.enable();
372
373        profiler.profile_operation("fast_gate", 1, || {
374            thread::sleep(Duration::from_millis(1));
375        });
376
377        profiler.profile_operation("slow_gate", 1, || {
378            thread::sleep(Duration::from_millis(10));
379        });
380
381        let report = profiler.generate_report();
382        assert!(report.contains("QuantRS2 Performance Profiling Report"));
383        assert!(report.contains("fast_gate"));
384        assert!(report.contains("slow_gate"));
385        assert!(report.contains("Performance Insights"));
386    }
387
388    #[test]
389    fn test_json_export() {
390        let profiler = QuantumProfiler::new();
391        profiler.enable();
392
393        profiler.profile_operation("test_operation", 1, || {
394            thread::sleep(Duration::from_millis(1));
395        });
396
397        let json_result = profiler.export_json();
398        assert!(json_result.is_ok());
399
400        let json = json_result.unwrap();
401        assert!(json.contains("test_operation"));
402        assert!(json.contains("execution_count"));
403    }
404}