Skip to main content

trustformers_debug/performance/
optimization.rs

1//! Performance optimization system for production debugging
2//!
3//! This module provides advanced performance optimizations including low overhead
4//! sessions, lazy evaluation, incremental processing, background processing,
5//! and selective debugging capabilities for production environments.
6// reason: debug/profiling scaffolding — structs are constructed and their fields/methods
7// are retained for the data model, serialization completeness, and future consumers that
8// do not yet read every member. Consolidated from many item-level #[allow(dead_code)].
9#![allow(dead_code)]
10
11use crate::core::session::{DebugConfig, DebugSession};
12use anyhow::Result;
13use serde::{Deserialize, Serialize};
14use std::collections::HashMap;
15
16/// Performance configuration for optimized debugging
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct PerformanceConfig {
19    /// Enable low overhead mode
20    pub low_overhead_mode: bool,
21    /// Enable selective debugging
22    pub selective_debugging: bool,
23    /// Enable lazy evaluation
24    pub lazy_evaluation: bool,
25    /// Enable incremental updates
26    pub incremental_updates: bool,
27    /// Enable background processing
28    pub background_processing: bool,
29    /// Sampling rate for performance-critical operations
30    pub sampling_rate: f32,
31    /// Maximum memory usage for debugging (in MB)
32    pub max_memory_mb: usize,
33    /// Maximum CPU usage percentage for debugging
34    pub max_cpu_percentage: f32,
35    /// Batch size for background processing
36    pub background_batch_size: usize,
37    /// Update interval for incremental processing (in milliseconds)
38    pub incremental_update_interval_ms: u64,
39}
40
41impl Default for PerformanceConfig {
42    fn default() -> Self {
43        Self {
44            low_overhead_mode: false,
45            selective_debugging: false,
46            lazy_evaluation: true,
47            incremental_updates: true,
48            background_processing: true,
49            sampling_rate: 1.0,
50            max_memory_mb: 1024,      // 1GB
51            max_cpu_percentage: 25.0, // 25% CPU
52            background_batch_size: 100,
53            incremental_update_interval_ms: 100,
54        }
55    }
56}
57
58/// Low overhead debugging session optimized for production use
59pub struct LowOverheadDebugSession {
60    session: DebugSession,
61    performance_config: PerformanceConfig,
62    selective_components: Vec<DebugComponent>,
63    lazy_evaluator: LazyEvaluator,
64    incremental_processor: IncrementalProcessor,
65    background_processor: Option<BackgroundProcessor>,
66}
67
68/// Debug component types for selective debugging
69#[derive(Debug, Clone, PartialEq, Eq, Hash)]
70pub enum DebugComponent {
71    TensorInspection,
72    GradientDebugging,
73    ModelDiagnostics,
74    MemoryProfiling,
75    ComputationGraphAnalysis,
76    AnomalyDetection,
77    PerformanceProfiling,
78    ArchitectureAnalysis,
79    BehaviorAnalysis,
80    TrainingDynamics,
81}
82
83impl LowOverheadDebugSession {
84    /// Create a new low overhead debug session
85    pub fn new(
86        mut config: DebugConfig,
87        performance_config: PerformanceConfig,
88        selective_components: Vec<DebugComponent>,
89    ) -> Self {
90        // Apply low overhead optimizations to config
91        if performance_config.low_overhead_mode {
92            config = Self::apply_low_overhead_config(config, &performance_config);
93        }
94
95        let session = DebugSession::new(config);
96        let lazy_evaluator = LazyEvaluator::new();
97        let incremental_processor =
98            IncrementalProcessor::new(performance_config.incremental_update_interval_ms);
99
100        let background_processor = if performance_config.background_processing {
101            Some(BackgroundProcessor::new(
102                performance_config.background_batch_size,
103            ))
104        } else {
105            None
106        };
107
108        Self {
109            session,
110            performance_config,
111            selective_components,
112            lazy_evaluator,
113            incremental_processor,
114            background_processor,
115        }
116    }
117
118    /// Apply low overhead configuration
119    fn apply_low_overhead_config(
120        mut config: DebugConfig,
121        perf_config: &PerformanceConfig,
122    ) -> DebugConfig {
123        config.sampling_rate = perf_config.sampling_rate;
124        config.max_tracked_tensors = std::cmp::min(config.max_tracked_tensors, 100);
125        config.max_gradient_history = std::cmp::min(config.max_gradient_history, 20);
126
127        // Disable expensive features in low overhead mode
128        if perf_config.low_overhead_mode {
129            config.enable_visualization = false;
130            config.enable_memory_profiling = false;
131        }
132
133        config
134    }
135
136    /// Start optimized debugging session
137    pub async fn start(&mut self) -> Result<()> {
138        // Start selective components only
139        for component in &self.selective_components {
140            match component {
141                DebugComponent::TensorInspection
142                    if self.session.config().enable_tensor_inspection =>
143                {
144                    self.session.tensor_inspector_mut().start().await?;
145                },
146                DebugComponent::GradientDebugging
147                    if self.session.config().enable_gradient_debugging =>
148                {
149                    self.session.gradient_debugger_mut().start().await?;
150                },
151                DebugComponent::ModelDiagnostics
152                    if self.session.config().enable_model_diagnostics =>
153                {
154                    self.session.model_diagnostics_mut().start().await?;
155                },
156                DebugComponent::MemoryProfiling => {
157                    if let Some(profiler) = self.session.memory_profiler_mut() {
158                        profiler.start().await?;
159                    }
160                },
161                DebugComponent::AnomalyDetection => {
162                    self.session.anomaly_detector_mut().start().await?;
163                },
164                DebugComponent::PerformanceProfiling => {
165                    self.session.profiler_mut().start().await?;
166                },
167                _ => {
168                    // Other components started on-demand
169                },
170            }
171        }
172
173        // Start background processor if enabled
174        if let Some(ref mut bg_processor) = self.background_processor {
175            bg_processor.start().await?;
176        }
177
178        Ok(())
179    }
180
181    /// Add data for lazy evaluation
182    pub fn add_lazy_evaluation<T: 'static + Send + Sync>(
183        &mut self,
184        key: String,
185        computation: Box<dyn LazyComputation<T>>,
186    ) {
187        self.lazy_evaluator.add_computation(key, computation);
188    }
189
190    /// Process incremental update
191    pub async fn process_incremental_update(&mut self, data: IncrementalData) -> Result<()> {
192        self.incremental_processor.process_update(data).await
193    }
194
195    /// Submit data for background processing
196    pub async fn submit_background_task(&mut self, task: BackgroundTask) -> Result<()> {
197        if let Some(ref mut bg_processor) = self.background_processor {
198            bg_processor.submit_task(task).await
199        } else {
200            Err(anyhow::anyhow!("Background processing not enabled"))
201        }
202    }
203
204    /// Get performance metrics
205    pub fn get_performance_metrics(&self) -> PerformanceMetrics {
206        PerformanceMetrics {
207            memory_usage_mb: self.get_memory_usage_mb(),
208            cpu_usage_percentage: self.get_cpu_usage_percentage(),
209            lazy_computations_pending: self.lazy_evaluator.pending_count(),
210            incremental_updates_processed: self.incremental_processor.processed_count(),
211            background_tasks_queued: self
212                .background_processor
213                .as_ref()
214                .map(|p| p.queued_count())
215                .unwrap_or(0),
216        }
217    }
218
219    /// Whether this process is inside the configured resource budget.
220    ///
221    /// `None` when nothing could be measured. Both inputs used to be hardcoded
222    /// (`0` MB and `0.0`%), so this method returned `true` unconditionally --
223    /// a "within limits" verdict backed by no measurement at all. Memory is now
224    /// a real RSS reading; CPU has no reading here (see
225    /// `Self::get_cpu_usage_percentage`), so the CPU half of the budget is
226    /// only enforced if and when one exists.
227    pub fn is_within_performance_limits(&self) -> Option<bool> {
228        let metrics = self.get_performance_metrics();
229        let memory_ok =
230            metrics.memory_usage_mb.map(|mb| mb <= self.performance_config.max_memory_mb);
231        let cpu_ok = metrics
232            .cpu_usage_percentage
233            .map(|pct| pct <= self.performance_config.max_cpu_percentage);
234        match (memory_ok, cpu_ok) {
235            (None, None) => None,
236            (a, b) => Some(a.unwrap_or(true) && b.unwrap_or(true)),
237        }
238    }
239
240    /// Real resident-set size of this process in MiB, via the same `sysinfo`
241    /// reader [`crate::utilities::performance::SystemMemoryProfiler`] uses.
242    /// `None` when the platform does not list this process.
243    fn get_memory_usage_mb(&self) -> Option<usize> {
244        crate::utilities::performance::SystemMemoryProfiler::current_memory_usage()
245            .map(|bytes| bytes / (1024 * 1024))
246    }
247
248    /// Always `None`: a process CPU percentage is a delta between two samples
249    /// of a long-lived `sysinfo::System`, and this optimizer owns no sampler
250    /// (its accessors take `&self`). It used to report a flat `0.0`, which
251    /// made every CPU budget check pass. See
252    /// [`crate::profiler::Profiler::analyze_cpu_bottlenecks`] for a type that
253    /// does keep the sampler needed to answer this.
254    fn get_cpu_usage_percentage(&self) -> Option<f32> {
255        None
256    }
257}
258
259/// Lazy evaluation system for expensive computations
260pub struct LazyEvaluator {
261    computations: HashMap<String, Box<dyn std::any::Any + Send + Sync>>,
262    evaluated: HashMap<String, bool>,
263}
264
265impl Default for LazyEvaluator {
266    fn default() -> Self {
267        Self::new()
268    }
269}
270
271impl LazyEvaluator {
272    pub fn new() -> Self {
273        Self {
274            computations: HashMap::new(),
275            evaluated: HashMap::new(),
276        }
277    }
278
279    /// Add a lazy computation
280    pub fn add_computation<T: 'static + Send + Sync>(
281        &mut self,
282        key: String,
283        computation: Box<dyn LazyComputation<T>>,
284    ) {
285        self.computations.insert(key.clone(), Box::new(computation));
286        self.evaluated.insert(key, false);
287    }
288
289    /// Evaluate computation on demand
290    pub async fn evaluate<T: 'static>(&mut self, key: &str) -> Result<Option<T>> {
291        if let Some(computation) = self.computations.remove(key) {
292            if let Ok(lazy_comp) = computation.downcast::<Box<dyn LazyComputation<T>>>() {
293                let result = lazy_comp.compute().await?;
294                self.evaluated.insert(key.to_string(), true);
295                return Ok(Some(result));
296            }
297        }
298        Ok(None)
299    }
300
301    /// Get number of pending computations
302    pub fn pending_count(&self) -> usize {
303        self.evaluated.values().filter(|&&v| !v).count()
304    }
305
306    /// Clear all computations
307    pub fn clear(&mut self) {
308        self.computations.clear();
309        self.evaluated.clear();
310    }
311}
312
313/// Trait for lazy computations
314pub trait LazyComputation<T>: Send + Sync {
315    fn compute(
316        &self,
317    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<T>> + Send + '_>>;
318}
319
320/// Incremental processing system for efficient updates
321pub struct IncrementalProcessor {
322    update_interval_ms: u64,
323    last_update: std::time::Instant,
324    accumulated_data: Vec<IncrementalData>,
325    processed_count: usize,
326}
327
328impl IncrementalProcessor {
329    pub fn new(update_interval_ms: u64) -> Self {
330        Self {
331            update_interval_ms,
332            last_update: std::time::Instant::now(),
333            accumulated_data: Vec::new(),
334            processed_count: 0,
335        }
336    }
337
338    /// Process incremental update
339    pub async fn process_update(&mut self, data: IncrementalData) -> Result<()> {
340        self.accumulated_data.push(data);
341
342        // Check if it's time to process accumulated data
343        if self.last_update.elapsed().as_millis() >= self.update_interval_ms as u128 {
344            self.process_accumulated_data().await?;
345            self.last_update = std::time::Instant::now();
346        }
347
348        Ok(())
349    }
350
351    /// Force processing of accumulated data
352    pub async fn flush(&mut self) -> Result<()> {
353        self.process_accumulated_data().await?;
354        self.last_update = std::time::Instant::now();
355        Ok(())
356    }
357
358    /// Process all accumulated data
359    async fn process_accumulated_data(&mut self) -> Result<()> {
360        if !self.accumulated_data.is_empty() {
361            // Process the accumulated data in batch
362            let batch_size = self.accumulated_data.len();
363
364            // Simplified processing - would implement actual incremental analysis
365            for _data in self.accumulated_data.drain(..) {
366                self.processed_count += 1;
367            }
368
369            tracing::debug!("Processed {} incremental updates", batch_size);
370        }
371
372        Ok(())
373    }
374
375    /// Get number of processed updates
376    pub fn processed_count(&self) -> usize {
377        self.processed_count
378    }
379}
380
381/// Data for incremental processing
382#[derive(Debug, Clone)]
383pub enum IncrementalData {
384    TensorUpdate {
385        tensor_id: String,
386        values: Vec<f32>,
387    },
388    GradientUpdate {
389        layer_id: String,
390        gradients: Vec<f32>,
391    },
392    MetricUpdate {
393        metric_name: String,
394        value: f64,
395        timestamp: std::time::Instant,
396    },
397    PerformanceUpdate {
398        operation: String,
399        latency_ms: f64,
400    },
401}
402
403/// Background processing system for non-critical tasks
404pub struct BackgroundProcessor {
405    batch_size: usize,
406    task_queue: Vec<BackgroundTask>,
407    processed_count: usize,
408    worker_handle: Option<tokio::task::JoinHandle<()>>,
409}
410
411impl BackgroundProcessor {
412    pub fn new(batch_size: usize) -> Self {
413        Self {
414            batch_size,
415            task_queue: Vec::new(),
416            processed_count: 0,
417            worker_handle: None,
418        }
419    }
420
421    /// Start background processing
422    pub async fn start(&mut self) -> Result<()> {
423        let (_sender, mut receiver) = tokio::sync::mpsc::channel::<BackgroundTask>(1000);
424
425        // Spawn background worker
426        let batch_size = self.batch_size;
427        let handle = tokio::spawn(async move {
428            let mut batch = Vec::with_capacity(batch_size);
429
430            while let Some(task) = receiver.recv().await {
431                batch.push(task);
432
433                if batch.len() >= batch_size {
434                    Self::process_batch(&mut batch).await;
435                    batch.clear();
436                }
437            }
438
439            // Process remaining tasks
440            if !batch.is_empty() {
441                Self::process_batch(&mut batch).await;
442            }
443        });
444
445        self.worker_handle = Some(handle);
446        Ok(())
447    }
448
449    /// Submit task for background processing
450    pub async fn submit_task(&mut self, task: BackgroundTask) -> Result<()> {
451        self.task_queue.push(task);
452        Ok(())
453    }
454
455    /// Process a batch of background tasks
456    async fn process_batch(batch: &mut Vec<BackgroundTask>) {
457        for task in batch.drain(..) {
458            match task {
459                BackgroundTask::ComputeStatistics { data } => {
460                    // Compute statistics in background
461                    let _stats = Self::compute_statistics(&data).await;
462                },
463                BackgroundTask::GenerateVisualization { plot_data } => {
464                    // Generate visualization in background
465                    let _viz = Self::generate_visualization(&plot_data).await;
466                },
467                BackgroundTask::ExportData { data, format } => {
468                    // Export data in background
469                    let _result = Self::export_data(&data, &format).await;
470                },
471                BackgroundTask::CleanupResources { resource_ids } => {
472                    // Cleanup resources in background
473                    Self::cleanup_resources(&resource_ids).await;
474                },
475            }
476        }
477    }
478
479    /// Compute statistics for background task
480    async fn compute_statistics(data: &[f32]) -> Vec<f64> {
481        // Simplified implementation
482        tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
483        vec![data.iter().map(|&x| x as f64).sum()]
484    }
485
486    /// Generate visualization for background task
487    async fn generate_visualization(plot_data: &PlotData) -> String {
488        // Simplified implementation
489        tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
490        format!(
491            "Generated visualization for {} data points",
492            plot_data.points.len()
493        )
494    }
495
496    /// Export data for background task
497    async fn export_data(data: &ExportData, format: &str) -> Result<String> {
498        // Simplified implementation
499        tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
500        Ok(format!(
501            "Exported {} items in {} format",
502            data.items.len(),
503            format
504        ))
505    }
506
507    /// Cleanup resources for background task
508    async fn cleanup_resources(resource_ids: &[String]) {
509        // Simplified implementation
510        tokio::time::sleep(tokio::time::Duration::from_millis(20)).await;
511        tracing::debug!("Cleaned up {} resources", resource_ids.len());
512    }
513
514    /// Get number of queued tasks
515    pub fn queued_count(&self) -> usize {
516        self.task_queue.len()
517    }
518
519    /// Stop background processing
520    pub async fn stop(&mut self) -> Result<()> {
521        if let Some(handle) = self.worker_handle.take() {
522            handle.abort();
523        }
524        Ok(())
525    }
526}
527
528/// Background task types
529#[derive(Debug, Clone)]
530pub enum BackgroundTask {
531    ComputeStatistics { data: Vec<f32> },
532    GenerateVisualization { plot_data: PlotData },
533    ExportData { data: ExportData, format: String },
534    CleanupResources { resource_ids: Vec<String> },
535}
536
537/// Plot data for background visualization
538#[derive(Debug, Clone)]
539pub struct PlotData {
540    pub points: Vec<(f64, f64)>,
541    pub title: String,
542    pub x_label: String,
543    pub y_label: String,
544}
545
546/// Export data for background processing
547#[derive(Debug, Clone)]
548pub struct ExportData {
549    pub items: Vec<String>,
550    pub metadata: HashMap<String, String>,
551}
552
553/// Performance metrics for monitoring
554#[derive(Debug, Serialize, Deserialize)]
555pub struct PerformanceMetrics {
556    /// Real process RSS in MiB, or `None` when unreadable. Previously always
557    /// the literal `0`.
558    pub memory_usage_mb: Option<usize>,
559    /// Always `None` -- see
560    /// `LowOverheadDebugSession::get_cpu_usage_percentage`. Previously always
561    /// the literal `0.0`.
562    pub cpu_usage_percentage: Option<f32>,
563    pub lazy_computations_pending: usize,
564    pub incremental_updates_processed: usize,
565    pub background_tasks_queued: usize,
566}
567
568/// Selective debugging configuration
569#[derive(Debug, Clone)]
570pub struct SelectiveDebugConfig {
571    pub components: Vec<DebugComponent>,
572    pub sampling_rules: HashMap<DebugComponent, f32>,
573    pub priority_rules: HashMap<DebugComponent, DebugPriority>,
574    pub resource_limits: ResourceLimits,
575}
576
577/// Debug priority levels
578#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
579pub enum DebugPriority {
580    Low,
581    Medium,
582    High,
583    Critical,
584}
585
586/// Resource limits for selective debugging
587#[derive(Debug, Clone)]
588pub struct ResourceLimits {
589    pub max_memory_per_component_mb: usize,
590    pub max_cpu_per_component_percentage: f32,
591    pub max_concurrent_operations: usize,
592}
593
594impl SelectiveDebugConfig {
595    /// Create config for production monitoring
596    pub fn production_monitoring() -> Self {
597        let mut sampling_rules = HashMap::new();
598        sampling_rules.insert(DebugComponent::AnomalyDetection, 1.0);
599        sampling_rules.insert(DebugComponent::PerformanceProfiling, 0.1);
600        sampling_rules.insert(DebugComponent::MemoryProfiling, 0.05);
601
602        let mut priority_rules = HashMap::new();
603        priority_rules.insert(DebugComponent::AnomalyDetection, DebugPriority::Critical);
604        priority_rules.insert(DebugComponent::PerformanceProfiling, DebugPriority::Medium);
605
606        Self {
607            components: vec![
608                DebugComponent::AnomalyDetection,
609                DebugComponent::PerformanceProfiling,
610            ],
611            sampling_rules,
612            priority_rules,
613            resource_limits: ResourceLimits {
614                max_memory_per_component_mb: 50,
615                max_cpu_per_component_percentage: 5.0,
616                max_concurrent_operations: 2,
617            },
618        }
619    }
620
621    /// Create config for development debugging
622    pub fn development_debugging() -> Self {
623        let mut sampling_rules = HashMap::new();
624        sampling_rules.insert(DebugComponent::TensorInspection, 0.5);
625        sampling_rules.insert(DebugComponent::GradientDebugging, 1.0);
626        sampling_rules.insert(DebugComponent::ModelDiagnostics, 1.0);
627        sampling_rules.insert(DebugComponent::AnomalyDetection, 1.0);
628
629        let mut priority_rules = HashMap::new();
630        priority_rules.insert(DebugComponent::GradientDebugging, DebugPriority::High);
631        priority_rules.insert(DebugComponent::AnomalyDetection, DebugPriority::Critical);
632        priority_rules.insert(DebugComponent::ModelDiagnostics, DebugPriority::Medium);
633
634        Self {
635            components: vec![
636                DebugComponent::TensorInspection,
637                DebugComponent::GradientDebugging,
638                DebugComponent::ModelDiagnostics,
639                DebugComponent::AnomalyDetection,
640            ],
641            sampling_rules,
642            priority_rules,
643            resource_limits: ResourceLimits {
644                max_memory_per_component_mb: 200,
645                max_cpu_per_component_percentage: 15.0,
646                max_concurrent_operations: 6,
647            },
648        }
649    }
650}
651
652/// Create optimized debug session for production use
653pub fn optimized_debug_session(
654    selective_config: SelectiveDebugConfig,
655    performance_config: PerformanceConfig,
656) -> LowOverheadDebugSession {
657    let debug_config = DebugConfig {
658        enable_tensor_inspection: selective_config
659            .components
660            .contains(&DebugComponent::TensorInspection),
661        enable_gradient_debugging: selective_config
662            .components
663            .contains(&DebugComponent::GradientDebugging),
664        enable_model_diagnostics: selective_config
665            .components
666            .contains(&DebugComponent::ModelDiagnostics),
667        enable_memory_profiling: selective_config
668            .components
669            .contains(&DebugComponent::MemoryProfiling),
670        enable_computation_graph_analysis: selective_config
671            .components
672            .contains(&DebugComponent::ComputationGraphAnalysis),
673        sampling_rate: performance_config.sampling_rate,
674        max_tracked_tensors: if performance_config.low_overhead_mode { 50 } else { 500 },
675        max_gradient_history: if performance_config.low_overhead_mode { 10 } else { 50 },
676        ..Default::default()
677    };
678
679    LowOverheadDebugSession::new(
680        debug_config,
681        performance_config,
682        selective_config.components,
683    )
684}
685
686/// Create ultra-low overhead session for production monitoring
687pub fn ultra_low_overhead_session() -> LowOverheadDebugSession {
688    let selective_config = SelectiveDebugConfig::production_monitoring();
689    let performance_config = PerformanceConfig {
690        low_overhead_mode: true,
691        selective_debugging: true,
692        lazy_evaluation: true,
693        incremental_updates: true,
694        background_processing: true,
695        sampling_rate: 0.01,
696        max_memory_mb: 100,
697        max_cpu_percentage: 5.0,
698        background_batch_size: 50,
699        incremental_update_interval_ms: 1000,
700    };
701
702    optimized_debug_session(selective_config, performance_config)
703}
704
705// ─────────────────────────────────────────────────────────────────────────────
706// Tests
707// ─────────────────────────────────────────────────────────────────────────────
708
709#[cfg(test)]
710mod tests {
711    use super::*;
712
713    // ── PerformanceConfig::default() ────────────────────────────────────────
714
715    #[test]
716    fn test_performance_config_default() {
717        let cfg = PerformanceConfig::default();
718        assert!(!cfg.low_overhead_mode);
719        assert!(!cfg.selective_debugging);
720        assert!(cfg.lazy_evaluation);
721        assert!(cfg.incremental_updates);
722        assert!(cfg.background_processing);
723        assert!((cfg.sampling_rate - 1.0).abs() < 1e-6);
724        assert!(cfg.max_memory_mb > 0);
725        assert!(cfg.max_cpu_percentage > 0.0);
726        assert!(cfg.background_batch_size > 0);
727        assert!(cfg.incremental_update_interval_ms > 0);
728    }
729
730    #[test]
731    fn test_performance_config_low_overhead() {
732        let cfg = PerformanceConfig {
733            low_overhead_mode: true,
734            selective_debugging: true,
735            sampling_rate: 0.01,
736            max_memory_mb: 100,
737            max_cpu_percentage: 5.0,
738            ..PerformanceConfig::default()
739        };
740        assert!(cfg.low_overhead_mode);
741        assert!((cfg.sampling_rate - 0.01).abs() < 1e-6);
742    }
743
744    // ── DebugComponent variants ───────────────────────────────────────────
745
746    #[test]
747    fn test_debug_component_variants() {
748        let components = [
749            DebugComponent::TensorInspection,
750            DebugComponent::GradientDebugging,
751            DebugComponent::ModelDiagnostics,
752            DebugComponent::MemoryProfiling,
753            DebugComponent::ComputationGraphAnalysis,
754            DebugComponent::AnomalyDetection,
755            DebugComponent::PerformanceProfiling,
756            DebugComponent::ArchitectureAnalysis,
757            DebugComponent::BehaviorAnalysis,
758            DebugComponent::TrainingDynamics,
759        ];
760        for c in &components {
761            assert!(!format!("{:?}", c).is_empty());
762        }
763    }
764
765    #[test]
766    fn test_debug_component_equality() {
767        assert_eq!(
768            DebugComponent::TensorInspection,
769            DebugComponent::TensorInspection
770        );
771        assert_ne!(
772            DebugComponent::TensorInspection,
773            DebugComponent::GradientDebugging
774        );
775    }
776
777    // ── DebugPriority variants ────────────────────────────────────────────
778
779    #[test]
780    fn test_debug_priority_variants() {
781        let priorities = [
782            DebugPriority::Low,
783            DebugPriority::Medium,
784            DebugPriority::High,
785            DebugPriority::Critical,
786        ];
787        for p in &priorities {
788            assert!(!format!("{:?}", p).is_empty());
789        }
790    }
791
792    // ── SelectiveDebugConfig ──────────────────────────────────────────────
793
794    #[test]
795    fn test_production_monitoring_config() {
796        let cfg = SelectiveDebugConfig::production_monitoring();
797        assert!(cfg.components.contains(&DebugComponent::AnomalyDetection));
798        assert!(!cfg.sampling_rules.is_empty());
799        assert!(!cfg.priority_rules.is_empty());
800    }
801
802    #[test]
803    fn test_development_debugging_config() {
804        let cfg = SelectiveDebugConfig::development_debugging();
805        assert!(cfg.components.contains(&DebugComponent::GradientDebugging));
806        assert!(cfg.components.contains(&DebugComponent::ModelDiagnostics));
807        assert!(cfg.resource_limits.max_memory_per_component_mb > 0);
808    }
809
810    #[test]
811    fn test_resource_limits_in_production_config() {
812        let cfg = SelectiveDebugConfig::production_monitoring();
813        let limits = &cfg.resource_limits;
814        assert!(limits.max_memory_per_component_mb > 0);
815        assert!(limits.max_cpu_per_component_percentage > 0.0);
816        assert!(limits.max_concurrent_operations > 0);
817    }
818
819    // ── optimized_debug_session ───────────────────────────────────────────
820
821    #[test]
822    fn test_optimized_debug_session_creation() {
823        let selective_cfg = SelectiveDebugConfig::production_monitoring();
824        let perf_cfg = PerformanceConfig::default();
825        // Verify session was created without panicking.
826        let _session = optimized_debug_session(selective_cfg, perf_cfg);
827    }
828
829    #[test]
830    fn test_low_overhead_session_creation() {
831        let selective_cfg = SelectiveDebugConfig::production_monitoring();
832        let perf_cfg = PerformanceConfig {
833            low_overhead_mode: true,
834            ..PerformanceConfig::default()
835        };
836        // Just verify construction doesn't panic.
837        let _session = optimized_debug_session(selective_cfg, perf_cfg);
838    }
839
840    #[test]
841    fn test_ultra_low_overhead_session_creation() {
842        // Verify creation of the ultra-low overhead session doesn't panic.
843        let _session = ultra_low_overhead_session();
844    }
845}