scirs2_sparse/realtime_performance_monitor/
metrics.rs

1//! Performance Metrics and Measurement
2//!
3//! This module contains structures for capturing and tracking performance metrics
4//! from various Advanced mode processors.
5
6use std::collections::HashMap;
7use std::time::{Instant, SystemTime, UNIX_EPOCH};
8
9/// Type of Advanced processor
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum ProcessorType {
12    QuantumInspired,
13    NeuralAdaptive,
14    QuantumNeuralHybrid,
15    MemoryCompression,
16}
17
18impl std::fmt::Display for ProcessorType {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        match self {
21            ProcessorType::QuantumInspired => write!(f, "QuantumInspired"),
22            ProcessorType::NeuralAdaptive => write!(f, "NeuralAdaptive"),
23            ProcessorType::QuantumNeuralHybrid => write!(f, "QuantumNeuralHybrid"),
24            ProcessorType::MemoryCompression => write!(f, "MemoryCompression"),
25        }
26    }
27}
28
29impl ProcessorType {
30    /// Get all processor types
31    pub fn all() -> Vec<ProcessorType> {
32        vec![
33            ProcessorType::QuantumInspired,
34            ProcessorType::NeuralAdaptive,
35            ProcessorType::QuantumNeuralHybrid,
36            ProcessorType::MemoryCompression,
37        ]
38    }
39
40    /// Check if processor type supports specific metrics
41    pub fn supports_quantum_metrics(&self) -> bool {
42        matches!(
43            self,
44            ProcessorType::QuantumInspired | ProcessorType::QuantumNeuralHybrid
45        )
46    }
47
48    pub fn supports_neural_metrics(&self) -> bool {
49        matches!(
50            self,
51            ProcessorType::NeuralAdaptive | ProcessorType::QuantumNeuralHybrid
52        )
53    }
54
55    pub fn supports_compression_metrics(&self) -> bool {
56        matches!(self, ProcessorType::MemoryCompression)
57    }
58}
59
60/// Individual performance sample
61#[derive(Debug, Clone)]
62pub struct PerformanceSample {
63    pub timestamp: u64,
64    pub processor_type: ProcessorType,
65    pub processor_id: String,
66    pub execution_time_ms: f64,
67    pub throughput_ops_per_sec: f64,
68    pub memory_usage_mb: f64,
69    pub cache_hit_ratio: f64,
70    pub error_rate: f64,
71    pub cpu_utilization: f64,
72    pub gpu_utilization: f64,
73    pub quantum_coherence: Option<f64>,
74    pub neural_confidence: Option<f64>,
75    pub compression_ratio: Option<f64>,
76    pub custom_metrics: HashMap<String, f64>,
77}
78
79impl PerformanceSample {
80    /// Create a new performance sample
81    pub fn new(processor_type: ProcessorType, processor_id: String) -> Self {
82        Self {
83            timestamp: SystemTime::now()
84                .duration_since(UNIX_EPOCH)
85                .unwrap_or_default()
86                .as_millis() as u64,
87            processor_type,
88            processor_id,
89            execution_time_ms: 0.0,
90            throughput_ops_per_sec: 0.0,
91            memory_usage_mb: 0.0,
92            cache_hit_ratio: 0.0,
93            error_rate: 0.0,
94            cpu_utilization: 0.0,
95            gpu_utilization: 0.0,
96            quantum_coherence: None,
97            neural_confidence: None,
98            compression_ratio: None,
99            custom_metrics: HashMap::new(),
100        }
101    }
102
103    /// Create sample with execution time
104    pub fn with_execution_time(mut self, execution_time_ms: f64) -> Self {
105        self.execution_time_ms = execution_time_ms;
106        self
107    }
108
109    /// Create sample with throughput
110    pub fn with_throughput(mut self, throughput_ops_per_sec: f64) -> Self {
111        self.throughput_ops_per_sec = throughput_ops_per_sec;
112        self
113    }
114
115    /// Create sample with memory usage
116    pub fn with_memory_usage(mut self, memory_usage_mb: f64) -> Self {
117        self.memory_usage_mb = memory_usage_mb;
118        self
119    }
120
121    /// Create sample with cache hit ratio
122    pub fn with_cache_hit_ratio(mut self, cache_hit_ratio: f64) -> Self {
123        self.cache_hit_ratio = cache_hit_ratio.clamp(0.0, 1.0);
124        self
125    }
126
127    /// Create sample with error rate
128    pub fn with_error_rate(mut self, error_rate: f64) -> Self {
129        self.error_rate = error_rate.clamp(0.0, 1.0);
130        self
131    }
132
133    /// Create sample with CPU utilization
134    pub fn with_cpu_utilization(mut self, cpu_utilization: f64) -> Self {
135        self.cpu_utilization = cpu_utilization.clamp(0.0, 1.0);
136        self
137    }
138
139    /// Create sample with GPU utilization
140    pub fn with_gpu_utilization(mut self, gpu_utilization: f64) -> Self {
141        self.gpu_utilization = gpu_utilization.clamp(0.0, 1.0);
142        self
143    }
144
145    /// Set quantum coherence (for quantum processors)
146    pub fn with_quantum_coherence(mut self, coherence: f64) -> Self {
147        if self.processor_type.supports_quantum_metrics() {
148            self.quantum_coherence = Some(coherence.clamp(0.0, 1.0));
149        }
150        self
151    }
152
153    /// Set neural confidence (for neural processors)
154    pub fn with_neural_confidence(mut self, confidence: f64) -> Self {
155        if self.processor_type.supports_neural_metrics() {
156            self.neural_confidence = Some(confidence.clamp(0.0, 1.0));
157        }
158        self
159    }
160
161    /// Set compression ratio (for memory compression)
162    pub fn with_compression_ratio(mut self, ratio: f64) -> Self {
163        if self.processor_type.supports_compression_metrics() {
164            self.compression_ratio = Some(ratio.max(0.0));
165        }
166        self
167    }
168
169    /// Add custom metric
170    pub fn with_custom_metric(mut self, name: String, value: f64) -> Self {
171        self.custom_metrics.insert(name, value);
172        self
173    }
174
175    /// Calculate efficiency score (composite metric)
176    pub fn efficiency_score(&self) -> f64 {
177        let mut score = 0.0;
178        let mut factors = 0;
179
180        // Throughput factor (higher is better)
181        if self.throughput_ops_per_sec > 0.0 {
182            score += (self.throughput_ops_per_sec / 1000.0).min(1.0);
183            factors += 1;
184        }
185
186        // Execution time factor (lower is better)
187        if self.execution_time_ms > 0.0 {
188            score += (1.0 / (1.0 + self.execution_time_ms / 1000.0)).min(1.0);
189            factors += 1;
190        }
191
192        // Cache hit ratio factor
193        score += self.cache_hit_ratio;
194        factors += 1;
195
196        // Error rate factor (lower is better)
197        score += 1.0 - self.error_rate;
198        factors += 1;
199
200        // Resource utilization factor (balanced is better)
201        let cpu_factor = if self.cpu_utilization > 0.9 {
202            0.5
203        } else {
204            self.cpu_utilization
205        };
206        let gpu_factor = if self.gpu_utilization > 0.9 {
207            0.5
208        } else {
209            self.gpu_utilization
210        };
211        score += (cpu_factor + gpu_factor) / 2.0;
212        factors += 1;
213
214        // Processor-specific factors
215        if let Some(coherence) = self.quantum_coherence {
216            score += coherence;
217            factors += 1;
218        }
219
220        if let Some(confidence) = self.neural_confidence {
221            score += confidence;
222            factors += 1;
223        }
224
225        if let Some(ratio) = self.compression_ratio {
226            score += (ratio / 10.0).min(1.0); // Normalize compression ratio
227            factors += 1;
228        }
229
230        if factors > 0 {
231            score / factors as f64
232        } else {
233            0.0
234        }
235    }
236
237    /// Check if sample indicates performance issues
238    pub fn has_performance_issues(&self) -> Vec<String> {
239        let mut issues = Vec::new();
240
241        if self.execution_time_ms > 1000.0 {
242            issues.push("High execution time".to_string());
243        }
244
245        if self.throughput_ops_per_sec < 10.0 {
246            issues.push("Low throughput".to_string());
247        }
248
249        if self.cache_hit_ratio < 0.5 {
250            issues.push("Low cache hit ratio".to_string());
251        }
252
253        if self.error_rate > 0.1 {
254            issues.push("High error rate".to_string());
255        }
256
257        if self.cpu_utilization > 0.95 {
258            issues.push("CPU overutilization".to_string());
259        }
260
261        if self.memory_usage_mb > 1000.0 {
262            issues.push("High memory usage".to_string());
263        }
264
265        if let Some(coherence) = self.quantum_coherence {
266            if coherence < 0.3 {
267                issues.push("Low quantum coherence".to_string());
268            }
269        }
270
271        if let Some(confidence) = self.neural_confidence {
272            if confidence < 0.5 {
273                issues.push("Low neural confidence".to_string());
274            }
275        }
276
277        issues
278    }
279
280    /// Get metric value by name
281    pub fn get_metric(&self, name: &str) -> Option<f64> {
282        match name {
283            "execution_time_ms" => Some(self.execution_time_ms),
284            "throughput_ops_per_sec" => Some(self.throughput_ops_per_sec),
285            "memory_usage_mb" => Some(self.memory_usage_mb),
286            "cache_hit_ratio" => Some(self.cache_hit_ratio),
287            "error_rate" => Some(self.error_rate),
288            "cpu_utilization" => Some(self.cpu_utilization),
289            "gpu_utilization" => Some(self.gpu_utilization),
290            "quantum_coherence" => self.quantum_coherence,
291            "neural_confidence" => self.neural_confidence,
292            "compression_ratio" => self.compression_ratio,
293            "efficiency_score" => Some(self.efficiency_score()),
294            _ => self.custom_metrics.get(name).copied(),
295        }
296    }
297
298    /// Get all available metric names
299    pub fn metric_names(&self) -> Vec<String> {
300        let mut names = vec![
301            "execution_time_ms".to_string(),
302            "throughput_ops_per_sec".to_string(),
303            "memory_usage_mb".to_string(),
304            "cache_hit_ratio".to_string(),
305            "error_rate".to_string(),
306            "cpu_utilization".to_string(),
307            "gpu_utilization".to_string(),
308            "efficiency_score".to_string(),
309        ];
310
311        if self.quantum_coherence.is_some() {
312            names.push("quantum_coherence".to_string());
313        }
314
315        if self.neural_confidence.is_some() {
316            names.push("neural_confidence".to_string());
317        }
318
319        if self.compression_ratio.is_some() {
320            names.push("compression_ratio".to_string());
321        }
322
323        names.extend(self.custom_metrics.keys().cloned());
324        names
325    }
326}
327
328/// Aggregated performance metrics
329#[derive(Debug, Default, Clone)]
330pub struct AggregatedMetrics {
331    pub avg_execution_time: f64,
332    pub avg_throughput: f64,
333    pub avg_memory_usage: f64,
334    pub avg_cache_hit_ratio: f64,
335    pub avg_error_rate: f64,
336    pub avg_cpu_utilization: f64,
337    pub avg_gpu_utilization: f64,
338    pub peak_throughput: f64,
339    pub min_execution_time: f64,
340    pub max_execution_time: f64,
341    pub total_operations: usize,
342    pub efficiency_score: f64,
343    pub sample_count: usize,
344}
345
346impl AggregatedMetrics {
347    /// Create new aggregated metrics
348    pub fn new() -> Self {
349        Self {
350            min_execution_time: f64::INFINITY,
351            max_execution_time: 0.0,
352            ..Default::default()
353        }
354    }
355
356    /// Update aggregated metrics with a new sample
357    pub fn update_with_sample(&mut self, sample: &PerformanceSample) {
358        let n = self.sample_count as f64;
359        let new_n = n + 1.0;
360
361        // Update running averages
362        self.avg_execution_time = (self.avg_execution_time * n + sample.execution_time_ms) / new_n;
363        self.avg_throughput = (self.avg_throughput * n + sample.throughput_ops_per_sec) / new_n;
364        self.avg_memory_usage = (self.avg_memory_usage * n + sample.memory_usage_mb) / new_n;
365        self.avg_cache_hit_ratio = (self.avg_cache_hit_ratio * n + sample.cache_hit_ratio) / new_n;
366        self.avg_error_rate = (self.avg_error_rate * n + sample.error_rate) / new_n;
367        self.avg_cpu_utilization = (self.avg_cpu_utilization * n + sample.cpu_utilization) / new_n;
368        self.avg_gpu_utilization = (self.avg_gpu_utilization * n + sample.gpu_utilization) / new_n;
369        self.efficiency_score = (self.efficiency_score * n + sample.efficiency_score()) / new_n;
370
371        // Update extremes
372        self.peak_throughput = self.peak_throughput.max(sample.throughput_ops_per_sec);
373        self.min_execution_time = self.min_execution_time.min(sample.execution_time_ms);
374        self.max_execution_time = self.max_execution_time.max(sample.execution_time_ms);
375
376        self.total_operations += 1;
377        self.sample_count += 1;
378    }
379
380    /// Reset all metrics
381    pub fn reset(&mut self) {
382        *self = Self::new();
383    }
384
385    /// Get performance variance for execution time
386    pub fn execution_time_variance(&self, samples: &[PerformanceSample]) -> f64 {
387        if samples.len() <= 1 {
388            return 0.0;
389        }
390
391        let mean = self.avg_execution_time;
392        let variance = samples
393            .iter()
394            .map(|s| (s.execution_time_ms - mean).powi(2))
395            .sum::<f64>()
396            / (samples.len() - 1) as f64;
397
398        variance
399    }
400
401    /// Get performance stability score (lower variance = higher stability)
402    pub fn stability_score(&self, samples: &[PerformanceSample]) -> f64 {
403        if samples.is_empty() {
404            return 0.0;
405        }
406
407        let variance = self.execution_time_variance(samples);
408        let coefficient_of_variation = if self.avg_execution_time > 0.0 {
409            variance.sqrt() / self.avg_execution_time
410        } else {
411            0.0
412        };
413
414        // Convert to stability score (0-1, higher is more stable)
415        (1.0 / (1.0 + coefficient_of_variation)).clamp(0.0, 1.0)
416    }
417}
418
419/// System metrics tracking
420#[derive(Debug, Clone)]
421pub struct SystemMetrics {
422    pub cpu_usage: f64,
423    pub memory_usage: f64,
424    pub gpu_usage: f64,
425    pub network_io: f64,
426    pub disk_io: f64,
427    pub temperature: f64,
428    pub power_consumption: f64,
429    pub system_load: f64,
430    pub available_memory_mb: f64,
431    pub cpu_frequency_mhz: f64,
432    pub timestamp: u64,
433}
434
435impl SystemMetrics {
436    /// Create new system metrics
437    pub fn new() -> Self {
438        Self {
439            cpu_usage: 0.0,
440            memory_usage: 0.0,
441            gpu_usage: 0.0,
442            network_io: 0.0,
443            disk_io: 0.0,
444            temperature: 0.0,
445            power_consumption: 0.0,
446            system_load: 0.0,
447            available_memory_mb: 0.0,
448            cpu_frequency_mhz: 0.0,
449            timestamp: SystemTime::now()
450                .duration_since(UNIX_EPOCH)
451                .unwrap_or_default()
452                .as_millis() as u64,
453        }
454    }
455
456    /// Update timestamp
457    pub fn update_timestamp(&mut self) {
458        self.timestamp = SystemTime::now()
459            .duration_since(UNIX_EPOCH)
460            .unwrap_or_default()
461            .as_millis() as u64;
462    }
463
464    /// Check if system is under high load
465    pub fn is_high_load(&self) -> bool {
466        self.cpu_usage > 0.8 || self.memory_usage > 0.9 || self.system_load > 2.0
467    }
468
469    /// Get system health score (0-1, higher is better)
470    pub fn health_score(&self) -> f64 {
471        let mut score = 0.0;
472        let mut factors = 0;
473
474        // CPU usage (optimal around 60-80%)
475        let cpu_score = if self.cpu_usage > 0.9 {
476            0.2
477        } else if self.cpu_usage > 0.8 {
478            0.8
479        } else if self.cpu_usage > 0.6 {
480            1.0
481        } else {
482            self.cpu_usage / 0.6
483        };
484        score += cpu_score;
485        factors += 1;
486
487        // Memory usage (lower is better)
488        score += 1.0 - self.memory_usage;
489        factors += 1;
490
491        // Temperature (assuming normal is < 70°C)
492        if self.temperature > 0.0 {
493            let temp_score = if self.temperature > 80.0 {
494                0.0
495            } else if self.temperature > 70.0 {
496                (80.0 - self.temperature) / 10.0
497            } else {
498                1.0
499            };
500            score += temp_score;
501            factors += 1;
502        }
503
504        // System load (lower is better)
505        let load_score = (1.0 / (1.0 + self.system_load)).clamp(0.0, 1.0);
506        score += load_score;
507        factors += 1;
508
509        if factors > 0 {
510            score / factors as f64
511        } else {
512            0.0
513        }
514    }
515}
516
517impl Default for SystemMetrics {
518    fn default() -> Self {
519        Self::new()
520    }
521}
522
523/// Execution timing helper for measuring performance
524#[derive(Debug)]
525pub struct ExecutionTimer {
526    start_time: Instant,
527    label: Option<String>,
528}
529
530impl ExecutionTimer {
531    /// Create a new execution timer
532    pub fn new() -> Self {
533        Self {
534            start_time: Instant::now(),
535            label: None,
536        }
537    }
538
539    /// Create a labeled execution timer
540    pub fn with_label(label: String) -> Self {
541        Self {
542            start_time: Instant::now(),
543            label: Some(label),
544        }
545    }
546
547    /// Get elapsed time in milliseconds
548    pub fn elapsed_ms(&self) -> f64 {
549        self.start_time.elapsed().as_millis() as f64
550    }
551
552    /// Get elapsed time in microseconds
553    pub fn elapsed_us(&self) -> f64 {
554        self.start_time.elapsed().as_micros() as f64
555    }
556
557    /// Get elapsed time in nanoseconds
558    pub fn elapsed_ns(&self) -> u64 {
559        self.start_time.elapsed().as_nanos() as u64
560    }
561
562    /// Restart the timer
563    pub fn restart(&mut self) {
564        self.start_time = Instant::now();
565    }
566
567    /// Get label if set
568    pub fn label(&self) -> Option<&str> {
569        self.label.as_deref()
570    }
571
572    /// Set label
573    pub fn set_label(&mut self, label: String) {
574        self.label = Some(label);
575    }
576
577    /// Create a performance sample from this timer
578    pub fn to_sample(
579        &self,
580        processor_type: ProcessorType,
581        processor_id: String,
582    ) -> PerformanceSample {
583        PerformanceSample::new(processor_type, processor_id).with_execution_time(self.elapsed_ms())
584    }
585}
586
587impl Default for ExecutionTimer {
588    fn default() -> Self {
589        Self::new()
590    }
591}
592
593#[cfg(test)]
594mod tests {
595    use super::*;
596
597    #[test]
598    fn test_processor_type_display() {
599        assert_eq!(
600            ProcessorType::QuantumInspired.to_string(),
601            "QuantumInspired"
602        );
603        assert_eq!(ProcessorType::NeuralAdaptive.to_string(), "NeuralAdaptive");
604        assert_eq!(
605            ProcessorType::QuantumNeuralHybrid.to_string(),
606            "QuantumNeuralHybrid"
607        );
608        assert_eq!(
609            ProcessorType::MemoryCompression.to_string(),
610            "MemoryCompression"
611        );
612    }
613
614    #[test]
615    fn test_processor_type_capabilities() {
616        assert!(ProcessorType::QuantumInspired.supports_quantum_metrics());
617        assert!(!ProcessorType::QuantumInspired.supports_neural_metrics());
618        assert!(!ProcessorType::QuantumInspired.supports_compression_metrics());
619
620        assert!(!ProcessorType::NeuralAdaptive.supports_quantum_metrics());
621        assert!(ProcessorType::NeuralAdaptive.supports_neural_metrics());
622        assert!(!ProcessorType::NeuralAdaptive.supports_compression_metrics());
623
624        assert!(ProcessorType::QuantumNeuralHybrid.supports_quantum_metrics());
625        assert!(ProcessorType::QuantumNeuralHybrid.supports_neural_metrics());
626        assert!(!ProcessorType::QuantumNeuralHybrid.supports_compression_metrics());
627
628        assert!(!ProcessorType::MemoryCompression.supports_quantum_metrics());
629        assert!(!ProcessorType::MemoryCompression.supports_neural_metrics());
630        assert!(ProcessorType::MemoryCompression.supports_compression_metrics());
631    }
632
633    #[test]
634    fn test_performance_sample_creation() {
635        let sample =
636            PerformanceSample::new(ProcessorType::QuantumInspired, "test-processor".to_string());
637
638        assert_eq!(sample.processor_type, ProcessorType::QuantumInspired);
639        assert_eq!(sample.processor_id, "test-processor");
640        assert_eq!(sample.execution_time_ms, 0.0);
641        assert!(sample.timestamp > 0);
642    }
643
644    #[test]
645    fn test_performance_sample_builder() {
646        let sample = PerformanceSample::new(ProcessorType::NeuralAdaptive, "test".to_string())
647            .with_execution_time(100.0)
648            .with_throughput(500.0)
649            .with_cache_hit_ratio(0.8)
650            .with_neural_confidence(0.9);
651
652        assert_eq!(sample.execution_time_ms, 100.0);
653        assert_eq!(sample.throughput_ops_per_sec, 500.0);
654        assert_eq!(sample.cache_hit_ratio, 0.8);
655        assert_eq!(sample.neural_confidence, Some(0.9));
656    }
657
658    #[test]
659    fn test_efficiency_score_calculation() {
660        let sample = PerformanceSample::new(ProcessorType::QuantumInspired, "test".to_string())
661            .with_execution_time(100.0)
662            .with_throughput(1000.0)
663            .with_cache_hit_ratio(0.9)
664            .with_error_rate(0.1)
665            .with_cpu_utilization(0.7)
666            .with_gpu_utilization(0.6);
667
668        let score = sample.efficiency_score();
669        assert!(score > 0.0 && score <= 1.0);
670    }
671
672    #[test]
673    fn test_performance_issues_detection() {
674        let problematic_sample = PerformanceSample::new(
675            ProcessorType::QuantumInspired,
676            "test".to_string(),
677        )
678        .with_execution_time(2000.0) // High execution time
679        .with_throughput(5.0) // Low throughput
680        .with_cache_hit_ratio(0.3) // Low cache hit ratio
681        .with_error_rate(0.2); // High error rate
682
683        let issues = problematic_sample.has_performance_issues();
684        assert!(!issues.is_empty());
685        assert!(issues.contains(&"High execution time".to_string()));
686        assert!(issues.contains(&"Low throughput".to_string()));
687        assert!(issues.contains(&"Low cache hit ratio".to_string()));
688        assert!(issues.contains(&"High error rate".to_string()));
689    }
690
691    #[test]
692    fn test_aggregated_metrics_update() {
693        let mut metrics = AggregatedMetrics::new();
694
695        let sample1 = PerformanceSample::new(ProcessorType::QuantumInspired, "test".to_string())
696            .with_execution_time(100.0)
697            .with_throughput(500.0);
698
699        let sample2 = PerformanceSample::new(ProcessorType::QuantumInspired, "test".to_string())
700            .with_execution_time(200.0)
701            .with_throughput(400.0);
702
703        metrics.update_with_sample(&sample1);
704        metrics.update_with_sample(&sample2);
705
706        assert_eq!(metrics.sample_count, 2);
707        assert_eq!(metrics.avg_execution_time, 150.0);
708        assert_eq!(metrics.avg_throughput, 450.0);
709        assert_eq!(metrics.peak_throughput, 500.0);
710        assert_eq!(metrics.min_execution_time, 100.0);
711        assert_eq!(metrics.max_execution_time, 200.0);
712    }
713
714    #[test]
715    fn test_system_metrics() {
716        let mut metrics = SystemMetrics::new();
717        assert_eq!(metrics.cpu_usage, 0.0);
718        assert!(metrics.timestamp > 0);
719
720        metrics.cpu_usage = 0.5;
721        metrics.memory_usage = 0.3;
722        metrics.temperature = 65.0;
723        metrics.system_load = 1.0;
724
725        assert!(!metrics.is_high_load());
726
727        let health = metrics.health_score();
728        assert!(health > 0.0 && health <= 1.0);
729    }
730
731    #[test]
732    fn test_execution_timer() {
733        let timer = ExecutionTimer::new();
734        std::thread::sleep(std::time::Duration::from_millis(10));
735
736        let elapsed = timer.elapsed_ms();
737        assert!(elapsed >= 10.0);
738
739        let sample = timer.to_sample(ProcessorType::QuantumInspired, "test".to_string());
740        assert!(sample.execution_time_ms >= 10.0);
741    }
742
743    #[test]
744    fn test_execution_timer_with_label() {
745        let mut timer = ExecutionTimer::with_label("test-operation".to_string());
746        assert_eq!(timer.label(), Some("test-operation"));
747
748        timer.set_label("new-operation".to_string());
749        assert_eq!(timer.label(), Some("new-operation"));
750    }
751
752    #[test]
753    fn test_metric_access() {
754        let sample = PerformanceSample::new(ProcessorType::QuantumInspired, "test".to_string())
755            .with_execution_time(100.0)
756            .with_custom_metric("custom_value".to_string(), 42.0);
757
758        assert_eq!(sample.get_metric("execution_time_ms"), Some(100.0));
759        assert_eq!(sample.get_metric("custom_value"), Some(42.0));
760        assert_eq!(sample.get_metric("nonexistent"), None);
761
762        let names = sample.metric_names();
763        assert!(names.contains(&"execution_time_ms".to_string()));
764        assert!(names.contains(&"custom_value".to_string()));
765    }
766}