quantrs2_core/optimizations/
profiling_integration.rs1use 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#[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
25pub struct QuantumProfiler {
27 profiles: Arc<Mutex<HashMap<String, QuantumOperationProfile>>>,
29 active_timers: Arc<Mutex<HashMap<String, Instant>>>,
31 enabled: Arc<Mutex<bool>>,
33 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 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 pub fn enable(&self) {
56 *self.enabled.lock().unwrap() = true;
57
58 if let Ok(mut profiler) = Profiler::global().lock() {
60 profiler.start();
61 }
62 }
63
64 pub fn disable(&self) {
66 *self.enabled.lock().unwrap() = false;
67
68 if let Ok(mut profiler) = Profiler::global().lock() {
70 profiler.stop();
71 }
72 }
73
74 pub fn is_enabled(&self) -> bool {
76 *self.enabled.lock().unwrap()
77 }
78
79 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 let mut tracker = self.memory_tracker.lock().unwrap();
90 *tracker = Some(MemoryTracker::start(operation_name));
91 }
92
93 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 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 0 } else {
115 0
116 }
117 };
118
119 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 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 pub fn get_profiles(&self) -> HashMap<String, QuantumOperationProfile> {
161 self.profiles.lock().unwrap().clone()
162 }
163
164 pub fn get_operation_profile(&self, operation_name: &str) -> Option<QuantumOperationProfile> {
166 self.profiles.lock().unwrap().get(operation_name).cloned()
167 }
168
169 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 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 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 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 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 pub fn clear(&self) {
241 self.profiles.lock().unwrap().clear();
242 self.active_timers.lock().unwrap().clear();
243 }
244
245 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()) }
250}
251
252static GLOBAL_QUANTUM_PROFILER: OnceLock<QuantumProfiler> = OnceLock::new();
254
255pub fn global_quantum_profiler() -> &'static QuantumProfiler {
257 GLOBAL_QUANTUM_PROFILER.get_or_init(QuantumProfiler::new)
258}
259
260pub fn enable_quantum_profiling() {
262 global_quantum_profiler().enable();
263}
264
265pub fn disable_quantum_profiling() {
267 global_quantum_profiler().disable();
268}
269
270pub fn is_profiling_active() -> bool {
272 global_quantum_profiler().is_enabled()
273}
274
275#[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_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 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 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); }
354
355 #[test]
356 fn test_profiling_disabled() {
357 let profiler = QuantumProfiler::new();
358 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()); }
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}