tailwind_rs_postcss/advanced_features/
performance_monitor.rs1use super::types::*;
7use std::collections::HashMap;
8use std::time::{Duration, Instant, SystemTime};
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
42 .insert(operation.to_string(), Instant::now());
43 timer
44 }
45
46 pub fn record_metrics(&mut self, operation: &str, metrics: OperationMetrics) {
48 self.metrics.total_time += metrics.duration;
50 self.metrics.memory_usage = self.metrics.memory_usage.max(metrics.memory_delta as usize);
51 self.metrics.cpu_usage = self.metrics.cpu_usage.max(metrics.cpu_usage);
52
53 self.profiler.record_operation(operation, metrics.clone());
55
56 self.check_performance_alerts(operation, &metrics);
58 }
59
60 pub fn generate_report(&self) -> PerformanceReport {
62 let operations = self.profiler.get_operation_metrics();
63 let recommendations = self.generate_recommendations(&operations);
64
65 PerformanceReport {
66 total_time: self.metrics.total_time,
67 operations,
68 memory_usage: self.metrics.memory_usage,
69 cpu_usage: self.metrics.cpu_usage,
70 alerts: self.alerts.clone(),
71 recommendations,
72 }
73 }
74
75 pub fn monitor_processing_pipeline(
77 &mut self,
78 css: &str,
79 pipeline: &ProcessingPipeline,
80 ) -> Result<String, AdvancedFeatureError> {
81 let start_time = Instant::now();
82 let start_memory = self.get_memory_usage();
83
84 let mut processed_css = css.to_string();
85
86 for step in &pipeline.steps {
87 let step_timer = self.start_monitoring(&step.name);
88
89 processed_css = (step.execute)(&processed_css)?;
91
92 let step_metrics = OperationMetrics {
94 operation: step.name.clone(),
95 duration: step_timer.elapsed(),
96 memory_delta: self.get_memory_usage() as i64 - start_memory as i64,
97 cpu_usage: self.get_cpu_usage(),
98 input_size: step.input_size,
99 output_size: processed_css.len(),
100 };
101
102 self.record_metrics(&step.name, step_metrics);
103 }
104
105 let total_time = start_time.elapsed();
106 let total_memory = self.get_memory_usage();
107
108 self.metrics.total_time = total_time;
110 self.metrics.memory_usage = total_memory;
111
112 self.check_performance_alerts(
114 "pipeline",
115 &OperationMetrics {
116 operation: "pipeline".to_string(),
117 duration: total_time,
118 memory_delta: total_memory as i64 - start_memory as i64,
119 cpu_usage: self.get_cpu_usage(),
120 input_size: css.len(),
121 output_size: processed_css.len(),
122 },
123 );
124
125 Ok(processed_css)
126 }
127
128 fn check_performance_alerts(&mut self, operation: &str, metrics: &OperationMetrics) {
130 if metrics.duration > Duration::from_millis(1000) {
132 self.alerts.push(PerformanceAlert {
133 operation: operation.to_string(),
134 issue: "Slow execution".to_string(),
135 severity: AlertSeverity::Medium,
136 timestamp: SystemTime::now(),
137 metrics: metrics.clone(),
138 });
139 }
140
141 if metrics.memory_delta > 100 * 1024 * 1024 {
143 self.alerts.push(PerformanceAlert {
145 operation: operation.to_string(),
146 issue: "High memory usage".to_string(),
147 severity: AlertSeverity::High,
148 timestamp: SystemTime::now(),
149 metrics: metrics.clone(),
150 });
151 }
152
153 if metrics.cpu_usage > 0.8 {
155 self.alerts.push(PerformanceAlert {
156 operation: operation.to_string(),
157 issue: "High CPU usage".to_string(),
158 severity: AlertSeverity::High,
159 timestamp: SystemTime::now(),
160 metrics: metrics.clone(),
161 });
162 }
163 }
164
165 fn generate_recommendations(
167 &self,
168 operations: &HashMap<String, OperationMetrics>,
169 ) -> Vec<String> {
170 let mut recommendations = Vec::new();
171
172 let mut sorted_operations: Vec<_> = operations.values().collect();
174 sorted_operations.sort_by(|a, b| b.duration.cmp(&a.duration));
175
176 if let Some(slowest) = sorted_operations.first() {
177 if slowest.duration > Duration::from_millis(500) {
178 recommendations.push(format!(
179 "Consider optimizing '{}' operation (took {:?})",
180 slowest.operation, slowest.duration
181 ));
182 }
183 }
184
185 let total_memory: usize = operations
187 .values()
188 .map(|m| m.memory_delta.max(0) as usize)
189 .sum();
190 if total_memory > 50 * 1024 * 1024 {
191 recommendations
193 .push("Consider implementing memory optimization strategies".to_string());
194 }
195
196 let avg_cpu: f64 =
198 operations.values().map(|m| m.cpu_usage).sum::<f64>() / operations.len() as f64;
199 if avg_cpu > 0.7 {
200 recommendations.push("Consider implementing CPU optimization strategies".to_string());
201 }
202
203 recommendations
204 }
205
206 fn get_memory_usage(&self) -> usize {
208 0
210 }
211
212 fn get_cpu_usage(&self) -> f64 {
214 0.0
216 }
217}
218
219pub struct PerformanceTimer {
221 operation: String,
222 start_time: Instant,
223}
224
225impl PerformanceTimer {
226 pub fn new(operation: String) -> Self {
228 Self {
229 operation,
230 start_time: Instant::now(),
231 }
232 }
233
234 pub fn elapsed(&self) -> Duration {
236 self.start_time.elapsed()
237 }
238
239 pub fn operation(&self) -> &str {
241 &self.operation
242 }
243}
244
245pub struct PerformanceProfiler {
247 operation_metrics: HashMap<String, OperationMetrics>,
248 operation_counts: HashMap<String, usize>,
249}
250
251impl PerformanceProfiler {
252 pub fn new() -> Self {
254 Self {
255 operation_metrics: HashMap::new(),
256 operation_counts: HashMap::new(),
257 }
258 }
259
260 pub fn record_operation(&mut self, operation: &str, metrics: OperationMetrics) {
262 self.operation_metrics
263 .insert(operation.to_string(), metrics);
264 *self
265 .operation_counts
266 .entry(operation.to_string())
267 .or_insert(0) += 1;
268 }
269
270 pub fn get_operation_metrics(&self) -> HashMap<String, OperationMetrics> {
272 self.operation_metrics.clone()
273 }
274
275 pub fn get_operation_counts(&self) -> HashMap<String, usize> {
277 self.operation_counts.clone()
278 }
279}
280
281pub struct PerformanceReporter;
283
284impl PerformanceReporter {
285 pub fn new() -> Self {
287 Self
288 }
289}
290
291pub struct ProcessingPipeline {
293 pub steps: Vec<ProcessingStep>,
294}
295
296impl ProcessingPipeline {
297 pub fn new() -> Self {
299 Self { steps: Vec::new() }
300 }
301
302 pub fn add_step(&mut self, step: ProcessingStep) {
304 self.steps.push(step);
305 }
306}
307
308pub struct ProcessingStep {
310 pub name: String,
311 pub input_size: usize,
312 pub execute: fn(&str) -> Result<String, AdvancedFeatureError>,
313}
314
315impl ProcessingStep {
316 pub fn new(
318 name: String,
319 input_size: usize,
320 execute: fn(&str) -> Result<String, AdvancedFeatureError>,
321 ) -> Self {
322 Self {
323 name,
324 input_size,
325 execute,
326 }
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[test]
335 fn test_performance_monitoring() {
336 let mut monitor = PostCSSPerformanceMonitor::new();
337 let timer = monitor.start_monitoring("test_operation");
338
339 std::thread::sleep(Duration::from_millis(100));
341
342 let metrics = OperationMetrics {
343 operation: "test_operation".to_string(),
344 duration: timer.elapsed(),
345 memory_delta: 1024,
346 cpu_usage: 0.5,
347 input_size: 100,
348 output_size: 200,
349 };
350
351 monitor.record_metrics("test_operation", metrics);
352 let report = monitor.generate_report();
353 assert!(report.operations.contains_key("test_operation"));
354 }
355
356 #[test]
357 fn test_performance_timer() {
358 let timer = PerformanceTimer::new("test".to_string());
359 std::thread::sleep(Duration::from_millis(10));
360 assert!(timer.elapsed() >= Duration::from_millis(10));
361 assert_eq!(timer.operation(), "test");
362 }
363
364 #[test]
365 fn test_performance_profiler() {
366 let mut profiler = PerformanceProfiler::new();
367 let metrics = OperationMetrics {
368 operation: "test".to_string(),
369 duration: Duration::from_millis(100),
370 memory_delta: 1024,
371 cpu_usage: 0.5,
372 input_size: 100,
373 output_size: 200,
374 };
375
376 profiler.record_operation("test", metrics);
377 let operation_metrics = profiler.get_operation_metrics();
378 assert!(operation_metrics.contains_key("test"));
379 }
380
381 #[test]
382 fn test_processing_pipeline() {
383 let mut pipeline = ProcessingPipeline::new();
384 let step = ProcessingStep::new("test_step".to_string(), 100, |input| Ok(input.to_string()));
385
386 pipeline.add_step(step);
387 assert_eq!(pipeline.steps.len(), 1);
388 }
389
390 #[test]
391 fn test_performance_alerts() {
392 let mut monitor = PostCSSPerformanceMonitor::new();
393 let slow_metrics = OperationMetrics {
394 operation: "slow_operation".to_string(),
395 duration: Duration::from_millis(2000), memory_delta: 1024,
397 cpu_usage: 0.5,
398 input_size: 100,
399 output_size: 200,
400 };
401
402 monitor.record_metrics("slow_operation", slow_metrics);
403 let report = monitor.generate_report();
404 assert!(!report.alerts.is_empty());
405 }
406}