safer_ring/pool/stats.rs
1//! Pool statistics and monitoring.
2
3/// Statistics about buffer pool usage.
4///
5/// Provides insights into pool performance and utilization patterns.
6/// All statistics are captured at a specific point in time and may
7/// become stale as the pool state changes.
8///
9/// # Examples
10///
11/// ```rust
12/// use safer_ring::pool::BufferPool;
13///
14/// let pool = BufferPool::new(10, 4096);
15/// let stats = pool.stats();
16///
17/// println!("Pool utilization: {:.1}%", stats.utilization_percent());
18/// println!("Success rate: {:.1}%", stats.success_rate_percent());
19/// ```
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub struct PoolStats {
22 /// Total capacity of the pool
23 pub capacity: usize,
24 /// Number of buffers currently available
25 pub available: usize,
26 /// Number of buffers currently in use
27 pub in_use: usize,
28 /// Size of each buffer in bytes
29 pub buffer_size: usize,
30 /// Total successful allocations since pool creation
31 pub total_allocations: u64,
32 /// Total failed allocation attempts since pool creation
33 pub failed_allocations: u64,
34 /// Current utilization as a ratio (0.0 to 1.0)
35 pub utilization: f64,
36 /// Total number of buffers in the pool (same as capacity)
37 pub total_buffers: usize,
38 /// Number of buffers currently available (same as available)
39 pub available_buffers: usize,
40 /// Number of buffers currently in use (same as in_use)
41 pub in_use_buffers: usize,
42}
43
44impl PoolStats {
45 /// Get utilization as a percentage (0.0 to 100.0).
46 ///
47 /// # Examples
48 ///
49 /// ```rust
50 /// # use safer_ring::pool::PoolStats;
51 /// let stats = PoolStats {
52 /// capacity: 10,
53 /// available: 3,
54 /// in_use: 7,
55 /// buffer_size: 4096,
56 /// total_allocations: 100,
57 /// failed_allocations: 5,
58 /// utilization: 0.7,
59 /// total_buffers: 10,
60 /// available_buffers: 3,
61 /// in_use_buffers: 7,
62 /// };
63 /// assert_eq!(stats.utilization_percent(), 70.0);
64 /// ```
65 pub fn utilization_percent(&self) -> f64 {
66 self.utilization * 100.0
67 }
68
69 /// Get the success rate of allocations as a percentage (0.0 to 100.0).
70 ///
71 /// Returns 100.0 if no allocation attempts have been made.
72 ///
73 /// # Examples
74 ///
75 /// ```rust
76 /// # use safer_ring::pool::PoolStats;
77 /// let stats = PoolStats {
78 /// capacity: 10,
79 /// available: 5,
80 /// in_use: 5,
81 /// buffer_size: 4096,
82 /// total_allocations: 95,
83 /// failed_allocations: 5,
84 /// utilization: 0.5,
85 /// total_buffers: 10,
86 /// available_buffers: 5,
87 /// in_use_buffers: 5,
88 /// };
89 /// assert_eq!(stats.success_rate_percent(), 95.0);
90 /// ```
91 pub fn success_rate_percent(&self) -> f64 {
92 let total_attempts = self.total_allocations + self.failed_allocations;
93 if total_attempts == 0 {
94 100.0 // No attempts means perfect success rate
95 } else {
96 (self.total_allocations as f64 / total_attempts as f64) * 100.0
97 }
98 }
99
100 /// Get the total memory allocated by the pool in bytes.
101 ///
102 /// # Examples
103 ///
104 /// ```rust
105 /// # use safer_ring::pool::PoolStats;
106 /// let stats = PoolStats {
107 /// capacity: 10,
108 /// buffer_size: 4096,
109 /// // ... other fields
110 /// # available: 5, in_use: 5, total_allocations: 100,
111 /// # failed_allocations: 0, utilization: 0.5,
112 /// # total_buffers: 10, available_buffers: 5, in_use_buffers: 5,
113 /// };
114 /// assert_eq!(stats.total_memory_bytes(), 40960); // 10 * 4096
115 /// ```
116 pub fn total_memory_bytes(&self) -> usize {
117 self.capacity * self.buffer_size
118 }
119
120 /// Get the memory currently in use in bytes.
121 pub fn memory_in_use_bytes(&self) -> usize {
122 self.in_use * self.buffer_size
123 }
124
125 /// Check if the pool is under high pressure (utilization > 80%).
126 ///
127 /// This can be used to trigger alerts or scaling decisions.
128 ///
129 /// # Examples
130 ///
131 /// ```rust
132 /// # use safer_ring::pool::PoolStats;
133 /// let high_pressure = PoolStats {
134 /// utilization: 0.85, // 85% utilization
135 /// # capacity: 10, available: 2, in_use: 8, buffer_size: 4096,
136 /// # total_allocations: 100, failed_allocations: 0,
137 /// # total_buffers: 10, available_buffers: 2, in_use_buffers: 8,
138 /// };
139 /// assert!(high_pressure.is_under_pressure());
140 ///
141 /// let normal_pressure = PoolStats {
142 /// utilization: 0.60, // 60% utilization
143 /// # capacity: 10, available: 4, in_use: 6, buffer_size: 4096,
144 /// # total_allocations: 100, failed_allocations: 0,
145 /// # total_buffers: 10, available_buffers: 4, in_use_buffers: 6,
146 /// };
147 /// assert!(!normal_pressure.is_under_pressure());
148 /// ```
149 pub fn is_under_pressure(&self) -> bool {
150 self.utilization > 0.8
151 }
152
153 /// Check if the pool has experienced allocation failures.
154 pub fn has_allocation_failures(&self) -> bool {
155 self.failed_allocations > 0
156 }
157}