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 get_borrow_history(&self) -> Vec<BorrowEvent> {
244 self.borrow_history
245 .safe_lock()
246 .map(|h| h.clone())
247 .unwrap_or_default()
248 }
249
250 pub fn analyze_borrow_patterns(&self) -> BorrowPatternAnalysis {
252 let history_data: Vec<_> = {
255 let history = match self.borrow_history.safe_lock() {
256 Ok(h) => h,
257 Err(_) => return BorrowPatternAnalysis::default(),
258 };
259 history.iter().cloned().collect()
260 };
261
262 let conflicts_data: Vec<_> = {
263 let conflicts = match self.conflicts.safe_lock() {
264 Ok(c) => c,
265 Err(_) => return BorrowPatternAnalysis::default(),
266 };
267 conflicts.iter().cloned().collect()
268 };
269
270 let mut patterns = Vec::new();
272
273 let long_lived_threshold = 1_000_000; let long_lived_count = history_data
276 .iter()
277 .filter(|event| {
278 if let Some(end_time) = event.borrow_info.end_time {
279 end_time - event.borrow_info.start_time > long_lived_threshold
280 } else {
281 false
282 }
283 })
284 .count();
285
286 if long_lived_count > 0 {
287 patterns.push(BorrowPattern {
288 pattern_type: BorrowPatternType::LongLivedBorrows,
289 description: format!("{long_lived_count} borrows lasted longer than 1ms"),
290 severity: if long_lived_count > 10 {
291 PatternSeverity::Warning
292 } else {
293 PatternSeverity::Info
294 },
295 suggestion: "Consider reducing borrow scope or using RAII patterns".to_string(),
296 });
297 }
298
299 if conflicts_data.len() > 5 {
301 patterns.push(BorrowPattern {
302 pattern_type: BorrowPatternType::FrequentConflicts,
303 description: format!("{} borrow conflicts detected", conflicts_data.len()),
304 severity: PatternSeverity::Warning,
305 suggestion: "Review borrow patterns and consider refactoring to reduce conflicts"
306 .to_string(),
307 });
308 }
309
310 let max_concurrent = self.calculate_max_concurrent_borrows();
312 if max_concurrent > 10 {
313 patterns.push(BorrowPattern {
314 pattern_type: BorrowPatternType::HighConcurrency,
315 description: format!("Up to {max_concurrent} concurrent borrows detected"),
316 severity: PatternSeverity::Info,
317 suggestion: "High concurrency detected - ensure this is intentional".to_string(),
318 });
319 }
320
321 BorrowPatternAnalysis {
322 patterns,
323 total_events: history_data.len(),
324 analysis_timestamp: current_timestamp(),
325 }
326 }
327
328 fn calculate_max_concurrent_borrows(&self) -> usize {
330 self.active_borrows
331 .safe_lock()
332 .map(|active| active.values().map(|v| v.len()).max().unwrap_or(0))
333 .unwrap_or(0)
334 }
335}
336
337#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
339pub struct BorrowId(u64);
340
341impl BorrowId {
342 fn new() -> Self {
343 use std::sync::atomic::{AtomicU64, Ordering};
344 static COUNTER: AtomicU64 = AtomicU64::new(1);
345 Self(COUNTER.fetch_add(1, Ordering::Relaxed))
346 }
347}
348
349#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
351pub enum BorrowType {
352 Immutable,
354 Mutable,
356 Shared,
358 Weak,
360}
361
362#[derive(Debug, Clone, Serialize, Deserialize)]
364pub struct BorrowInfo {
365 pub id: BorrowId,
367 pub ptr: usize,
369 pub borrow_type: BorrowType,
371 pub var_name: String,
373 pub start_time: u64,
375 pub end_time: Option<u64>,
377 pub thread_id: String,
379 pub call_stack: Vec<String>,
381}
382
383#[derive(Debug, Clone, Serialize, Deserialize)]
385pub struct BorrowEvent {
386 pub borrow_info: BorrowInfo,
388 pub event_type: BorrowEventType,
390 pub timestamp: u64,
392}
393
394#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
396pub enum BorrowEventType {
397 BorrowStart,
399 BorrowEnd,
401}
402
403#[derive(Debug, Clone, Serialize, Deserialize)]
405pub struct BorrowConflict {
406 pub ptr: usize,
408 pub existing_borrow: BorrowInfo,
410 pub conflicting_borrow: BorrowInfo,
412 pub conflict_type: ConflictType,
414 pub timestamp: u64,
416}
417
418#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
420pub enum ConflictType {
421 MultipleMutableBorrows,
423 MutableImmutableConflict,
425 Other,
427}
428
429#[derive(Debug, Clone, Default, Serialize, Deserialize)]
431pub struct BorrowStatistics {
432 pub total_borrows: usize,
434 pub active_borrows: usize,
436 pub total_conflicts: usize,
438 pub avg_borrow_duration: u64,
440 pub max_borrow_duration: u64,
442 pub by_type: HashMap<String, usize>,
444}
445
446#[derive(Debug, Clone, Default, Serialize, Deserialize)]
450pub struct BorrowPatternAnalysis {
451 pub patterns: Vec<BorrowPattern>,
453 pub total_events: usize,
455 pub analysis_timestamp: u64,
457}
458
459#[derive(Debug, Clone, Serialize, Deserialize)]
461pub struct BorrowPattern {
462 pub pattern_type: BorrowPatternType,
464 pub description: String,
466 pub severity: PatternSeverity,
468 pub suggestion: String,
470}
471
472#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
474pub enum BorrowPatternType {
475 LongLivedBorrows,
477 FrequentConflicts,
479 HighConcurrency,
481 NestedBorrows,
483}
484
485#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
487pub enum PatternSeverity {
488 Info,
490 Warning,
492 Error,
494}
495
496fn current_timestamp() -> u64 {
498 SystemTime::now()
499 .duration_since(UNIX_EPOCH)
500 .unwrap_or_default()
501 .as_nanos() as u64
502}
503
504fn capture_call_stack() -> Vec<String> {
506 #[cfg(feature = "backtrace")]
508 {
509 let bt = backtrace::Backtrace::new();
510 bt.frames()
511 .iter()
512 .skip(2) .filter_map(|frame| {
514 frame
515 .symbols()
516 .first()
517 .and_then(|sym| sym.name())
518 .map(|name| name.to_string())
519 })
520 .collect()
521 }
522
523 #[cfg(not(feature = "backtrace"))]
524 {
525 Vec::new()
527 }
528}
529
530#[cfg(test)]
531mod tests {
532 use super::*;
533
534 #[test]
535 fn test_borrow_tracking() {
536 let analyzer = BorrowAnalyzer::new();
537
538 let borrow_id = analyzer.track_borrow(0x1000, BorrowType::Immutable, "test_var");
540
541 let active = analyzer.get_active_borrows(0x1000);
543 assert_eq!(active.len(), 1);
544 assert_eq!(active[0].borrow_type, BorrowType::Immutable);
545
546 analyzer.end_borrow(borrow_id);
548
549 let active = analyzer.get_active_borrows(0x1000);
551 assert_eq!(active.len(), 0);
552 }
553
554 #[test]
555 fn test_borrow_conflicts() {
556 let analyzer = BorrowAnalyzer::new();
557
558 analyzer.track_borrow(0x1000, BorrowType::Mutable, "test_var1");
560
561 analyzer.track_borrow(0x1000, BorrowType::Mutable, "test_var2");
563
564 let conflicts = analyzer.get_conflicts();
566 assert!(!conflicts.is_empty());
567 assert_eq!(
568 conflicts[0].conflict_type,
569 ConflictType::MultipleMutableBorrows
570 );
571 }
572}