rustorch 0.6.29

Production-ready PyTorch-compatible deep learning library in Rust with special mathematical functions (gamma, Bessel, error functions), statistical distributions, Fourier transforms (FFT/RFFT), matrix decomposition (SVD/QR/LU/eigenvalue), automatic differentiation, neural networks, computer vision transforms, complete GPU acceleration (CUDA/Metal/OpenCL), SIMD optimizations, parallel processing, WebAssembly browser support, comprehensive distributed learning support, and performance validation
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
//! Memory Analytics and Profiling System
//! メモリ分析・プロファイリングシステム
//!
//! Features:
//! - Detailed memory usage tracking
//! - Memory leak detection
//! - Allocation pattern analysis
//! - Memory hotspot identification
//! - Performance impact analysis

use crate::error::{RusTorchError, RusTorchResult};
use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
use std::time::{Duration, Instant, SystemTime};

/// Memory allocation record
/// メモリ割り当て記録
#[derive(Debug, Clone)]
pub struct AllocationRecord {
    /// Allocation ID (unique)
    /// 割り当てID(ユニーク)
    pub id: u64,
    /// Size in bytes
    /// サイズ(バイト)
    pub size: usize,
    /// Timestamp when allocated
    /// 割り当て時のタイムスタンプ
    pub allocated_at: SystemTime,
    /// Source location (file:line)
    /// ソース位置(ファイル:行)
    pub source_location: String,
    /// Call stack (simplified)
    /// コールスタック(簡略化)
    pub call_stack: Vec<String>,
    /// Deallocation timestamp (None if still allocated)
    /// 解放タイムスタンプ(まだ割り当てられている場合はNone)
    pub deallocated_at: Option<SystemTime>,
    /// Lifetime (duration from allocation to deallocation)
    /// ライフタイム(割り当てから解放まての期間)
    pub lifetime: Option<Duration>,
    /// Memory pattern classification
    /// メモリパターン分類
    pub pattern: AllocationPattern,
}

/// Memory allocation patterns
/// メモリ割り当てパターン
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum AllocationPattern {
    /// Short-lived allocations (< 1 second)
    /// 短期割り当て(< 1秒)
    ShortLived,
    /// Medium-lived allocations (1 second - 1 minute)
    /// 中期割り当て(1秒 - 1分)
    MediumLived,
    /// Long-lived allocations (> 1 minute)
    /// 長期割り当て(> 1分)
    LongLived,
    /// Leaked allocations (never deallocated)
    /// リークした割り当て(解放されない)
    Leaked,
    /// Cyclic allocations (repetitive pattern)
    /// 循環割り当て(反復パターン)
    Cyclic,
}

impl AllocationPattern {
    /// Classify allocation pattern based on lifetime
    /// ライフタイムに基づいて割り当てパターンを分類
    pub fn classify(lifetime: Option<Duration>, allocated_at: SystemTime) -> Self {
        match lifetime {
            Some(duration) => {
                if duration < Duration::from_secs(1) {
                    AllocationPattern::ShortLived
                } else if duration < Duration::from_secs(60) {
                    AllocationPattern::MediumLived
                } else {
                    AllocationPattern::LongLived
                }
            }
            None => {
                // Check if allocation is old enough to be considered leaked
                let age = SystemTime::now()
                    .duration_since(allocated_at)
                    .unwrap_or(Duration::from_secs(0));

                if age > Duration::from_secs(300) {
                    // 5 minutes
                    AllocationPattern::Leaked
                } else {
                    AllocationPattern::MediumLived
                }
            }
        }
    }
}

/// Memory hotspot information
/// メモリホットスポット情報
#[derive(Debug, Clone)]
pub struct MemoryHotspot {
    /// Source location
    /// ソース位置
    pub location: String,
    /// Total allocations at this location
    /// この位置での総割り当て数
    pub total_allocations: usize,
    /// Total memory allocated (bytes)
    /// 総割り当てメモリ(バイト)
    pub total_memory: usize,
    /// Average allocation size
    /// 平均割り当てサイズ
    pub avg_size: f64,
    /// Peak concurrent allocations
    /// ピーク同時割り当て数
    pub peak_concurrent: usize,
    /// Memory leak count
    /// メモリリーク数
    pub leak_count: usize,
    /// Allocation frequency (allocations per second)
    /// 割り当て頻度(毎秒の割り当て数)
    pub frequency: f64,
}

