1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, thiserror::Error)]
7pub enum TrackingError {
8 #[error("Failed to acquire lock: {0}")]
10 LockError(String),
11
12 #[error("Invalid pointer association: {ptr:?}")]
14 InvalidPointer {
15 ptr: usize,
17 },
18
19 #[error("Allocation tracking disabled")]
21 TrackingDisabled,
22
23 #[error("Memory corruption detected")]
25 MemoryCorruption,
26
27 #[error("Serialization error: {0}")]
29 SerializationError(String),
30
31 #[error("IO error: {0}")]
33 IoError(#[from] std::io::Error),
34}
35
36pub type TrackingResult<T> = Result<T, TrackingError>;
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct AllocationInfo {
42 pub ptr: usize,
44 pub size: usize,
46 pub timestamp_alloc: u128,
48 pub timestamp_dealloc: Option<u128>,
50 pub var_name: Option<String>,
52 pub type_name: Option<String>,
54 pub thread_id: String,
56 #[cfg(feature = "backtrace")]
58 pub backtrace: Option<Vec<String>>,
59
60 pub peak_size: Option<usize>,
63 pub growth_events: usize,
65 pub scope_name: Option<String>,
67 pub ownership_pattern: Option<OwnershipPattern>,
69 pub risk_level: Option<RiskLevel>,
71 pub efficiency_score: Option<f64>,
73 pub borrow_count: usize,
75 pub mut_borrow_count: usize,
77 pub transfer_count: usize,
79 pub metadata_tags: Vec<String>,
81}
82
83impl AllocationInfo {
84 pub fn new(ptr: usize, size: usize) -> Self {
86 let timestamp = std::time::SystemTime::now()
87 .duration_since(std::time::UNIX_EPOCH)
88 .unwrap_or_default()
89 .as_millis();
90
91 let thread_id = format!("{:?}", std::thread::current().id());
92
93 Self {
94 ptr,
95 size,
96 timestamp_alloc: timestamp,
97 timestamp_dealloc: None,
98 var_name: None,
99 type_name: None,
100 thread_id,
101 #[cfg(feature = "backtrace")]
102 backtrace: None,
103
104 peak_size: Some(size), growth_events: 0,
107 scope_name: None,
108 ownership_pattern: None,
109 risk_level: None,
110 efficiency_score: Some(1.0), borrow_count: 0,
112 mut_borrow_count: 0,
113 transfer_count: 0,
114 metadata_tags: Vec::new(),
115 }
116 }
117
118 pub fn mark_deallocated(&mut self) {
120 let timestamp = std::time::SystemTime::now()
121 .duration_since(std::time::UNIX_EPOCH)
122 .unwrap_or_default()
123 .as_millis();
124
125 self.timestamp_dealloc = Some(timestamp);
126 }
127
128 pub fn is_active(&self) -> bool {
130 self.timestamp_dealloc.is_none()
131 }
132
133 pub fn lifetime_ms(&self) -> Option<u128> {
135 self.timestamp_dealloc
136 .map(|dealloc| dealloc - self.timestamp_alloc)
137 }
138
139 pub fn record_growth(&mut self, new_size: usize) {
141 self.growth_events += 1;
142 if let Some(peak) = self.peak_size {
143 self.peak_size = Some(peak.max(new_size));
144 } else {
145 self.peak_size = Some(new_size);
146 }
147
148 if let Some(peak) = self.peak_size {
150 self.efficiency_score = Some(self.size as f64 / peak as f64);
151 }
152 }
153
154 pub fn record_borrow(&mut self, is_mutable: bool) {
156 if is_mutable {
157 self.mut_borrow_count += 1;
158 } else {
159 self.borrow_count += 1;
160 }
161 }
162
163 pub fn record_transfer(&mut self) {
165 self.transfer_count += 1;
166 }
167
168 pub fn add_metadata_tag(&mut self, tag: String) {
170 if !self.metadata_tags.contains(&tag) {
171 self.metadata_tags.push(tag);
172 }
173 }
174
175 pub fn memory_growth_factor(&self) -> f64 {
177 if let Some(peak) = self.peak_size {
178 peak as f64 / self.size.max(1) as f64
179 } else {
180 1.0
181 }
182 }
183
184 pub fn classify_risk(&mut self) {
186 let growth_factor = self.memory_growth_factor();
187 let lifetime = self.lifetime_ms().unwrap_or(0) as f64;
188
189 self.risk_level = Some(if self.size > 1024 * 1024 || growth_factor > 3.0 {
190 RiskLevel::Critical
191 } else if self.size > 1024 || growth_factor > 2.0 || lifetime > 10000.0 {
192 RiskLevel::High
193 } else if self.size > 256 || growth_factor > 1.5 || lifetime > 1000.0 {
194 RiskLevel::Medium
195 } else {
196 RiskLevel::Low
197 });
198 }
199
200 pub fn determine_ownership_pattern(&mut self) {
202 if let Some(type_name) = &self.type_name {
203 self.ownership_pattern =
204 Some(if type_name.contains("Rc") || type_name.contains("Arc") {
205 OwnershipPattern::Shared
206 } else if type_name.starts_with('&') {
207 OwnershipPattern::Borrowed
208 } else if self.transfer_count > 0 && self.borrow_count > 0 {
209 OwnershipPattern::Mixed
210 } else {
211 OwnershipPattern::Owned
212 });
213 }
214 }
215}
216
217#[derive(Debug, Clone, Serialize, Deserialize, Default)]
219pub struct MemoryStats {
220 pub total_allocations: usize,
222 pub total_deallocations: usize,
224 pub total_allocated: usize,
226 pub total_deallocated: usize,
228 pub active_allocations: usize,
230 pub active_memory: usize,
232 pub peak_allocations: usize,
234 pub peak_memory: usize,
236 pub lifecycle_stats: LifecycleStats,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct TypeMemoryUsage {
243 pub type_name: String,
245 pub total_size: usize,
247 pub allocation_count: usize,
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize)]
253pub struct HotspotInfo {
254 pub location: String,
256 pub count: usize,
258 pub total_size: usize,
260 pub average_size: f64,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize, Default)]
266pub struct LifecycleStats {
267 pub completed_allocations: usize,
269 pub average_lifetime_ms: f64,
271 pub median_lifetime_ms: f64,
273 pub lifetime_percentiles: LifecyclePercentiles,
275 pub min_lifetime_ms: u128,
277 pub max_lifetime_ms: u128,
279 pub instant_allocations: usize,
281 pub short_term_allocations: usize,
283 pub medium_term_allocations: usize,
285 pub long_term_allocations: usize,
287 pub suspected_leaks: usize,
289
290 pub memory_growth_events: usize,
293 pub peak_concurrent_variables: usize,
295 pub memory_efficiency_ratio: f64,
297 pub ownership_transfer_events: usize,
299 pub borrowing_violations: usize,
301 pub fragmentation_score: f64,
303 pub risk_distribution: RiskDistribution,
305 pub scope_metrics: Vec<ScopeLifecycleMetrics>,
307 pub type_lifecycle_patterns: Vec<TypeLifecyclePattern>,
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize, Default)]
313pub struct LifecyclePercentiles {
314 pub p50: f64,
316 pub p90: f64,
318 pub p95: f64,
320 pub p99: f64,
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize)]
326pub struct TypeLifecycleStats {
327 pub type_name: String,
329 pub average_lifetime_ms: f64,
331 pub allocation_count: usize,
333 pub category: LifecycleCategory,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize)]
339pub enum LifecycleCategory {
340 Instant,
342 ShortTerm,
344 MediumTerm,
346 LongTerm,
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize, Default)]
352pub struct RiskDistribution {
353 pub high_memory_risk: usize,
355 pub potential_growth_risk: usize,
357 pub short_lifecycle_risk: usize,
359 pub low_risk: usize,
361 pub leak_risk: usize,
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct ScopeLifecycleMetrics {
368 pub scope_name: String,
370 pub variable_count: usize,
372 pub avg_lifetime_ms: f64,
374 pub total_memory_bytes: usize,
376 pub peak_concurrent_vars: usize,
378 pub efficiency_score: f64,
380}
381
382#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct TypeLifecyclePattern {
385 pub type_name: String,
387 pub avg_allocations_per_var: f64,
389 pub memory_growth_factor: f64,
391 pub typical_lifetime_range: (u64, u64), pub ownership_pattern: OwnershipPattern,
395 pub risk_level: RiskLevel,
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize)]
401pub enum OwnershipPattern {
402 Owned,
404 Shared,
406 Borrowed,
408 Mixed,
410}
411
412#[derive(Debug, Clone, Serialize, Deserialize)]
414pub enum RiskLevel {
415 Low,
417 Medium,
419 High,
421 Critical,
423}