amari_core/
aligned_alloc.rs1use alloc::alloc::{alloc, dealloc, Layout};
7use alloc::boxed::Box;
8use alloc::vec;
9use alloc::vec::Vec;
10use core::ptr::NonNull;
11
12pub const AVX2_ALIGNMENT: usize = 32;
14
15pub const SSE_ALIGNMENT: usize = 16;
17
18pub const CACHE_LINE_SIZE: usize = 64;
20
21#[repr(C)]
23pub struct AlignedMemory<T> {
24 ptr: NonNull<T>,
25 layout: Layout,
26}
27
28impl<T> AlignedMemory<T> {
29 pub fn new(count: usize, alignment: usize) -> Result<Self, &'static str> {
31 let size = count * core::mem::size_of::<T>();
32 let layout = Layout::from_size_align(size, alignment)
33 .map_err(|_| "Invalid layout for aligned allocation")?;
34
35 let ptr = unsafe { alloc(layout) as *mut T };
36 if ptr.is_null() {
37 return Err("Failed to allocate aligned memory");
38 }
39
40 let ptr = unsafe { NonNull::new_unchecked(ptr) };
41
42 Ok(Self { ptr, layout })
43 }
44
45 pub fn as_ptr(&self) -> *const T {
47 self.ptr.as_ptr()
48 }
49
50 pub fn as_mut_ptr(&mut self) -> *mut T {
52 self.ptr.as_ptr()
53 }
54
55 pub fn capacity(&self) -> usize {
57 self.layout.size() / core::mem::size_of::<T>()
58 }
59}
60
61impl<T> Drop for AlignedMemory<T> {
62 fn drop(&mut self) {
63 unsafe {
64 dealloc(self.ptr.as_ptr() as *mut u8, self.layout);
65 }
66 }
67}
68
69pub fn create_aligned_f64_vec(count: usize) -> Vec<f64> {
71 if count <= 16 {
73 return vec![0.0; count];
74 }
75
76 let mut vec = Vec::with_capacity(count);
78 vec.resize(count, 0.0);
79
80 let ptr = vec.as_ptr() as usize;
82 if count == 8 && !ptr.is_multiple_of(AVX2_ALIGNMENT) {
83 let mut aligned_vec = Vec::with_capacity(count + (AVX2_ALIGNMENT / 8));
85 aligned_vec.resize(count, 0.0);
86
87 let start_ptr = aligned_vec.as_ptr() as usize;
89 let aligned_offset = (AVX2_ALIGNMENT - (start_ptr % AVX2_ALIGNMENT)) % AVX2_ALIGNMENT / 8;
90
91 if aligned_offset < aligned_vec.len() - count {
92 aligned_vec.drain(0..aligned_offset);
94 aligned_vec.truncate(count);
95 return aligned_vec;
96 }
97 }
98
99 vec
100}
101
102pub struct MemoryPool {
104 blocks: Vec<AlignedMemory<f64>>,
105 block_size: usize,
106 alignment: usize,
107}
108
109impl MemoryPool {
110 pub fn new(block_size: usize, alignment: usize) -> Self {
112 Self {
113 blocks: Vec::new(),
114 block_size,
115 alignment,
116 }
117 }
118
119 pub fn for_3d_clifford() -> Self {
121 Self::new(8, AVX2_ALIGNMENT)
123 }
124
125 pub fn allocate(&mut self) -> Result<Box<[f64]>, &'static str> {
127 let coefficients = create_aligned_f64_vec(self.block_size);
130 Ok(coefficients.into_boxed_slice())
131 }
132
133 pub fn pre_allocate(&mut self, count: usize) -> Result<(), &'static str> {
135 for _ in 0..count {
136 let block = AlignedMemory::new(self.block_size, self.alignment)?;
137 self.blocks.push(block);
138 }
139 Ok(())
140 }
141}
142
143pub struct AlignedCoefficients {
145 data: Box<[f64]>,
146}
147
148impl AlignedCoefficients {
149 pub fn new(count: usize) -> Self {
151 Self {
152 data: create_aligned_f64_vec(count).into_boxed_slice(),
153 }
154 }
155
156 pub fn zero(count: usize) -> Self {
158 let mut coeffs = Self::new(count);
159 coeffs.data.fill(0.0);
160 coeffs
161 }
162
163 pub fn as_slice(&self) -> &[f64] {
165 &self.data
166 }
167
168 pub fn as_mut_slice(&mut self) -> &mut [f64] {
170 &mut self.data
171 }
172
173 pub fn into_boxed_slice(self) -> Box<[f64]> {
175 self.data
176 }
177
178 pub fn is_simd_aligned(&self) -> bool {
180 let ptr = self.data.as_ptr() as usize;
181 ptr.is_multiple_of(AVX2_ALIGNMENT)
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_aligned_memory() {
191 let mem = AlignedMemory::<f64>::new(8, AVX2_ALIGNMENT).unwrap();
192 let ptr = mem.as_ptr() as usize;
193 assert_eq!(ptr % AVX2_ALIGNMENT, 0);
194 assert_eq!(mem.capacity(), 8);
195 }
196
197 #[test]
198 fn test_aligned_coefficients() {
199 let coeffs = AlignedCoefficients::zero(8);
200 assert_eq!(coeffs.as_slice().len(), 8);
201 assert!(coeffs.as_slice().iter().all(|&x| x == 0.0));
202 }
203
204 #[test]
205 fn test_memory_pool() {
206 let mut pool = MemoryPool::for_3d_clifford();
207 let _block = pool.allocate().unwrap();
208 assert_eq!(pool.block_size, 8);
209 assert_eq!(pool.alignment, AVX2_ALIGNMENT);
210 }
211
212 #[test]
213 fn test_aligned_f64_vec() {
214 let vec = create_aligned_f64_vec(8);
215 assert_eq!(vec.len(), 8);
216
217 let ptr = vec.as_ptr() as usize;
219 assert_eq!(ptr % 8, 0);
221 }
222}