1use crate::core::safe_operations::SafeLock;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use std::sync::{Arc, Mutex, OnceLock};
12use std::time::{SystemTime, UNIX_EPOCH};
13
14static GLOBAL_BORROW_ANALYZER: OnceLock<Arc<BorrowAnalyzer>> = OnceLock::new();
16
17pub fn get_global_borrow_analyzer() -> Arc<BorrowAnalyzer> {
19 GLOBAL_BORROW_ANALYZER
20 .get_or_init(|| Arc::new(BorrowAnalyzer::new()))
21 .clone()
22}
23
24pub struct BorrowAnalyzer {
26 active_borrows: Mutex<HashMap<usize, Vec<BorrowInfo>>>,
28 borrow_history: Mutex<Vec<BorrowEvent>>,
30 conflicts: Mutex<Vec<BorrowConflict>>,
32}
33
34impl Default for BorrowAnalyzer {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl BorrowAnalyzer {
41 pub fn new() -> Self {
43 Self {
44 active_borrows: Mutex::new(HashMap::new()),
45 borrow_history: Mutex::new(Vec::new()),
46 conflicts: Mutex::new(Vec::new()),
47 }
48 }
49
50 pub fn track_borrow(&self, ptr: usize, borrow_type: BorrowType, var_name: &str) -> BorrowId {
52 let borrow_id = BorrowId::new();
53 let borrow_info = BorrowInfo {
54 id: borrow_id,
55 ptr,
56 borrow_type: borrow_type.clone(),
57 var_name: var_name.to_string(),
58 start_time: current_timestamp(),
59 end_time: None,
60 thread_id: format!("{:?}", std::thread::current().id()),
61 call_stack: capture_call_stack(),
62 };
63
64 self.check_borrow_conflicts(ptr, &borrow_type, &borrow_info);
66
67 if let Ok(mut active) = self.active_borrows.lock() {
69 active.entry(ptr).or_default().push(borrow_info.clone());
70 }
71
72 let event = BorrowEvent {
74 borrow_info: borrow_info.clone(),
75 event_type: BorrowEventType::BorrowStart,
76 timestamp: current_timestamp(),
77 };
78
79 if let Ok(mut history) = self.borrow_history.lock() {
80 history.push(event);
81 }
82
83 borrow_id
84 }
85
86 pub fn end_borrow(&self, borrow_id: BorrowId) {
88 let end_time = current_timestamp();
89
90 if let Ok(mut active) = self.active_borrows.lock() {
92 for (_, borrows) in active.iter_mut() {
93 if let Some(pos) = borrows.iter().position(|b| b.id == borrow_id) {
94 let mut borrow_info = borrows.remove(pos);
95 borrow_info.end_time = Some(end_time);
96
97 let event = BorrowEvent {
99 borrow_info: borrow_info.clone(),
100 event_type: BorrowEventType::BorrowEnd,
101 timestamp: end_time,
102 };
103
104 if let Ok(mut history) = self.borrow_history.lock() {
105 history.push(event);
106 }
107 break;
108 }
109 }
110 }
111 }
112
113 fn check_borrow_conflicts(
115 &self,
116 ptr: usize,
117 new_borrow_type: &BorrowType,
118 new_borrow: &BorrowInfo,
119 ) {
120 if let Ok(active) = self.active_borrows.lock() {
121 if let Some(existing_borrows) = active.get(&ptr) {
122 for existing in existing_borrows {
123 if self.is_conflicting_borrow(&existing.borrow_type, new_borrow_type) {
124 let conflict = BorrowConflict {
125 ptr,
126 existing_borrow: existing.clone(),
127 conflicting_borrow: new_borrow.clone(),
128 conflict_type: self
129 .determine_conflict_type(&existing.borrow_type, new_borrow_type),
130 timestamp: current_timestamp(),
131 };
132
133 if let Ok(mut conflicts) = self.conflicts.lock() {
134 conflicts.push(conflict);
135 }
136 }
137 }
138 }
139 }
140 }
141
142 fn is_conflicting_borrow(&self, existing: &BorrowType, new: &BorrowType) -> bool {
144 match (existing, new) {
145 (BorrowType::Mutable, _) | (_, BorrowType::Mutable) => true,
147 (BorrowType::Immutable, BorrowType::Immutable) => false,
149 (BorrowType::Shared, BorrowType::Immutable)
151 | (BorrowType::Immutable, BorrowType::Shared) => false,
152 _ => false,
154 }
155 }
156
157 fn determine_conflict_type(&self, existing: &BorrowType, new: &BorrowType) -> ConflictType {
159 match (existing, new) {
160 (BorrowType::Mutable, BorrowType::Mutable) => ConflictType::MultipleMutableBorrows,
161 (BorrowType::Mutable, BorrowType::Immutable)
162 | (BorrowType::Immutable, BorrowType::Mutable) => {
163 ConflictType::MutableImmutableConflict
164 }
165 _ => ConflictType::Other,
166 }
167 }
168
169 pub fn get_active_borrows(&self, ptr: usize) -> Vec<BorrowInfo> {
171 if let Ok(active) = self.active_borrows.lock() {
172 active.get(&ptr).cloned().unwrap_or_default()
173 } else {
174 Vec::new()
175 }
176 }
177
178 pub fn get_borrow_statistics(&self) -> BorrowStatistics {
180 let (total_borrows, durations, by_type) = {
182 let history = match self.borrow_history.safe_lock() {
183 Ok(h) => h,
184 Err(_) => return BorrowStatistics::default(),
185 };
186 let total = history.len();
187 let mut durations = Vec::new();
188 let mut by_type = HashMap::new();
189
190 for event in history.iter() {
191 if let Some(end_time) = event.borrow_info.end_time {
192 durations.push(end_time - event.borrow_info.start_time);
193 }
194 let type_name = format!("{:?}", event.borrow_info.borrow_type);
195 *by_type.entry(type_name).or_insert(0) += 1;
196 }
197 (total, durations, by_type)
198 };
199
200 let total_conflicts = {
201 let conflicts = match self.conflicts.safe_lock() {
202 Ok(c) => c,
203 Err(_) => return BorrowStatistics::default(),
204 };
205 conflicts.len()
206 };
207
208 let active_borrows: usize = {
209 let active = match self.active_borrows.safe_lock() {
210 Ok(a) => a,
211 Err(_) => return BorrowStatistics::default(),
212 };
213 active.values().map(|v| v.len()).sum()
214 };
215
216 let avg_borrow_duration = if !durations.is_empty() {
217 durations.iter().sum::<u64>() / durations.len() as u64
218 } else {
219 0
220 };
221
222 let max_borrow_duration = durations.iter().max().copied().unwrap_or(0);
223
224 BorrowStatistics {
225 total_borrows,
226 active_borrows,
227 total_conflicts,
228 avg_borrow_duration,
229 max_borrow_duration,
230 by_type,
231 }
232 }
233
234 pub fn get_conflicts(&self) -> Vec<BorrowConflict> {
236 self.conflicts
237 .safe_lock()
238 .map(|c| c.clone())
239 .unwrap_or_default()
240 }
241
242 pub fn analyze_borrow_patterns(&self) -> BorrowPatternAnalysis {
244 let history = match self.borrow_history.safe_lock() {
245 Ok(h) => h,
246 Err(_) => return BorrowPatternAnalysis::default(),
247 };
248 let conflicts = match self.conflicts.safe_lock() {
249 Ok(c) => c,
250 Err(_) => return BorrowPatternAnalysis::default(),
251 };
252
253 let mut patterns = Vec::new();
255
256 let long_lived_threshold = 1_000_000; let long_lived_count = history
259 .iter()
260 .filter(|event| {
261 if let Some(end_time) = event.borrow_info.end_time {
262 end_time - event.borrow_info.start_time > long_lived_threshold
263 } else {
264 false
265 }
266 })
267 .count();
268
269 if long_lived_count > 0 {
270 patterns.push(BorrowPattern {
271 pattern_type: BorrowPatternType::LongLivedBorrows,
272 description: format!("{long_lived_count} borrows lasted longer than 1ms"),
273 severity: if long_lived_count > 10 {
274 PatternSeverity::Warning
275 } else {
276 PatternSeverity::Info
277 },
278 suggestion: "Consider reducing borrow scope or using RAII patterns".to_string(),
279 });
280 }
281
282 if conflicts.len() > 5 {
284 patterns.push(BorrowPattern {
285 pattern_type: BorrowPatternType::FrequentConflicts,
286 description: format!("{} borrow conflicts detected", conflicts.len()),
287 severity: PatternSeverity::Warning,
288 suggestion: "Review borrow patterns and consider refactoring to reduce conflicts"
289 .to_string(),
290 });
291 }
292
293 let max_concurrent = self.calculate_max_concurrent_borrows();
295 if max_concurrent > 10 {
296 patterns.push(BorrowPattern {
297 pattern_type: BorrowPatternType::HighConcurrency,
298 description: format!("Up to {max_concurrent} concurrent borrows detected"),
299 severity: PatternSeverity::Info,
300 suggestion: "High concurrency detected - ensure this is intentional".to_string(),
301 });
302 }
303
304 BorrowPatternAnalysis {
305 patterns,
306 total_events: history.len(),
307 analysis_timestamp: current_timestamp(),
308 }
309 }
310
311 fn calculate_max_concurrent_borrows(&self) -> usize {
313 self.active_borrows
314 .safe_lock()
315 .map(|active| active.values().map(|v| v.len()).max().unwrap_or(0))
316 .unwrap_or(0)
317 }
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
322pub struct BorrowId(u64);
323
324impl BorrowId {
325 fn new() -> Self {
326 use std::sync::atomic::{AtomicU64, Ordering};
327 static COUNTER: AtomicU64 = AtomicU64::new(1);
328 Self(COUNTER.fetch_add(1, Ordering::Relaxed))
329 }
330}
331
332#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
334pub enum BorrowType {
335 Immutable,
337 Mutable,
339 Shared,
341 Weak,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct BorrowInfo {
348 pub id: BorrowId,
350 pub ptr: usize,
352 pub borrow_type: BorrowType,
354 pub var_name: String,
356 pub start_time: u64,
358 pub end_time: Option<u64>,
360 pub thread_id: String,
362 pub call_stack: Vec<String>,
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
368pub struct BorrowEvent {
369 pub borrow_info: BorrowInfo,
371 pub event_type: BorrowEventType,
373 pub timestamp: u64,
375}
376
377#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
379pub enum BorrowEventType {
380 BorrowStart,
382 BorrowEnd,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct BorrowConflict {
389 pub ptr: usize,
391 pub existing_borrow: BorrowInfo,
393 pub conflicting_borrow: BorrowInfo,
395 pub conflict_type: ConflictType,
397 pub timestamp: u64,
399}
400
401#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
403pub enum ConflictType {
404 MultipleMutableBorrows,
406 MutableImmutableConflict,
408 Other,
410}
411
412#[derive(Debug, Clone, Default, Serialize, Deserialize)]
414pub struct BorrowStatistics {
415 pub total_borrows: usize,
417 pub active_borrows: usize,
419 pub total_conflicts: usize,
421 pub avg_borrow_duration: u64,
423 pub max_borrow_duration: u64,
425 pub by_type: HashMap<String, usize>,
427}
428
429#[derive(Debug, Clone, Default, Serialize, Deserialize)]
433pub struct BorrowPatternAnalysis {
434 pub patterns: Vec<BorrowPattern>,
436 pub total_events: usize,
438 pub analysis_timestamp: u64,
440}
441
442#[derive(Debug, Clone, Serialize, Deserialize)]
444pub struct BorrowPattern {
445 pub pattern_type: BorrowPatternType,
447 pub description: String,
449 pub severity: PatternSeverity,
451 pub suggestion: String,
453}
454
455#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
457pub enum BorrowPatternType {
458 LongLivedBorrows,
460 FrequentConflicts,
462 HighConcurrency,
464 NestedBorrows,
466}
467
468#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
470pub enum PatternSeverity {
471 Info,
473 Warning,
475 Error,
477}
478
479fn current_timestamp() -> u64 {
481 SystemTime::now()
482 .duration_since(UNIX_EPOCH)
483 .unwrap_or_default()
484 .as_nanos() as u64
485}
486
487fn capture_call_stack() -> Vec<String> {
489 vec!["<call_stack_placeholder>".to_string()]
492}
493
494#[cfg(test)]
495mod tests {
496 use super::*;
497
498 #[test]
499 fn test_borrow_tracking() {
500 let analyzer = BorrowAnalyzer::new();
501
502 let borrow_id = analyzer.track_borrow(0x1000, BorrowType::Immutable, "test_var");
504
505 let active = analyzer.get_active_borrows(0x1000);
507 assert_eq!(active.len(), 1);
508 assert_eq!(active[0].borrow_type, BorrowType::Immutable);
509
510 analyzer.end_borrow(borrow_id);
512
513 let active = analyzer.get_active_borrows(0x1000);
515 assert_eq!(active.len(), 0);
516 }
517
518 #[test]
519 fn test_borrow_conflicts() {
520 let analyzer = BorrowAnalyzer::new();
521
522 analyzer.track_borrow(0x1000, BorrowType::Mutable, "test_var1");
524
525 analyzer.track_borrow(0x1000, BorrowType::Mutable, "test_var2");
527
528 let conflicts = analyzer.get_conflicts();
530 assert!(!conflicts.is_empty());
531 assert_eq!(
532 conflicts[0].conflict_type,
533 ConflictType::MultipleMutableBorrows
534 );
535 }
536}