/// Memory usage report
/// メモリ使用レポート
#[derive(Debug, Clone)]
pub struct MemoryReport {
    /// Report generation timestamp
    /// レポート生成タイムスタンプ
    pub generated_at: SystemTime,
    /// Total allocations tracked
    /// 追跡された総割り当て数
    pub total_allocations: usize,
    /// Total deallocations tracked
    /// 追跡された総解放数
    pub total_deallocations: usize,
    /// Current active allocations
    /// 現在のアクティブ割り当て数
    pub active_allocations: usize,
    /// Total memory allocated (bytes)
    /// 総割り当てメモリ(バイト)
    pub total_allocated_bytes: usize,
    /// Current memory usage (bytes)
    /// 現在のメモリ使用量(バイト)
    pub current_memory_usage: usize,
    /// Peak memory usage (bytes)
    /// ピークメモリ使用量(バイト)
    pub peak_memory_usage: usize,
    /// Average allocation size
    /// 平均割り当てサイズ
    pub avg_allocation_size: f64,
    /// Memory leak statistics
    /// メモリリーク統計
    pub leak_stats: LeakStats,
    /// Allocation pattern distribution
    /// 割り当てパターン分布
    pub pattern_distribution: HashMap<AllocationPattern, usize>,
    /// Top memory hotspots
    /// トップメモリホットスポット
    pub hotspots: Vec<MemoryHotspot>,
    /// Memory fragmentation analysis
    /// メモリ断片化分析
    pub fragmentation_analysis: FragmentationAnalysis,
}

/// Memory leak statistics
/// メモリリーク統計
#[derive(Debug, Clone)]
pub struct LeakStats {
    /// Number of potential leaks
    /// 潜在的リーク数
    pub potential_leaks: usize,
    /// Total leaked memory (bytes)
    /// 総リークメモリ(バイト)
    pub leaked_bytes: usize,
    /// Oldest leak age
    /// 最も古いリークの年数
    pub oldest_leak_age: Option<Duration>,
    /// Leak rate (leaks per hour)
    /// リーク率(1時間あたりのリーク数)
    pub leak_rate: f64,
}

/// Memory fragmentation analysis
/// メモリ断片化分析
#[derive(Debug, Clone)]
pub struct FragmentationAnalysis {
    /// Fragmentation ratio (0.0 - 1.0)
    /// 断片化率(0.0 - 1.0)
    pub fragmentation_ratio: f64,
    /// Number of memory pools
    /// メモリプール数
    pub pool_count: usize,
    /// Average pool utilization
    /// 平均プール利用率
    pub avg_pool_utilization: f64,
    /// Wasted memory due to fragmentation (bytes)
    /// 断片化による無駄メモリ(バイト)
    pub wasted_memory: usize,
}

/// Memory analytics configuration
/// メモリ分析設定
#[derive(Clone, Debug)]
pub struct AnalyticsConfig {
    /// Maximum number of allocation records to keep
    /// 保持する最大割り当て記録数
    pub max_records: usize,
    /// Enable call stack tracking
    /// コールスタック追跡を有効化
    pub enable_stack_trace: bool,
    /// Stack trace depth
    /// スタックトレース深度
    pub stack_trace_depth: usize,
    /// Memory leak detection threshold (seconds)
    /// メモリリーク検出閾値(秒)
    pub leak_threshold: Duration,
    /// Report generation interval
    /// レポート生成間隔
    pub report_interval: Duration,
    /// Enable hotspot analysis
    /// ホットスポット分析を有効化
    pub enable_hotspot_analysis: bool,
    /// Hotspot threshold (minimum allocations)
    /// ホットスポット閾値(最小割り当て数)
    pub hotspot_threshold: usize,
}

