1use serde::{Deserialize, Serialize};
7
8use super::allocation::ImpactLevel;
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub struct EnhancedFragmentationAnalysis {
13 pub total_heap_size: usize,
15 pub used_heap_size: usize,
17 pub free_heap_size: usize,
19 pub free_block_count: usize,
21 pub free_block_distribution: Vec<BlockSizeRange>,
23 pub fragmentation_metrics: FragmentationMetrics,
25 pub fragmentation_causes: Vec<FragmentationCause>,
27}
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
31pub struct BlockSizeRange {
32 pub min_size: usize,
34 pub max_size: usize,
36 pub block_count: usize,
38 pub total_size: usize,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44pub struct FragmentationMetrics {
45 pub external_fragmentation: f64,
47 pub internal_fragmentation: f64,
49 pub largest_free_block: usize,
51 pub average_free_block_size: f64,
53 pub severity_level: FragmentationSeverity,
55}
56
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
59pub enum FragmentationSeverity {
60 Low,
62 Moderate,
64 High,
66 Critical,
68}
69
70#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
72pub struct FragmentationCause {
73 pub cause_type: FragmentationCauseType,
75 pub description: String,
77 pub impact_level: ImpactLevel,
79 pub mitigation_suggestion: String,
81}
82
83#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85pub enum FragmentationCauseType {
86 MixedAllocationSizes,
88 FrequentAllocDealloc,
90 LongLivedAllocations,
92 PoorAllocationStrategy,
94 MemoryLeaks,
96}
97
98impl From<crate::core::types::EnhancedFragmentationAnalysis> for EnhancedFragmentationAnalysis {
100 fn from(old: crate::core::types::EnhancedFragmentationAnalysis) -> Self {
101 Self {
102 total_heap_size: old.total_heap_size,
103 used_heap_size: old.used_heap_size,
104 free_heap_size: old.free_heap_size,
105 free_block_count: old.free_block_count,
106 free_block_distribution: old
107 .free_block_distribution
108 .into_iter()
109 .map(|b| BlockSizeRange {
110 min_size: b.min_size,
111 max_size: b.max_size,
112 block_count: b.block_count,
113 total_size: b.total_size,
114 })
115 .collect(),
116 fragmentation_metrics: FragmentationMetrics {
117 external_fragmentation: old.fragmentation_metrics.external_fragmentation,
118 internal_fragmentation: old.fragmentation_metrics.internal_fragmentation,
119 largest_free_block: old.fragmentation_metrics.largest_free_block,
120 average_free_block_size: old.fragmentation_metrics.average_free_block_size,
121 severity_level: match old.fragmentation_metrics.severity_level {
122 crate::core::types::FragmentationSeverity::Low => FragmentationSeverity::Low,
123 crate::core::types::FragmentationSeverity::Moderate => {
124 FragmentationSeverity::Moderate
125 }
126 crate::core::types::FragmentationSeverity::High => FragmentationSeverity::High,
127 crate::core::types::FragmentationSeverity::Critical => {
128 FragmentationSeverity::Critical
129 }
130 },
131 },
132 fragmentation_causes: old
133 .fragmentation_causes
134 .into_iter()
135 .map(|c| FragmentationCause {
136 cause_type: match c.cause_type {
137 crate::core::types::FragmentationCauseType::MixedAllocationSizes => {
138 FragmentationCauseType::MixedAllocationSizes
139 }
140 crate::core::types::FragmentationCauseType::FrequentAllocDealloc => {
141 FragmentationCauseType::FrequentAllocDealloc
142 }
143 crate::core::types::FragmentationCauseType::LongLivedAllocations => {
144 FragmentationCauseType::LongLivedAllocations
145 }
146 crate::core::types::FragmentationCauseType::PoorAllocationStrategy => {
147 FragmentationCauseType::PoorAllocationStrategy
148 }
149 crate::core::types::FragmentationCauseType::MemoryLeaks => {
150 FragmentationCauseType::MemoryLeaks
151 }
152 },
153 description: c.description,
154 impact_level: match c.impact_level {
155 crate::core::types::ImpactLevel::Low => ImpactLevel::Low,
156 crate::core::types::ImpactLevel::Medium => ImpactLevel::Medium,
157 crate::core::types::ImpactLevel::High => ImpactLevel::High,
158 crate::core::types::ImpactLevel::Critical => ImpactLevel::Critical,
159 },
160 mitigation_suggestion: c.mitigation_suggestion,
161 })
162 .collect(),
163 }
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn test_enhanced_fragmentation_analysis() {
173 let analysis = EnhancedFragmentationAnalysis {
174 total_heap_size: 1024 * 1024,
175 used_heap_size: 512 * 1024,
176 free_heap_size: 512 * 1024,
177 free_block_count: 10,
178 free_block_distribution: vec![],
179 fragmentation_metrics: FragmentationMetrics {
180 external_fragmentation: 0.3,
181 internal_fragmentation: 0.1,
182 largest_free_block: 256 * 1024,
183 average_free_block_size: 51200.0,
184 severity_level: FragmentationSeverity::Low,
185 },
186 fragmentation_causes: vec![],
187 };
188
189 assert_eq!(analysis.total_heap_size, 1024 * 1024);
190 assert_eq!(analysis.free_block_count, 10);
191 }
192
193 #[test]
194 fn test_fragmentation_severity() {
195 let severity = FragmentationSeverity::High;
196 assert!(matches!(severity, FragmentationSeverity::High));
197 }
198
199 #[test]
200 fn test_fragmentation_cause_type() {
201 let cause = FragmentationCauseType::MixedAllocationSizes;
202 assert!(matches!(
203 cause,
204 FragmentationCauseType::MixedAllocationSizes
205 ));
206 }
207
208 #[test]
209 fn test_block_size_range_creation() {
210 let range = BlockSizeRange {
211 min_size: 0,
212 max_size: 1024,
213 block_count: 50,
214 total_size: 25600,
215 };
216
217 assert_eq!(range.min_size, 0);
218 assert_eq!(range.max_size, 1024);
219 assert_eq!(range.block_count, 50);
220 assert_eq!(range.total_size, 25600);
221 }
222
223 #[test]
224 fn test_block_size_range_serialization() {
225 let range = BlockSizeRange {
226 min_size: 1024,
227 max_size: 4096,
228 block_count: 25,
229 total_size: 64000,
230 };
231
232 let json = serde_json::to_string(&range).unwrap();
233 let deserialized: BlockSizeRange = serde_json::from_str(&json).unwrap();
234 assert_eq!(deserialized, range);
235 }
236
237 #[test]
238 fn test_fragmentation_metrics_all_severities() {
239 let severities = [
240 FragmentationSeverity::Low,
241 FragmentationSeverity::Moderate,
242 FragmentationSeverity::High,
243 FragmentationSeverity::Critical,
244 ];
245
246 for severity in severities {
247 let metrics = FragmentationMetrics {
248 external_fragmentation: 0.5,
249 internal_fragmentation: 0.2,
250 largest_free_block: 1024,
251 average_free_block_size: 512.0,
252 severity_level: severity.clone(),
253 };
254 assert_eq!(metrics.severity_level, severity);
255 }
256 }
257
258 #[test]
259 fn test_fragmentation_metrics_boundary_values() {
260 let metrics = FragmentationMetrics {
261 external_fragmentation: 0.0,
262 internal_fragmentation: 1.0,
263 largest_free_block: 0,
264 average_free_block_size: 0.0,
265 severity_level: FragmentationSeverity::Critical,
266 };
267
268 assert!((metrics.external_fragmentation - 0.0).abs() < f64::EPSILON);
269 assert!((metrics.internal_fragmentation - 1.0).abs() < f64::EPSILON);
270 assert_eq!(metrics.largest_free_block, 0);
271 }
272
273 #[test]
274 fn test_fragmentation_metrics_serialization() {
275 let metrics = FragmentationMetrics {
276 external_fragmentation: 0.75,
277 internal_fragmentation: 0.25,
278 largest_free_block: 2048,
279 average_free_block_size: 1024.0,
280 severity_level: FragmentationSeverity::High,
281 };
282
283 let json = serde_json::to_string(&metrics).unwrap();
284 let deserialized: FragmentationMetrics = serde_json::from_str(&json).unwrap();
285 assert_eq!(deserialized, metrics);
286 }
287
288 #[test]
289 fn test_fragmentation_cause_creation() {
290 let cause = FragmentationCause {
291 cause_type: FragmentationCauseType::FrequentAllocDealloc,
292 description: "Frequent allocation and deallocation pattern".to_string(),
293 impact_level: ImpactLevel::High,
294 mitigation_suggestion: "Use object pooling".to_string(),
295 };
296
297 assert!(matches!(
298 cause.cause_type,
299 FragmentationCauseType::FrequentAllocDealloc
300 ));
301 assert_eq!(
302 cause.description,
303 "Frequent allocation and deallocation pattern"
304 );
305 assert!(matches!(cause.impact_level, ImpactLevel::High));
306 }
307
308 #[test]
309 fn test_all_fragmentation_cause_types() {
310 let cause_types = [
311 FragmentationCauseType::MixedAllocationSizes,
312 FragmentationCauseType::FrequentAllocDealloc,
313 FragmentationCauseType::LongLivedAllocations,
314 FragmentationCauseType::PoorAllocationStrategy,
315 FragmentationCauseType::MemoryLeaks,
316 ];
317
318 for cause_type in cause_types {
319 let cause = FragmentationCause {
320 cause_type: cause_type.clone(),
321 description: "Test description".to_string(),
322 impact_level: ImpactLevel::Low,
323 mitigation_suggestion: "Test mitigation".to_string(),
324 };
325 assert_eq!(cause.cause_type, cause_type);
326 }
327 }
328
329 #[test]
330 fn test_fragmentation_cause_serialization() {
331 let cause = FragmentationCause {
332 cause_type: FragmentationCauseType::MemoryLeaks,
333 description: "Memory leak detected".to_string(),
334 impact_level: ImpactLevel::Critical,
335 mitigation_suggestion: "Fix memory leaks".to_string(),
336 };
337
338 let json = serde_json::to_string(&cause).unwrap();
339 let deserialized: FragmentationCause = serde_json::from_str(&json).unwrap();
340 assert_eq!(deserialized, cause);
341 }
342
343 #[test]
344 fn test_all_fragmentation_severities_serialization() {
345 let severities = vec![
346 FragmentationSeverity::Low,
347 FragmentationSeverity::Moderate,
348 FragmentationSeverity::High,
349 FragmentationSeverity::Critical,
350 ];
351
352 for severity in severities {
353 let json = serde_json::to_string(&severity).unwrap();
354 let deserialized: FragmentationSeverity = serde_json::from_str(&json).unwrap();
355 assert_eq!(deserialized, severity);
356 }
357 }
358
359 #[test]
360 fn test_all_cause_types_serialization() {
361 let cause_types = vec![
362 FragmentationCauseType::MixedAllocationSizes,
363 FragmentationCauseType::FrequentAllocDealloc,
364 FragmentationCauseType::LongLivedAllocations,
365 FragmentationCauseType::PoorAllocationStrategy,
366 FragmentationCauseType::MemoryLeaks,
367 ];
368
369 for cause_type in cause_types {
370 let json = serde_json::to_string(&cause_type).unwrap();
371 let deserialized: FragmentationCauseType = serde_json::from_str(&json).unwrap();
372 assert_eq!(deserialized, cause_type);
373 }
374 }
375
376 #[test]
377 fn test_enhanced_fragmentation_analysis_with_distribution() {
378 let distribution = vec![
379 BlockSizeRange {
380 min_size: 0,
381 max_size: 256,
382 block_count: 100,
383 total_size: 12800,
384 },
385 BlockSizeRange {
386 min_size: 256,
387 max_size: 1024,
388 block_count: 50,
389 total_size: 32000,
390 },
391 ];
392
393 let causes = vec![FragmentationCause {
394 cause_type: FragmentationCauseType::MixedAllocationSizes,
395 description: "Mixed allocation sizes".to_string(),
396 impact_level: ImpactLevel::Medium,
397 mitigation_suggestion: "Use size classes".to_string(),
398 }];
399
400 let analysis = EnhancedFragmentationAnalysis {
401 total_heap_size: 1024 * 1024,
402 used_heap_size: 768 * 1024,
403 free_heap_size: 256 * 1024,
404 free_block_count: 150,
405 free_block_distribution: distribution.clone(),
406 fragmentation_metrics: FragmentationMetrics {
407 external_fragmentation: 0.6,
408 internal_fragmentation: 0.15,
409 largest_free_block: 65536,
410 average_free_block_size: 1706.0,
411 severity_level: FragmentationSeverity::Moderate,
412 },
413 fragmentation_causes: causes.clone(),
414 };
415
416 assert_eq!(analysis.free_block_distribution.len(), 2);
417 assert_eq!(analysis.free_block_distribution[0].block_count, 100);
418 assert_eq!(analysis.fragmentation_causes.len(), 1);
419 }
420
421 #[test]
422 fn test_enhanced_fragmentation_analysis_serialization() {
423 let analysis = EnhancedFragmentationAnalysis {
424 total_heap_size: 2048 * 1024,
425 used_heap_size: 1024 * 1024,
426 free_heap_size: 1024 * 1024,
427 free_block_count: 25,
428 free_block_distribution: vec![BlockSizeRange {
429 min_size: 0,
430 max_size: 4096,
431 block_count: 25,
432 total_size: 51200,
433 }],
434 fragmentation_metrics: FragmentationMetrics {
435 external_fragmentation: 0.4,
436 internal_fragmentation: 0.1,
437 largest_free_block: 32768,
438 average_free_block_size: 40960.0,
439 severity_level: FragmentationSeverity::Low,
440 },
441 fragmentation_causes: vec![],
442 };
443
444 let json = serde_json::to_string(&analysis).unwrap();
445 let deserialized: EnhancedFragmentationAnalysis = serde_json::from_str(&json).unwrap();
446 assert_eq!(deserialized, analysis);
447 }
448
449 #[test]
450 fn test_enhanced_fragmentation_analysis_clone() {
451 let analysis = EnhancedFragmentationAnalysis {
452 total_heap_size: 1024,
453 used_heap_size: 512,
454 free_heap_size: 512,
455 free_block_count: 5,
456 free_block_distribution: vec![],
457 fragmentation_metrics: FragmentationMetrics {
458 external_fragmentation: 0.5,
459 internal_fragmentation: 0.2,
460 largest_free_block: 256,
461 average_free_block_size: 102.4,
462 severity_level: FragmentationSeverity::Moderate,
463 },
464 fragmentation_causes: vec![],
465 };
466
467 let cloned = analysis.clone();
468 assert_eq!(cloned.total_heap_size, analysis.total_heap_size);
469 assert_eq!(cloned.free_block_count, analysis.free_block_count);
470 }
471
472 #[test]
473 fn test_enhanced_fragmentation_analysis_debug() {
474 let analysis = EnhancedFragmentationAnalysis {
475 total_heap_size: 1024,
476 used_heap_size: 512,
477 free_heap_size: 512,
478 free_block_count: 5,
479 free_block_distribution: vec![],
480 fragmentation_metrics: FragmentationMetrics {
481 external_fragmentation: 0.5,
482 internal_fragmentation: 0.2,
483 largest_free_block: 256,
484 average_free_block_size: 102.4,
485 severity_level: FragmentationSeverity::Low,
486 },
487 fragmentation_causes: vec![],
488 };
489
490 let debug_str = format!("{:?}", analysis);
491 assert!(debug_str.contains("EnhancedFragmentationAnalysis"));
492 assert!(debug_str.contains("total_heap_size"));
493 }
494
495 #[test]
496 fn test_block_size_range_equality() {
497 let range1 = BlockSizeRange {
498 min_size: 0,
499 max_size: 1024,
500 block_count: 10,
501 total_size: 5120,
502 };
503 let range2 = BlockSizeRange {
504 min_size: 0,
505 max_size: 1024,
506 block_count: 10,
507 total_size: 5120,
508 };
509 let range3 = BlockSizeRange {
510 min_size: 0,
511 max_size: 2048,
512 block_count: 10,
513 total_size: 5120,
514 };
515
516 assert_eq!(range1, range2);
517 assert_ne!(range1, range3);
518 }
519
520 #[test]
521 fn test_fragmentation_severity_equality() {
522 assert_eq!(FragmentationSeverity::Low, FragmentationSeverity::Low);
523 assert_ne!(FragmentationSeverity::Low, FragmentationSeverity::High);
524 assert_ne!(
525 FragmentationSeverity::Moderate,
526 FragmentationSeverity::Critical
527 );
528 }
529
530 #[test]
531 fn test_fragmentation_cause_type_equality() {
532 assert_eq!(
533 FragmentationCauseType::MixedAllocationSizes,
534 FragmentationCauseType::MixedAllocationSizes
535 );
536 assert_ne!(
537 FragmentationCauseType::MixedAllocationSizes,
538 FragmentationCauseType::MemoryLeaks
539 );
540 }
541
542 #[test]
543 fn test_fragmentation_cause_with_all_impact_levels() {
544 let impact_levels = [
545 ImpactLevel::Low,
546 ImpactLevel::Medium,
547 ImpactLevel::High,
548 ImpactLevel::Critical,
549 ];
550
551 for impact in impact_levels {
552 let cause = FragmentationCause {
553 cause_type: FragmentationCauseType::PoorAllocationStrategy,
554 description: "Test".to_string(),
555 impact_level: impact.clone(),
556 mitigation_suggestion: "Fix it".to_string(),
557 };
558 assert_eq!(cause.impact_level, impact);
559 }
560 }
561
562 #[test]
563 fn test_empty_free_block_distribution() {
564 let analysis = EnhancedFragmentationAnalysis {
565 total_heap_size: 1024,
566 used_heap_size: 0,
567 free_heap_size: 1024,
568 free_block_count: 0,
569 free_block_distribution: vec![],
570 fragmentation_metrics: FragmentationMetrics {
571 external_fragmentation: 0.0,
572 internal_fragmentation: 0.0,
573 largest_free_block: 1024,
574 average_free_block_size: 0.0,
575 severity_level: FragmentationSeverity::Low,
576 },
577 fragmentation_causes: vec![],
578 };
579
580 assert!(analysis.free_block_distribution.is_empty());
581 assert_eq!(analysis.free_block_count, 0);
582 }
583
584 #[test]
585 fn test_large_heap_analysis() {
586 let analysis = EnhancedFragmentationAnalysis {
587 total_heap_size: usize::MAX / 2,
588 used_heap_size: usize::MAX / 4,
589 free_heap_size: usize::MAX / 4,
590 free_block_count: 1000000,
591 free_block_distribution: vec![],
592 fragmentation_metrics: FragmentationMetrics {
593 external_fragmentation: f64::MAX,
594 internal_fragmentation: f64::MIN,
595 largest_free_block: usize::MAX,
596 average_free_block_size: f64::INFINITY,
597 severity_level: FragmentationSeverity::Critical,
598 },
599 fragmentation_causes: vec![],
600 };
601
602 assert_eq!(analysis.total_heap_size, usize::MAX / 2);
603 assert!(
604 analysis
605 .fragmentation_metrics
606 .external_fragmentation
607 .is_finite()
608 || analysis
609 .fragmentation_metrics
610 .external_fragmentation
611 .is_infinite()
612 );
613 }
614}