tailwind_rs_postcss/advanced_features/
performance_monitor.rs

1//! Performance Monitor
2//! 
3//! This module provides comprehensive performance monitoring for
4//! PostCSS operations with metrics collection and analysis.
5
6use std::collections::HashMap;
7use std::time::{Duration, Instant, SystemTime};
8use super::types::*;
9
10/// PostCSS performance monitor
11pub struct PostCSSPerformanceMonitor {
12    metrics: PerformanceMetrics,
13    profiler: PerformanceProfiler,
14    reporter: PerformanceReporter,
15    alerts: Vec<PerformanceAlert>,
16    operation_timers: HashMap<String, Instant>,
17}
18
19impl PostCSSPerformanceMonitor {
20    /// Create new performance monitor
21    pub fn new() -> Self {
22        Self {
23            metrics: PerformanceMetrics {
24                total_time: Duration::from_secs(0),
25                parsing_time: Duration::from_secs(0),
26                transformation_time: Duration::from_secs(0),
27                generation_time: Duration::from_secs(0),
28                memory_usage: 0,
29                cpu_usage: 0.0,
30            },
31            profiler: PerformanceProfiler::new(),
32            reporter: PerformanceReporter::new(),
33            alerts: Vec::new(),
34            operation_timers: HashMap::new(),
35        }
36    }
37    
38    /// Start performance monitoring
39    pub fn start_monitoring(&mut self, operation: &str) -> PerformanceTimer {
40        let timer = PerformanceTimer::new(operation.to_string());
41        self.operation_timers.insert(operation.to_string(), Instant::now());
42        timer
43    }
44    
45    /// Record performance metrics
46    pub fn record_metrics(&mut self, operation: &str, metrics: OperationMetrics) {
47        // Update overall metrics
48        self.metrics.total_time += metrics.duration;
49        self.metrics.memory_usage = self.metrics.memory_usage.max(metrics.memory_delta as usize);
50        self.metrics.cpu_usage = self.metrics.cpu_usage.max(metrics.cpu_usage);
51        
52        // Record operation metrics
53        self.profiler.record_operation(operation, metrics.clone());
54        
55        // Check for performance alerts
56        self.check_performance_alerts(operation, &metrics);
57    }
58    
59    /// Generate performance report
60    pub fn generate_report(&self) -> PerformanceReport {
61        let operations = self.profiler.get_operation_metrics();
62        let recommendations = self.generate_recommendations(&operations);
63        
64        PerformanceReport {
65            total_time: self.metrics.total_time,
66            operations,
67            memory_usage: self.metrics.memory_usage,
68            cpu_usage: self.metrics.cpu_usage,
69            alerts: self.alerts.clone(),
70            recommendations,
71        }
72    }
73    
74    /// Monitor processing pipeline
75    pub fn monitor_processing_pipeline(&mut self, css: &str, pipeline: &ProcessingPipeline) -> Result<String, AdvancedFeatureError> {
76        let start_time = Instant::now();
77        let start_memory = self.get_memory_usage();
78        
79        let mut processed_css = css.to_string();
80        
81        for step in &pipeline.steps {
82            let step_timer = self.start_monitoring(&step.name);
83            
84            // Execute step
85            processed_css = (step.execute)(&processed_css)?;
86            
87            // Record metrics
88            let step_metrics = OperationMetrics {
89                operation: step.name.clone(),
90                duration: step_timer.elapsed(),
91                memory_delta: self.get_memory_usage() as i64 - start_memory as i64,
92                cpu_usage: self.get_cpu_usage(),
93                input_size: step.input_size,
94                output_size: processed_css.len(),
95            };
96            
97            self.record_metrics(&step.name, step_metrics);
98        }
99        
100        let total_time = start_time.elapsed();
101        let total_memory = self.get_memory_usage();
102        
103        // Record overall metrics
104        self.metrics.total_time = total_time;
105        self.metrics.memory_usage = total_memory;
106        
107        // Check for performance alerts
108        self.check_performance_alerts("pipeline", &OperationMetrics {
109            operation: "pipeline".to_string(),
110            duration: total_time,
111            memory_delta: total_memory as i64 - start_memory as i64,
112            cpu_usage: self.get_cpu_usage(),
113            input_size: css.len(),
114            output_size: processed_css.len(),
115        });
116        
117        Ok(processed_css)
118    }
119    
120    /// Check for performance alerts
121    fn check_performance_alerts(&mut self, operation: &str, metrics: &OperationMetrics) {
122        // Check for slow operations
123        if metrics.duration > Duration::from_millis(1000) {
124            self.alerts.push(PerformanceAlert {
125                operation: operation.to_string(),
126                issue: "Slow execution".to_string(),
127                severity: AlertSeverity::Medium,
128                timestamp: SystemTime::now(),
129                metrics: metrics.clone(),
130            });
131        }
132        
133        // Check for high memory usage
134        if metrics.memory_delta > 100 * 1024 * 1024 { // 100MB
135            self.alerts.push(PerformanceAlert {
136                operation: operation.to_string(),
137                issue: "High memory usage".to_string(),
138                severity: AlertSeverity::High,
139                timestamp: SystemTime::now(),
140                metrics: metrics.clone(),
141            });
142        }
143        
144        // Check for high CPU usage
145        if metrics.cpu_usage > 0.8 {
146            self.alerts.push(PerformanceAlert {
147                operation: operation.to_string(),
148                issue: "High CPU usage".to_string(),
149                severity: AlertSeverity::High,
150                timestamp: SystemTime::now(),
151                metrics: metrics.clone(),
152            });
153        }
154    }
155    
156    /// Generate performance recommendations
157    fn generate_recommendations(&self, operations: &HashMap<String, OperationMetrics>) -> Vec<String> {
158        let mut recommendations = Vec::new();
159        
160        // Find slowest operations
161        let mut sorted_operations: Vec<_> = operations.values().collect();
162        sorted_operations.sort_by(|a, b| b.duration.cmp(&a.duration));
163        
164        if let Some(slowest) = sorted_operations.first() {
165            if slowest.duration > Duration::from_millis(500) {
166                recommendations.push(format!(
167                    "Consider optimizing '{}' operation (took {:?})",
168                    slowest.operation, slowest.duration
169                ));
170            }
171        }
172        
173        // Check memory usage
174        let total_memory: usize = operations.values().map(|m| m.memory_delta.max(0) as usize).sum();
175        if total_memory > 50 * 1024 * 1024 { // 50MB
176            recommendations.push("Consider implementing memory optimization strategies".to_string());
177        }
178        
179        // Check CPU usage
180        let avg_cpu: f64 = operations.values().map(|m| m.cpu_usage).sum::<f64>() / operations.len() as f64;
181        if avg_cpu > 0.7 {
182            recommendations.push("Consider implementing CPU optimization strategies".to_string());
183        }
184        
185        recommendations
186    }
187    
188    /// Get current memory usage
189    fn get_memory_usage(&self) -> usize {
190        // Simplified implementation - would use actual memory monitoring
191        0
192    }
193    
194    /// Get current CPU usage
195    fn get_cpu_usage(&self) -> f64 {
196        // Simplified implementation - would use actual CPU monitoring
197        0.0
198    }
199}
200
201/// Performance timer
202pub struct PerformanceTimer {
203    operation: String,
204    start_time: Instant,
205}
206
207impl PerformanceTimer {
208    /// Create new performance timer
209    pub fn new(operation: String) -> Self {
210        Self {
211            operation,
212            start_time: Instant::now(),
213        }
214    }
215    
216    /// Get elapsed time
217    pub fn elapsed(&self) -> Duration {
218        self.start_time.elapsed()
219    }
220    
221    /// Get operation name
222    pub fn operation(&self) -> &str {
223        &self.operation
224    }
225}
226
227/// Performance profiler
228pub struct PerformanceProfiler {
229    operation_metrics: HashMap<String, OperationMetrics>,
230    operation_counts: HashMap<String, usize>,
231}
232
233impl PerformanceProfiler {
234    /// Create new performance profiler
235    pub fn new() -> Self {
236        Self {
237            operation_metrics: HashMap::new(),
238            operation_counts: HashMap::new(),
239        }
240    }
241    
242    /// Record operation metrics
243    pub fn record_operation(&mut self, operation: &str, metrics: OperationMetrics) {
244        self.operation_metrics.insert(operation.to_string(), metrics);
245        *self.operation_counts.entry(operation.to_string()).or_insert(0) += 1;
246    }
247    
248    /// Get operation metrics
249    pub fn get_operation_metrics(&self) -> HashMap<String, OperationMetrics> {
250        self.operation_metrics.clone()
251    }
252    
253    /// Get operation counts
254    pub fn get_operation_counts(&self) -> HashMap<String, usize> {
255        self.operation_counts.clone()
256    }
257}
258
259/// Performance reporter
260pub struct PerformanceReporter;
261
262impl PerformanceReporter {
263    /// Create new performance reporter
264    pub fn new() -> Self {
265        Self
266    }
267}
268
269/// Processing pipeline
270pub struct ProcessingPipeline {
271    pub steps: Vec<ProcessingStep>,
272}
273
274impl ProcessingPipeline {
275    /// Create new processing pipeline
276    pub fn new() -> Self {
277        Self {
278            steps: Vec::new(),
279        }
280    }
281    
282    /// Add processing step
283    pub fn add_step(&mut self, step: ProcessingStep) {
284        self.steps.push(step);
285    }
286}
287
288/// Processing step
289pub struct ProcessingStep {
290    pub name: String,
291    pub input_size: usize,
292    pub execute: fn(&str) -> Result<String, AdvancedFeatureError>,
293}
294
295impl ProcessingStep {
296    /// Create new processing step
297    pub fn new(name: String, input_size: usize, execute: fn(&str) -> Result<String, AdvancedFeatureError>) -> Self {
298        Self {
299            name,
300            input_size,
301            execute,
302        }
303    }
304}
305
306#[cfg(test)]
307mod tests {
308    use super::*;
309    
310    #[test]
311    fn test_performance_monitoring() {
312        let mut monitor = PostCSSPerformanceMonitor::new();
313        let timer = monitor.start_monitoring("test_operation");
314        
315        // Simulate work
316        std::thread::sleep(Duration::from_millis(100));
317        
318        let metrics = OperationMetrics {
319            operation: "test_operation".to_string(),
320            duration: timer.elapsed(),
321            memory_delta: 1024,
322            cpu_usage: 0.5,
323            input_size: 100,
324            output_size: 200,
325        };
326        
327        monitor.record_metrics("test_operation", metrics);
328        let report = monitor.generate_report();
329        assert!(report.operations.contains_key("test_operation"));
330    }
331    
332    #[test]
333    fn test_performance_timer() {
334        let timer = PerformanceTimer::new("test".to_string());
335        std::thread::sleep(Duration::from_millis(10));
336        assert!(timer.elapsed() >= Duration::from_millis(10));
337        assert_eq!(timer.operation(), "test");
338    }
339    
340    #[test]
341    fn test_performance_profiler() {
342        let mut profiler = PerformanceProfiler::new();
343        let metrics = OperationMetrics {
344            operation: "test".to_string(),
345            duration: Duration::from_millis(100),
346            memory_delta: 1024,
347            cpu_usage: 0.5,
348            input_size: 100,
349            output_size: 200,
350        };
351        
352        profiler.record_operation("test", metrics);
353        let operation_metrics = profiler.get_operation_metrics();
354        assert!(operation_metrics.contains_key("test"));
355    }
356    
357    #[test]
358    fn test_processing_pipeline() {
359        let mut pipeline = ProcessingPipeline::new();
360        let step = ProcessingStep::new(
361            "test_step".to_string(),
362            100,
363            |input| Ok(input.to_string())
364        );
365        
366        pipeline.add_step(step);
367        assert_eq!(pipeline.steps.len(), 1);
368    }
369    
370    #[test]
371    fn test_performance_alerts() {
372        let mut monitor = PostCSSPerformanceMonitor::new();
373        let slow_metrics = OperationMetrics {
374            operation: "slow_operation".to_string(),
375            duration: Duration::from_millis(2000), // 2 seconds
376            memory_delta: 1024,
377            cpu_usage: 0.5,
378            input_size: 100,
379            output_size: 200,
380        };
381        
382        monitor.record_metrics("slow_operation", slow_metrics);
383        let report = monitor.generate_report();
384        assert!(!report.alerts.is_empty());
385    }
386}