1use super::{MetricValue, MetricsCollector};
2use std::collections::HashMap;
3use std::time::Duration;
4
5pub struct PerformanceAnalyzer {
8 baselines: HashMap<String, Benchmark>,
10 thresholds: AnalysisThresholds,
12}
13
14#[derive(Debug, Clone)]
16pub struct Benchmark {
17 pub operation: String,
19 pub avg_duration: Duration,
21 pub memory_overhead: usize,
23 pub throughput: f64,
25 pub accuracy: f64,
27 pub sample_size: usize,
29}
30
31#[derive(Debug, Clone)]
33pub struct AnalysisThresholds {
34 pub max_tracking_overhead: f64,
36 pub max_allocation_latency: Duration,
38 pub max_symbol_resolution_time: Duration,
40 pub min_tracking_completeness: f64,
42 pub max_analysis_memory: usize,
44}
45
46#[derive(Debug, Clone)]
48pub struct PerformanceReport {
49 pub efficiency_score: f64,
51 pub tracking_performance: TrackingPerformance,
53 pub symbol_performance: SymbolPerformance,
55 pub pointer_performance: PointerPerformance,
57 pub memory_efficiency: MemoryEfficiency,
59 pub recommendations: Vec<String>,
61}
62
63#[derive(Debug, Clone, Default)]
65pub struct TrackingPerformance {
66 pub avg_allocation_time: Duration,
68 pub completeness: f64,
70 pub overhead_bytes: usize,
72 pub throughput: f64,
74}
75
76#[derive(Debug, Clone, Default)]
78pub struct SymbolPerformance {
79 pub avg_resolution_time: Duration,
81 pub cache_hit_ratio: f64,
83 pub resolution_rate: f64,
85 pub cache_memory_usage: usize,
87}
88
89#[derive(Debug, Clone, Default)]
91pub struct PointerPerformance {
92 pub analysis_time: Duration,
94 pub leak_detection_accuracy: f64,
96 pub analysis_rate: f64,
98}
99
100#[derive(Debug, Clone, Default)]
102pub struct MemoryEfficiency {
103 pub total_memory_mb: f64,
105 pub memory_per_allocation: f64,
107 pub growth_rate: f64,
109 pub fragmentation_ratio: f64,
111}
112
113impl PerformanceAnalyzer {
114 pub fn new() -> Self {
116 Self {
117 baselines: HashMap::new(),
118 thresholds: AnalysisThresholds::default(),
119 }
120 }
121
122 pub fn with_thresholds(thresholds: AnalysisThresholds) -> Self {
124 Self {
125 baselines: HashMap::new(),
126 thresholds,
127 }
128 }
129
130 pub fn analyze_performance(&self, collector: &MetricsCollector) -> PerformanceReport {
132 let tracking_perf = self.analyze_tracking_performance(collector);
133 let symbol_perf = self.analyze_symbol_performance(collector);
134 let pointer_perf = self.analyze_pointer_performance(collector);
135 let memory_eff = self.analyze_memory_efficiency(collector);
136
137 let efficiency_score = self.calculate_efficiency_score(
138 &tracking_perf,
139 &symbol_perf,
140 &pointer_perf,
141 &memory_eff,
142 );
143
144 let recommendations =
145 self.generate_recommendations(&tracking_perf, &symbol_perf, &pointer_perf, &memory_eff);
146
147 PerformanceReport {
148 efficiency_score,
149 tracking_performance: tracking_perf,
150 symbol_performance: symbol_perf,
151 pointer_performance: pointer_perf,
152 memory_efficiency: memory_eff,
153 recommendations,
154 }
155 }
156
157 pub fn set_baseline(&mut self, operation: &str, benchmark: Benchmark) {
159 self.baselines.insert(operation.to_string(), benchmark);
160 }
161
162 pub fn compare_to_baseline(
164 &self,
165 operation: &str,
166 current: &Benchmark,
167 ) -> Option<PerformanceComparison> {
168 self.baselines
169 .get(operation)
170 .map(|baseline| PerformanceComparison {
171 operation: operation.to_string(),
172 baseline: baseline.clone(),
173 current: current.clone(),
174 duration_ratio: current.avg_duration.as_nanos() as f64
175 / baseline.avg_duration.as_nanos() as f64,
176 memory_ratio: current.memory_overhead as f64 / baseline.memory_overhead as f64,
177 throughput_ratio: current.throughput / baseline.throughput,
178 accuracy_diff: current.accuracy - baseline.accuracy,
179 })
180 }
181
182 fn analyze_tracking_performance(&self, collector: &MetricsCollector) -> TrackingPerformance {
183 let avg_allocation_time = collector
184 .get_metric("allocation_tracking_time")
185 .and_then(|m| match &m.value {
186 MetricValue::Timer(timer) => Some(timer.average_duration()),
187 _ => None,
188 })
189 .unwrap_or(Duration::from_nanos(0));
190
191 let completeness = collector
192 .get_metric("tracking_completeness")
193 .and_then(|m| match &m.value {
194 MetricValue::Gauge(value) => Some(*value),
195 _ => None,
196 })
197 .unwrap_or(0.0);
198
199 let overhead_bytes = collector
200 .get_metric("tracking_memory_overhead")
201 .and_then(|m| match &m.value {
202 MetricValue::Gauge(value) => Some(*value as usize),
203 _ => None,
204 })
205 .unwrap_or(0);
206
207 let throughput = collector
208 .get_metric("allocations_per_second")
209 .and_then(|m| match &m.value {
210 MetricValue::Rate(rate) => Some(rate.current_rate),
211 _ => None,
212 })
213 .unwrap_or(0.0);
214
215 TrackingPerformance {
216 avg_allocation_time,
217 completeness,
218 overhead_bytes,
219 throughput,
220 }
221 }
222
223 fn analyze_symbol_performance(&self, collector: &MetricsCollector) -> SymbolPerformance {
224 let avg_resolution_time = collector
225 .get_metric("symbol_resolution_time")
226 .and_then(|m| match &m.value {
227 MetricValue::Timer(timer) => Some(timer.average_duration()),
228 _ => None,
229 })
230 .unwrap_or(Duration::from_nanos(0));
231
232 let cache_hit_ratio = collector
233 .get_metric("symbol_cache_hit_ratio")
234 .and_then(|m| match &m.value {
235 MetricValue::Gauge(value) => Some(*value),
236 _ => None,
237 })
238 .unwrap_or(0.0);
239
240 let resolution_rate = collector
241 .get_metric("symbols_resolved_per_second")
242 .and_then(|m| match &m.value {
243 MetricValue::Rate(rate) => Some(rate.current_rate),
244 _ => None,
245 })
246 .unwrap_or(0.0);
247
248 let cache_memory_usage = collector
249 .get_metric("symbol_cache_memory")
250 .and_then(|m| match &m.value {
251 MetricValue::Gauge(value) => Some(*value as usize),
252 _ => None,
253 })
254 .unwrap_or(0);
255
256 SymbolPerformance {
257 avg_resolution_time,
258 cache_hit_ratio,
259 resolution_rate,
260 cache_memory_usage,
261 }
262 }
263
264 fn analyze_pointer_performance(&self, collector: &MetricsCollector) -> PointerPerformance {
265 let analysis_time = collector
266 .get_metric("pointer_analysis_time")
267 .and_then(|m| match &m.value {
268 MetricValue::Timer(timer) => Some(timer.average_duration()),
269 _ => None,
270 })
271 .unwrap_or(Duration::from_nanos(0));
272
273 let leak_detection_accuracy = collector
274 .get_metric("leak_detection_accuracy")
275 .and_then(|m| match &m.value {
276 MetricValue::Gauge(value) => Some(*value),
277 _ => None,
278 })
279 .unwrap_or(0.0);
280
281 let analysis_rate = collector
282 .get_metric("pointers_analyzed_per_second")
283 .and_then(|m| match &m.value {
284 MetricValue::Rate(rate) => Some(rate.current_rate),
285 _ => None,
286 })
287 .unwrap_or(0.0);
288
289 PointerPerformance {
290 analysis_time,
291 leak_detection_accuracy,
292 analysis_rate,
293 }
294 }
295
296 fn analyze_memory_efficiency(&self, collector: &MetricsCollector) -> MemoryEfficiency {
297 let total_memory_mb = collector
298 .get_metric("total_analysis_memory")
299 .and_then(|m| match &m.value {
300 MetricValue::Gauge(value) => Some(*value),
301 _ => None,
302 })
303 .unwrap_or(0.0);
304
305 let memory_per_allocation = collector
306 .get_metric("memory_per_tracked_allocation")
307 .and_then(|m| match &m.value {
308 MetricValue::Gauge(value) => Some(*value),
309 _ => None,
310 })
311 .unwrap_or(0.0);
312
313 let growth_rate = collector
314 .get_metric("memory_growth_rate")
315 .and_then(|m| match &m.value {
316 MetricValue::Gauge(value) => Some(*value),
317 _ => None,
318 })
319 .unwrap_or(0.0);
320
321 let fragmentation_ratio = collector
322 .get_metric("memory_fragmentation")
323 .and_then(|m| match &m.value {
324 MetricValue::Gauge(value) => Some(*value),
325 _ => None,
326 })
327 .unwrap_or(0.0);
328
329 MemoryEfficiency {
330 total_memory_mb,
331 memory_per_allocation,
332 growth_rate,
333 fragmentation_ratio,
334 }
335 }
336
337 fn calculate_efficiency_score(
338 &self,
339 tracking: &TrackingPerformance,
340 symbol: &SymbolPerformance,
341 pointer: &PointerPerformance,
342 memory: &MemoryEfficiency,
343 ) -> f64 {
344 let tracking_score = self.score_tracking_performance(tracking);
345 let symbol_score = self.score_symbol_performance(symbol);
346 let pointer_score = self.score_pointer_performance(pointer);
347 let memory_score = self.score_memory_efficiency(memory);
348
349 tracking_score * 0.4 + symbol_score * 0.25 + pointer_score * 0.2 + memory_score * 0.15
351 }
352
353 fn score_tracking_performance(&self, tracking: &TrackingPerformance) -> f64 {
354 let mut score = 1.0;
355
356 if tracking.avg_allocation_time > self.thresholds.max_allocation_latency {
358 score *= 0.7;
359 }
360
361 if tracking.completeness < self.thresholds.min_tracking_completeness {
363 score *= tracking.completeness / self.thresholds.min_tracking_completeness;
364 }
365
366 if tracking.throughput > 10000.0 {
368 score *= 1.1;
369 }
370
371 score.clamp(0.0, 1.0)
372 }
373
374 fn score_symbol_performance(&self, symbol: &SymbolPerformance) -> f64 {
375 let mut score = 1.0;
376
377 if symbol.avg_resolution_time > self.thresholds.max_symbol_resolution_time {
379 score *= 0.8;
380 }
381
382 score *= symbol.cache_hit_ratio;
384
385 if symbol.cache_memory_usage > 100 * 1024 * 1024 {
387 score *= 0.9;
389 }
390
391 score.clamp(0.0, 1.0)
392 }
393
394 fn score_pointer_performance(&self, _pointer: &PointerPerformance) -> f64 {
395 let mut score: f64 = 1.0;
396
397 score *= _pointer.leak_detection_accuracy;
399
400 if _pointer.analysis_time > Duration::from_millis(100) {
402 score *= 0.8;
403 }
404
405 score.clamp(0.0, 1.0)
406 }
407
408 fn score_memory_efficiency(&self, memory: &MemoryEfficiency) -> f64 {
409 let mut score: f64 = 1.0;
410
411 if memory.total_memory_mb > self.thresholds.max_analysis_memory as f64 {
413 score *= 0.7;
414 }
415
416 if memory.fragmentation_ratio > 0.3 {
418 score *= 0.8;
419 }
420
421 if memory.growth_rate > 10.0 {
423 score *= 0.9;
425 }
426
427 score.clamp(0.0, 1.0)
428 }
429
430 fn generate_recommendations(
431 &self,
432 tracking: &TrackingPerformance,
433 symbol: &SymbolPerformance,
434 _pointer: &PointerPerformance,
435 memory: &MemoryEfficiency,
436 ) -> Vec<String> {
437 let mut recommendations = Vec::new();
438
439 if tracking.completeness < 0.95 {
441 recommendations
442 .push("Improve tracking completeness by reducing lock contention".to_string());
443 }
444 if tracking.avg_allocation_time > Duration::from_micros(100) {
445 recommendations.push("Optimize allocation tracking path for lower latency".to_string());
446 }
447
448 if symbol.cache_hit_ratio < 0.8 {
450 recommendations.push("Increase symbol cache size to improve hit ratio".to_string());
451 }
452 if symbol.avg_resolution_time > Duration::from_millis(10) {
453 recommendations.push("Consider preloading frequently used symbols".to_string());
454 }
455
456 if memory.total_memory_mb > 512.0 {
458 recommendations
459 .push("Consider reducing memory usage or implementing memory limits".to_string());
460 }
461 if memory.fragmentation_ratio > 0.2 {
462 recommendations.push("Implement memory compaction to reduce fragmentation".to_string());
463 }
464
465 recommendations
466 }
467}
468
469#[derive(Debug, Clone)]
471pub struct PerformanceComparison {
472 pub operation: String,
474 pub baseline: Benchmark,
476 pub current: Benchmark,
478 pub duration_ratio: f64,
480 pub memory_ratio: f64,
482 pub throughput_ratio: f64,
484 pub accuracy_diff: f64,
486}
487
488impl Default for AnalysisThresholds {
489 fn default() -> Self {
490 Self {
491 max_tracking_overhead: 0.05, max_allocation_latency: Duration::from_micros(50),
493 max_symbol_resolution_time: Duration::from_millis(5),
494 min_tracking_completeness: 0.95,
495 max_analysis_memory: 512, }
497 }
498}
499
500impl Default for PerformanceAnalyzer {
501 fn default() -> Self {
502 Self::new()
503 }
504}
505
506#[cfg(test)]
507mod tests {
508 use super::*;
509
510 #[test]
511 fn test_performance_analyzer_creation() {
512 let analyzer = PerformanceAnalyzer::new();
513 assert!(analyzer.baselines.is_empty());
514
515 let custom_thresholds = AnalysisThresholds {
516 max_tracking_overhead: 0.1,
517 ..Default::default()
518 };
519 let analyzer = PerformanceAnalyzer::with_thresholds(custom_thresholds);
520 assert_eq!(analyzer.thresholds.max_tracking_overhead, 0.1);
521 }
522
523 #[test]
524 fn test_benchmark_comparison() {
525 let mut analyzer = PerformanceAnalyzer::new();
526
527 let baseline = Benchmark {
528 operation: "allocation_tracking".to_string(),
529 avg_duration: Duration::from_micros(100),
530 memory_overhead: 1024,
531 throughput: 1000.0,
532 accuracy: 0.95,
533 sample_size: 10000,
534 };
535
536 analyzer.set_baseline("allocation_tracking", baseline.clone());
537
538 let current = Benchmark {
539 operation: "allocation_tracking".to_string(),
540 avg_duration: Duration::from_micros(120),
541 memory_overhead: 1200,
542 throughput: 900.0,
543 accuracy: 0.97,
544 sample_size: 10000,
545 };
546
547 let comparison = analyzer.compare_to_baseline("allocation_tracking", ¤t);
548 assert!(comparison.is_some());
549
550 let comparison = comparison.expect("Comparison should exist");
551 assert!(comparison.duration_ratio > 1.0); assert!(comparison.memory_ratio > 1.0); assert!(comparison.throughput_ratio < 1.0); assert!(comparison.accuracy_diff > 0.0); }
556
557 #[test]
558 fn test_efficiency_scoring() {
559 let analyzer = PerformanceAnalyzer::new();
560
561 let good_tracking = TrackingPerformance {
562 avg_allocation_time: Duration::from_micros(10),
563 completeness: 0.98,
564 overhead_bytes: 1024,
565 throughput: 50000.0,
566 };
567
568 let score = analyzer.score_tracking_performance(&good_tracking);
569 assert!(score > 0.9);
570
571 let bad_tracking = TrackingPerformance {
572 avg_allocation_time: Duration::from_millis(1),
573 completeness: 0.8,
574 overhead_bytes: 10240,
575 throughput: 100.0,
576 };
577
578 let score = analyzer.score_tracking_performance(&bad_tracking);
579 assert!(score < 0.7);
580 }
581}