impl Default for AnalyticsConfig {
    fn default() -> Self {
        Self {
            max_records: 100_000,
            enable_stack_trace: true,
            stack_trace_depth: 10,
            leak_threshold: Duration::from_secs(300), // 5 minutes
            report_interval: Duration::from_secs(60), // 1 minute
            enable_hotspot_analysis: true,
            hotspot_threshold: 10,
        }
    }
}

/// Memory analytics engine
/// メモリ分析エンジン
pub struct MemoryAnalytics {
    /// Configuration
    /// 設定
    config: AnalyticsConfig,
    /// Allocation records
    /// 割り当て記録
    records: RwLock<HashMap<u64, AllocationRecord>>,
    /// Next allocation ID
    /// 次の割り当てID
    next_id: Mutex<u64>,
    /// Current memory usage
    /// 現在のメモリ使用量
    current_usage: RwLock<usize>,
    /// Peak memory usage
    /// ピークメモリ使用量
    peak_usage: RwLock<usize>,
    /// Statistics
    /// 統計
    stats: RwLock<AnalyticsStats>,
    /// Background analysis thread
    /// バックグラウンド分析スレッド
    analysis_thread: Mutex<Option<thread::JoinHandle<()>>>,
    /// Running flag
    /// 実行フラグ
    running: Arc<RwLock<bool>>,
}

/// Analytics statistics
/// 分析統計
#[derive(Debug, Clone)]
pub struct AnalyticsStats {
    /// Total allocations tracked
    /// 追跡された総割り当て数
    pub total_allocations: usize,
    /// Total deallocations tracked
    /// 追跡された総解放数
    pub total_deallocations: usize,
    /// Reports generated
    /// 生成されたレポート数
    pub reports_generated: usize,
    /// Last report generation time
    /// 最後のレポート生成時間
    pub last_report_time: Option<SystemTime>,
    /// Analysis overhead (time spent in analytics)
    /// 分析オーバーヘッド(分析に費やされた時間)
    pub analysis_overhead: Duration,
}

impl Default for AnalyticsStats {
    fn default() -> Self {
        Self {
            total_allocations: 0,
            total_deallocations: 0,
            reports_generated: 0,
            last_report_time: None,
            analysis_overhead: Duration::from_millis(0),
        }
    }
}

impl MemoryAnalytics {
    /// Create new memory analytics engine
    /// 新しいメモリ分析エンジンを作成
    pub fn new(config: AnalyticsConfig) -> Self {
        Self {
            config,
            records: RwLock::new(HashMap::new()),
            next_id: Mutex::new(1),
            current_usage: RwLock::new(0),
            peak_usage: RwLock::new(0),
            stats: RwLock::new(AnalyticsStats::default()),
            analysis_thread: Mutex::new(None),
            running: Arc::new(RwLock::new(false)),
        }
    }

    /// Record memory allocation
    /// メモリ割り当てを記録
    pub fn record_allocation(&self, size: usize, source_location: String) -> RusTorchResult<u64> {
        let start_time = Instant::now();

        let id = {
            let mut next_id = self
                .next_id
                .lock()
                .map_err(|_| RusTorchError::MemoryError("Failed to acquire ID lock".to_string()))?;
            let id = *next_id;
            *next_id += 1;
            id
        };

        let mut call_stack = Vec::new();
        if self.config.enable_stack_trace {
            // In a real implementation, we would capture the actual call stack
            // For now, we'll use a placeholder
            call_stack.push("tensor::core::Tensor::new".to_string());
            call_stack.push("main".to_string());
        }

        let record = AllocationRecord {
            id,
            size,
            allocated_at: SystemTime::now(),
            source_location,
            call_stack,
            deallocated_at: None,
            lifetime: None,
            pattern: AllocationPattern::MediumLived, // Will be updated on deallocation
        };

        // Update current usage
        {
            let mut current = self.current_usage.write().map_err(|_| {
                RusTorchError::MemoryError("Failed to acquire usage write lock".to_string())
            })?;
            *current += size;

            // Update peak usage
            let mut peak = self.peak_usage.write().map_err(|_| {
                RusTorchError::MemoryError("Failed to acquire peak write lock".to_string())
            })?;
            if *current > *peak {
                *peak = *current;
            }
        }

        // Store record
        {
            let mut records = self.records.write().map_err(|_| {
                RusTorchError::MemoryError("Failed to acquire records write lock".to_string())
            })?;

            records.insert(id, record);

            // Clean up old records if necessary
            if records.len() > self.config.max_records {
                Self::cleanup_old_records(&mut records, self.config.max_records / 2);
            }
        }

        // Update statistics
        {
            let mut stats = self.stats.write().map_err(|_| {
                RusTorchError::MemoryError("Failed to acquire stats write lock".to_string())
            })?;
            stats.total_allocations += 1;
            stats.analysis_overhead += start_time.elapsed();
        }

        Ok(id)
    }

