1use std::collections::HashMap;
2use std::time::{Duration, Instant};
3
4pub struct PerformanceChecker {
6 benchmarks: HashMap<String, PerformanceBenchmark>,
7 thresholds: PerformanceThresholds,
8 config: CheckerConfig,
9}
10
11impl PerformanceChecker {
12 pub fn config(&self) -> &CheckerConfig {
13 &self.config
14 }
15}
16
17pub struct MemoryLeakChecker {
19 baseline_measurements: HashMap<String, MemoryBaseline>,
20 config: LeakDetectionConfig,
21 sensitivity: LeakSensitivity,
22}
23
24impl MemoryLeakChecker {
25 pub fn config(&self) -> &LeakDetectionConfig {
26 &self.config
27 }
28}
29
30pub struct SafetyChecker {
32 violation_patterns: Vec<SafetyPattern>,
33 safety_requirements: HashMap<String, SafetyRequirement>,
34 config: SafetyConfig,
35}
36
37impl SafetyChecker {
38 pub fn violation_patterns(&self) -> &[SafetyPattern] {
39 &self.violation_patterns
40 }
41 pub fn safety_requirements(&self) -> &HashMap<String, SafetyRequirement> {
42 &self.safety_requirements
43 }
44 pub fn config(&self) -> &SafetyConfig {
45 &self.config
46 }
47}
48
49#[derive(Debug, Clone)]
51pub struct PerformanceBenchmark {
52 pub operation: String,
54 pub expected_duration: Duration,
56 pub max_duration: Duration,
58 pub expected_memory: usize,
60 pub max_memory: usize,
62 pub expected_throughput: f64,
64 pub min_throughput: f64,
66}
67
68#[derive(Debug, Clone)]
70pub struct PerformanceThresholds {
71 pub allocation_latency: Duration,
73 pub symbol_resolution: Duration,
75 pub stack_trace_capture: Duration,
77 pub memory_overhead_pct: f64,
79 pub min_completeness: f64,
81}
82
83#[derive(Debug, Clone)]
85pub struct MemoryBaseline {
86 pub initial_memory: usize,
88 pub growth_pattern: GrowthPattern,
90 pub timestamp: Instant,
92 pub allocation_count: usize,
94}
95
96#[derive(Debug, Clone, PartialEq)]
98pub enum GrowthPattern {
99 Constant,
101 Linear { bytes_per_allocation: f64 },
103 Logarithmic,
105 Stabilizing { max_growth: usize },
107 Custom { description: String },
109}
110
111#[derive(Debug, Clone, PartialEq)]
113pub enum LeakSensitivity {
114 Low,
116 Medium,
118 High,
120 Paranoid,
122}
123
124#[derive(Debug, Clone)]
126pub struct SafetyPattern {
127 pub id: String,
129 pub description: String,
131 pub detector: SafetyDetector,
133 pub severity: SafetySeverity,
135}
136
137pub type SafetyDetector = fn(&SafetyContext) -> Vec<SafetyViolation>;
139
140#[derive(Debug, Clone)]
142pub struct SafetyRequirement {
143 pub properties: Vec<SafetyProperty>,
145 pub thread_safe: bool,
147 pub error_handling: bool,
149 pub max_risk_level: RiskLevel,
151}
152
153#[derive(Debug, Clone, PartialEq)]
155pub enum SafetyProperty {
156 NoMemoryLeaks,
158 NoDataRaces,
160 NoUseAfterFree,
162 NoBufferOverflow,
164 ErrorPropagation,
166 ResourceCleanup,
168}
169
170#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
172pub enum SafetySeverity {
173 Low,
175 Medium,
177 High,
179 Critical,
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
185pub enum RiskLevel {
186 Minimal,
188 Low,
190 Medium,
192 High,
194 Critical,
196}
197
198#[derive(Debug)]
200pub struct SafetyContext {
201 pub operation: String,
203 pub memory_accesses: Vec<MemoryAccess>,
205 pub thread_interactions: Vec<ThreadInteraction>,
207 pub error_handling: bool,
209 pub resource_usage: ResourceUsage,
211}
212
213#[derive(Debug, Clone)]
215pub struct MemoryAccess {
216 pub access_type: AccessType,
218 pub address: Option<usize>,
220 pub size: usize,
222 pub synchronized: bool,
224}
225
226#[derive(Debug, Clone, PartialEq)]
228pub enum AccessType {
229 Read,
231 Write,
233 Allocate,
235 Deallocate,
237}
238
239#[derive(Debug, Clone)]
241pub struct ThreadInteraction {
242 pub interaction_type: InteractionType,
244 pub resource_id: String,
246 pub synchronization: Option<SyncMechanism>,
248}
249
250#[derive(Debug, Clone, PartialEq)]
252pub enum InteractionType {
253 SharedRead,
255 ExclusiveWrite,
257 MessagePassing,
259 LockAcquisition,
261}
262
263#[derive(Debug, Clone, PartialEq)]
265pub enum SyncMechanism {
266 Mutex,
268 RwLock,
270 Atomic,
272 LockFree,
274 None,
276}
277
278#[derive(Debug, Clone)]
280pub struct ResourceUsage {
281 pub memory_bytes: usize,
283 pub file_descriptors: usize,
285 pub network_connections: usize,
287 pub cpu_time: Duration,
289}
290
291#[derive(Debug, Clone)]
293pub struct SafetyViolation {
294 pub violation_type: String,
296 pub severity: SafetySeverity,
298 pub description: String,
300 pub suggestion: String,
302 pub location: Option<String>,
304}
305
306#[derive(Debug, Clone)]
308pub struct CheckerConfig {
309 pub deep_analysis: bool,
311 pub max_check_time: Duration,
313 pub realtime_checking: bool,
315 pub sample_rate: f64,
317}
318
319#[derive(Debug, Clone)]
321pub struct LeakDetectionConfig {
322 pub measurement_interval: Duration,
324 pub measurement_history: usize,
326 pub growth_threshold: f64,
328 pub track_allocations: bool,
330}
331
332#[derive(Debug, Clone)]
334pub struct SafetyConfig {
335 pub enabled_patterns: Vec<String>,
337 pub min_severity: SafetySeverity,
339 pub check_thread_safety: bool,
341 pub check_memory_safety: bool,
343}
344
345impl PerformanceChecker {
346 pub fn new() -> Self {
348 Self {
349 benchmarks: HashMap::new(),
350 thresholds: PerformanceThresholds::default(),
351 config: CheckerConfig::default(),
352 }
353 }
354
355 pub fn add_benchmark(&mut self, benchmark: PerformanceBenchmark) {
357 self.benchmarks
358 .insert(benchmark.operation.clone(), benchmark);
359 }
360
361 pub fn check_performance(
363 &self,
364 operation: &str,
365 actual: &PerformanceMetrics,
366 ) -> PerformanceCheckResult {
367 let mut violations = Vec::new();
368
369 if let Some(benchmark) = self.benchmarks.get(operation) {
371 violations.extend(self.check_against_benchmark(benchmark, actual));
372 }
373
374 violations.extend(self.check_against_thresholds(operation, actual));
376
377 let status = if violations
378 .iter()
379 .any(|v| v.severity == PerformanceIssueType::Critical)
380 {
381 PerformanceStatus::Critical
382 } else if violations
383 .iter()
384 .any(|v| v.severity == PerformanceIssueType::Major)
385 {
386 PerformanceStatus::Poor
387 } else if violations
388 .iter()
389 .any(|v| v.severity == PerformanceIssueType::Minor)
390 {
391 PerformanceStatus::Acceptable
392 } else {
393 PerformanceStatus::Optimal
394 };
395
396 let overall_score = self.calculate_performance_score(&violations);
397
398 PerformanceCheckResult {
399 operation: operation.to_string(),
400 status,
401 violations,
402 overall_score,
403 }
404 }
405
406 fn check_against_benchmark(
407 &self,
408 benchmark: &PerformanceBenchmark,
409 actual: &PerformanceMetrics,
410 ) -> Vec<PerformanceViolation> {
411 let mut violations = Vec::new();
412
413 if actual.duration > benchmark.max_duration {
415 violations.push(PerformanceViolation {
416 metric: "duration".to_string(),
417 expected: benchmark.expected_duration.as_micros() as f64,
418 actual: actual.duration.as_micros() as f64,
419 severity: PerformanceIssueType::Major,
420 description: format!(
421 "Duration {:.2}ms exceeds maximum {:.2}ms",
422 actual.duration.as_millis(),
423 benchmark.max_duration.as_millis()
424 ),
425 });
426 }
427
428 if actual.memory_usage > benchmark.max_memory {
430 violations.push(PerformanceViolation {
431 metric: "memory".to_string(),
432 expected: benchmark.expected_memory as f64,
433 actual: actual.memory_usage as f64,
434 severity: PerformanceIssueType::Major,
435 description: format!(
436 "Memory usage {:.2}MB exceeds maximum {:.2}MB",
437 actual.memory_usage as f64 / (1024.0 * 1024.0),
438 benchmark.max_memory as f64 / (1024.0 * 1024.0)
439 ),
440 });
441 }
442
443 if actual.throughput < benchmark.min_throughput {
445 violations.push(PerformanceViolation {
446 metric: "throughput".to_string(),
447 expected: benchmark.expected_throughput,
448 actual: actual.throughput,
449 severity: PerformanceIssueType::Minor,
450 description: format!(
451 "Throughput {:.0}/sec below minimum {:.0}/sec",
452 actual.throughput, benchmark.min_throughput
453 ),
454 });
455 }
456
457 violations
458 }
459
460 fn check_against_thresholds(
461 &self,
462 operation: &str,
463 actual: &PerformanceMetrics,
464 ) -> Vec<PerformanceViolation> {
465 let mut violations = Vec::new();
466
467 if operation.contains("allocation") && actual.duration > self.thresholds.allocation_latency
469 {
470 violations.push(PerformanceViolation {
471 metric: "allocation_latency".to_string(),
472 expected: self.thresholds.allocation_latency.as_micros() as f64,
473 actual: actual.duration.as_micros() as f64,
474 severity: PerformanceIssueType::Critical,
475 description: "Allocation tracking latency exceeds threshold".to_string(),
476 });
477 }
478
479 if operation.contains("symbol") && actual.duration > self.thresholds.symbol_resolution {
481 violations.push(PerformanceViolation {
482 metric: "symbol_resolution".to_string(),
483 expected: self.thresholds.symbol_resolution.as_millis() as f64,
484 actual: actual.duration.as_millis() as f64,
485 severity: PerformanceIssueType::Major,
486 description: "Symbol resolution time exceeds threshold".to_string(),
487 });
488 }
489
490 violations
491 }
492
493 fn calculate_performance_score(&self, violations: &[PerformanceViolation]) -> f64 {
494 if violations.is_empty() {
495 return 1.0;
496 }
497
498 let penalty: f64 = violations
499 .iter()
500 .map(|v| match v.severity {
501 PerformanceIssueType::Critical => 0.5,
502 PerformanceIssueType::Major => 0.3,
503 PerformanceIssueType::Minor => 0.1,
504 })
505 .sum();
506
507 (1.0 - penalty).max(0.0)
508 }
509}
510
511impl MemoryLeakChecker {
512 pub fn new() -> Self {
514 Self {
515 baseline_measurements: HashMap::new(),
516 config: LeakDetectionConfig::default(),
517 sensitivity: LeakSensitivity::Medium,
518 }
519 }
520
521 pub fn set_baseline(&mut self, operation: &str, memory: usize, allocations: usize) {
523 let baseline = MemoryBaseline {
524 initial_memory: memory,
525 growth_pattern: GrowthPattern::Constant,
526 timestamp: Instant::now(),
527 allocation_count: allocations,
528 };
529 self.baseline_measurements
530 .insert(operation.to_string(), baseline);
531 }
532
533 pub fn check_for_leaks(&self, operation: &str, current: &MemorySnapshot) -> LeakCheckResult {
535 if let Some(baseline) = self.baseline_measurements.get(operation) {
536 let growth_rate = self.calculate_growth_rate(baseline, current);
537 let leak_indicators = self.detect_leak_indicators(baseline, current, growth_rate);
538
539 let severity = self.assess_leak_severity(&leak_indicators);
540 let confidence = self.calculate_confidence(&leak_indicators);
541
542 LeakCheckResult {
543 operation: operation.to_string(),
544 leak_detected: !leak_indicators.is_empty(),
545 severity,
546 confidence,
547 indicators: leak_indicators,
548 growth_rate,
549 }
550 } else {
551 LeakCheckResult {
552 operation: operation.to_string(),
553 leak_detected: false,
554 severity: LeakSeverity::None,
555 confidence: 0.0,
556 indicators: Vec::new(),
557 growth_rate: 0.0,
558 }
559 }
560 }
561
562 fn calculate_growth_rate(&self, baseline: &MemoryBaseline, current: &MemorySnapshot) -> f64 {
563 let time_elapsed = baseline.timestamp.elapsed().as_secs_f64();
564 if time_elapsed > 0.0 {
565 (current.memory_usage as f64 - baseline.initial_memory as f64) / time_elapsed
566 } else {
567 0.0
568 }
569 }
570
571 fn detect_leak_indicators(
572 &self,
573 baseline: &MemoryBaseline,
574 current: &MemorySnapshot,
575 growth_rate: f64,
576 ) -> Vec<LeakIndicator> {
577 let mut indicators = Vec::new();
578
579 if growth_rate > self.config.growth_threshold {
581 indicators.push(LeakIndicator {
582 indicator_type: "excessive_growth".to_string(),
583 description: format!(
584 "Memory growing at {:.2}MB/sec",
585 growth_rate / (1024.0 * 1024.0)
586 ),
587 severity: LeakSeverity::High,
588 });
589 }
590
591 let alloc_growth = current.allocation_count as f64 - baseline.allocation_count as f64;
593 let memory_growth = current.memory_usage as f64 - baseline.initial_memory as f64;
594
595 if alloc_growth > 0.0 && memory_growth / alloc_growth > 1024.0 {
596 indicators.push(LeakIndicator {
598 indicator_type: "allocation_imbalance".to_string(),
599 description: "High memory per allocation ratio".to_string(),
600 severity: LeakSeverity::Medium,
601 });
602 }
603
604 indicators
605 }
606
607 fn assess_leak_severity(&self, indicators: &[LeakIndicator]) -> LeakSeverity {
608 indicators
609 .iter()
610 .map(|i| &i.severity)
611 .max()
612 .cloned()
613 .unwrap_or(LeakSeverity::None)
614 }
615
616 fn calculate_confidence(&self, indicators: &[LeakIndicator]) -> f64 {
617 if indicators.is_empty() {
618 0.0
619 } else {
620 match self.sensitivity {
621 LeakSensitivity::Low => 0.5,
622 LeakSensitivity::Medium => 0.7,
623 LeakSensitivity::High => 0.85,
624 LeakSensitivity::Paranoid => 0.95,
625 }
626 }
627 }
628}
629
630#[derive(Debug, Clone)]
632pub struct PerformanceMetrics {
633 pub duration: Duration,
634 pub memory_usage: usize,
635 pub throughput: f64,
636 pub cpu_usage: f64,
637}
638
639#[derive(Debug, Clone)]
640pub struct PerformanceCheckResult {
641 pub operation: String,
642 pub status: PerformanceStatus,
643 pub violations: Vec<PerformanceViolation>,
644 pub overall_score: f64,
645}
646
647#[derive(Debug, Clone, PartialEq)]
648pub enum PerformanceStatus {
649 Optimal,
650 Acceptable,
651 Poor,
652 Critical,
653}
654
655#[derive(Debug, Clone)]
656pub struct PerformanceViolation {
657 pub metric: String,
658 pub expected: f64,
659 pub actual: f64,
660 pub severity: PerformanceIssueType,
661 pub description: String,
662}
663
664#[derive(Debug, Clone, PartialEq)]
665pub enum PerformanceIssueType {
666 Minor,
667 Major,
668 Critical,
669}
670
671#[derive(Debug, Clone)]
672pub struct MemorySnapshot {
673 pub memory_usage: usize,
674 pub allocation_count: usize,
675 pub timestamp: Instant,
676}
677
678#[derive(Debug, Clone)]
679pub struct LeakCheckResult {
680 pub operation: String,
681 pub leak_detected: bool,
682 pub severity: LeakSeverity,
683 pub confidence: f64,
684 pub indicators: Vec<LeakIndicator>,
685 pub growth_rate: f64,
686}
687
688#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
689pub enum LeakSeverity {
690 None,
691 Low,
692 Medium,
693 High,
694 Critical,
695}
696
697#[derive(Debug, Clone)]
698pub struct LeakIndicator {
699 pub indicator_type: String,
700 pub description: String,
701 pub severity: LeakSeverity,
702}
703
704impl Default for PerformanceThresholds {
706 fn default() -> Self {
707 Self {
708 allocation_latency: Duration::from_micros(50),
709 symbol_resolution: Duration::from_millis(5),
710 stack_trace_capture: Duration::from_millis(10),
711 memory_overhead_pct: 5.0,
712 min_completeness: 0.95,
713 }
714 }
715}
716
717impl Default for CheckerConfig {
718 fn default() -> Self {
719 Self {
720 deep_analysis: true,
721 max_check_time: Duration::from_secs(5),
722 realtime_checking: false,
723 sample_rate: 0.1,
724 }
725 }
726}
727
728impl Default for LeakDetectionConfig {
729 fn default() -> Self {
730 Self {
731 measurement_interval: Duration::from_secs(60),
732 measurement_history: 100,
733 growth_threshold: 1024.0 * 1024.0, track_allocations: true,
735 }
736 }
737}
738
739impl Default for SafetyConfig {
740 fn default() -> Self {
741 Self {
742 enabled_patterns: vec![
743 "memory_safety".to_string(),
744 "thread_safety".to_string(),
745 "error_handling".to_string(),
746 ],
747 min_severity: SafetySeverity::Low,
748 check_thread_safety: true,
749 check_memory_safety: true,
750 }
751 }
752}
753
754impl Default for PerformanceChecker {
755 fn default() -> Self {
756 Self::new()
757 }
758}
759
760impl Default for MemoryLeakChecker {
761 fn default() -> Self {
762 Self::new()
763 }
764}
765
766#[cfg(test)]
767mod tests {
768 use super::*;
769
770 #[test]
771 fn test_performance_checker() {
772 let mut checker = PerformanceChecker::new();
773
774 let benchmark = PerformanceBenchmark {
775 operation: "allocation_tracking".to_string(),
776 expected_duration: Duration::from_micros(10),
777 max_duration: Duration::from_micros(50),
778 expected_memory: 1024,
779 max_memory: 2048,
780 expected_throughput: 10000.0,
781 min_throughput: 5000.0,
782 };
783
784 checker.add_benchmark(benchmark);
785
786 let good_metrics = PerformanceMetrics {
787 duration: Duration::from_micros(20),
788 memory_usage: 1500,
789 throughput: 8000.0,
790 cpu_usage: 5.0,
791 };
792
793 let result = checker.check_performance("allocation_tracking", &good_metrics);
794 assert!(matches!(
795 result.status,
796 PerformanceStatus::Optimal | PerformanceStatus::Acceptable
797 ));
798
799 let bad_metrics = PerformanceMetrics {
800 duration: Duration::from_micros(100),
801 memory_usage: 3000,
802 throughput: 1000.0,
803 cpu_usage: 50.0,
804 };
805
806 let result = checker.check_performance("allocation_tracking", &bad_metrics);
807 assert!(matches!(
808 result.status,
809 PerformanceStatus::Poor | PerformanceStatus::Critical
810 ));
811 assert!(!result.violations.is_empty());
812 }
813
814 #[test]
815 fn test_memory_leak_checker() {
816 let mut checker = MemoryLeakChecker::new();
817
818 checker.set_baseline("test_operation", 1024 * 1024, 100);
819
820 let current = MemorySnapshot {
821 memory_usage: 1200 * 1024, allocation_count: 120,
823 timestamp: Instant::now(),
824 };
825
826 let result = checker.check_for_leaks("test_operation", ¤t);
827 let _ = result; }
830
831 #[test]
832 fn test_growth_patterns() {
833 assert_eq!(GrowthPattern::Constant, GrowthPattern::Constant);
834
835 let linear = GrowthPattern::Linear {
836 bytes_per_allocation: 64.0,
837 };
838 assert!(matches!(linear, GrowthPattern::Linear { .. }));
839 }
840}