axonml_core/allocator.rs
1//! Allocator - Memory Allocation Traits and Implementations
2//!
3//! Provides the allocator abstraction for device-specific memory management.
4//! Each backend implements the Allocator trait for its memory operations.
5//!
6//! # Key Features
7//! - Unified allocator trait for all devices
8//! - Pluggable allocator implementations
9//! - Memory pool support for performance
10//!
11//! @version 0.1.0
12//! @author `AutomataNexus` Development Team
13
14use crate::device::Device;
15use crate::dtype::Scalar;
16use crate::error::Result;
17use sysinfo::System;
18
19// =============================================================================
20// Default Allocator
21// =============================================================================
22
23/// Default CPU allocator using system memory.
24#[derive(Debug, Clone, Copy, Default)]
25pub struct DefaultAllocator;
26
27impl DefaultAllocator {
28 /// Creates a new default allocator.
29 #[must_use]
30 pub const fn new() -> Self {
31 Self
32 }
33
34 /// Returns the device this allocator is for.
35 #[must_use]
36 pub const fn device(&self) -> Device {
37 Device::Cpu
38 }
39
40 /// Allocates memory for `count` elements of type T.
41 pub fn allocate<T: Scalar>(&self, count: usize) -> Result<*mut T> {
42 let mut vec = Vec::<T>::with_capacity(count);
43 let ptr = vec.as_mut_ptr();
44 core::mem::forget(vec);
45 Ok(ptr)
46 }
47
48 /// Deallocates memory previously allocated.
49 ///
50 /// # Safety
51 /// The pointer must have been allocated by this allocator.
52 pub unsafe fn deallocate<T: Scalar>(&self, ptr: *mut T, count: usize) {
53 drop(Vec::from_raw_parts(ptr, 0, count));
54 }
55
56 /// Copies memory from one location to another.
57 ///
58 /// # Safety
59 /// Both pointers must be valid for `count` elements.
60 pub unsafe fn copy<T: Scalar>(&self, dst: *mut T, src: *const T, count: usize) {
61 core::ptr::copy_nonoverlapping(src, dst, count);
62 }
63
64 /// Fills memory with zeros.
65 ///
66 /// # Safety
67 /// The pointer must be valid for `count` elements.
68 pub unsafe fn zero<T: Scalar>(&self, ptr: *mut T, count: usize) {
69 core::ptr::write_bytes(ptr, 0, count);
70 }
71
72 /// Returns the total memory available on the device.
73 #[must_use]
74 pub fn total_memory(&self) -> usize {
75 let sys = System::new_all();
76 sys.total_memory() as usize
77 }
78
79 /// Returns the currently free memory on the device.
80 #[must_use]
81 pub fn free_memory(&self) -> usize {
82 let sys = System::new_all();
83 sys.available_memory() as usize
84 }
85}
86
87// =============================================================================
88// Allocator Trait (for future extensibility)
89// =============================================================================
90
91/// Marker trait for types that can act as allocators.
92///
93/// Note: Due to Rust's object safety rules, we use concrete types
94/// instead of dynamic dispatch for allocators.
95pub trait Allocator {
96 /// Returns the device this allocator is for.
97 fn device(&self) -> Device;
98
99 /// Returns the total memory available.
100 fn total_memory(&self) -> usize;
101
102 /// Returns the free memory available.
103 fn free_memory(&self) -> usize;
104}
105
106impl Allocator for DefaultAllocator {
107 fn device(&self) -> Device {
108 Device::Cpu
109 }
110
111 fn total_memory(&self) -> usize {
112 self.total_memory()
113 }
114
115 fn free_memory(&self) -> usize {
116 self.free_memory()
117 }
118}
119
120// =============================================================================
121// Tests
122// =============================================================================
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_default_allocator() {
130 let alloc = DefaultAllocator::new();
131 assert_eq!(alloc.device(), Device::Cpu);
132 assert!(alloc.total_memory() > 0);
133 }
134
135 #[test]
136 fn test_allocate_deallocate() {
137 let alloc = DefaultAllocator::new();
138
139 let ptr = alloc.allocate::<f32>(100).unwrap();
140 assert!(!ptr.is_null());
141
142 unsafe {
143 alloc.zero(ptr, 100);
144 alloc.deallocate(ptr, 100);
145 }
146 }
147
148 #[test]
149 fn test_copy() {
150 let alloc = DefaultAllocator::new();
151
152 let src = alloc.allocate::<f32>(10).unwrap();
153 let dst = alloc.allocate::<f32>(10).unwrap();
154
155 unsafe {
156 for i in 0..10 {
157 *src.add(i) = i as f32;
158 }
159
160 alloc.copy(dst, src, 10);
161
162 for i in 0..10 {
163 assert_eq!(*dst.add(i), i as f32);
164 }
165
166 alloc.deallocate(src, 10);
167 alloc.deallocate(dst, 10);
168 }
169 }
170}