use std::{
marker::PhantomData,
ops::Range,
ptr::NonNull,
sync::{atomic::AtomicUsize, Arc},
};
use tracing::trace;
use crate::{
lamellae::{CommProgress, CommSlice, Lamellae, Remote},
lamellar_team::IntoLamellarTeam,
memregion::{LamellarMemoryRegion, OneSidedMemoryRegion, SharedMemoryRegion},
};
pub trait AsLamellarBuffer<T: Remote>: Send + 'static {
fn as_slice(&self) -> &[T];
fn as_mut_slice(&mut self) -> &mut [T];
}
impl<T: Remote> AsLamellarBuffer<T> for Vec<T> {
fn as_slice(&self) -> &[T] {
self.as_slice()
}
fn as_mut_slice(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T: Remote> AsLamellarBuffer<T> for LamellarMemoryRegion<T> {
fn as_slice(&self) -> &[T] {
unsafe { self.as_slice() }
}
fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { LamellarMemoryRegion::as_mut_slice(self) }
}
}
impl<T: Remote> AsLamellarBuffer<T> for SharedMemoryRegion<T> {
fn as_slice(&self) -> &[T] {
unsafe { self.as_slice() }
}
fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { SharedMemoryRegion::as_mut_slice(self) }
}
}
impl<T: Remote> AsLamellarBuffer<T> for OneSidedMemoryRegion<T> {
fn as_slice(&self) -> &[T] {
unsafe { self.as_slice() }
}
fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { OneSidedMemoryRegion::as_mut_slice(self) }
}
}
impl<T: Remote> AsLamellarBuffer<T> for CommSlice<T> {
fn as_slice(&self) -> &[T] {
self.as_slice()
}
fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { self.as_mut_slice() }
}
}
struct BufferInner<T> {
cnt: AtomicUsize,
data: T,
}
unsafe impl<T: Send> Send for BufferInner<T> {}
unsafe impl<T: Sync> Sync for BufferInner<T> {}
impl<T> BufferInner<T> {
fn new(data: T) -> Self {
BufferInner {
cnt: AtomicUsize::new(1),
data,
}
}
}
pub struct LamellarBuffer<T: Remote, B: AsLamellarBuffer<T>> {
data: NonNull<BufferInner<B>>,
range: Range<usize>,
lamellae: Arc<Lamellae>,
_phantom: PhantomData<T>,
}
unsafe impl<T: Remote, B: AsLamellarBuffer<T>> Send for LamellarBuffer<T, B> {}
unsafe impl<T: Remote, B: AsLamellarBuffer<T>> Sync for LamellarBuffer<T, B> {}
impl<T: Remote, B: AsLamellarBuffer<T>> std::fmt::Debug for LamellarBuffer<T, B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"LamellarBuffer(range={:?}, current cnt={:?})",
self.range,
unsafe {
self.data
.as_ref()
.cnt
.load(std::sync::atomic::Ordering::SeqCst)
}
)
}
}
impl<T: Remote> LamellarBuffer<T, SharedMemoryRegion<T>> {
pub unsafe fn from_shared_memory_region(mem_region: SharedMemoryRegion<T>) -> Self {
let len = mem_region.len();
let lamellae = mem_region.lamellae();
LamellarBuffer {
data: NonNull::new(Box::into_raw(Box::new(BufferInner::new(mem_region))).into())
.unwrap(),
range: 0..len,
lamellae,
_phantom: PhantomData,
}
}
}
impl<T: Remote> From<SharedMemoryRegion<T>> for LamellarBuffer<T, SharedMemoryRegion<T>> {
fn from(mem_region: SharedMemoryRegion<T>) -> Self {
unsafe { LamellarBuffer::from_shared_memory_region(mem_region) }
}
}
impl<T: Remote> LamellarBuffer<T, OneSidedMemoryRegion<T>> {
pub unsafe fn from_one_sided_memory_region(mem_region: OneSidedMemoryRegion<T>) -> Self {
let len = mem_region.len();
let lamellae = mem_region.lamellae();
LamellarBuffer {
data: NonNull::new(Box::into_raw(Box::new(BufferInner::new(mem_region))).into())
.unwrap(),
range: 0..len,
lamellae,
_phantom: PhantomData,
}
}
}
impl<T: Remote> From<OneSidedMemoryRegion<T>> for LamellarBuffer<T, OneSidedMemoryRegion<T>> {
fn from(mem_region: OneSidedMemoryRegion<T>) -> Self {
unsafe { LamellarBuffer::from_one_sided_memory_region(mem_region) }
}
}
impl<T: Remote> LamellarBuffer<T, CommSlice<T>> {
pub(crate) unsafe fn from_comm_slice(
comm_slice: CommSlice<T>,
lamellae: Arc<Lamellae>,
) -> Self {
let len = comm_slice.len();
trace!(target: "lamellae_debug", "creating LamellarBuffer from CommSlice with len {:?} lamellae cnt: {:?}", len, Arc::strong_count(&lamellae));
LamellarBuffer {
data: NonNull::new(Box::into_raw(Box::new(BufferInner::new(comm_slice))).into())
.unwrap(),
range: 0..len,
lamellae,
_phantom: PhantomData,
}
}
}
impl<T: Remote> LamellarBuffer<T, Vec<T>> {
pub fn from_vec<U: Into<IntoLamellarTeam>>(team: U, vec: Vec<T>) -> Self {
let len = vec.len();
let lamellae = team.into().team.lamellae.clone();
LamellarBuffer {
data: NonNull::new(Box::into_raw(Box::new(BufferInner::new(vec))).into()).unwrap(),
range: 0..len,
lamellae,
_phantom: PhantomData,
}
}
pub(crate) fn from_vec_with_lamellae(vec: Vec<T>, lamellae: Arc<Lamellae>) -> Self {
let len = vec.len();
trace!(target: "lamellae_debug", "creating LamellarBuffer from Vec with len {:?} lamellae cnt: {:?}", len, Arc::strong_count(&lamellae));
LamellarBuffer {
data: NonNull::new(Box::into_raw(Box::new(BufferInner::new(vec))).into()).unwrap(),
range: 0..len,
lamellae,
_phantom: PhantomData,
}
}
}
impl<T: Remote, B: AsLamellarBuffer<T>> LamellarBuffer<T, B> {
pub fn len(&self) -> usize {
self.range.end - self.range.start
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn split(self, at: usize) -> (Self, Self) {
unsafe {
self.data
.as_ref()
.cnt
.fetch_add(2, std::sync::atomic::Ordering::SeqCst)
}; assert!(at <= self.len());
let left = LamellarBuffer {
data: self.data.clone(),
range: self.range.start..(self.range.start + at),
lamellae: self.lamellae.clone(),
_phantom: PhantomData,
};
let right = LamellarBuffer {
data: self.data,
range: (self.range.start + at)..self.range.end,
lamellae: self.lamellae.clone(),
_phantom: PhantomData,
};
trace!(target: "lamellae_debug", "split LamellarBuffer at {:?} into left range {:?} and right range {:?} lamellae cnt: {:?}", at, left.range, right.range, Arc::strong_count(&self.lamellae));
(left, right)
}
pub fn split_off(&mut self, at: usize) -> Self {
unsafe {
self.data
.as_ref()
.cnt
.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
};
assert!(at <= self.len());
let right = LamellarBuffer {
data: self.data,
range: (self.range.start + at)..self.range.end,
lamellae: self.lamellae.clone(),
_phantom: PhantomData,
};
self.range = self.range.start..(self.range.start + at);
trace!(target: "lamellae_debug", "split_off LamellarBuffer at {:?} into left range {:?} and right range {:?} lamellae cnt: {:?}", at, self.range, right.range, Arc::strong_count(&self.lamellae));
right
}
pub fn try_unwrap(self) -> Result<B, Self> {
if unsafe {
self.data
.as_ref()
.cnt
.load(std::sync::atomic::Ordering::SeqCst)
} == 1
{
let mut this = std::mem::ManuallyDrop::new(self);
let data = unsafe { Box::from_raw(this.data.as_ptr()) };
unsafe { std::ptr::drop_in_place(&mut this.lamellae as *mut Arc<Lamellae>) };
Ok(data.data)
} else {
Err(self)
}
}
pub async fn async_unwrap(self) -> B {
while unsafe {
self.data
.as_ref()
.cnt
.load(std::sync::atomic::Ordering::SeqCst)
} != 1
{
trace!("Waiting to unwrap LamellarBuffer: {:?}", self);
async_std::task::yield_now().await;
}
let mut this = std::mem::ManuallyDrop::new(self);
let data = unsafe { Box::from_raw(this.data.as_ptr()) };
trace!(target: "lamellae_debug", "successfully unwrapped LamellarBuffer, lamellae cnt: {:?}", Arc::strong_count(&this.lamellae));
unsafe { std::ptr::drop_in_place(&mut this.lamellae as *mut Arc<Lamellae>) };
data.data
}
pub fn try_reset(&mut self) -> bool {
if unsafe {
self.data
.as_ref()
.cnt
.load(std::sync::atomic::Ordering::SeqCst)
} == 1
{
let len = self.as_slice().len();
self.range = 0..len;
true
} else {
false
}
}
pub fn as_slice(&self) -> &[T] {
unsafe { &self.data.as_ref().data.as_slice()[self.range.clone()] }
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { &mut self.data.as_mut().data.as_mut_slice()[self.range.clone()] }
}
#[allow(dead_code)]
pub(crate) unsafe fn orig_as_slice(&self) -> &[T] {
unsafe { self.data.as_ref().data.as_slice() }
}
#[allow(dead_code)]
pub(crate) unsafe fn orig_as_casted_slice<P>(&self) -> &[P] {
unsafe {
std::slice::from_raw_parts(
self.data.as_ref().data.as_slice().as_ptr() as *const P,
self.data.as_ref().data.as_slice().len() * std::mem::size_of::<T>()
/ std::mem::size_of::<P>(),
)
}
}
#[allow(dead_code)]
pub(crate) unsafe fn orig_as_ptr(&self) -> *const T {
unsafe { self.data.as_ref().data.as_slice().as_ptr() as *const T }
}
#[allow(dead_code)]
pub(crate) unsafe fn orig_as_casted_ptr<P>(&self) -> *const P {
unsafe { self.data.as_ref().data.as_slice().as_ptr() as *const P }
}
#[allow(dead_code)]
pub(crate) fn orig_num_bytes(&self) -> usize {
unsafe { &self.data.as_ref().data.as_slice().len() * std::mem::size_of::<T>() }
}
}
impl<T: Remote, B: AsLamellarBuffer<T>> Drop for LamellarBuffer<T, B> {
fn drop(&mut self) {
trace!(target: "drop", "begin drop LamellarBuffer");
if unsafe {
self.data
.as_ref()
.cnt
.fetch_sub(1, std::sync::atomic::Ordering::SeqCst)
} == 1
{
self.lamellae.comm().flush_all();
unsafe {
let _ = Box::from_raw(self.data.as_ptr());
}
}
trace!(target: "lamellae_debug", "end drop LamellarBuffer lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
}
}