    /// Record memory deallocation
    /// メモリ解放を記録
    pub fn record_deallocation(&self, id: u64) -> RusTorchResult<()> {
        let start_time = Instant::now();
        let dealloc_time = SystemTime::now();

        let size = {
            let mut records = self.records.write().map_err(|_| {
                RusTorchError::MemoryError("Failed to acquire records write lock".to_string())
            })?;

            if let Some(record) = records.get_mut(&id) {
                record.deallocated_at = Some(dealloc_time);
                record.lifetime = dealloc_time.duration_since(record.allocated_at).ok();
                record.pattern = AllocationPattern::classify(record.lifetime, record.allocated_at);
                record.size
            } else {
                return Err(RusTorchError::MemoryError(format!(
                    "Allocation ID {} not found",
                    id
                )));
            }
        };

        // Update current usage
        {
            let mut current = self.current_usage.write().map_err(|_| {
                RusTorchError::MemoryError("Failed to acquire usage write lock".to_string())
            })?;
            *current = current.saturating_sub(size);
        }

        // Update statistics
        {
            let mut stats = self.stats.write().map_err(|_| {
                RusTorchError::MemoryError("Failed to acquire stats write lock".to_string())
            })?;
            stats.total_deallocations += 1;
            stats.analysis_overhead += start_time.elapsed();
        }

        Ok(())
    }

