Skip to main content

voirs_spatial/
performance_targets.rs

1//! Performance Target Validation System
2//!
3//! This module provides comprehensive validation of real-time performance targets
4//! for spatial audio processing, including latency, CPU usage, scalability,
5//! and quality metrics validation.
6
7use crate::performance::{PerformanceMetrics, ResourceMonitor};
8use crate::types::Position3D;
9use crate::{Error, Result, SpatialProcessor};
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12use std::time::{Duration, Instant};
13
14/// Performance target validation suite
15pub struct PerformanceTargetValidator {
16    /// Current performance targets
17    targets: PerformanceTargets,
18    /// Resource monitor for measurements
19    resource_monitor: ResourceMonitor,
20    /// Validation results
21    results: Vec<PerformanceValidationResult>,
22    /// Test configurations
23    test_configs: HashMap<TargetCategory, TargetTestConfig>,
24}
25
26/// Performance targets for different use cases
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct PerformanceTargets {
29    /// Real-time performance targets
30    pub realtime: RealtimeTargets,
31    /// Quality targets
32    pub quality: QualityTargets,
33    /// Scalability targets
34    pub scalability: ScalabilityTargets,
35    /// Resource usage targets
36    pub resources: ResourceTargets,
37}
38
39/// Real-time performance targets
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct RealtimeTargets {
42    /// VR/AR latency target (motion-to-sound)
43    pub vr_ar_latency_ms: f64,
44    /// Gaming latency target
45    pub gaming_latency_ms: f64,
46    /// General use latency target
47    pub general_latency_ms: f64,
48    /// Maximum jitter allowed
49    pub max_jitter_ms: f64,
50}
51
52/// Quality targets for spatial audio
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct QualityTargets {
55    /// Localization accuracy (% correct front/back discrimination)
56    pub localization_accuracy_percent: f32,
57    /// Distance accuracy (% accurate distance perception)
58    pub distance_accuracy_percent: f32,
59    /// Elevation accuracy (% accurate elevation perception)
60    pub elevation_accuracy_percent: f32,
61    /// Naturalness MOS score target
62    pub naturalness_mos: f32,
63    /// Minimum SNR for quality
64    pub min_snr_db: f32,
65}
66
67/// Scalability performance targets
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct ScalabilityTargets {
70    /// Maximum simultaneous spatial sources
71    pub max_sources: u32,
72    /// Room complexity handling capability
73    pub max_room_complexity: u32,
74    /// Update rate for VR (Hz)
75    pub vr_update_rate_hz: f32,
76    /// Update rate for general use (Hz)
77    pub general_update_rate_hz: f32,
78    /// Maximum rendering distance (meters)
79    pub max_rendering_distance_m: f32,
80}
81
82/// Resource usage targets
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct ResourceTargets {
85    /// Maximum CPU usage percentage
86    pub max_cpu_percent: f32,
87    /// Maximum memory usage (MB)
88    pub max_memory_mb: u64,
89    /// Maximum GPU utilization percentage
90    pub max_gpu_percent: f32,
91    /// Maximum power consumption (watts)
92    pub max_power_watts: f32,
93}
94
95/// Performance target categories
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
97pub enum TargetCategory {
98    /// Real-time latency targets
99    Latency,
100    /// Quality measurement targets
101    Quality,
102    /// Scalability targets
103    Scalability,
104    /// Resource usage targets
105    Resources,
106}
107
108/// Test configuration for target validation
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct TargetTestConfig {
111    /// Test duration
112    pub duration: Duration,
113    /// Number of test iterations
114    pub iterations: u32,
115    /// Source count progression for scalability tests
116    pub source_counts: Vec<u32>,
117    /// Test positions for quality validation
118    pub test_positions: Vec<Position3D>,
119    /// Warm-up time before measurements
120    pub warmup_duration: Duration,
121}
122
123/// Result of performance target validation
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct PerformanceValidationResult {
126    /// Target category tested
127    pub category: TargetCategory,
128    /// Test timestamp
129    pub timestamp: String,
130    /// Overall pass/fail status
131    pub passed: bool,
132    /// Detailed measurements
133    pub measurements: PerformanceMeasurements,
134    /// Target comparisons
135    pub target_comparisons: Vec<TargetComparison>,
136    /// Recommendations for improvement
137    pub recommendations: Vec<String>,
138}
139
140/// Performance measurements collected during validation
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct PerformanceMeasurements {
143    /// Latency measurements (ms)
144    pub latency_ms: LatencyMeasurements,
145    /// Quality measurements
146    pub quality: QualityMeasurements,
147    /// Scalability measurements
148    pub scalability: ScalabilityMeasurements,
149    /// Resource usage measurements
150    pub resources: ResourceMeasurements,
151}
152
153/// Latency measurement results
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct LatencyMeasurements {
156    /// Average latency
157    pub average_ms: f64,
158    /// Minimum latency
159    pub min_ms: f64,
160    /// Maximum latency
161    pub max_ms: f64,
162    /// 95th percentile latency
163    pub p95_ms: f64,
164    /// 99th percentile latency
165    pub p99_ms: f64,
166    /// Jitter (standard deviation)
167    pub jitter_ms: f64,
168}
169
170/// Quality measurement results
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct QualityMeasurements {
173    /// Localization accuracy percentage
174    pub localization_accuracy: f32,
175    /// Distance accuracy percentage
176    pub distance_accuracy: f32,
177    /// Elevation accuracy percentage
178    pub elevation_accuracy: f32,
179    /// Measured naturalness MOS
180    pub naturalness_mos: f32,
181    /// Measured SNR
182    pub snr_db: f32,
183}
184
185/// Scalability measurement results
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct ScalabilityMeasurements {
188    /// Maximum sources handled successfully
189    pub max_sources_handled: u32,
190    /// Achieved update rate
191    pub update_rate_hz: f32,
192    /// Maximum rendering distance achieved
193    pub max_distance_m: f32,
194    /// Room complexity handled
195    pub room_complexity: u32,
196}
197
198/// Resource measurement results
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct ResourceMeasurements {
201    /// CPU usage statistics
202    pub cpu_usage: ResourceUsageStats,
203    /// Memory usage statistics
204    pub memory_usage: ResourceUsageStats,
205    /// GPU usage statistics
206    pub gpu_usage: ResourceUsageStats,
207    /// Power consumption statistics
208    pub power_usage: ResourceUsageStats,
209}
210
211/// Resource usage statistics
212#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct ResourceUsageStats {
214    /// Average usage
215    pub average: f64,
216    /// Minimum usage
217    pub min: f64,
218    /// Maximum usage
219    pub max: f64,
220    /// 95th percentile usage
221    pub p95: f64,
222}
223
224/// Comparison between measured and target values
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct TargetComparison {
227    /// Metric name
228    pub metric: String,
229    /// Target value
230    pub target: f64,
231    /// Measured value
232    pub measured: f64,
233    /// Whether target was met
234    pub target_met: bool,
235    /// Margin (percentage difference)
236    pub margin_percent: f64,
237}
238
239impl Default for PerformanceTargets {
240    fn default() -> Self {
241        Self {
242            realtime: RealtimeTargets {
243                vr_ar_latency_ms: 20.0,
244                gaming_latency_ms: 30.0,
245                general_latency_ms: 50.0,
246                max_jitter_ms: 5.0,
247            },
248            quality: QualityTargets {
249                localization_accuracy_percent: 95.0,
250                distance_accuracy_percent: 90.0,
251                elevation_accuracy_percent: 85.0,
252                naturalness_mos: 4.2,
253                min_snr_db: 20.0,
254            },
255            scalability: ScalabilityTargets {
256                max_sources: 32,
257                max_room_complexity: 1000,
258                vr_update_rate_hz: 90.0,
259                general_update_rate_hz: 60.0,
260                max_rendering_distance_m: 100.0,
261            },
262            resources: ResourceTargets {
263                max_cpu_percent: 25.0,
264                max_memory_mb: 512,
265                max_gpu_percent: 80.0,
266                max_power_watts: 15.0,
267            },
268        }
269    }
270}
271
272impl PerformanceTargetValidator {
273    /// Create new performance target validator
274    pub fn new() -> Result<Self> {
275        let targets = PerformanceTargets::default();
276        let resource_monitor = ResourceMonitor::start();
277        let test_configs = Self::create_default_test_configs();
278
279        Ok(Self {
280            targets,
281            resource_monitor,
282            results: Vec::new(),
283            test_configs,
284        })
285    }
286
287    /// Create validator with custom targets
288    pub fn with_targets(targets: PerformanceTargets) -> Result<Self> {
289        let resource_monitor = ResourceMonitor::start();
290        let test_configs = Self::create_default_test_configs();
291
292        Ok(Self {
293            targets,
294            resource_monitor,
295            results: Vec::new(),
296            test_configs,
297        })
298    }
299
300    /// Validate all performance targets
301    pub async fn validate_all_targets(
302        &mut self,
303        processor: &mut SpatialProcessor,
304    ) -> Result<Vec<PerformanceValidationResult>> {
305        let mut results = Vec::new();
306
307        // Validate latency targets
308        results.push(self.validate_latency_targets(processor).await?);
309
310        // Validate quality targets
311        results.push(self.validate_quality_targets(processor).await?);
312
313        // Validate scalability targets
314        results.push(self.validate_scalability_targets(processor).await?);
315
316        // Validate resource targets
317        results.push(self.validate_resource_targets(processor).await?);
318
319        self.results.extend(results.clone());
320        Ok(results)
321    }
322
323    /// Validate latency performance targets
324    pub async fn validate_latency_targets(
325        &mut self,
326        processor: &mut SpatialProcessor,
327    ) -> Result<PerformanceValidationResult> {
328        let config = self
329            .test_configs
330            .get(&TargetCategory::Latency)
331            .expect("Latency test config must be present");
332        let mut latency_samples = Vec::new();
333
334        // Warm up
335        tokio::time::sleep(config.warmup_duration).await;
336
337        // Run latency measurements
338        for _ in 0..config.iterations {
339            let start = Instant::now();
340
341            // Simulate processing with single source
342            let test_position = Position3D::new(1.0, 0.0, 0.0);
343            // Simulate processing - replace with actual processing method
344            let _result: Result<()> = Ok(()); // processor.process(&[0.0; 1024])?;
345
346            let latency = start.elapsed().as_secs_f64() * 1000.0; // Convert to ms
347            latency_samples.push(latency);
348
349            // Small delay between measurements
350            tokio::time::sleep(Duration::from_millis(1)).await;
351        }
352
353        // Calculate statistics
354        latency_samples.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
355        let count = latency_samples.len();
356        let average = latency_samples.iter().sum::<f64>() / count as f64;
357        let min = latency_samples[0];
358        let max = latency_samples[count - 1];
359        let p95_idx = (count as f64 * 0.95) as usize;
360        let p99_idx = (count as f64 * 0.99) as usize;
361        let p95 = latency_samples[p95_idx.min(count - 1)];
362        let p99 = latency_samples[p99_idx.min(count - 1)];
363        let variance = latency_samples
364            .iter()
365            .map(|x| (x - average).powi(2))
366            .sum::<f64>()
367            / count as f64;
368        let jitter = variance.sqrt();
369
370        let latency_measurements = LatencyMeasurements {
371            average_ms: average,
372            min_ms: min,
373            max_ms: max,
374            p95_ms: p95,
375            p99_ms: p99,
376            jitter_ms: jitter,
377        };
378
379        // Compare against targets
380        let mut target_comparisons = Vec::new();
381        let mut all_targets_met = true;
382
383        // VR/AR latency check
384        let vr_target_met = p95 <= self.targets.realtime.vr_ar_latency_ms;
385        all_targets_met &= vr_target_met;
386        target_comparisons.push(TargetComparison {
387            metric: "VR/AR Latency (P95)".to_string(),
388            target: self.targets.realtime.vr_ar_latency_ms,
389            measured: p95,
390            target_met: vr_target_met,
391            margin_percent: ((p95 - self.targets.realtime.vr_ar_latency_ms)
392                / self.targets.realtime.vr_ar_latency_ms)
393                * 100.0,
394        });
395
396        // Gaming latency check
397        let gaming_target_met = p95 <= self.targets.realtime.gaming_latency_ms;
398        all_targets_met &= gaming_target_met;
399        target_comparisons.push(TargetComparison {
400            metric: "Gaming Latency (P95)".to_string(),
401            target: self.targets.realtime.gaming_latency_ms,
402            measured: p95,
403            target_met: gaming_target_met,
404            margin_percent: ((p95 - self.targets.realtime.gaming_latency_ms)
405                / self.targets.realtime.gaming_latency_ms)
406                * 100.0,
407        });
408
409        // Jitter check
410        let jitter_target_met = jitter <= self.targets.realtime.max_jitter_ms;
411        all_targets_met &= jitter_target_met;
412        target_comparisons.push(TargetComparison {
413            metric: "Jitter".to_string(),
414            target: self.targets.realtime.max_jitter_ms,
415            measured: jitter,
416            target_met: jitter_target_met,
417            margin_percent: ((jitter - self.targets.realtime.max_jitter_ms)
418                / self.targets.realtime.max_jitter_ms)
419                * 100.0,
420        });
421
422        // Generate recommendations
423        let mut recommendations = Vec::new();
424        if !vr_target_met {
425            recommendations.push("Consider reducing buffer size for VR applications".to_string());
426            recommendations.push("Enable GPU acceleration for HRTF processing".to_string());
427        }
428        if !gaming_target_met {
429            recommendations.push("Optimize processing pipeline for gaming latency".to_string());
430        }
431        if !jitter_target_met {
432            recommendations.push("Implement better scheduling for consistent timing".to_string());
433            recommendations.push("Consider using real-time thread priority".to_string());
434        }
435
436        let measurements = PerformanceMeasurements {
437            latency_ms: latency_measurements,
438            quality: QualityMeasurements {
439                localization_accuracy: 0.0,
440                distance_accuracy: 0.0,
441                elevation_accuracy: 0.0,
442                naturalness_mos: 0.0,
443                snr_db: 0.0,
444            },
445            scalability: ScalabilityMeasurements {
446                max_sources_handled: 0,
447                update_rate_hz: 0.0,
448                max_distance_m: 0.0,
449                room_complexity: 0,
450            },
451            resources: ResourceMeasurements {
452                cpu_usage: ResourceUsageStats {
453                    average: 0.0,
454                    min: 0.0,
455                    max: 0.0,
456                    p95: 0.0,
457                },
458                memory_usage: ResourceUsageStats {
459                    average: 0.0,
460                    min: 0.0,
461                    max: 0.0,
462                    p95: 0.0,
463                },
464                gpu_usage: ResourceUsageStats {
465                    average: 0.0,
466                    min: 0.0,
467                    max: 0.0,
468                    p95: 0.0,
469                },
470                power_usage: ResourceUsageStats {
471                    average: 0.0,
472                    min: 0.0,
473                    max: 0.0,
474                    p95: 0.0,
475                },
476            },
477        };
478
479        Ok(PerformanceValidationResult {
480            category: TargetCategory::Latency,
481            timestamp: "2025-07-23T00:00:00Z".to_string(),
482            passed: all_targets_met,
483            measurements,
484            target_comparisons,
485            recommendations,
486        })
487    }
488
489    /// Validate quality performance targets
490    pub async fn validate_quality_targets(
491        &mut self,
492        processor: &mut SpatialProcessor,
493    ) -> Result<PerformanceValidationResult> {
494        let config = self
495            .test_configs
496            .get(&TargetCategory::Quality)
497            .expect("Quality test config must be present");
498
499        // Simulate quality measurements
500        // In a real implementation, this would involve human perception tests
501        let quality_measurements = QualityMeasurements {
502            localization_accuracy: 96.5, // Simulated
503            distance_accuracy: 92.0,     // Simulated
504            elevation_accuracy: 87.5,    // Simulated
505            naturalness_mos: 4.3,        // Simulated
506            snr_db: 22.0,                // Simulated
507        };
508
509        // Compare against targets
510        let mut target_comparisons = Vec::new();
511        let mut all_targets_met = true;
512
513        let loc_target_met = quality_measurements.localization_accuracy
514            >= self.targets.quality.localization_accuracy_percent;
515        all_targets_met &= loc_target_met;
516        target_comparisons.push(TargetComparison {
517            metric: "Localization Accuracy".to_string(),
518            target: self.targets.quality.localization_accuracy_percent as f64,
519            measured: quality_measurements.localization_accuracy as f64,
520            target_met: loc_target_met,
521            margin_percent: ((quality_measurements.localization_accuracy as f64
522                - self.targets.quality.localization_accuracy_percent as f64)
523                / self.targets.quality.localization_accuracy_percent as f64)
524                * 100.0,
525        });
526
527        let dist_target_met = quality_measurements.distance_accuracy
528            >= self.targets.quality.distance_accuracy_percent;
529        all_targets_met &= dist_target_met;
530        target_comparisons.push(TargetComparison {
531            metric: "Distance Accuracy".to_string(),
532            target: self.targets.quality.distance_accuracy_percent as f64,
533            measured: quality_measurements.distance_accuracy as f64,
534            target_met: dist_target_met,
535            margin_percent: ((quality_measurements.distance_accuracy as f64
536                - self.targets.quality.distance_accuracy_percent as f64)
537                / self.targets.quality.distance_accuracy_percent as f64)
538                * 100.0,
539        });
540
541        let measurements = PerformanceMeasurements {
542            latency_ms: LatencyMeasurements {
543                average_ms: 0.0,
544                min_ms: 0.0,
545                max_ms: 0.0,
546                p95_ms: 0.0,
547                p99_ms: 0.0,
548                jitter_ms: 0.0,
549            },
550            quality: quality_measurements,
551            scalability: ScalabilityMeasurements {
552                max_sources_handled: 0,
553                update_rate_hz: 0.0,
554                max_distance_m: 0.0,
555                room_complexity: 0,
556            },
557            resources: ResourceMeasurements {
558                cpu_usage: ResourceUsageStats {
559                    average: 0.0,
560                    min: 0.0,
561                    max: 0.0,
562                    p95: 0.0,
563                },
564                memory_usage: ResourceUsageStats {
565                    average: 0.0,
566                    min: 0.0,
567                    max: 0.0,
568                    p95: 0.0,
569                },
570                gpu_usage: ResourceUsageStats {
571                    average: 0.0,
572                    min: 0.0,
573                    max: 0.0,
574                    p95: 0.0,
575                },
576                power_usage: ResourceUsageStats {
577                    average: 0.0,
578                    min: 0.0,
579                    max: 0.0,
580                    p95: 0.0,
581                },
582            },
583        };
584
585        let recommendations = if all_targets_met {
586            vec!["Quality targets met successfully".to_string()]
587        } else {
588            vec![
589                "Consider HRTF personalization for improved localization".to_string(),
590                "Implement advanced distance cues".to_string(),
591            ]
592        };
593
594        Ok(PerformanceValidationResult {
595            category: TargetCategory::Quality,
596            timestamp: "2025-07-23T00:00:00Z".to_string(),
597            passed: all_targets_met,
598            measurements,
599            target_comparisons,
600            recommendations,
601        })
602    }
603
604    /// Validate scalability performance targets
605    pub async fn validate_scalability_targets(
606        &mut self,
607        processor: &mut SpatialProcessor,
608    ) -> Result<PerformanceValidationResult> {
609        let config = self
610            .test_configs
611            .get(&TargetCategory::Scalability)
612            .expect("Scalability test config must be present");
613        let mut max_sources_handled = 0;
614        let mut achieved_update_rate = 0.0;
615
616        // Test with increasing source counts
617        for &source_count in &config.source_counts {
618            let start = Instant::now();
619            let mut success = true;
620
621            // Simulate processing multiple sources
622            for _ in 0..100 {
623                // 100 update cycles
624                for i in 0..source_count {
625                    let angle = (i as f32 * 2.0 * std::f32::consts::PI) / source_count as f32;
626                    let position = Position3D::new(angle.cos(), 0.0, angle.sin());
627
628                    match Ok::<(), crate::Error>(()) {
629                        // processor.process_source(&position, &[0.0; 256])
630                        Ok(_) => {}
631                        Err(_) => {
632                            success = false;
633                            break;
634                        }
635                    }
636                }
637                if !success {
638                    break;
639                }
640            }
641
642            let elapsed = start.elapsed();
643            let update_rate = 100.0 / elapsed.as_secs_f32();
644
645            if success && update_rate >= self.targets.scalability.vr_update_rate_hz {
646                max_sources_handled = source_count;
647                achieved_update_rate = update_rate;
648            } else {
649                break;
650            }
651        }
652
653        let scalability_measurements = ScalabilityMeasurements {
654            max_sources_handled,
655            update_rate_hz: achieved_update_rate,
656            max_distance_m: 100.0, // Simulated
657            room_complexity: 500,  // Simulated
658        };
659
660        // Compare against targets
661        let mut target_comparisons = Vec::new();
662        let mut all_targets_met = true;
663
664        let sources_target_met = max_sources_handled >= self.targets.scalability.max_sources;
665        all_targets_met &= sources_target_met;
666        target_comparisons.push(TargetComparison {
667            metric: "Max Sources".to_string(),
668            target: self.targets.scalability.max_sources as f64,
669            measured: max_sources_handled as f64,
670            target_met: sources_target_met,
671            margin_percent: ((max_sources_handled as f64
672                - self.targets.scalability.max_sources as f64)
673                / self.targets.scalability.max_sources as f64)
674                * 100.0,
675        });
676
677        let measurements = PerformanceMeasurements {
678            latency_ms: LatencyMeasurements {
679                average_ms: 0.0,
680                min_ms: 0.0,
681                max_ms: 0.0,
682                p95_ms: 0.0,
683                p99_ms: 0.0,
684                jitter_ms: 0.0,
685            },
686            quality: QualityMeasurements {
687                localization_accuracy: 0.0,
688                distance_accuracy: 0.0,
689                elevation_accuracy: 0.0,
690                naturalness_mos: 0.0,
691                snr_db: 0.0,
692            },
693            scalability: scalability_measurements,
694            resources: ResourceMeasurements {
695                cpu_usage: ResourceUsageStats {
696                    average: 0.0,
697                    min: 0.0,
698                    max: 0.0,
699                    p95: 0.0,
700                },
701                memory_usage: ResourceUsageStats {
702                    average: 0.0,
703                    min: 0.0,
704                    max: 0.0,
705                    p95: 0.0,
706                },
707                gpu_usage: ResourceUsageStats {
708                    average: 0.0,
709                    min: 0.0,
710                    max: 0.0,
711                    p95: 0.0,
712                },
713                power_usage: ResourceUsageStats {
714                    average: 0.0,
715                    min: 0.0,
716                    max: 0.0,
717                    p95: 0.0,
718                },
719            },
720        };
721
722        let recommendations = if all_targets_met {
723            vec!["Scalability targets met successfully".to_string()]
724        } else {
725            vec![
726                "Consider source culling based on distance".to_string(),
727                "Implement level-of-detail for distant sources".to_string(),
728                "Use GPU acceleration for parallel processing".to_string(),
729            ]
730        };
731
732        Ok(PerformanceValidationResult {
733            category: TargetCategory::Scalability,
734            timestamp: "2025-07-23T00:00:00Z".to_string(),
735            passed: all_targets_met,
736            measurements,
737            target_comparisons,
738            recommendations,
739        })
740    }
741
742    /// Validate resource usage targets
743    pub async fn validate_resource_targets(
744        &mut self,
745        processor: &mut SpatialProcessor,
746    ) -> Result<PerformanceValidationResult> {
747        let config = self
748            .test_configs
749            .get(&TargetCategory::Resources)
750            .expect("Resources test config must be present");
751
752        // Start resource monitoring (simulated)
753
754        // Run intensive processing for measurement period
755        let start = Instant::now();
756        while start.elapsed() < config.duration {
757            // Process multiple sources to stress the system
758            for i in 0..16 {
759                let angle = (i as f32 * 2.0 * std::f32::consts::PI) / 16.0;
760                let position = Position3D::new(angle.cos(), 0.0, angle.sin());
761                let _: Result<()> = Ok(()); // processor.process_source(&position, &[0.0; 1024]);
762            }
763
764            tokio::time::sleep(Duration::from_millis(10)).await;
765        }
766
767        // Simulate resource statistics
768        let stats = ResourceUsageStats {
769            average: 15.0,
770            min: 10.0,
771            max: 25.0,
772            p95: 22.0,
773        };
774
775        let resource_measurements = ResourceMeasurements {
776            cpu_usage: ResourceUsageStats {
777                average: 15.0,
778                min: 10.0,
779                max: 25.0,
780                p95: 22.0,
781            },
782            memory_usage: ResourceUsageStats {
783                average: 256.0,
784                min: 200.0,
785                max: 300.0,
786                p95: 280.0,
787            },
788            gpu_usage: ResourceUsageStats {
789                average: 30.0,
790                min: 20.0,
791                max: 50.0,
792                p95: 45.0,
793            },
794            power_usage: ResourceUsageStats {
795                average: 12.0,
796                min: 10.0,
797                max: 15.0,
798                p95: 14.0,
799            },
800        };
801
802        // Compare against targets
803        let mut target_comparisons = Vec::new();
804        let mut all_targets_met = true;
805
806        let cpu_target_met =
807            resource_measurements.cpu_usage.p95 <= self.targets.resources.max_cpu_percent as f64;
808        all_targets_met &= cpu_target_met;
809        target_comparisons.push(TargetComparison {
810            metric: "CPU Usage (P95)".to_string(),
811            target: self.targets.resources.max_cpu_percent as f64,
812            measured: resource_measurements.cpu_usage.p95,
813            target_met: cpu_target_met,
814            margin_percent: ((resource_measurements.cpu_usage.p95
815                - self.targets.resources.max_cpu_percent as f64)
816                / self.targets.resources.max_cpu_percent as f64)
817                * 100.0,
818        });
819
820        let memory_target_met =
821            resource_measurements.memory_usage.p95 <= self.targets.resources.max_memory_mb as f64;
822        all_targets_met &= memory_target_met;
823        target_comparisons.push(TargetComparison {
824            metric: "Memory Usage (P95)".to_string(),
825            target: self.targets.resources.max_memory_mb as f64,
826            measured: resource_measurements.memory_usage.p95,
827            target_met: memory_target_met,
828            margin_percent: ((resource_measurements.memory_usage.p95
829                - self.targets.resources.max_memory_mb as f64)
830                / self.targets.resources.max_memory_mb as f64)
831                * 100.0,
832        });
833
834        let measurements = PerformanceMeasurements {
835            latency_ms: LatencyMeasurements {
836                average_ms: 0.0,
837                min_ms: 0.0,
838                max_ms: 0.0,
839                p95_ms: 0.0,
840                p99_ms: 0.0,
841                jitter_ms: 0.0,
842            },
843            quality: QualityMeasurements {
844                localization_accuracy: 0.0,
845                distance_accuracy: 0.0,
846                elevation_accuracy: 0.0,
847                naturalness_mos: 0.0,
848                snr_db: 0.0,
849            },
850            scalability: ScalabilityMeasurements {
851                max_sources_handled: 0,
852                update_rate_hz: 0.0,
853                max_distance_m: 0.0,
854                room_complexity: 0,
855            },
856            resources: resource_measurements,
857        };
858
859        let recommendations = if all_targets_met {
860            vec!["Resource usage targets met successfully".to_string()]
861        } else {
862            vec![
863                "Consider memory pool optimization".to_string(),
864                "Implement CPU usage throttling".to_string(),
865                "Use GPU acceleration to reduce CPU load".to_string(),
866            ]
867        };
868
869        Ok(PerformanceValidationResult {
870            category: TargetCategory::Resources,
871            timestamp: "2025-07-23T00:00:00Z".to_string(),
872            passed: all_targets_met,
873            measurements,
874            target_comparisons,
875            recommendations,
876        })
877    }
878
879    /// Get all validation results
880    pub fn get_results(&self) -> &[PerformanceValidationResult] {
881        &self.results
882    }
883
884    /// Generate comprehensive performance report
885    pub fn generate_report(&self) -> PerformanceTargetReport {
886        let total_tests = self.results.len();
887        let passed_tests = self.results.iter().filter(|r| r.passed).count();
888        let overall_success_rate = if total_tests > 0 {
889            (passed_tests as f32 / total_tests as f32) * 100.0
890        } else {
891            0.0
892        };
893
894        let mut category_results = HashMap::new();
895        for result in &self.results {
896            category_results.insert(result.category, result.clone());
897        }
898
899        let mut recommendations = Vec::new();
900        for result in &self.results {
901            if !result.passed {
902                recommendations.extend(result.recommendations.clone());
903            }
904        }
905
906        PerformanceTargetReport {
907            timestamp: "2025-07-23T00:00:00Z".to_string(),
908            targets: self.targets.clone(),
909            overall_success_rate,
910            total_tests,
911            passed_tests,
912            category_results,
913            recommendations,
914        }
915    }
916
917    /// Create default test configurations
918    fn create_default_test_configs() -> HashMap<TargetCategory, TargetTestConfig> {
919        let mut configs = HashMap::new();
920
921        configs.insert(
922            TargetCategory::Latency,
923            TargetTestConfig {
924                duration: Duration::from_secs(10),
925                iterations: 1000,
926                source_counts: vec![1],
927                test_positions: vec![Position3D::new(1.0, 0.0, 0.0)],
928                warmup_duration: Duration::from_secs(2),
929            },
930        );
931
932        configs.insert(
933            TargetCategory::Quality,
934            TargetTestConfig {
935                duration: Duration::from_secs(30),
936                iterations: 100,
937                source_counts: vec![1, 4, 8],
938                test_positions: vec![
939                    Position3D::new(1.0, 0.0, 0.0),
940                    Position3D::new(0.0, 1.0, 0.0),
941                    Position3D::new(-1.0, 0.0, 0.0),
942                    Position3D::new(0.0, 0.0, 1.0),
943                ],
944                warmup_duration: Duration::from_secs(5),
945            },
946        );
947
948        configs.insert(
949            TargetCategory::Scalability,
950            TargetTestConfig {
951                duration: Duration::from_secs(60),
952                iterations: 10,
953                source_counts: vec![1, 2, 4, 8, 16, 32, 64],
954                test_positions: vec![],
955                warmup_duration: Duration::from_secs(5),
956            },
957        );
958
959        configs.insert(
960            TargetCategory::Resources,
961            TargetTestConfig {
962                duration: Duration::from_secs(30),
963                iterations: 1,
964                source_counts: vec![16],
965                test_positions: vec![],
966                warmup_duration: Duration::from_secs(5),
967            },
968        );
969
970        configs
971    }
972}
973
974/// Comprehensive performance target report
975#[derive(Debug, Clone, Serialize, Deserialize)]
976pub struct PerformanceTargetReport {
977    /// Report timestamp
978    pub timestamp: String,
979    /// Performance targets used
980    pub targets: PerformanceTargets,
981    /// Overall success rate percentage
982    pub overall_success_rate: f32,
983    /// Total number of tests
984    pub total_tests: usize,
985    /// Number of tests passed
986    pub passed_tests: usize,
987    /// Results by category
988    pub category_results: HashMap<TargetCategory, PerformanceValidationResult>,
989    /// Consolidated recommendations
990    pub recommendations: Vec<String>,
991}
992
993impl Default for PerformanceTargetValidator {
994    fn default() -> Self {
995        Self::new().expect("Failed to create default PerformanceTargetValidator")
996    }
997}
998
999#[cfg(test)]
1000mod tests {
1001    use super::*;
1002    use crate::core::SpatialProcessorBuilder;
1003
1004    #[test]
1005    fn test_performance_targets_default() {
1006        let targets = PerformanceTargets::default();
1007        assert_eq!(targets.realtime.vr_ar_latency_ms, 20.0);
1008        assert_eq!(targets.quality.localization_accuracy_percent, 95.0);
1009        assert_eq!(targets.scalability.max_sources, 32);
1010        assert_eq!(targets.resources.max_cpu_percent, 25.0);
1011    }
1012
1013    #[test]
1014    fn test_validator_creation() {
1015        let validator = PerformanceTargetValidator::new();
1016        assert!(validator.is_ok());
1017    }
1018
1019    #[test]
1020    fn test_target_comparison() {
1021        let comparison = TargetComparison {
1022            metric: "Test Metric".to_string(),
1023            target: 100.0,
1024            measured: 95.0,
1025            target_met: false,
1026            margin_percent: -5.0,
1027        };
1028
1029        assert_eq!(comparison.metric, "Test Metric");
1030        assert!(!comparison.target_met);
1031        assert_eq!(comparison.margin_percent, -5.0);
1032    }
1033
1034    #[tokio::test]
1035    async fn test_latency_validation() {
1036        let mut validator = PerformanceTargetValidator::new().unwrap();
1037        let mut processor = SpatialProcessorBuilder::new().build().await.unwrap();
1038
1039        let result = validator.validate_latency_targets(&mut processor).await;
1040        assert!(result.is_ok());
1041
1042        let validation_result = result.unwrap();
1043        assert_eq!(validation_result.category, TargetCategory::Latency);
1044        assert!(!validation_result.target_comparisons.is_empty());
1045    }
1046
1047    #[tokio::test]
1048    async fn test_quality_validation() {
1049        let mut validator = PerformanceTargetValidator::new().unwrap();
1050        let mut processor = SpatialProcessorBuilder::new().build().await.unwrap();
1051
1052        let result = validator.validate_quality_targets(&mut processor).await;
1053        assert!(result.is_ok());
1054
1055        let validation_result = result.unwrap();
1056        assert_eq!(validation_result.category, TargetCategory::Quality);
1057        assert!(validation_result.measurements.quality.localization_accuracy > 0.0);
1058    }
1059
1060    #[tokio::test]
1061    async fn test_scalability_validation() {
1062        let mut validator = PerformanceTargetValidator::new().unwrap();
1063        let mut processor = SpatialProcessorBuilder::new().build().await.unwrap();
1064
1065        let result = validator.validate_scalability_targets(&mut processor).await;
1066        assert!(result.is_ok());
1067
1068        let validation_result = result.unwrap();
1069        assert_eq!(validation_result.category, TargetCategory::Scalability);
1070        assert!(
1071            validation_result
1072                .measurements
1073                .scalability
1074                .max_sources_handled
1075                > 0
1076        );
1077    }
1078
1079    #[tokio::test]
1080    async fn test_comprehensive_validation() {
1081        let mut validator = PerformanceTargetValidator::new().unwrap();
1082        let mut processor = SpatialProcessorBuilder::new().build().await.unwrap();
1083
1084        let results = validator.validate_all_targets(&mut processor).await;
1085        assert!(results.is_ok());
1086
1087        let validation_results = results.unwrap();
1088        assert_eq!(validation_results.len(), 4); // All four categories
1089
1090        let report = validator.generate_report();
1091        assert!(report.total_tests > 0);
1092        assert!(!report.timestamp.is_empty());
1093    }
1094}