#![allow(dead_code)] /* This file is almost identical to the aligned_memory.rs file in the spiral-rs crate. The name is modified from AlignedMemory to AlignedMemoryMT, and there is one (unsafe!) change to the API: pub unsafe fn as_mut_ptr(&mut self) -> *mut u64 has changed to: pub unsafe fn as_mut_ptr(&self) -> *mut u64 The reason for this change is explicitly to allow multiple threads to *write* into the memory pool concurrently, with the caveat that the threads *must not* try to write into the same memory location. In Spiral, each polynomial created from the database ends up scattered into noncontiguous words of memory, but any one word still only comes from one polynomial. So with this change, different threads can read different parts of the database to produce different polynomials, and write those polynomials into the same memory pool (but *not* the same memory locations) at the same time. */ use std::{ alloc::{alloc_zeroed, dealloc, Layout}, mem::size_of, ops::{Index, IndexMut}, slice::{from_raw_parts, from_raw_parts_mut}, }; const ALIGN_SIMD: usize = 64; // enough to support AVX-512 pub type AlignedMemoryMT64 = AlignedMemoryMT; pub struct AlignedMemoryMT { p: *mut u64, sz_u64: usize, layout: Layout, } impl AlignedMemoryMT<{ ALIGN }> { pub fn new(sz_u64: usize) -> Self { let sz_bytes = sz_u64 * size_of::(); let layout = Layout::from_size_align(sz_bytes, ALIGN).unwrap(); let ptr; unsafe { ptr = alloc_zeroed(layout); } Self { p: ptr as *mut u64, sz_u64, layout, } } // pub fn from(data: &[u8]) -> Self { // let sz_u64 = (data.len() + size_of::() - 1) / size_of::(); // let mut out = Self::new(sz_u64); // let out_slice = out.as_mut_slice(); // let mut i = 0; // for chunk in data.chunks(size_of::()) { // out_slice[i] = u64::from_ne_bytes(chunk); // i += 1; // } // out // } pub fn as_slice(&self) -> &[u64] { unsafe { from_raw_parts(self.p, self.sz_u64) } } pub fn as_mut_slice(&mut self) -> &mut [u64] { unsafe { from_raw_parts_mut(self.p, self.sz_u64) } } pub unsafe fn as_ptr(&self) -> *const u64 { self.p } pub unsafe fn as_mut_ptr(&self) -> *mut u64 { self.p } pub fn len(&self) -> usize { self.sz_u64 } } unsafe impl Send for AlignedMemoryMT<{ ALIGN }> {} unsafe impl Sync for AlignedMemoryMT<{ ALIGN }> {} impl Drop for AlignedMemoryMT<{ ALIGN }> { fn drop(&mut self) { unsafe { dealloc(self.p as *mut u8, self.layout); } } } impl Index for AlignedMemoryMT<{ ALIGN }> { type Output = u64; fn index(&self, index: usize) -> &Self::Output { &self.as_slice()[index] } } impl IndexMut for AlignedMemoryMT<{ ALIGN }> { fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut self.as_mut_slice()[index] } } impl Clone for AlignedMemoryMT<{ ALIGN }> { fn clone(&self) -> Self { let mut out = Self::new(self.sz_u64); out.as_mut_slice().copy_from_slice(self.as_slice()); out } }