    /// Generate comprehensive memory report
    /// 包括的なメモリレポートを生成
    pub fn generate_report(&self) -> RusTorchResult<MemoryReport> {
        let start_time = Instant::now();

        let records = self.records.read().map_err(|_| {
            RusTorchError::MemoryError("Failed to acquire records read lock".to_string())
        })?;

        let current_usage = *self.current_usage.read().map_err(|_| {
            RusTorchError::MemoryError("Failed to acquire usage read lock".to_string())
        })?;

        let peak_usage = *self.peak_usage.read().map_err(|_| {
            RusTorchError::MemoryError("Failed to acquire peak read lock".to_string())
        })?;

        let stats = self.stats.read().map_err(|_| {
            RusTorchError::MemoryError("Failed to acquire stats read lock".to_string())
        })?;

        // Analyze records
        let mut pattern_distribution = HashMap::new();
        let mut location_stats = HashMap::new();
        let mut total_allocated = 0;
        let mut active_count = 0;
        let mut leaked_count = 0;
        let mut leaked_bytes = 0;
        let mut oldest_leak_age = None;

        for record in records.values() {
            // Update pattern distribution
            *pattern_distribution
                .entry(record.pattern.clone())
                .or_insert(0) += 1;

            // Update location statistics
            let location_stat = location_stats
                .entry(record.source_location.clone())
                .or_insert((0, 0, 0)); // (count, total_size, leak_count)
            location_stat.0 += 1;
            location_stat.1 += record.size;

            total_allocated += record.size;

            if record.deallocated_at.is_none() {
                active_count += 1;

                // Check for potential leaks
                let age = SystemTime::now()
                    .duration_since(record.allocated_at)
                    .unwrap_or(Duration::from_secs(0));

                if age > self.config.leak_threshold {
                    leaked_count += 1;
                    leaked_bytes += record.size;
                    location_stat.2 += 1;

                    if oldest_leak_age.is_none() || age > oldest_leak_age.unwrap() {
                        oldest_leak_age = Some(age);
                    }
                }
            }
        }

        // Generate hotspots
        let mut hotspots = Vec::new();
        if self.config.enable_hotspot_analysis {
            for (location, (count, total_size, leak_count)) in location_stats {
                if count >= self.config.hotspot_threshold {
                    hotspots.push(MemoryHotspot {
                        location,
                        total_allocations: count,
                        total_memory: total_size,
                        avg_size: total_size as f64 / count as f64,
                        peak_concurrent: count, // Simplified
                        leak_count,
                        frequency: count as f64 / 3600.0, // Simplified: allocations per hour
                    });
                }
            }

            // Sort by total memory usage
            hotspots.sort_by(|a, b| b.total_memory.cmp(&a.total_memory));
        }

        let leak_stats = LeakStats {
            potential_leaks: leaked_count,
            leaked_bytes,
            oldest_leak_age,
            leak_rate: leaked_count as f64 / 3600.0, // Simplified
        };

        let fragmentation_analysis = FragmentationAnalysis {
            fragmentation_ratio: 0.1,            // Simplified
            pool_count: 8,                       // Simplified
            avg_pool_utilization: 0.75,          // Simplified
            wasted_memory: total_allocated / 20, // Simplified: 5% waste
        };

        let avg_allocation_size = if stats.total_allocations > 0 {
            total_allocated as f64 / stats.total_allocations as f64
        } else {
            0.0
        };

        let report = MemoryReport {
            generated_at: SystemTime::now(),
            total_allocations: stats.total_allocations,
            total_deallocations: stats.total_deallocations,
            active_allocations: active_count,
            total_allocated_bytes: total_allocated,
            current_memory_usage: current_usage,
            peak_memory_usage: peak_usage,
            avg_allocation_size,
            leak_stats,
            pattern_distribution,
            hotspots,
            fragmentation_analysis,
        };

        // Update statistics
        drop(stats);
        {
            let mut stats = self.stats.write().map_err(|_| {
                RusTorchError::MemoryError("Failed to acquire stats write lock".to_string())
            })?;
            stats.reports_generated += 1;
            stats.last_report_time = Some(SystemTime::now());
            stats.analysis_overhead += start_time.elapsed();
        }

        Ok(report)
    }

    /// Start background analysis
    /// バックグラウンド分析を開始
    pub fn start_analysis(&self) -> RusTorchResult<()> {
        let mut running = self.running.write().map_err(|_| {
            RusTorchError::MemoryError("Failed to acquire running write lock".to_string())
        })?;

        if *running {
            return Err(RusTorchError::MemoryError(
                "Analysis already running".to_string(),
            ));
        }

        *running = true;

        // We would spawn a background thread here for continuous analysis
        // For now, we'll just mark as running

        Ok(())
    }

    /// Stop background analysis
    /// バックグラウンド分析を停止
    pub fn stop_analysis(&self) -> RusTorchResult<()> {
        let mut running = self.running.write().map_err(|_| {
            RusTorchError::MemoryError("Failed to acquire running write lock".to_string())
        })?;

        *running = false;
        Ok(())
    }

    /// Get current analytics statistics
    /// 現在の分析統計を取得
    pub fn get_stats(&self) -> RusTorchResult<AnalyticsStats> {
        let stats = self.stats.read().map_err(|_| {
            RusTorchError::MemoryError("Failed to acquire stats read lock".to_string())
        })?;

        Ok(stats.clone())
    }

    // Private helper methods

    fn cleanup_old_records(records: &mut HashMap<u64, AllocationRecord>, target_size: usize) {
        if records.len() <= target_size {
            return;
        }

        // Sort by allocation time and remove oldest deallocated records
        let mut to_remove = Vec::new();
        let mut deallocated_records: Vec<_> = records
            .iter()
            .filter(|(_, record)| record.deallocated_at.is_some())
            .collect();

        deallocated_records.sort_by_key(|(_, record)| record.allocated_at);

        let remove_count = records.len() - target_size;
        for (id, _) in deallocated_records.into_iter().take(remove_count) {
            to_remove.push(*id);
        }

        for id in to_remove {
            records.remove(&id);
        }
    }
}

