1use crate::error_handling::{AutogradError, AutogradResult};
8use std::alloc::{alloc, dealloc, Layout};
9use std::collections::{HashMap, VecDeque};
10use std::ptr::NonNull;
11use std::sync::{Arc, Mutex, RwLock};
12use std::time::{Duration, Instant};
13use torsh_core::sync::{MutexExt, RwLockExt};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
17pub enum BufferSizeCategory {
18 Tiny = 0, Small = 1, Medium = 2, Large = 3, Huge = 4, }
24
25impl BufferSizeCategory {
26 pub fn from_size(size: usize) -> Self {
28 if size < 1024 {
29 BufferSizeCategory::Tiny
30 } else if size < 16 * 1024 {
31 BufferSizeCategory::Small
32 } else if size < 256 * 1024 {
33 BufferSizeCategory::Medium
34 } else if size < 4 * 1024 * 1024 {
35 BufferSizeCategory::Large
36 } else {
37 BufferSizeCategory::Huge
38 }
39 }
40
41 pub fn max_size(&self) -> usize {
43 match self {
44 BufferSizeCategory::Tiny => 1024,
45 BufferSizeCategory::Small => 16 * 1024,
46 BufferSizeCategory::Medium => 256 * 1024,
47 BufferSizeCategory::Large => 4 * 1024 * 1024,
48 BufferSizeCategory::Huge => usize::MAX,
49 }
50 }
51
52 pub fn min_size(&self) -> usize {
54 match self {
55 BufferSizeCategory::Tiny => 0,
56 BufferSizeCategory::Small => 1024,
57 BufferSizeCategory::Medium => 16 * 1024,
58 BufferSizeCategory::Large => 256 * 1024,
59 BufferSizeCategory::Huge => 4 * 1024 * 1024,
60 }
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum AllocationStrategy {
67 Pooled,
69 Direct,
71 Hybrid,
73 MemoryMapped,
75 StackBased,
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
81pub enum BufferAlignment {
82 None,
84 Align8 = 8,
86 Align16 = 16,
88 Align32 = 32,
90 Align64 = 64,
92 PageAligned = 4096,
94}
95
96#[derive(Debug, Clone)]
98pub struct BufferMetadata {
99 pub size: usize,
100 pub alignment: BufferAlignment,
101 pub category: BufferSizeCategory,
102 pub allocation_time: Instant,
103 pub last_access_time: Instant,
104 pub access_count: usize,
105 pub allocation_location: String,
106 pub is_active: bool,
107}
108
109#[derive(Debug)]
111pub struct TempBuffer {
112 ptr: NonNull<u8>,
113 metadata: BufferMetadata,
114 layout: Layout,
115}
116
117impl TempBuffer {
118 pub fn new(size: usize, alignment: BufferAlignment, location: &str) -> AutogradResult<Self> {
120 let align = match alignment {
121 BufferAlignment::None => 1,
122 BufferAlignment::Align8 => 8,
123 BufferAlignment::Align16 => 16,
124 BufferAlignment::Align32 => 32,
125 BufferAlignment::Align64 => 64,
126 BufferAlignment::PageAligned => 4096,
127 };
128
129 let layout = Layout::from_size_align(size, align).map_err(|e| {
130 AutogradError::gradient_computation(
131 "buffer_allocation",
132 format!("Invalid buffer layout: {}", e),
133 )
134 })?;
135
136 let ptr = unsafe { alloc(layout) };
137 if ptr.is_null() {
138 return Err(AutogradError::gradient_computation(
139 "buffer_allocation",
140 "Failed to allocate buffer memory",
141 ));
142 }
143
144 let metadata = BufferMetadata {
145 size,
146 alignment,
147 category: BufferSizeCategory::from_size(size),
148 allocation_time: Instant::now(),
149 last_access_time: Instant::now(),
150 access_count: 0,
151 allocation_location: location.to_string(),
152 is_active: true,
153 };
154
155 Ok(Self {
156 ptr: NonNull::new(ptr).expect("memory allocation returned null pointer"),
157 metadata,
158 layout,
159 })
160 }
161
162 pub fn as_ptr(&self) -> *mut u8 {
164 self.ptr.as_ptr()
165 }
166
167 pub fn as_mut_slice(&mut self) -> &mut [u8] {
169 self.metadata.last_access_time = Instant::now();
170 self.metadata.access_count += 1;
171 unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.metadata.size) }
172 }
173
174 pub fn size(&self) -> usize {
176 self.metadata.size
177 }
178
179 pub fn metadata(&self) -> &BufferMetadata {
181 &self.metadata
182 }
183
184 pub fn is_reusable(&self, required_size: usize, required_alignment: BufferAlignment) -> bool {
186 self.metadata.size >= required_size
187 && self.metadata.alignment as usize >= required_alignment as usize
188 }
189
190 pub fn mark_accessed(&mut self) {
192 self.metadata.last_access_time = Instant::now();
193 self.metadata.access_count += 1;
194 }
195}
196
197unsafe impl Send for TempBuffer {}
198unsafe impl Sync for TempBuffer {}
199
200impl Drop for TempBuffer {
201 fn drop(&mut self) {
202 unsafe {
203 dealloc(self.ptr.as_ptr(), self.layout);
204 }
205 }
206}
207
208#[derive(Debug)]
210pub struct BufferPool {
211 pools: HashMap<BufferSizeCategory, VecDeque<TempBuffer>>,
212 max_pool_size: usize,
213 max_idle_time: Duration,
214 allocation_stats: AllocationStats,
215}
216
217impl BufferPool {
218 pub fn new(max_pool_size: usize, max_idle_time: Duration) -> Self {
220 Self {
221 pools: HashMap::new(),
222 max_pool_size,
223 max_idle_time,
224 allocation_stats: AllocationStats::default(),
225 }
226 }
227
228 pub fn get_buffer(
230 &mut self,
231 size: usize,
232 alignment: BufferAlignment,
233 location: &str,
234 ) -> AutogradResult<TempBuffer> {
235 let category = BufferSizeCategory::from_size(size);
236
237 if let Some(pool) = self.pools.get_mut(&category) {
239 for i in 0..pool.len() {
241 if pool[i].is_reusable(size, alignment) {
242 let mut buffer = pool.remove(i).expect("index i is within pool bounds");
243 buffer.mark_accessed();
244 self.allocation_stats.pool_hits += 1;
245 return Ok(buffer);
246 }
247 }
248 }
249
250 let buffer = TempBuffer::new(size, alignment, location)?;
252 self.allocation_stats.new_allocations += 1;
253 self.allocation_stats.total_allocated += size;
254 Ok(buffer)
255 }
256
257 pub fn return_buffer(&mut self, mut buffer: TempBuffer) {
259 buffer.metadata.is_active = false;
260 let category = buffer.metadata.category;
261
262 self.cleanup_idle_buffers();
264
265 let pool = self.pools.entry(category).or_insert_with(VecDeque::new);
267 if pool.len() < self.max_pool_size {
268 pool.push_back(buffer);
269 } else {
270 self.allocation_stats.buffers_dropped += 1;
272 }
273 }
274
275 pub fn cleanup_idle_buffers(&mut self) {
277 let now = Instant::now();
278 let max_idle = self.max_idle_time;
279
280 for pool in self.pools.values_mut() {
281 pool.retain(|buffer| {
282 let idle_time = now.duration_since(buffer.metadata.last_access_time);
283 if idle_time > max_idle {
284 self.allocation_stats.buffers_cleaned += 1;
285 false
286 } else {
287 true
288 }
289 });
290 }
291 }
292
293 pub fn get_stats(&self) -> AllocationStats {
295 self.allocation_stats.clone()
296 }
297
298 pub fn get_pool_utilization(&self) -> HashMap<BufferSizeCategory, (usize, usize)> {
300 let mut utilization = HashMap::new();
301 for (&category, pool) in &self.pools {
302 utilization.insert(category, (pool.len(), self.max_pool_size));
303 }
304 utilization
305 }
306}
307
308#[derive(Debug, Clone, Default)]
310pub struct AllocationStats {
311 pub new_allocations: usize,
312 pub pool_hits: usize,
313 pub buffers_dropped: usize,
314 pub buffers_cleaned: usize,
315 pub total_allocated: usize,
316 pub peak_pool_size: usize,
317}
318
319impl AllocationStats {
320 pub fn hit_rate(&self) -> f64 {
322 let total_requests = self.new_allocations + self.pool_hits;
323 if total_requests == 0 {
324 0.0
325 } else {
326 self.pool_hits as f64 / total_requests as f64
327 }
328 }
329
330 pub fn average_allocation_size(&self) -> f64 {
332 if self.new_allocations == 0 {
333 0.0
334 } else {
335 self.total_allocated as f64 / self.new_allocations as f64
336 }
337 }
338}
339
340#[derive(Debug)]
342pub struct OptimizedBufferAllocator {
343 strategy: AllocationStrategy,
344 pool: Option<Arc<Mutex<BufferPool>>>,
345 allocation_patterns: AllocationPatternAnalyzer,
346 cache_optimization: CacheOptimizer,
347}
348
349impl OptimizedBufferAllocator {
350 pub fn new(strategy: AllocationStrategy) -> Self {
352 let pool = match strategy {
353 AllocationStrategy::Pooled | AllocationStrategy::Hybrid => {
354 Some(Arc::new(Mutex::new(BufferPool::new(
355 1000, Duration::from_secs(300), ))))
358 }
359 _ => None,
360 };
361
362 Self {
363 strategy,
364 pool,
365 allocation_patterns: AllocationPatternAnalyzer::new(),
366 cache_optimization: CacheOptimizer::new(),
367 }
368 }
369
370 pub fn allocate(
372 &mut self,
373 size: usize,
374 alignment: BufferAlignment,
375 location: &str,
376 ) -> AutogradResult<TempBuffer> {
377 self.allocation_patterns
379 .record_allocation(size, alignment, location);
380
381 let optimized_size = self.cache_optimization.optimize_size(size);
383 let optimized_alignment = self.cache_optimization.optimize_alignment(alignment);
384
385 match self.strategy {
386 AllocationStrategy::Pooled => {
387 if let Some(ref pool) = self.pool {
388 pool.lock_or_recover()
389 .get_buffer(optimized_size, optimized_alignment, location)
390 } else {
391 TempBuffer::new(optimized_size, optimized_alignment, location)
392 }
393 }
394 AllocationStrategy::Direct => {
395 TempBuffer::new(optimized_size, optimized_alignment, location)
396 }
397 AllocationStrategy::Hybrid => {
398 let category = BufferSizeCategory::from_size(optimized_size);
399 if matches!(
400 category,
401 BufferSizeCategory::Tiny
402 | BufferSizeCategory::Small
403 | BufferSizeCategory::Medium
404 ) {
405 if let Some(ref pool) = self.pool {
407 pool.lock_or_recover().get_buffer(
408 optimized_size,
409 optimized_alignment,
410 location,
411 )
412 } else {
413 TempBuffer::new(optimized_size, optimized_alignment, location)
414 }
415 } else {
416 TempBuffer::new(optimized_size, optimized_alignment, location)
418 }
419 }
420 AllocationStrategy::MemoryMapped => {
421 if optimized_size > 16 * 1024 * 1024 {
423 TempBuffer::new(optimized_size, optimized_alignment, location)
425 } else {
426 TempBuffer::new(optimized_size, optimized_alignment, location)
427 }
428 }
429 AllocationStrategy::StackBased => {
430 TempBuffer::new(optimized_size, optimized_alignment, location)
432 }
433 }
434 }
435
436 pub fn deallocate(&mut self, buffer: TempBuffer) {
438 match self.strategy {
439 AllocationStrategy::Pooled | AllocationStrategy::Hybrid => {
440 if let Some(ref pool) = self.pool {
441 pool.lock_or_recover().return_buffer(buffer);
442 }
443 }
445 _ => {
446 }
448 }
449 }
450
451 pub fn get_allocation_stats(&self) -> Option<AllocationStats> {
453 self.pool
454 .as_ref()
455 .map(|pool| pool.lock_or_recover().get_stats())
456 }
457
458 pub fn get_pattern_analysis(&self) -> &AllocationPatternAnalyzer {
460 &self.allocation_patterns
461 }
462
463 pub fn perform_maintenance(&mut self) {
465 if let Some(ref pool) = self.pool {
466 pool.lock_or_recover().cleanup_idle_buffers();
467 }
468 self.allocation_patterns.analyze_patterns();
469 self.cache_optimization
470 .update_optimizations(&self.allocation_patterns);
471 }
472}
473
474#[derive(Debug)]
476pub struct AllocationPatternAnalyzer {
477 allocation_history: VecDeque<AllocationRecord>,
478 size_frequency: HashMap<usize, usize>,
479 alignment_frequency: HashMap<BufferAlignment, usize>,
480 location_frequency: HashMap<String, usize>,
481 max_history_size: usize,
482}
483
484#[derive(Debug, Clone)]
485struct AllocationRecord {
486 size: usize,
487 alignment: BufferAlignment,
488 location: String,
489 timestamp: Instant,
490}
491
492impl AllocationPatternAnalyzer {
493 pub fn new() -> Self {
495 Self {
496 allocation_history: VecDeque::new(),
497 size_frequency: HashMap::new(),
498 alignment_frequency: HashMap::new(),
499 location_frequency: HashMap::new(),
500 max_history_size: 10000,
501 }
502 }
503
504 pub fn record_allocation(&mut self, size: usize, alignment: BufferAlignment, location: &str) {
506 let record = AllocationRecord {
507 size,
508 alignment,
509 location: location.to_string(),
510 timestamp: Instant::now(),
511 };
512
513 self.allocation_history.push_back(record);
514
515 *self.size_frequency.entry(size).or_insert(0) += 1;
517 *self.alignment_frequency.entry(alignment).or_insert(0) += 1;
518 *self
519 .location_frequency
520 .entry(location.to_string())
521 .or_insert(0) += 1;
522
523 if self.allocation_history.len() > self.max_history_size {
525 if let Some(old_record) = self.allocation_history.pop_front() {
526 if let Some(count) = self.size_frequency.get_mut(&old_record.size) {
528 *count = count.saturating_sub(1);
529 if *count == 0 {
530 self.size_frequency.remove(&old_record.size);
531 }
532 }
533 if let Some(count) = self.alignment_frequency.get_mut(&old_record.alignment) {
534 *count = count.saturating_sub(1);
535 if *count == 0 {
536 self.alignment_frequency.remove(&old_record.alignment);
537 }
538 }
539 if let Some(count) = self.location_frequency.get_mut(&old_record.location) {
540 *count = count.saturating_sub(1);
541 if *count == 0 {
542 self.location_frequency.remove(&old_record.location);
543 }
544 }
545 }
546 }
547 }
548
549 pub fn analyze_patterns(&self) -> PatternAnalysis {
551 let most_common_sizes: Vec<_> = {
552 let mut sizes: Vec<_> = self.size_frequency.iter().collect();
553 sizes.sort_by(|a, b| b.1.cmp(a.1));
554 sizes
555 .into_iter()
556 .take(10)
557 .map(|(&size, &count)| (size, count))
558 .collect()
559 };
560
561 let most_common_alignments: Vec<_> = {
562 let mut alignments: Vec<_> = self.alignment_frequency.iter().collect();
563 alignments.sort_by(|a, b| b.1.cmp(a.1));
564 alignments
565 .into_iter()
566 .take(5)
567 .map(|(&alignment, &count)| (alignment, count))
568 .collect()
569 };
570
571 let hottest_locations: Vec<_> = {
572 let mut locations: Vec<_> = self.location_frequency.iter().collect();
573 locations.sort_by(|a, b| b.1.cmp(a.1));
574 locations
575 .into_iter()
576 .take(10)
577 .map(|(location, &count)| (location.clone(), count))
578 .collect()
579 };
580
581 PatternAnalysis {
582 total_allocations: self.allocation_history.len(),
583 most_common_sizes,
584 most_common_alignments,
585 hottest_locations,
586 }
587 }
588
589 pub fn get_allocation_rate(&self) -> f64 {
591 if self.allocation_history.is_empty() {
592 return 0.0;
593 }
594
595 let now = Instant::now();
596 let cutoff = now - Duration::from_secs(60); let recent_allocations = self
599 .allocation_history
600 .iter()
601 .rev()
602 .take_while(|record| record.timestamp > cutoff)
603 .count();
604
605 recent_allocations as f64 / 60.0
606 }
607}
608
609#[derive(Debug)]
611pub struct PatternAnalysis {
612 pub total_allocations: usize,
613 pub most_common_sizes: Vec<(usize, usize)>,
614 pub most_common_alignments: Vec<(BufferAlignment, usize)>,
615 pub hottest_locations: Vec<(String, usize)>,
616}
617
618#[derive(Debug)]
620pub struct CacheOptimizer {
621 cache_line_size: usize,
622 preferred_alignments: HashMap<usize, BufferAlignment>,
623 size_adjustments: HashMap<usize, usize>,
624}
625
626impl CacheOptimizer {
627 pub fn new() -> Self {
629 Self {
630 cache_line_size: 64, preferred_alignments: HashMap::new(),
632 size_adjustments: HashMap::new(),
633 }
634 }
635
636 pub fn optimize_size(&self, size: usize) -> usize {
638 if let Some(&adjusted_size) = self.size_adjustments.get(&size) {
640 return adjusted_size;
641 }
642
643 if size > self.cache_line_size {
645 let cache_lines = (size + self.cache_line_size - 1) / self.cache_line_size;
646 cache_lines * self.cache_line_size
647 } else {
648 size.next_power_of_two()
650 }
651 }
652
653 pub fn optimize_alignment(&self, alignment: BufferAlignment) -> BufferAlignment {
655 match alignment {
656 BufferAlignment::None => BufferAlignment::Align8,
657 BufferAlignment::Align8 => BufferAlignment::Align16,
658 other => other,
659 }
660 }
661
662 pub fn update_optimizations(&mut self, analyzer: &AllocationPatternAnalyzer) {
664 let analysis = analyzer.analyze_patterns();
665
666 for (alignment, count) in analysis.most_common_alignments {
668 if count > 100 {
669 for (size, _) in &analysis.most_common_sizes {
671 self.preferred_alignments.insert(*size, alignment);
672 }
673 }
674 }
675 }
676}
677
678static GLOBAL_ALLOCATOR: std::sync::OnceLock<Arc<RwLock<OptimizedBufferAllocator>>> =
680 std::sync::OnceLock::new();
681
682pub fn get_global_allocator() -> &'static Arc<RwLock<OptimizedBufferAllocator>> {
684 GLOBAL_ALLOCATOR.get_or_init(|| {
685 Arc::new(RwLock::new(OptimizedBufferAllocator::new(
686 AllocationStrategy::Hybrid,
687 )))
688 })
689}
690
691pub fn allocate_temp_buffer(
693 size: usize,
694 alignment: BufferAlignment,
695 location: &str,
696) -> AutogradResult<TempBuffer> {
697 get_global_allocator()
698 .write_or_recover()
699 .allocate(size, alignment, location)
700}
701
702pub fn deallocate_temp_buffer(buffer: TempBuffer) {
703 get_global_allocator().write_or_recover().deallocate(buffer);
704}
705
706pub fn get_global_allocation_stats() -> Option<AllocationStats> {
707 get_global_allocator()
708 .read_or_recover()
709 .get_allocation_stats()
710}
711
712pub fn perform_global_maintenance() {
713 get_global_allocator()
714 .write_or_recover()
715 .perform_maintenance();
716}
717
718#[derive(Debug)]
720pub struct AutoBuffer {
721 buffer: Option<TempBuffer>,
722}
723
724impl AutoBuffer {
725 pub fn new(size: usize, alignment: BufferAlignment, location: &str) -> AutogradResult<Self> {
727 let buffer = allocate_temp_buffer(size, alignment, location)?;
728 Ok(Self {
729 buffer: Some(buffer),
730 })
731 }
732
733 pub fn as_mut_slice(&mut self) -> Option<&mut [u8]> {
735 self.buffer.as_mut().map(|b| b.as_mut_slice())
736 }
737
738 pub fn size(&self) -> Option<usize> {
740 self.buffer.as_ref().map(|b| b.size())
741 }
742
743 pub fn take(mut self) -> Option<TempBuffer> {
745 self.buffer.take()
746 }
747}
748
749impl Drop for AutoBuffer {
750 fn drop(&mut self) {
751 if let Some(buffer) = self.buffer.take() {
752 deallocate_temp_buffer(buffer);
753 }
754 }
755}
756
757#[macro_export]
759macro_rules! temp_buffer {
760 ($size:expr) => {
761 $crate::buffer_optimization::AutoBuffer::new(
762 $size,
763 $crate::buffer_optimization::BufferAlignment::Align16,
764 concat!(file!(), ":", line!()),
765 )
766 };
767 ($size:expr, $align:expr) => {
768 $crate::buffer_optimization::AutoBuffer::new($size, $align, concat!(file!(), ":", line!()))
769 };
770}
771
772#[cfg(test)]
773mod tests {
774 use super::*;
775
776 #[test]
777 fn test_buffer_size_category() {
778 assert_eq!(BufferSizeCategory::from_size(512), BufferSizeCategory::Tiny);
779 assert_eq!(
780 BufferSizeCategory::from_size(8192),
781 BufferSizeCategory::Small
782 );
783 assert_eq!(
784 BufferSizeCategory::from_size(128 * 1024),
785 BufferSizeCategory::Medium
786 );
787 assert_eq!(
788 BufferSizeCategory::from_size(2 * 1024 * 1024),
789 BufferSizeCategory::Large
790 );
791 assert_eq!(
792 BufferSizeCategory::from_size(8 * 1024 * 1024),
793 BufferSizeCategory::Huge
794 );
795 }
796
797 #[test]
798 fn test_temp_buffer_creation() {
799 let buffer = TempBuffer::new(1024, BufferAlignment::Align16, "test").unwrap();
800 assert_eq!(buffer.size(), 1024);
801 assert_eq!(buffer.metadata().alignment, BufferAlignment::Align16);
802 }
803
804 #[test]
805 fn test_buffer_pool() {
806 let mut pool = BufferPool::new(10, Duration::from_secs(60));
807
808 let buffer1 = pool
810 .get_buffer(1024, BufferAlignment::Align16, "test1")
811 .unwrap();
812 assert_eq!(buffer1.size(), 1024);
813
814 pool.return_buffer(buffer1);
816
817 let buffer2 = pool
819 .get_buffer(1024, BufferAlignment::Align16, "test2")
820 .unwrap();
821 assert_eq!(buffer2.size(), 1024);
822
823 let stats = pool.get_stats();
824 assert_eq!(stats.pool_hits, 1);
825 assert_eq!(stats.new_allocations, 1);
826 }
827
828 #[test]
829 fn test_optimized_allocator() {
830 let mut allocator = OptimizedBufferAllocator::new(AllocationStrategy::Pooled);
831
832 let buffer1 = allocator
833 .allocate(1024, BufferAlignment::Align16, "test1")
834 .unwrap();
835 assert_eq!(buffer1.size(), 1024);
836
837 allocator.deallocate(buffer1);
838
839 let buffer2 = allocator
840 .allocate(1024, BufferAlignment::Align16, "test2")
841 .unwrap();
842 assert_eq!(buffer2.size(), 1024);
843
844 if let Some(stats) = allocator.get_allocation_stats() {
845 assert!(stats.total_allocated > 0);
846 }
847 }
848
849 #[test]
850 fn test_allocation_pattern_analyzer() {
851 let mut analyzer = AllocationPatternAnalyzer::new();
852
853 analyzer.record_allocation(1024, BufferAlignment::Align16, "test1");
855 analyzer.record_allocation(1024, BufferAlignment::Align16, "test2");
856 analyzer.record_allocation(2048, BufferAlignment::Align32, "test3");
857
858 let analysis = analyzer.analyze_patterns();
859 assert_eq!(analysis.total_allocations, 3);
860 assert!(!analysis.most_common_sizes.is_empty());
861 assert!(!analysis.most_common_alignments.is_empty());
862
863 let rate = analyzer.get_allocation_rate();
864 assert!(rate >= 0.0);
865 }
866
867 #[test]
868 fn test_cache_optimizer() {
869 let optimizer = CacheOptimizer::new();
870
871 let optimized_size = optimizer.optimize_size(100);
873 assert!(optimized_size >= 100);
874
875 let optimized_alignment = optimizer.optimize_alignment(BufferAlignment::None);
877 assert_ne!(optimized_alignment, BufferAlignment::None);
878 }
879
880 #[test]
881 fn test_auto_buffer() {
882 let mut auto_buffer = AutoBuffer::new(1024, BufferAlignment::Align16, "test").unwrap();
883 assert_eq!(auto_buffer.size(), Some(1024));
884
885 if let Some(slice) = auto_buffer.as_mut_slice() {
886 assert_eq!(slice.len(), 1024);
887 slice[0] = 42;
888 assert_eq!(slice[0], 42);
889 }
890 }
891
892 #[test]
893 fn test_global_allocator() {
894 let buffer = allocate_temp_buffer(1024, BufferAlignment::Align16, "test").unwrap();
895 assert_eq!(buffer.size(), 1024);
896
897 deallocate_temp_buffer(buffer);
898
899 if let Some(stats) = get_global_allocation_stats() {
900 assert!(stats.total_allocated > 0);
901 }
902
903 perform_global_maintenance();
904 }
905}