fastalloc/stats/
mod.rs

1//! Statistics collection and reporting for memory pools.
2
3mod collector;
4mod reporter;
5
6pub use collector::StatisticsCollector;
7pub use reporter::StatisticsReporter;
8
9use core::fmt;
10
11/// Statistics about pool usage and performance.
12///
13/// # Examples
14///
15/// ```rust
16/// #[cfg(feature = "stats")]
17/// {
18///     use fastalloc::FixedPool;
19///
20///     let pool = FixedPool::<i32>::new(100).unwrap();
21///     
22///     let _h1 = pool.allocate(1).unwrap();
23///     let _h2 = pool.allocate(2).unwrap();
24///     
25///     let stats = pool.statistics();
26///     assert_eq!(stats.current_usage, 2);
27///     assert_eq!(stats.total_allocations, 2);
28/// }
29/// ```
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct PoolStatistics {
33    /// Total number of allocations ever made
34    pub total_allocations: usize,
35
36    /// Total number of deallocations ever made
37    pub total_deallocations: usize,
38
39    /// Current number of allocated objects
40    pub current_usage: usize,
41
42    /// Peak number of simultaneously allocated objects
43    pub peak_usage: usize,
44
45    /// Current capacity of the pool
46    pub capacity: usize,
47
48    /// Number of times the pool has grown (for growing pools)
49    pub growth_count: usize,
50
51    /// Number of allocation failures
52    pub allocation_failures: usize,
53}
54
55impl PoolStatistics {
56    /// Creates a new statistics instance with all counters at zero.
57    pub fn new(capacity: usize) -> Self {
58        Self {
59            total_allocations: 0,
60            total_deallocations: 0,
61            current_usage: 0,
62            peak_usage: 0,
63            capacity,
64            growth_count: 0,
65            allocation_failures: 0,
66        }
67    }
68
69    /// Returns the utilization rate as a percentage (0.0 to 100.0).
70    #[inline]
71    pub fn utilization_rate(&self) -> f64 {
72        if self.capacity == 0 {
73            0.0
74        } else {
75            (self.current_usage as f64 / self.capacity as f64) * 100.0
76        }
77    }
78
79    /// Returns the peak utilization rate as a percentage (0.0 to 100.0).
80    #[inline]
81    pub fn peak_utilization_rate(&self) -> f64 {
82        if self.capacity == 0 {
83            0.0
84        } else {
85            (self.peak_usage as f64 / self.capacity as f64) * 100.0
86        }
87    }
88
89    /// Returns the hit rate (successful allocations / total attempts).
90    #[inline]
91    pub fn hit_rate(&self) -> f64 {
92        let total_attempts = self.total_allocations + self.allocation_failures;
93        if total_attempts == 0 {
94            1.0
95        } else {
96            self.total_allocations as f64 / total_attempts as f64
97        }
98    }
99
100    /// Returns the number of currently available slots.
101    #[inline]
102    pub fn available(&self) -> usize {
103        self.capacity.saturating_sub(self.current_usage)
104    }
105}
106
107impl fmt::Display for PoolStatistics {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        writeln!(f, "Pool Statistics:")?;
110        writeln!(f, "  Capacity:            {}", self.capacity)?;
111        writeln!(
112            f,
113            "  Current Usage:       {} ({:.1}%)",
114            self.current_usage,
115            self.utilization_rate()
116        )?;
117        writeln!(
118            f,
119            "  Peak Usage:          {} ({:.1}%)",
120            self.peak_usage,
121            self.peak_utilization_rate()
122        )?;
123        writeln!(f, "  Total Allocations:   {}", self.total_allocations)?;
124        writeln!(f, "  Total Deallocations: {}", self.total_deallocations)?;
125        writeln!(f, "  Allocation Failures: {}", self.allocation_failures)?;
126        writeln!(f, "  Hit Rate:            {:.2}%", self.hit_rate() * 100.0)?;
127        writeln!(f, "  Growth Count:        {}", self.growth_count)?;
128        Ok(())
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn statistics_utilization() {
138        let stats = PoolStatistics {
139            capacity: 100,
140            current_usage: 50,
141            peak_usage: 75,
142            ..PoolStatistics::new(100)
143        };
144
145        assert_eq!(stats.utilization_rate(), 50.0);
146        assert_eq!(stats.peak_utilization_rate(), 75.0);
147    }
148
149    #[test]
150    fn statistics_hit_rate() {
151        let stats = PoolStatistics {
152            total_allocations: 90,
153            allocation_failures: 10,
154            ..PoolStatistics::new(100)
155        };
156
157        assert_eq!(stats.hit_rate(), 0.9);
158    }
159
160    #[test]
161    fn statistics_available() {
162        let stats = PoolStatistics {
163            capacity: 100,
164            current_usage: 30,
165            ..PoolStatistics::new(100)
166        };
167
168        assert_eq!(stats.available(), 70);
169    }
170}