impl std::fmt::Display for MemoryReport {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        writeln!(f, "Memory Analytics Report")?;
        writeln!(f, "======================")?;
        writeln!(f, "Generated: {:?}", self.generated_at)?;
        writeln!(f, "")?;
        writeln!(f, "Allocation Summary:")?;
        writeln!(f, "  Total Allocations: {}", self.total_allocations)?;
        writeln!(f, "  Total Deallocations: {}", self.total_deallocations)?;
        writeln!(f, "  Active Allocations: {}", self.active_allocations)?;
        writeln!(f, "  Current Usage: {} bytes", self.current_memory_usage)?;
        writeln!(f, "  Peak Usage: {} bytes", self.peak_memory_usage)?;
        writeln!(f, "  Average Size: {:.2} bytes", self.avg_allocation_size)?;
        writeln!(f, "")?;
        writeln!(f, "Leak Detection:")?;
        writeln!(f, "  Potential Leaks: {}", self.leak_stats.potential_leaks)?;
        writeln!(f, "  Leaked Memory: {} bytes", self.leak_stats.leaked_bytes)?;
        writeln!(f, "  Leak Rate: {:.2}/hour", self.leak_stats.leak_rate)?;
        writeln!(f, "")?;
        writeln!(f, "Memory Hotspots:")?;
        for (i, hotspot) in self.hotspots.iter().take(5).enumerate() {
            writeln!(
                f,
                "  {}. {} ({} allocs, {} bytes)",
                i + 1,
                hotspot.location,
                hotspot.total_allocations,
                hotspot.total_memory
            )?;
        }
        writeln!(f, "")?;
        writeln!(f, "Fragmentation:")?;
        writeln!(
            f,
            "  Fragmentation Ratio: {:.2}%",
            self.fragmentation_analysis.fragmentation_ratio * 100.0
        )?;
        writeln!(
            f,
            "  Pool Utilization: {:.2}%",
            self.fragmentation_analysis.avg_pool_utilization * 100.0
        )?;
        writeln!(
            f,
            "  Wasted Memory: {} bytes",
            self.fragmentation_analysis.wasted_memory
        )?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_allocation_pattern_classification() {
        let now = SystemTime::now();

        assert_eq!(
            AllocationPattern::classify(Some(Duration::from_millis(500)), now),
            AllocationPattern::ShortLived
        );

        assert_eq!(
            AllocationPattern::classify(Some(Duration::from_secs(30)), now),
            AllocationPattern::MediumLived
        );

        assert_eq!(
            AllocationPattern::classify(Some(Duration::from_secs(120)), now),
            AllocationPattern::LongLived
        );
    }

    #[test]
    fn test_analytics_creation() {
        let config = AnalyticsConfig::default();
        let analytics = MemoryAnalytics::new(config);

        let stats = analytics.get_stats().unwrap();
        assert_eq!(stats.total_allocations, 0);
    }

    #[test]
    fn test_allocation_tracking() {
        let config = AnalyticsConfig::default();
        let analytics = MemoryAnalytics::new(config);

        // Record allocation
        let id = analytics
            .record_allocation(1024, "test.rs:10".to_string())
            .unwrap();
        assert!(id > 0);

        // Record deallocation
        analytics.record_deallocation(id).unwrap();

        let stats = analytics.get_stats().unwrap();
        assert_eq!(stats.total_allocations, 1);
        assert_eq!(stats.total_deallocations, 1);
    }

    #[test]
    fn test_report_generation() {
        let config = AnalyticsConfig::default();
        let analytics = MemoryAnalytics::new(config);

        // Create some allocations
        let id1 = analytics
            .record_allocation(1024, "test.rs:10".to_string())
            .unwrap();
        let _id2 = analytics
            .record_allocation(2048, "test.rs:20".to_string())
            .unwrap();
        analytics.record_deallocation(id1).unwrap();

        let report = analytics.generate_report().unwrap();
        assert_eq!(report.total_allocations, 2);
        assert_eq!(report.total_deallocations, 1);
        assert_eq!(report.active_allocations, 1);
        assert!(report.current_memory_usage > 0);
    }
}