memscope_rs/snapshot/memory/
config.rs1use crate::core::{MemScopeError, MemScopeResult};
2use std::time::Duration;
3
4#[derive(Debug, Clone)]
9pub struct MemoryConfig {
10 pub max_allocations: usize,
12 pub max_history_age: Duration,
14 pub memory_limit_mb: usize,
16 pub enable_warnings: bool,
18 pub cleanup_threshold: f64,
20 pub batch_cleanup_size: usize,
22 pub enable_auto_compaction: bool,
24 pub compaction_interval: Duration,
26}
27
28impl Default for MemoryConfig {
29 fn default() -> Self {
30 Self {
31 max_allocations: 100_000,
32 max_history_age: Duration::from_secs(3600), memory_limit_mb: 512, enable_warnings: true,
35 cleanup_threshold: 0.8, batch_cleanup_size: 1000, enable_auto_compaction: true,
38 compaction_interval: Duration::from_secs(300), }
40 }
41}
42
43impl MemoryConfig {
44 pub fn development() -> Self {
46 Self {
47 max_allocations: 1_000_000,
48 max_history_age: Duration::from_secs(7200), memory_limit_mb: 1024, enable_warnings: true,
51 cleanup_threshold: 0.9,
52 batch_cleanup_size: 10000,
53 enable_auto_compaction: true,
54 compaction_interval: Duration::from_secs(600), }
56 }
57
58 pub fn production() -> Self {
60 Self {
61 max_allocations: 50_000,
62 max_history_age: Duration::from_secs(1800), memory_limit_mb: 256, enable_warnings: true,
65 cleanup_threshold: 0.7,
66 batch_cleanup_size: 500,
67 enable_auto_compaction: true,
68 compaction_interval: Duration::from_secs(120), }
70 }
71
72 pub fn testing() -> Self {
74 Self {
75 max_allocations: 1000,
76 max_history_age: Duration::from_secs(60), memory_limit_mb: 32, enable_warnings: false, cleanup_threshold: 0.8,
80 batch_cleanup_size: 100,
81 enable_auto_compaction: false, compaction_interval: Duration::from_secs(30),
83 }
84 }
85
86 pub fn high_performance() -> Self {
88 Self {
89 max_allocations: 200_000,
90 max_history_age: Duration::from_secs(900), memory_limit_mb: 512,
92 enable_warnings: false, cleanup_threshold: 0.85,
94 batch_cleanup_size: 2000, enable_auto_compaction: false, compaction_interval: Duration::from_secs(3600),
97 }
98 }
99
100 pub fn validate(&self) -> MemScopeResult<()> {
102 if self.max_allocations == 0 {
103 return Err(MemScopeError::error(
104 "config",
105 "validate",
106 "max_allocations must be greater than 0",
107 ));
108 }
109
110 if self.memory_limit_mb == 0 {
111 return Err(MemScopeError::error(
112 "config",
113 "validate",
114 "memory_limit_mb must be greater than 0",
115 ));
116 }
117
118 if self.cleanup_threshold <= 0.0 || self.cleanup_threshold >= 1.0 {
119 return Err(MemScopeError::error(
120 "config",
121 "validate",
122 "cleanup_threshold must be between 0.0 and 1.0",
123 ));
124 }
125
126 if self.batch_cleanup_size == 0 {
127 return Err(MemScopeError::error(
128 "config",
129 "validate",
130 "batch_cleanup_size must be greater than 0",
131 ));
132 }
133
134 if self.batch_cleanup_size > self.max_allocations {
135 return Err(MemScopeError::error(
136 "config",
137 "validate",
138 "batch_cleanup_size should not exceed max_allocations",
139 ));
140 }
141
142 Ok(())
143 }
144
145 pub fn auto_adjust_for_system(&mut self) -> MemScopeResult<()> {
147 let system_memory_mb = self.get_system_memory_mb()?;
149
150 let max_allowed_mb = (system_memory_mb as f64 * 0.1) as usize;
152 if self.memory_limit_mb > max_allowed_mb {
153 self.memory_limit_mb = max_allowed_mb.max(64); }
155
156 self.max_allocations = (self.memory_limit_mb * 1024 * 1024 / 512).min(self.max_allocations);
158 self.batch_cleanup_size = (self.max_allocations / 100).max(100);
159
160 Ok(())
161 }
162
163 fn get_system_memory_mb(&self) -> MemScopeResult<usize> {
165 #[cfg(target_os = "linux")]
166 {
167 use std::fs;
168 let meminfo = fs::read_to_string("/proc/meminfo").map_err(|_| {
169 MemScopeError::error("config", "get_system_memory_mb", "System info unavailable")
170 })?;
171
172 for line in meminfo.lines() {
173 if line.starts_with("MemTotal:") {
174 let parts: Vec<&str> = line.split_whitespace().collect();
175 if parts.len() >= 2 {
176 let kb: usize = parts[1].parse().map_err(|_| {
177 MemScopeError::error(
178 "config",
179 "get_system_memory_mb",
180 "Failed to parse memory info",
181 )
182 })?;
183 return Ok(kb / 1024); }
185 }
186 }
187 }
188
189 #[cfg(target_os = "windows")]
190 {
191 Ok(8192)
192 }
193 #[cfg(target_os = "macos")]
194 {
195 Ok(8192)
196 }
197 #[cfg(not(any(target_os = "windows", target_os = "macos")))]
198 {
199 Ok(4096)
200 }
201 }
202
203 pub fn for_current_system() -> MemScopeResult<Self> {
205 let mut config = Self::default();
206 config.auto_adjust_for_system()?;
207 config.validate()?;
208 Ok(config)
209 }
210
211 pub fn estimate_memory_usage(&self) -> MemoryEstimate {
213 let avg_allocation_size = 128; let max_memory_usage = self.max_allocations * avg_allocation_size;
216 let configured_limit = self.memory_limit_mb * 1024 * 1024;
217
218 MemoryEstimate {
219 max_entries: self.max_allocations,
220 estimated_max_usage_mb: (max_memory_usage / (1024 * 1024)) as f64,
221 configured_limit_mb: self.memory_limit_mb as f64,
222 effective_limit_mb: (configured_limit.min(max_memory_usage) / (1024 * 1024)) as f64,
223 cleanup_trigger_mb: (configured_limit as f64 * self.cleanup_threshold)
224 / (1024.0 * 1024.0),
225 }
226 }
227}
228
229#[derive(Debug, Clone)]
231pub struct MemoryEstimate {
232 pub max_entries: usize,
234 pub estimated_max_usage_mb: f64,
236 pub configured_limit_mb: f64,
238 pub effective_limit_mb: f64,
240 pub cleanup_trigger_mb: f64,
242}
243
244impl MemoryEstimate {
245 pub fn is_reasonable(&self) -> bool {
247 self.effective_limit_mb >= 1.0 && self.cleanup_trigger_mb < self.effective_limit_mb && self.max_entries >= 10 }
251
252 pub fn get_recommendations(&self) -> Vec<String> {
254 let mut recommendations = Vec::new();
255
256 if self.effective_limit_mb < 64.0 {
257 recommendations.push(
258 "Consider increasing memory limit to at least 64MB for better performance".into(),
259 );
260 }
261
262 if self.max_entries < 10000 {
263 recommendations
264 .push("Low max_entries may cause frequent cleanup, consider increasing".into());
265 }
266
267 if self.cleanup_trigger_mb / self.effective_limit_mb > 0.9 {
268 recommendations.push("Cleanup threshold is too high, may cause memory pressure".into());
269 }
270
271 if self.estimated_max_usage_mb > self.configured_limit_mb * 2.0 {
272 recommendations.push("Estimated usage significantly exceeds configured limit".into());
273 }
274
275 recommendations
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn test_default_config_validation() {
285 let config = MemoryConfig::default();
286 assert!(config.validate().is_ok());
287 }
288
289 #[test]
290 fn test_preset_configs() {
291 let configs = vec![
292 MemoryConfig::development(),
293 MemoryConfig::production(),
294 MemoryConfig::testing(),
295 MemoryConfig::high_performance(),
296 ];
297
298 for config in configs {
299 assert!(config.validate().is_ok(), "Preset config should be valid");
300 }
301 }
302
303 #[test]
304 fn test_invalid_configs() {
305 let config = MemoryConfig {
307 max_allocations: 0,
308 ..Default::default()
309 };
310 assert!(config.validate().is_err());
311
312 let config2 = MemoryConfig {
314 cleanup_threshold: 1.5,
315 ..Default::default()
316 };
317 assert!(config2.validate().is_err());
318
319 let config3 = MemoryConfig {
320 cleanup_threshold: -0.1,
321 ..Default::default()
322 };
323 assert!(config3.validate().is_err());
324 }
325
326 #[test]
327 fn test_memory_estimation() {
328 let config = MemoryConfig::default();
329 let estimate = config.estimate_memory_usage();
330
331 let _ = estimate.is_reasonable(); assert!(estimate.effective_limit_mb > 0.0);
334 let _ = estimate.cleanup_trigger_mb; }
337
338 #[test]
339 fn test_recommendations() {
340 let config = MemoryConfig {
341 max_allocations: 500, memory_limit_mb: 16, cleanup_threshold: 0.95, ..Default::default()
345 };
346
347 let estimate = config.estimate_memory_usage();
348 let recommendations = estimate.get_recommendations();
349
350 assert!(!recommendations.is_empty());
351 assert!(recommendations.len() >= 2); }
353
354 #[test]
355 fn test_system_config_creation() {
356 match MemoryConfig::for_current_system() {
358 Ok(config) => {
359 assert!(config.validate().is_ok());
360 assert!(config.memory_limit_mb >= 64);
361 }
362 Err(_) => {
363 }
365 }
366 }
367}