1use crate::error::{GpuAdvancedError, Result};
28use parking_lot::{Mutex, RwLock};
29use std::collections::{BTreeMap, HashMap};
30use std::ops::Range;
31use std::sync::Arc;
32use std::sync::atomic::{AtomicU64, Ordering};
33use std::time::{Duration, Instant};
34use wgpu::{Buffer, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Device, Queue};
35
36#[derive(Debug, Clone)]
38struct MemoryBlock {
39 offset: u64,
41 size: u64,
43 is_free: bool,
45 allocation_id: Option<u64>,
47 movable: bool,
49 ref_count: u32,
51}
52
53#[derive(Debug, Clone)]
55pub struct DefragMove {
56 pub allocation_id: u64,
58 pub src_offset: u64,
60 pub dst_offset: u64,
62 pub size: u64,
64}
65
66#[derive(Debug, Clone, Default)]
68pub struct DefragmentationPlan {
69 pub moves: Vec<DefragMove>,
71 pub total_bytes: u64,
73 pub expected_fragmentation: f64,
75 pub current_fragmentation: f64,
77}
78
79impl DefragmentationPlan {
80 pub fn is_worthwhile(&self, min_improvement: f64) -> bool {
82 if self.moves.is_empty() {
83 return false;
84 }
85 let improvement = self.current_fragmentation - self.expected_fragmentation;
86 improvement >= min_improvement
87 }
88
89 pub fn move_count(&self) -> usize {
91 self.moves.len()
92 }
93}
94
95#[derive(Debug, Clone)]
97pub struct DefragmentationResult {
98 pub performed: bool,
100 pub blocks_moved: usize,
102 pub bytes_moved: u64,
104 pub fragmentation_before: f64,
106 pub fragmentation_after: f64,
108 pub duration: Duration,
110 pub unmovable_blocks: usize,
112}
113
114impl Default for DefragmentationResult {
115 fn default() -> Self {
116 Self {
117 performed: false,
118 blocks_moved: 0,
119 bytes_moved: 0,
120 fragmentation_before: 0.0,
121 fragmentation_after: 0.0,
122 duration: Duration::ZERO,
123 unmovable_blocks: 0,
124 }
125 }
126}
127
128#[derive(Debug, Clone)]
130pub struct DefragConfig {
131 pub min_fragmentation_threshold: f64,
133 pub min_improvement: f64,
135 pub max_moves_per_pass: usize,
137 pub skip_unmovable: bool,
139 pub compaction_alignment: u64,
141}
142
143impl Default for DefragConfig {
144 fn default() -> Self {
145 Self {
146 min_fragmentation_threshold: 0.2,
147 min_improvement: 0.1,
148 max_moves_per_pass: 100,
149 skip_unmovable: true,
150 compaction_alignment: 256,
151 }
152 }
153}
154
155pub struct MemoryPool {
157 device: Arc<Device>,
159 buffer: Arc<Mutex<Option<Buffer>>>,
161 pool_size: u64,
163 blocks: Arc<RwLock<BTreeMap<u64, MemoryBlock>>>,
165 next_alloc_id: Arc<Mutex<u64>>,
167 usage: BufferUsages,
169 current_usage: Arc<Mutex<u64>>,
171 peak_usage: Arc<Mutex<u64>>,
173 allocation_count: Arc<Mutex<u64>>,
175 deallocation_count: Arc<Mutex<u64>>,
177 defrag_count: Arc<Mutex<u64>>,
179 allocation_offsets: Arc<RwLock<HashMap<u64, u64>>>,
182 defrag_config: RwLock<DefragConfig>,
184 last_defrag_time: Arc<Mutex<Option<Instant>>>,
186 total_bytes_defragged: Arc<AtomicU64>,
188}
189
190pub struct MemoryAllocation {
196 id: u64,
198 original_offset: u64,
200 size: u64,
202 pool: Arc<MemoryPool>,
204}
205
206impl MemoryPool {
207 pub fn new(device: Arc<Device>, pool_size: u64, usage: BufferUsages) -> Result<Self> {
209 Self::with_config(device, pool_size, usage, DefragConfig::default())
210 }
211
212 pub fn with_config(
214 device: Arc<Device>,
215 pool_size: u64,
216 usage: BufferUsages,
217 defrag_config: DefragConfig,
218 ) -> Result<Self> {
219 let usage_with_copy = usage | BufferUsages::COPY_SRC | BufferUsages::COPY_DST;
221
222 let buffer = device.create_buffer(&BufferDescriptor {
224 label: Some("Memory Pool"),
225 size: pool_size,
226 usage: usage_with_copy,
227 mapped_at_creation: false,
228 });
229
230 let mut blocks = BTreeMap::new();
232 blocks.insert(
233 0,
234 MemoryBlock {
235 offset: 0,
236 size: pool_size,
237 is_free: true,
238 allocation_id: None,
239 movable: true,
240 ref_count: 0,
241 },
242 );
243
244 Ok(Self {
245 device,
246 buffer: Arc::new(Mutex::new(Some(buffer))),
247 pool_size,
248 blocks: Arc::new(RwLock::new(blocks)),
249 next_alloc_id: Arc::new(Mutex::new(0)),
250 usage: usage_with_copy,
251 current_usage: Arc::new(Mutex::new(0)),
252 peak_usage: Arc::new(Mutex::new(0)),
253 allocation_count: Arc::new(Mutex::new(0)),
254 deallocation_count: Arc::new(Mutex::new(0)),
255 defrag_count: Arc::new(Mutex::new(0)),
256 allocation_offsets: Arc::new(RwLock::new(HashMap::new())),
257 defrag_config: RwLock::new(defrag_config),
258 last_defrag_time: Arc::new(Mutex::new(None)),
259 total_bytes_defragged: Arc::new(AtomicU64::new(0)),
260 })
261 }
262
263 pub fn allocate(self: &Arc<Self>, size: u64, alignment: u64) -> Result<MemoryAllocation> {
265 let aligned_size = Self::align_up(size, alignment);
266
267 let alloc_id = {
268 let mut next_id = self.next_alloc_id.lock();
269 let id = *next_id;
270 *next_id = next_id.wrapping_add(1);
271 id
272 };
273
274 let (offset, block_offset) = {
276 let blocks = self.blocks.read();
277
278 let mut found: Option<(u64, u64)> = None;
279
280 for (blk_offset, block) in blocks.iter() {
281 if block.is_free && block.size >= aligned_size {
282 let aligned_offset = Self::align_up(*blk_offset, alignment);
283 let waste = aligned_offset - blk_offset;
284
285 if block.size >= aligned_size + waste {
286 found = Some((aligned_offset, *blk_offset));
287 break;
288 }
289 }
290 }
291
292 found.ok_or_else(|| GpuAdvancedError::AllocationFailed {
293 size: aligned_size,
294 available: self.get_available_memory(),
295 })?
296 };
297
298 {
300 let mut blocks = self.blocks.write();
301
302 let block = blocks
303 .remove(&block_offset)
304 .ok_or_else(|| GpuAdvancedError::memory_pool_error("Block not found"))?;
305
306 let waste = offset - block_offset;
307
308 if waste > 0 {
310 blocks.insert(
311 block_offset,
312 MemoryBlock {
313 offset: block_offset,
314 size: waste,
315 is_free: true,
316 allocation_id: None,
317 movable: true,
318 ref_count: 0,
319 },
320 );
321 }
322
323 blocks.insert(
325 offset,
326 MemoryBlock {
327 offset,
328 size: aligned_size,
329 is_free: false,
330 allocation_id: Some(alloc_id),
331 movable: true,
332 ref_count: 1,
333 },
334 );
335
336 let remainder = block.size - aligned_size - waste;
338 if remainder > 0 {
339 blocks.insert(
340 offset + aligned_size,
341 MemoryBlock {
342 offset: offset + aligned_size,
343 size: remainder,
344 is_free: true,
345 allocation_id: None,
346 movable: true,
347 ref_count: 0,
348 },
349 );
350 }
351 }
352
353 {
355 let mut offsets = self.allocation_offsets.write();
356 offsets.insert(alloc_id, offset);
357 }
358
359 {
361 let mut usage = self.current_usage.lock();
362 *usage = usage.saturating_add(aligned_size);
363
364 let mut peak = self.peak_usage.lock();
365 *peak = (*peak).max(*usage);
366
367 let mut count = self.allocation_count.lock();
368 *count = count.saturating_add(1);
369 }
370
371 Ok(MemoryAllocation {
372 id: alloc_id,
373 original_offset: offset,
374 size: aligned_size,
375 pool: Arc::clone(self),
376 })
377 }
378
379 pub fn get_allocation_offset(&self, alloc_id: u64) -> Option<u64> {
382 self.allocation_offsets.read().get(&alloc_id).copied()
383 }
384
385 pub fn pin_allocation(&self, alloc_id: u64) -> Result<()> {
387 let offsets = self.allocation_offsets.read();
388 let offset = offsets
389 .get(&alloc_id)
390 .copied()
391 .ok_or_else(|| GpuAdvancedError::memory_pool_error("Allocation not found"))?;
392 drop(offsets);
393
394 let mut blocks = self.blocks.write();
395 if let Some(block) = blocks.get_mut(&offset) {
396 block.movable = false;
397 Ok(())
398 } else {
399 Err(GpuAdvancedError::memory_pool_error(
400 "Block not found for allocation",
401 ))
402 }
403 }
404
405 pub fn unpin_allocation(&self, alloc_id: u64) -> Result<()> {
407 let offsets = self.allocation_offsets.read();
408 let offset = offsets
409 .get(&alloc_id)
410 .copied()
411 .ok_or_else(|| GpuAdvancedError::memory_pool_error("Allocation not found"))?;
412 drop(offsets);
413
414 let mut blocks = self.blocks.write();
415 if let Some(block) = blocks.get_mut(&offset) {
416 block.movable = true;
417 Ok(())
418 } else {
419 Err(GpuAdvancedError::memory_pool_error(
420 "Block not found for allocation",
421 ))
422 }
423 }
424
425 pub fn set_defrag_config(&self, config: DefragConfig) {
427 *self.defrag_config.write() = config;
428 }
429
430 pub fn get_defrag_config(&self) -> DefragConfig {
432 self.defrag_config.read().clone()
433 }
434
435 fn deallocate(&self, allocation: &MemoryAllocation) -> Result<()> {
437 let current_offset = self
439 .allocation_offsets
440 .read()
441 .get(&allocation.id)
442 .copied()
443 .unwrap_or(allocation.original_offset);
444
445 let mut blocks = self.blocks.write();
446
447 if let Some(block) = blocks.get_mut(¤t_offset) {
449 if block.allocation_id == Some(allocation.id) {
450 block.is_free = true;
451 block.allocation_id = None;
452 block.ref_count = 0;
453 } else {
454 return Err(GpuAdvancedError::memory_pool_error("Invalid allocation ID"));
455 }
456 } else {
457 return Err(GpuAdvancedError::memory_pool_error("Block not found"));
458 }
459
460 {
462 let mut offsets = self.allocation_offsets.write();
463 offsets.remove(&allocation.id);
464 }
465
466 {
468 let mut usage = self.current_usage.lock();
469 *usage = usage.saturating_sub(allocation.size);
470
471 let mut count = self.deallocation_count.lock();
472 *count = count.saturating_add(1);
473 }
474
475 self.coalesce_free_blocks(&mut blocks);
477
478 Ok(())
479 }
480
481 fn coalesce_free_blocks(&self, blocks: &mut BTreeMap<u64, MemoryBlock>) {
483 let mut to_merge: Vec<u64> = Vec::new();
484
485 let mut prev_offset: Option<u64> = None;
486 for (offset, block) in blocks.iter() {
487 if block.is_free {
488 if let Some(prev_off) = prev_offset
489 && let Some(prev_block) = blocks.get(&prev_off)
490 && prev_block.is_free
491 && prev_block.offset + prev_block.size == *offset
492 {
493 to_merge.push(*offset);
494 }
495 prev_offset = Some(*offset);
496 } else {
497 prev_offset = None;
498 }
499 }
500
501 for offset in to_merge {
503 if let Some(block) = blocks.remove(&offset) {
504 let prev_offset = blocks.range(..offset).next_back().map(|(k, _)| *k);
506
507 if let Some(prev_off) = prev_offset
508 && let Some(prev_block) = blocks.get_mut(&prev_off)
509 && prev_block.is_free
510 {
511 prev_block.size += block.size;
512 }
513 }
514 }
515 }
516
517 pub fn plan_defragmentation(&self) -> DefragmentationPlan {
522 let config = self.defrag_config.read().clone();
523 let blocks = self.blocks.read();
524
525 let current_fragmentation = self.calculate_fragmentation_internal(&blocks);
526
527 let mut allocated_blocks: Vec<_> = blocks
529 .iter()
530 .filter(|(_, b)| !b.is_free && b.allocation_id.is_some())
531 .map(|(offset, b)| (*offset, b.clone()))
532 .collect();
533
534 allocated_blocks.sort_by_key(|(offset, _)| *offset);
535
536 let mut moves = Vec::new();
538 let mut total_bytes = 0u64;
539 let mut next_offset = 0u64;
540
541 for (current_offset, block) in &allocated_blocks {
542 let aligned_offset = Self::align_up(next_offset, config.compaction_alignment);
543
544 if aligned_offset < *current_offset && block.movable {
546 if let Some(alloc_id) = block.allocation_id {
547 moves.push(DefragMove {
548 allocation_id: alloc_id,
549 src_offset: *current_offset,
550 dst_offset: aligned_offset,
551 size: block.size,
552 });
553 total_bytes += block.size;
554 }
555 next_offset = aligned_offset + block.size;
556 } else {
557 next_offset = current_offset + block.size;
559 }
560 }
561
562 let expected_fragmentation = if moves.is_empty() {
564 current_fragmentation
565 } else {
566 let unmovable_count = allocated_blocks.iter().filter(|(_, b)| !b.movable).count();
569 if unmovable_count == 0 {
570 0.0
571 } else {
572 (unmovable_count as f64 / allocated_blocks.len().max(1) as f64) * 0.5
574 }
575 };
576
577 DefragmentationPlan {
578 moves,
579 total_bytes,
580 expected_fragmentation,
581 current_fragmentation,
582 }
583 }
584
585 pub fn defragment(&self) -> Result<DefragmentationResult> {
593 let start = Instant::now();
594 let plan = self.plan_defragmentation();
595
596 if plan.moves.is_empty() {
597 return Ok(DefragmentationResult {
598 performed: false,
599 fragmentation_before: plan.current_fragmentation,
600 fragmentation_after: plan.current_fragmentation,
601 duration: start.elapsed(),
602 ..Default::default()
603 });
604 }
605
606 let config = self.defrag_config.read().clone();
607
608 if !plan.is_worthwhile(config.min_improvement) {
610 return Ok(DefragmentationResult {
611 performed: false,
612 fragmentation_before: plan.current_fragmentation,
613 fragmentation_after: plan.current_fragmentation,
614 duration: start.elapsed(),
615 ..Default::default()
616 });
617 }
618
619 let result = self.execute_defrag_plan_logical(&plan, &config)?;
621
622 {
624 let mut count = self.defrag_count.lock();
625 *count = count.saturating_add(1);
626 }
627
628 self.total_bytes_defragged
629 .fetch_add(result.bytes_moved, Ordering::Relaxed);
630
631 *self.last_defrag_time.lock() = Some(Instant::now());
632
633 Ok(DefragmentationResult {
634 duration: start.elapsed(),
635 ..result
636 })
637 }
638
639 pub fn defragment_with_queue(&self, queue: &Queue) -> Result<DefragmentationResult> {
650 let start = Instant::now();
651 let plan = self.plan_defragmentation();
652
653 if plan.moves.is_empty() {
654 return Ok(DefragmentationResult {
655 performed: false,
656 fragmentation_before: plan.current_fragmentation,
657 fragmentation_after: plan.current_fragmentation,
658 duration: start.elapsed(),
659 ..Default::default()
660 });
661 }
662
663 let config = self.defrag_config.read().clone();
664
665 if plan.current_fragmentation < config.min_fragmentation_threshold {
667 return Ok(DefragmentationResult {
668 performed: false,
669 fragmentation_before: plan.current_fragmentation,
670 fragmentation_after: plan.current_fragmentation,
671 duration: start.elapsed(),
672 ..Default::default()
673 });
674 }
675
676 if !plan.is_worthwhile(config.min_improvement) {
677 return Ok(DefragmentationResult {
678 performed: false,
679 fragmentation_before: plan.current_fragmentation,
680 fragmentation_after: plan.current_fragmentation,
681 duration: start.elapsed(),
682 ..Default::default()
683 });
684 }
685
686 let result = self.execute_defrag_plan_gpu(&plan, &config, queue)?;
688
689 {
691 let mut count = self.defrag_count.lock();
692 *count = count.saturating_add(1);
693 }
694
695 self.total_bytes_defragged
696 .fetch_add(result.bytes_moved, Ordering::Relaxed);
697
698 *self.last_defrag_time.lock() = Some(Instant::now());
699
700 Ok(DefragmentationResult {
701 duration: start.elapsed(),
702 ..result
703 })
704 }
705
706 fn execute_defrag_plan_logical(
708 &self,
709 plan: &DefragmentationPlan,
710 config: &DefragConfig,
711 ) -> Result<DefragmentationResult> {
712 let mut blocks = self.blocks.write();
713 let mut allocation_offsets = self.allocation_offsets.write();
714
715 let mut blocks_moved = 0usize;
716 let mut bytes_moved = 0u64;
717 let mut unmovable_blocks = 0usize;
718
719 let moves_to_execute: Vec<_> = plan
720 .moves
721 .iter()
722 .take(config.max_moves_per_pass)
723 .cloned()
724 .collect();
725
726 for defrag_move in &moves_to_execute {
727 let block = match blocks.remove(&defrag_move.src_offset) {
729 Some(b) => b,
730 None => {
731 if config.skip_unmovable {
732 unmovable_blocks += 1;
733 continue;
734 } else {
735 return Err(GpuAdvancedError::memory_pool_error(
736 "Block not found during defragmentation",
737 ));
738 }
739 }
740 };
741
742 if !block.movable {
743 blocks.insert(defrag_move.src_offset, block);
745 unmovable_blocks += 1;
746 continue;
747 }
748
749 let new_block = MemoryBlock {
751 offset: defrag_move.dst_offset,
752 size: block.size,
753 is_free: false,
754 allocation_id: block.allocation_id,
755 movable: block.movable,
756 ref_count: block.ref_count,
757 };
758
759 blocks.insert(defrag_move.dst_offset, new_block);
760
761 if let Some(alloc_id) = block.allocation_id {
763 allocation_offsets.insert(alloc_id, defrag_move.dst_offset);
764 }
765
766 blocks_moved += 1;
767 bytes_moved += defrag_move.size;
768 }
769
770 drop(blocks);
772 drop(allocation_offsets);
773 self.rebuild_free_blocks()?;
774
775 let blocks = self.blocks.read();
777 let fragmentation_after = self.calculate_fragmentation_internal(&blocks);
778
779 Ok(DefragmentationResult {
780 performed: blocks_moved > 0,
781 blocks_moved,
782 bytes_moved,
783 fragmentation_before: plan.current_fragmentation,
784 fragmentation_after,
785 duration: Duration::ZERO, unmovable_blocks,
787 })
788 }
789
790 fn execute_defrag_plan_gpu(
792 &self,
793 plan: &DefragmentationPlan,
794 config: &DefragConfig,
795 queue: &Queue,
796 ) -> Result<DefragmentationResult> {
797 let buffer_guard = self.buffer.lock();
798 let buffer = buffer_guard
799 .as_ref()
800 .ok_or_else(|| GpuAdvancedError::memory_pool_error("Pool buffer not available"))?;
801
802 let staging_buffer = self.device.create_buffer(&BufferDescriptor {
805 label: Some("Defrag Staging Buffer"),
806 size: plan.total_bytes,
807 usage: BufferUsages::COPY_SRC | BufferUsages::COPY_DST,
808 mapped_at_creation: false,
809 });
810
811 let moves_to_execute: Vec<_> = plan
812 .moves
813 .iter()
814 .take(config.max_moves_per_pass)
815 .cloned()
816 .collect();
817
818 let mut encoder = self
820 .device
821 .create_command_encoder(&CommandEncoderDescriptor {
822 label: Some("Defrag Copy to Staging"),
823 });
824
825 let mut staging_offset = 0u64;
826 let mut staging_map: Vec<(DefragMove, u64)> = Vec::new();
827
828 for defrag_move in &moves_to_execute {
829 encoder.copy_buffer_to_buffer(
830 buffer,
831 defrag_move.src_offset,
832 &staging_buffer,
833 staging_offset,
834 defrag_move.size,
835 );
836 staging_map.push((defrag_move.clone(), staging_offset));
837 staging_offset += defrag_move.size;
838 }
839
840 queue.submit(std::iter::once(encoder.finish()));
841
842 let mut encoder = self
844 .device
845 .create_command_encoder(&CommandEncoderDescriptor {
846 label: Some("Defrag Copy from Staging"),
847 });
848
849 for (defrag_move, staging_off) in &staging_map {
850 encoder.copy_buffer_to_buffer(
851 &staging_buffer,
852 *staging_off,
853 buffer,
854 defrag_move.dst_offset,
855 defrag_move.size,
856 );
857 }
858
859 queue.submit(std::iter::once(encoder.finish()));
860
861 drop(buffer_guard);
865
866 let mut blocks = self.blocks.write();
868 let mut allocation_offsets = self.allocation_offsets.write();
869
870 let mut blocks_moved = 0usize;
871 let mut bytes_moved = 0u64;
872 let mut unmovable_blocks = 0usize;
873
874 for defrag_move in &moves_to_execute {
875 let block = match blocks.remove(&defrag_move.src_offset) {
877 Some(b) => b,
878 None => {
879 unmovable_blocks += 1;
880 continue;
881 }
882 };
883
884 let new_block = MemoryBlock {
886 offset: defrag_move.dst_offset,
887 size: block.size,
888 is_free: false,
889 allocation_id: block.allocation_id,
890 movable: block.movable,
891 ref_count: block.ref_count,
892 };
893
894 blocks.insert(defrag_move.dst_offset, new_block);
895
896 if let Some(alloc_id) = block.allocation_id {
898 allocation_offsets.insert(alloc_id, defrag_move.dst_offset);
899 }
900
901 blocks_moved += 1;
902 bytes_moved += defrag_move.size;
903 }
904
905 drop(blocks);
906 drop(allocation_offsets);
907
908 self.rebuild_free_blocks()?;
910
911 let blocks = self.blocks.read();
913 let fragmentation_after = self.calculate_fragmentation_internal(&blocks);
914
915 Ok(DefragmentationResult {
916 performed: blocks_moved > 0,
917 blocks_moved,
918 bytes_moved,
919 fragmentation_before: plan.current_fragmentation,
920 fragmentation_after,
921 duration: Duration::ZERO, unmovable_blocks,
923 })
924 }
925
926 fn rebuild_free_blocks(&self) -> Result<()> {
930 let mut blocks = self.blocks.write();
931
932 let allocated_ranges: Vec<(u64, u64)> = blocks
934 .iter()
935 .filter(|(_, b)| !b.is_free)
936 .map(|(offset, b)| (*offset, b.size))
937 .collect();
938
939 let offsets_to_remove: Vec<u64> = blocks
941 .iter()
942 .filter(|(_, b)| b.is_free)
943 .map(|(offset, _)| *offset)
944 .collect();
945
946 for offset in offsets_to_remove {
947 blocks.remove(&offset);
948 }
949
950 let mut last_end = 0u64;
952
953 for (offset, size) in &allocated_ranges {
954 if *offset > last_end {
955 blocks.insert(
957 last_end,
958 MemoryBlock {
959 offset: last_end,
960 size: offset - last_end,
961 is_free: true,
962 allocation_id: None,
963 movable: true,
964 ref_count: 0,
965 },
966 );
967 }
968 last_end = offset + size;
969 }
970
971 if last_end < self.pool_size {
973 blocks.insert(
974 last_end,
975 MemoryBlock {
976 offset: last_end,
977 size: self.pool_size - last_end,
978 is_free: true,
979 allocation_id: None,
980 movable: true,
981 ref_count: 0,
982 },
983 );
984 }
985
986 self.coalesce_free_blocks(&mut blocks);
988
989 Ok(())
990 }
991
992 fn calculate_fragmentation_internal(&self, blocks: &BTreeMap<u64, MemoryBlock>) -> f64 {
994 let free_blocks: Vec<u64> = blocks
995 .values()
996 .filter(|b| b.is_free)
997 .map(|b| b.size)
998 .collect();
999
1000 self.calculate_fragmentation(&free_blocks)
1001 }
1002
1003 pub fn needs_defragmentation(&self) -> bool {
1005 let config = self.defrag_config.read();
1006 let stats = self.get_stats();
1007
1008 stats.fragmentation >= config.min_fragmentation_threshold
1009 }
1010
1011 pub fn get_fragmentation(&self) -> f64 {
1013 let blocks = self.blocks.read();
1014 self.calculate_fragmentation_internal(&blocks)
1015 }
1016
1017 pub fn get_total_bytes_defragged(&self) -> u64 {
1019 self.total_bytes_defragged.load(Ordering::Relaxed)
1020 }
1021
1022 pub fn time_since_last_defrag(&self) -> Option<Duration> {
1024 self.last_defrag_time
1025 .lock()
1026 .map(|instant| instant.elapsed())
1027 }
1028
1029 pub fn buffer(&self) -> Option<Buffer> {
1031 self.buffer.lock().as_ref().map(|_b| {
1033 self.device.create_buffer(&BufferDescriptor {
1034 label: Some("Memory Pool Access"),
1035 size: self.pool_size,
1036 usage: self.usage,
1037 mapped_at_creation: false,
1038 })
1039 })
1040 }
1041
1042 pub fn get_available_memory(&self) -> u64 {
1044 let blocks = self.blocks.read();
1045 blocks
1046 .values()
1047 .filter(|block| block.is_free)
1048 .map(|block| block.size)
1049 .sum()
1050 }
1051
1052 pub fn get_current_usage(&self) -> u64 {
1054 *self.current_usage.lock()
1055 }
1056
1057 pub fn get_peak_usage(&self) -> u64 {
1059 *self.peak_usage.lock()
1060 }
1061
1062 pub fn get_stats(&self) -> MemoryPoolStats {
1064 let blocks = self.blocks.read();
1065 let free_blocks: Vec<_> = blocks
1066 .values()
1067 .filter(|b| b.is_free)
1068 .map(|b| b.size)
1069 .collect();
1070
1071 let allocated_blocks: Vec<_> = blocks
1072 .values()
1073 .filter(|b| !b.is_free)
1074 .map(|b| b.size)
1075 .collect();
1076
1077 MemoryPoolStats {
1078 pool_size: self.pool_size,
1079 current_usage: *self.current_usage.lock(),
1080 peak_usage: *self.peak_usage.lock(),
1081 available: self.get_available_memory(),
1082 allocation_count: *self.allocation_count.lock(),
1083 deallocation_count: *self.deallocation_count.lock(),
1084 defrag_count: *self.defrag_count.lock(),
1085 free_block_count: free_blocks.len(),
1086 allocated_block_count: allocated_blocks.len(),
1087 largest_free_block: free_blocks.iter().max().copied().unwrap_or(0),
1088 fragmentation: self.calculate_fragmentation(&free_blocks),
1089 }
1090 }
1091
1092 fn calculate_fragmentation(&self, free_blocks: &[u64]) -> f64 {
1094 if free_blocks.is_empty() {
1095 return 0.0;
1096 }
1097
1098 let total_free: u64 = free_blocks.iter().sum();
1099 let largest = free_blocks.iter().max().copied().unwrap_or(0);
1100
1101 if total_free == 0 {
1102 return 0.0;
1103 }
1104
1105 1.0 - (largest as f64 / total_free as f64)
1106 }
1107
1108 fn align_up(value: u64, alignment: u64) -> u64 {
1110 if alignment == 0 {
1111 return value;
1112 }
1113 value.div_ceil(alignment) * alignment
1114 }
1115
1116 pub fn print_stats(&self) {
1118 let stats = self.get_stats();
1119 println!("\nMemory Pool Statistics:");
1120 println!(" Pool size: {} bytes", stats.pool_size);
1121 println!(
1122 " Current usage: {} bytes ({:.1}%)",
1123 stats.current_usage,
1124 (stats.current_usage as f64 / stats.pool_size as f64) * 100.0
1125 );
1126 println!(
1127 " Peak usage: {} bytes ({:.1}%)",
1128 stats.peak_usage,
1129 (stats.peak_usage as f64 / stats.pool_size as f64) * 100.0
1130 );
1131 println!(" Available: {} bytes", stats.available);
1132 println!(" Allocations: {}", stats.allocation_count);
1133 println!(" Deallocations: {}", stats.deallocation_count);
1134 println!(" Defragmentations: {}", stats.defrag_count);
1135 println!(" Free blocks: {}", stats.free_block_count);
1136 println!(" Allocated blocks: {}", stats.allocated_block_count);
1137 println!(" Largest free block: {} bytes", stats.largest_free_block);
1138 println!(" Fragmentation: {:.1}%", stats.fragmentation * 100.0);
1139 }
1140}
1141
1142#[derive(Debug, Clone)]
1144pub struct MemoryPoolStats {
1145 pub pool_size: u64,
1147 pub current_usage: u64,
1149 pub peak_usage: u64,
1151 pub available: u64,
1153 pub allocation_count: u64,
1155 pub deallocation_count: u64,
1157 pub defrag_count: u64,
1159 pub free_block_count: usize,
1161 pub allocated_block_count: usize,
1163 pub largest_free_block: u64,
1165 pub fragmentation: f64,
1167}
1168
1169impl MemoryAllocation {
1170 pub fn offset(&self) -> u64 {
1175 self.pool
1178 .get_allocation_offset(self.id)
1179 .unwrap_or(self.original_offset)
1180 }
1181
1182 pub fn size(&self) -> u64 {
1184 self.size
1185 }
1186
1187 pub fn range(&self) -> Range<u64> {
1189 let offset = self.offset();
1190 offset..(offset + self.size)
1191 }
1192
1193 pub fn id(&self) -> u64 {
1195 self.id
1196 }
1197}
1198
1199impl Drop for MemoryAllocation {
1200 fn drop(&mut self) {
1201 let _ = self.pool.deallocate(self);
1203 }
1204}
1205
1206#[cfg(test)]
1207mod tests {
1208 use super::*;
1209
1210 #[test]
1211 fn test_align_up() {
1212 assert_eq!(MemoryPool::align_up(0, 256), 0);
1213 assert_eq!(MemoryPool::align_up(1, 256), 256);
1214 assert_eq!(MemoryPool::align_up(256, 256), 256);
1215 assert_eq!(MemoryPool::align_up(257, 256), 512);
1216 }
1217
1218 #[test]
1219 fn test_memory_block() {
1220 let block = MemoryBlock {
1221 offset: 0,
1222 size: 1024,
1223 is_free: true,
1224 allocation_id: None,
1225 movable: true,
1226 ref_count: 0,
1227 };
1228
1229 assert!(block.is_free);
1230 assert_eq!(block.size, 1024);
1231 assert!(block.movable);
1232 assert_eq!(block.ref_count, 0);
1233 }
1234}