tailwind_rs_postcss/advanced_features/
performance_monitor.rs1use std::collections::HashMap;
7use std::time::{Duration, Instant, SystemTime};
8use super::types::*;
9
10pub 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 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 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 pub fn record_metrics(&mut self, operation: &str, metrics: OperationMetrics) {
47 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 self.profiler.record_operation(operation, metrics.clone());
54
55 self.check_performance_alerts(operation, &metrics);
57 }
58
59 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 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 processed_css = (step.execute)(&processed_css)?;
86
87 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 self.metrics.total_time = total_time;
105 self.metrics.memory_usage = total_memory;
106
107 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 fn check_performance_alerts(&mut self, operation: &str, metrics: &OperationMetrics) {
122 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 if metrics.memory_delta > 100 * 1024 * 1024 { 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 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 fn generate_recommendations(&self, operations: &HashMap<String, OperationMetrics>) -> Vec<String> {
158 let mut recommendations = Vec::new();
159
160 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 let total_memory: usize = operations.values().map(|m| m.memory_delta.max(0) as usize).sum();
175 if total_memory > 50 * 1024 * 1024 { recommendations.push("Consider implementing memory optimization strategies".to_string());
177 }
178
179 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 fn get_memory_usage(&self) -> usize {
190 0
192 }
193
194 fn get_cpu_usage(&self) -> f64 {
196 0.0
198 }
199}
200
201pub struct PerformanceTimer {
203 operation: String,
204 start_time: Instant,
205}
206
207impl PerformanceTimer {
208 pub fn new(operation: String) -> Self {
210 Self {
211 operation,
212 start_time: Instant::now(),
213 }
214 }
215
216 pub fn elapsed(&self) -> Duration {
218 self.start_time.elapsed()
219 }
220
221 pub fn operation(&self) -> &str {
223 &self.operation
224 }
225}
226
227pub struct PerformanceProfiler {
229 operation_metrics: HashMap<String, OperationMetrics>,
230 operation_counts: HashMap<String, usize>,
231}
232
233impl PerformanceProfiler {
234 pub fn new() -> Self {
236 Self {
237 operation_metrics: HashMap::new(),
238 operation_counts: HashMap::new(),
239 }
240 }
241
242 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 pub fn get_operation_metrics(&self) -> HashMap<String, OperationMetrics> {
250 self.operation_metrics.clone()
251 }
252
253 pub fn get_operation_counts(&self) -> HashMap<String, usize> {
255 self.operation_counts.clone()
256 }
257}
258
259pub struct PerformanceReporter;
261
262impl PerformanceReporter {
263 pub fn new() -> Self {
265 Self
266 }
267}
268
269pub struct ProcessingPipeline {
271 pub steps: Vec<ProcessingStep>,
272}
273
274impl ProcessingPipeline {
275 pub fn new() -> Self {
277 Self {
278 steps: Vec::new(),
279 }
280 }
281
282 pub fn add_step(&mut self, step: ProcessingStep) {
284 self.steps.push(step);
285 }
286}
287
288pub struct ProcessingStep {
290 pub name: String,
291 pub input_size: usize,
292 pub execute: fn(&str) -> Result<String, AdvancedFeatureError>,
293}
294
295impl ProcessingStep {
296 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 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), 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}