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