use crate::{
active_messaging::{AMCounters, AmDist, RemotePtr},
array::{
LamellarArrayRdmaInput, LamellarArrayRdmaOutput, LamellarRead, LamellarWrite, TeamFrom,
TeamTryFrom,
},
darc::Darc,
lamellae::{
collective::{
BroadcastInput, CollectiveAllGatherIntoBufferOpHandle, CollectiveAllGatherOpHandle,
CollectiveAllReduceInPlaceOpHandle, CollectiveAllReduceIntoBufferOpHandle,
CollectiveAllReduceOpHandle, CollectiveAllToAllIntoBufferOpHandle,
CollectiveAllToAllOpHandle, CollectiveBroadcastIntoBufferOpHandle,
CollectiveBroadcastOpHandle, CollectiveGatherIntoBufferOpHandle,
CollectiveGatherOpHandle, CollectiveReduceIntoBufferOpHandle, CollectiveReduceOpHandle,
CollectiveReduceScatterIntoBufferOpHandle, CollectiveReduceScatterOpHandle,
CollectiveScatterIntoBufferOpHandle, CollectiveScatterOpHandle,
CommAllocCollectiveAllGather, CommAllocCollectiveAllReduce,
CommAllocCollectiveAllToAll, CommAllocCollectiveBroadcast, CommAllocCollectiveGather,
CommAllocCollectiveReduce, CommAllocCollectiveReduceScatter,
CommAllocCollectiveScatter, ReduceOp, RootOrLamellarBuffer, RootSrcOrLamellarBuffer,
ScatterInput,
},
AllocationType, AtomicFetchOpHandle, AtomicOp, AtomicOpHandle, Backend, CommAlloc,
CommAllocAddr, CommAllocAtomic, CommAllocRdma, CommInfo, CommMem, CommProgress, CommSlice,
Lamellae, RdmaGetBufferHandle, RdmaGetHandle, RdmaGetIntoBufferHandle, RdmaHandle, Remote,
},
lamellar_team::{LamellarTeam, LamellarTeamRT},
scheduler::Scheduler,
LamellarEnv,
};
use core::marker::PhantomData;
use std::sync::Arc;
use std::{
hash::{Hash, Hasher},
sync::atomic::AtomicUsize,
};
pub mod prelude;
pub(crate) mod shared;
pub use shared::SharedMemoryRegion;
pub(crate) mod one_sided;
pub use one_sided::OneSidedMemoryRegion;
pub(crate) mod handle;
use handle::{FallibleSharedMemoryRegionHandle, SharedMemoryRegionHandle};
pub(crate) mod input;
pub use input::MemregionRdmaInput;
pub(crate) use input::MemregionRdmaInputInner;
pub(crate) mod buffer;
pub use buffer::{AsLamellarBuffer, LamellarBuffer};
use enum_dispatch::enum_dispatch;
use tracing::trace;
#[derive(Debug, Clone, Copy)]
pub enum MemRegionError {
MemNotLocalError,
MemNotAlignedError,
}
impl std::fmt::Display for MemRegionError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MemRegionError::MemNotLocalError => write!(
f,
"trying to access the local data of a mem region that is remote",
),
MemRegionError::MemNotAlignedError => {
write!(f, "trying to convert a mem region to a non aligned type",)
}
}
}
}
impl std::error::Error for MemRegionError {}
pub type MemResult<T> = Result<T, MemRegionError>;
pub trait Dist:
AmDist + Remote + Sync + serde::ser::Serialize + serde::de::DeserializeOwned
{
}
#[enum_dispatch(RegisteredMemoryRegion<T>, MemoryRegionRDMA<T>,RTMemoryRegionRDMA<T>,MemRegionId, AsBase,LamellarEnv)]
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
#[serde(bound = "T: Remote + serde::Serialize + serde::de::DeserializeOwned")]
pub enum LamellarMemoryRegion<T: Remote> {
Shared(SharedMemoryRegion<T>),
Local(OneSidedMemoryRegion<T>),
}
#[lamellar_prof::prof]
impl<T: Remote> crate::active_messaging::DarcSerde for LamellarMemoryRegion<T> {
fn ser(&self, num_pes: usize, darcs: &mut Vec<RemotePtr>) {
match self {
LamellarMemoryRegion::Shared(mr) => mr.ser(num_pes, darcs),
LamellarMemoryRegion::Local(mr) => mr.ser(num_pes, darcs),
}
}
}
#[lamellar_prof::prof]
impl<T: Remote> LamellarMemoryRegion<T> {
pub unsafe fn as_mut_slice(&self) -> &mut [T] {
match self {
LamellarMemoryRegion::Shared(memregion) => memregion.as_mut_slice(),
LamellarMemoryRegion::Local(memregion) => memregion.as_mut_slice(),
}
}
pub unsafe fn as_slice(&self) -> &[T] {
match self {
LamellarMemoryRegion::Shared(memregion) => memregion.as_slice(),
LamellarMemoryRegion::Local(memregion) => memregion.as_slice(),
}
}
}
#[lamellar_prof::prof]
impl<T: Remote> SubRegion<T> for LamellarMemoryRegion<T> {
fn sub_region<R: std::ops::RangeBounds<usize>>(&self, range: R) -> Self {
match self {
LamellarMemoryRegion::Shared(memregion) => memregion.sub_region(range).into(),
LamellarMemoryRegion::Local(memregion) => memregion.sub_region(range).into(),
}
}
}
#[lamellar_prof::prof]
impl<T: Dist> From<LamellarArrayRdmaOutput<T>> for LamellarMemoryRegion<T> {
fn from(output: LamellarArrayRdmaOutput<T>) -> Self {
match output {
LamellarArrayRdmaOutput::LamellarMemRegion(mr) => mr,
LamellarArrayRdmaOutput::SharedMemRegion(mr) => mr.into(),
LamellarArrayRdmaOutput::LocalMemRegion(mr) => mr.into(),
}
}
}
#[lamellar_prof::prof]
impl<T: Dist> From<LamellarArrayRdmaInput<T>> for LamellarMemoryRegion<T> {
fn from(input: LamellarArrayRdmaInput<T>) -> Self {
match input {
LamellarArrayRdmaInput::LamellarMemRegion(mr) => mr,
LamellarArrayRdmaInput::SharedMemRegion(mr) => mr.into(),
LamellarArrayRdmaInput::LocalMemRegion(mr) => mr.into(),
LamellarArrayRdmaInput::Owned(_) | LamellarArrayRdmaInput::OwnedVec(_) => {
panic!("Owned values are not supported")
}
}
}
}
#[lamellar_prof::prof]
impl<T: Dist> From<&LamellarMemoryRegion<T>> for LamellarArrayRdmaInput<T> {
fn from(mr: &LamellarMemoryRegion<T>) -> Self {
LamellarArrayRdmaInput::LamellarMemRegion(mr.clone())
}
}
#[lamellar_prof::prof]
impl<T: Dist> TeamFrom<&LamellarMemoryRegion<T>> for LamellarArrayRdmaInput<T> {
fn team_from(mr: &LamellarMemoryRegion<T>, _team: &Arc<LamellarTeam>) -> Self {
LamellarArrayRdmaInput::LamellarMemRegion(mr.clone())
}
}
#[lamellar_prof::prof]
impl<T: Dist> TeamFrom<LamellarMemoryRegion<T>> for LamellarArrayRdmaInput<T> {
fn team_from(mr: LamellarMemoryRegion<T>, _team: &Arc<LamellarTeam>) -> Self {
LamellarArrayRdmaInput::LamellarMemRegion(mr)
}
}
#[lamellar_prof::prof]
impl<T: Dist> TeamTryFrom<&LamellarMemoryRegion<T>> for LamellarArrayRdmaInput<T> {
fn team_try_from(
mr: &LamellarMemoryRegion<T>,
_team: &Arc<LamellarTeam>,
) -> Result<Self, anyhow::Error> {
Ok(LamellarArrayRdmaInput::LamellarMemRegion(mr.clone()))
}
}
#[lamellar_prof::prof]
impl<T: Dist> TeamTryFrom<LamellarMemoryRegion<T>> for LamellarArrayRdmaInput<T> {
fn team_try_from(
mr: LamellarMemoryRegion<T>,
_team: &Arc<LamellarTeam>,
) -> Result<Self, anyhow::Error> {
Ok(LamellarArrayRdmaInput::LamellarMemRegion(mr))
}
}
#[lamellar_prof::prof]
impl<T: Dist> From<&LamellarMemoryRegion<T>> for LamellarArrayRdmaOutput<T> {
fn from(mr: &LamellarMemoryRegion<T>) -> Self {
LamellarArrayRdmaOutput::LamellarMemRegion(mr.clone())
}
}
#[lamellar_prof::prof]
impl<T: Dist> TeamFrom<&LamellarMemoryRegion<T>> for LamellarArrayRdmaOutput<T> {
fn team_from(mr: &LamellarMemoryRegion<T>, _team: &Arc<LamellarTeam>) -> Self {
LamellarArrayRdmaOutput::LamellarMemRegion(mr.clone())
}
}
#[lamellar_prof::prof]
impl<T: Dist> TeamFrom<LamellarMemoryRegion<T>> for LamellarArrayRdmaOutput<T> {
fn team_from(mr: LamellarMemoryRegion<T>, _team: &Arc<LamellarTeam>) -> Self {
LamellarArrayRdmaOutput::LamellarMemRegion(mr)
}
}
#[lamellar_prof::prof]
impl<T: Dist> TeamTryFrom<&LamellarMemoryRegion<T>> for LamellarArrayRdmaOutput<T> {
fn team_try_from(
mr: &LamellarMemoryRegion<T>,
_team: &Arc<LamellarTeam>,
) -> Result<Self, anyhow::Error> {
Ok(LamellarArrayRdmaOutput::LamellarMemRegion(mr.clone()))
}
}
#[lamellar_prof::prof]
impl<T: Dist> TeamTryFrom<LamellarMemoryRegion<T>> for LamellarArrayRdmaOutput<T> {
fn team_try_from(
mr: LamellarMemoryRegion<T>,
_team: &Arc<LamellarTeam>,
) -> Result<Self, anyhow::Error> {
Ok(LamellarArrayRdmaOutput::LamellarMemRegion(mr))
}
}
#[enum_dispatch]
pub(crate) trait RegisteredMemoryRegion<T: Remote> {
#[doc(alias("One-sided", "onesided"))]
fn len(&self) -> usize;
#[doc(hidden)]
fn addr(&self) -> MemResult<CommAllocAddr>;
#[doc(alias("One-sided", "onesided"))]
unsafe fn as_slice(&self) -> &[T];
#[doc(alias("One-sided", "onesided"))]
unsafe fn as_mut_slice(&self) -> &mut [T];
#[doc(alias("One-sided", "onesided"))]
unsafe fn as_ptr(&self) -> MemResult<*const T>;
#[doc(alias("One-sided", "onesided"))]
unsafe fn as_mut_ptr(&self) -> MemResult<*mut T>;
}
#[enum_dispatch]
pub(crate) trait MemRegionId {
fn id(&self) -> usize;
}
pub trait SubRegion<T: Remote> {
#[doc(alias("One-sided", "onesided"))]
fn sub_region<R: std::ops::RangeBounds<usize>>(&self, range: R) -> Self;
}
#[enum_dispatch]
pub(crate) trait RTMemoryRegionRDMA<T: Remote> {
#[doc(alias("One-sided", "onesided"))]
unsafe fn put(&self, pe: usize, index: usize, data: T) -> RdmaHandle<T>;
#[doc(alias("One-sided", "onesided"))]
unsafe fn put_blocking(&self, pe: usize, index: usize, data: T);
#[doc(alias("One-sided", "onesided"))]
unsafe fn put_unmanaged(&self, pe: usize, index: usize, data: T);
#[doc(alias("One-sided", "onesided"))]
unsafe fn put_buffer(
&self,
pe: usize,
index: usize,
data: impl Into<MemregionRdmaInputInner<T>>,
) -> RdmaHandle<T>;
#[doc(alias("One-sided", "onesided"))]
unsafe fn put_buffer_unmanaged(
&self,
pe: usize,
index: usize,
data: impl Into<MemregionRdmaInputInner<T>>,
);
unsafe fn put_all(&self, index: usize, data: T) -> RdmaHandle<T>;
unsafe fn put_all_unmanaged(&self, index: usize, data: T);
unsafe fn put_all_buffer(
&self,
index: usize,
data: impl Into<MemregionRdmaInputInner<T>>,
) -> RdmaHandle<T>;
unsafe fn put_all_buffer_unmanaged(
&self,
index: usize,
data: impl Into<MemregionRdmaInputInner<T>>,
);
#[doc(alias("One-sided", "onesided"))]
unsafe fn get(&self, pe: usize, index: usize) -> RdmaGetHandle<T>;
#[doc(alias("One-sided", "onesided"))]
unsafe fn get_buffer(&self, pe: usize, index: usize, len: usize) -> RdmaGetBufferHandle<T>;
unsafe fn get_into_buffer<B: AsLamellarBuffer<T>>(
&self,
pe: usize,
index: usize,
data: LamellarBuffer<T, B>,
) -> RdmaGetIntoBufferHandle<T, B>;
unsafe fn get_into_buffer_unmanaged<B: AsLamellarBuffer<T>>(
&self,
pe: usize,
index: usize,
data: LamellarBuffer<T, B>,
);
}
impl<T: Remote> Hash for LamellarMemoryRegion<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id().hash(state);
}
}
impl<T: Remote> PartialEq for LamellarMemoryRegion<T> {
fn eq(&self, other: &LamellarMemoryRegion<T>) -> bool {
self.id() == other.id()
}
}
impl<T: Remote> Eq for LamellarMemoryRegion<T> {}
impl<T: Remote> LamellarWrite for LamellarMemoryRegion<T> {}
impl<T: Remote> LamellarWrite for &LamellarMemoryRegion<T> {}
impl<T: Remote> LamellarRead for LamellarMemoryRegion<T> {}
impl<T: Remote> LamellarRead for &LamellarMemoryRegion<T> {}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum Mode {
Local,
Remote,
Shared,
}
pub(crate) struct MemoryRegion<T: Remote> {
pub(crate) alloc: CommAlloc,
pub(crate) coll_sync_alloc: Option<Arc<CommAlloc>>,
pub(crate) coll_ticket: Arc<AtomicUsize>,
pub(crate) coll_now_serving: Arc<AtomicUsize>,
pe: usize,
backend: Backend,
pub(crate) scheduler: Arc<Scheduler>,
pub(crate) counters: Option<Arc<[Arc<AMCounters>]>>,
pub(crate) rdma: Arc<Lamellae>,
mode: Mode,
phantom: PhantomData<T>,
}
#[lamellar_prof::prof]
impl<T: Remote> MemoryRegion<T> {
pub(crate) fn new(
num_elems: usize, scheduler: &Arc<Scheduler>,
counters: Option<Arc<[Arc<AMCounters>]>>,
lamellae: &Arc<Lamellae>,
alloc: AllocationType,
) -> MemoryRegion<T> {
if let Ok(memreg) = MemoryRegion::try_new(num_elems, scheduler, counters, lamellae, alloc) {
memreg
} else {
unsafe { std::ptr::null_mut::<i32>().write(1) };
panic!("out of memory")
}
}
pub(crate) fn try_new(
num_elems: usize, scheduler: &Arc<Scheduler>,
counters: Option<Arc<[Arc<AMCounters>]>>,
lamellae: &Arc<Lamellae>,
alloc: AllocationType,
) -> Result<MemoryRegion<T>, anyhow::Error> {
trace!(
"creating new lamellar memory region size: {:?} align: {:?}",
num_elems * std::mem::size_of::<T>(),
std::mem::align_of::<T>()
);
let mut mode = Mode::Shared;
let mut coll_sync_alloc = None;
let alloc = if num_elems > 0 {
if let AllocationType::Local = alloc {
mode = Mode::Local;
lamellae.comm().rt_alloc(
num_elems * std::mem::size_of::<T>(),
std::mem::align_of::<T>(),
)?
} else {
let bytes = match &alloc {
AllocationType::Local => unreachable!(),
AllocationType::Global => {
(lamellae.comm().num_pes() + 2) * std::mem::size_of::<AtomicUsize>()
}
AllocationType::Sub(pes) => {
(pes.len() + 2) * std::mem::size_of::<AtomicUsize>()
}
};
let sync_alloc = lamellae.comm().alloc(
bytes,
alloc.clone(),
std::mem::align_of::<AtomicUsize>(),
)?;
let sync_slice = sync_alloc.as_comm_slice::<AtomicUsize>();
sync_slice
.iter()
.for_each(|elem| elem.store(0, std::sync::atomic::Ordering::SeqCst));
coll_sync_alloc = Some(Arc::new(sync_alloc));
lamellae.comm().alloc(
num_elems * std::mem::size_of::<T>(),
alloc,
std::mem::align_of::<T>(),
)? }
} else {
println!(
"cant have zero sized memregion {:?}",
std::backtrace::Backtrace::capture()
);
panic!("cant have zero sized memregion");
};
let temp = MemoryRegion {
alloc,
coll_sync_alloc,
coll_ticket: Arc::new(AtomicUsize::new(0)),
coll_now_serving: Arc::new(AtomicUsize::new(0)),
pe: lamellae.comm().my_pe(),
scheduler: scheduler.clone(),
counters: counters,
backend: lamellae.comm().backend(),
rdma: lamellae.clone(),
mode: mode,
phantom: PhantomData,
};
trace!(target: "lamellae_debug", "new memregion id: {:?} pe: {:?} alloc: {:?} num_bytes: {:?} mode: {:?} lamellae cnt: {:?}", temp.id(), temp.pe, temp.alloc, temp.alloc.num_bytes(), temp.mode, Arc::strong_count(&temp.rdma));
Ok(temp)
}
pub(crate) fn num_bytes(&self) -> usize {
self.alloc.num_bytes()
}
pub(crate) fn from_remote_addr(
addr: usize,
pe: usize,
num_bytes: usize,
team: Darc<LamellarTeamRT>,
lamellae: Arc<Lamellae>,
) -> Result<MemoryRegion<T>, anyhow::Error> {
trace!(
"creating new lamellar memory region from remote addr: {:?} pe: {:?} num_bytes: {:?}",
addr,
pe,
num_bytes
);
let mem_region = Ok(MemoryRegion {
alloc: lamellae.comm().one_sided_alloc_from_remote_pe_and_addr(
pe,
addr.into(),
num_bytes,
),
coll_sync_alloc: None,
coll_ticket: Arc::new(AtomicUsize::new(0)),
coll_now_serving: Arc::new(AtomicUsize::new(0)),
pe: pe,
scheduler: team.scheduler.clone(),
counters: team.counters(),
backend: lamellae.comm().backend(),
rdma: lamellae,
mode: Mode::Remote,
phantom: PhantomData,
});
trace!(target: "lamellae_debug", "new memregion from remote addr id: {:?} pe: {:?} num_bytes: {:?} mode: {:?} lamellae cnt: {:?}", mem_region.as_ref().unwrap().id(), pe, num_bytes, Mode::Remote, Arc::strong_count(&mem_region.as_ref().unwrap().rdma));
mem_region
}
#[allow(dead_code)]
pub(crate) unsafe fn to_base<B: Dist>(self) -> MemoryRegion<B> {
assert_eq!(
self.alloc.num_bytes() % std::mem::size_of::<B>(),
0,
"Error converting memregion to new base, does not align"
);
MemoryRegion {
alloc: self.alloc.clone(),
coll_sync_alloc: self.coll_sync_alloc.clone(),
coll_ticket: self.coll_ticket.clone(),
coll_now_serving: self.coll_now_serving.clone(),
pe: self.pe,
scheduler: self.scheduler.clone(),
counters: self.counters.clone(),
backend: self.backend,
rdma: self.rdma.clone(),
mode: self.mode,
phantom: PhantomData,
}
}
pub(crate) unsafe fn as_base<B: Remote>(&self) -> MemoryRegion<B> {
assert_eq!(
self.alloc.num_bytes() % std::mem::size_of::<B>(),
0,
"Error converting memregion to new base, does not align"
);
MemoryRegion {
alloc: self.alloc.clone(),
coll_sync_alloc: self.coll_sync_alloc.clone(),
coll_ticket: self.coll_ticket.clone(),
coll_now_serving: self.coll_now_serving.clone(),
pe: self.pe,
scheduler: self.scheduler.clone(),
counters: self.counters.clone(),
backend: self.backend,
rdma: self.rdma.clone(),
mode: self.mode,
phantom: PhantomData,
}
}
pub(crate) fn get_collective_sync_alloc(&self) -> Option<Arc<CommAlloc>> {
self.coll_sync_alloc.clone()
}
pub(crate) fn get_collective_ticket_state(&self) -> (Arc<AtomicUsize>, Arc<AtomicUsize>) {
(self.coll_ticket.clone(), self.coll_now_serving.clone())
}
pub(crate) unsafe fn put(&self, pe: usize, index: usize, data: T) -> RdmaHandle<T> {
trace!("put memregion {:?} index: {:?}", self.alloc, index);
self.alloc
.inner_alloc
.put(&self.scheduler, self.counters.clone(), data, pe, index)
}
pub(crate) unsafe fn put_blocking(&self, pe: usize, index: usize, data: T) {
trace!("put blocking memregion {:?} index: {:?}", self.alloc, index);
self.alloc
.inner_alloc
.put_blocking(&self.scheduler, data, pe, index)
}
pub(crate) unsafe fn put_unmanaged(&self, pe: usize, index: usize, data: T) {
trace!(
"put unmanaged memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc.inner_alloc.put_unmanaged(data, pe, index)
}
pub(crate) unsafe fn put_buffer(
&self,
pe: usize,
index: usize,
data: impl Into<MemregionRdmaInputInner<T>>,
) -> RdmaHandle<T> {
trace!("put buffer memregion {:?} index: {:?}", self.alloc, index);
let data = data.into();
self.alloc
.inner_alloc
.put_buffer(&self.scheduler, self.counters.clone(), data, pe, index)
}
pub(crate) unsafe fn put_buffer_unmanaged(
&self,
pe: usize,
index: usize,
data: impl Into<MemregionRdmaInputInner<T>>,
) {
trace!("put buffer memregion {:?} index: {:?}", self.alloc, index);
let data = data.into();
self.alloc.inner_alloc.put_buffer_unmanaged(data, pe, index)
}
pub(crate) unsafe fn put_all(&self, offset: usize, data: T) -> RdmaHandle<T> {
trace!("put all memregion {:?} index: {:?}", self.alloc, offset);
self.alloc
.inner_alloc
.put_all(&self.scheduler, self.counters.clone(), data, offset)
}
pub(crate) unsafe fn put_all_unmanaged(&self, offset: usize, data: T) {
trace!(
"put all unmanaged memregion {:?} index: {:?}",
self.alloc,
offset
);
self.alloc.inner_alloc.put_all_unmanaged(data, offset);
}
pub(crate) unsafe fn put_all_buffer(
&self,
offset: usize,
data: impl Into<MemregionRdmaInputInner<T>>,
) -> RdmaHandle<T> {
trace!(
"put all buffer memregion {:?} index: {:?}",
self.alloc,
offset
);
let data = data.into();
self.alloc
.inner_alloc
.put_all_buffer(&self.scheduler, self.counters.clone(), data, offset)
}
pub(crate) unsafe fn put_all_buffer_unmanaged(
&self,
offset: usize,
data: impl Into<MemregionRdmaInputInner<T>>,
) {
trace!(
"put all buffer unmanaged memregion {:?} index: {:?}",
self.alloc,
offset
);
let data = data.into();
self.alloc
.inner_alloc
.put_all_buffer_unmanaged(data, offset);
}
pub(crate) unsafe fn get(&self, pe: usize, index: usize) -> RdmaGetHandle<T> {
trace!("get memregion {:?} index: {:?}", self.alloc, index);
self.alloc
.inner_alloc
.get(&self.scheduler, self.counters.clone(), pe, index)
}
pub(crate) unsafe fn blocking_get(&self, pe: usize, index: usize) -> T {
trace!("get blocking memregion {:?} index: {:?}", self.alloc, index);
self.alloc
.inner_alloc
.blocking_get(&self.scheduler, pe, index)
}
pub(crate) unsafe fn get_buffer(
&self,
pe: usize,
index: usize,
len: usize,
) -> RdmaGetBufferHandle<T> {
trace!(
"get buffer memregion pe: {:?} index: {:?} num_elems: {:?} alloc {:?}",
pe,
index,
len,
self.alloc
);
self.alloc
.inner_alloc
.get_buffer(&self.scheduler, self.counters.clone(), pe, index, len)
}
pub(crate) unsafe fn blocking_get_buffer(&self, pe: usize, index: usize, len: usize) -> Vec<T> {
trace!(
"get buffer blocking memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc
.inner_alloc
.blocking_get_buffer(&self.scheduler, pe, index, len)
}
pub(crate) unsafe fn get_into_buffer<B: AsLamellarBuffer<T>>(
&self,
pe: usize,
index: usize,
data: LamellarBuffer<T, B>,
) -> RdmaGetIntoBufferHandle<T, B> {
trace!(
"get into buffer memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc.inner_alloc.get_into_buffer(
&self.scheduler,
self.counters.clone(),
pe,
index,
data,
)
}
pub(crate) unsafe fn blocking_get_into_buffer<B: AsLamellarBuffer<T>>(
&self,
pe: usize,
index: usize,
data: LamellarBuffer<T, B>,
) {
trace!(
"get into buffer blocking memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc
.inner_alloc
.blocking_get_into_buffer(&self.scheduler, pe, index, data)
}
pub(crate) unsafe fn get_into_buffer_unmanaged<B: AsLamellarBuffer<T>>(
&self,
pe: usize,
index: usize,
data: LamellarBuffer<T, B>,
) {
trace!(
"get into buffer unmanaged memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc
.inner_alloc
.get_into_buffer_unmanaged(pe, index, data);
}
pub(crate) fn atomic_op(&self, pe: usize, index: usize, op: AtomicOp<T>) -> AtomicOpHandle<T> {
trace!("atomic_op memregion {:?} index: {:?}", self.alloc, index);
self.alloc
.inner_alloc
.atomic_op(&self.scheduler, self.counters.clone(), op, pe, index)
}
pub(crate) fn atomic_op_blocking(&self, pe: usize, index: usize, op: AtomicOp<T>) {
trace!(
"atomic_op blocking memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc
.inner_alloc
.atomic_op_blocking(&self.scheduler, op, pe, index)
}
pub(crate) fn atomic_op_unmanaged(&self, pe: usize, index: usize, op: AtomicOp<T>) {
trace!(
"atomic_op unmanaged memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc.inner_alloc.atomic_op_unmanaged(op, pe, index)
}
pub(crate) fn atomic_op_all(&self, offset: usize, op: AtomicOp<T>) -> AtomicOpHandle<T> {
trace!(
"atomic_op_all memregion {:?} index: {:?}",
self.alloc,
offset
);
self.alloc
.inner_alloc
.atomic_op_all(&self.scheduler, self.counters.clone(), op, offset)
}
pub(crate) fn atomic_op_all_unmanaged(&self, offset: usize, op: AtomicOp<T>) {
trace!(
"atomic_op_all unmanaged memregion {:?} index: {:?}",
self.alloc,
offset
);
self.alloc.inner_alloc.atomic_op_all_unmanaged(op, offset)
}
pub(crate) fn atomic_fetch_op(
&self,
pe: usize,
index: usize,
op: AtomicOp<T>,
) -> AtomicFetchOpHandle<T> {
trace!(
"atomic_fetch_op memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc.inner_alloc.atomic_fetch_op(
&self.scheduler,
self.counters.clone(),
op,
pe,
index,
)
}
pub(crate) fn atomic_fetch_op_blocking(&self, pe: usize, index: usize, op: AtomicOp<T>) -> T {
trace!(
"atomic_fetch_op memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc
.inner_alloc
.atomic_fetch_op_blocking(&self.scheduler, op, pe, index)
}
pub(crate) fn reduce_all(
&self,
index: usize,
len: usize,
op: ReduceOp,
) -> CollectiveAllReduceOpHandle<T> {
trace!("reduce_all memregion {:?} ", self.alloc,);
self.alloc
.inner_alloc
.reduce_all(&self.scheduler, self.counters.clone(), index, len, op)
}
pub(crate) fn reduce_all_into_buffer<B: AsLamellarBuffer<T>>(
&self,
index: usize,
len: usize,
op: ReduceOp,
buffer: LamellarBuffer<T, B>,
) -> CollectiveAllReduceIntoBufferOpHandle<T, B> {
trace!("reduce_all into buffer memregion {:?} ", self.alloc,);
self.alloc.inner_alloc.reduce_all_into_buffer(
&self.scheduler,
self.counters.clone(),
index,
len,
op,
buffer,
)
}
pub(crate) fn reduce_all_in_place<B: AsLamellarBuffer<T>>(
&self,
src_and_dst: LamellarBuffer<T, B>,
op: ReduceOp,
) -> CollectiveAllReduceInPlaceOpHandle<T, B> {
trace!("reduce_all in place memregion {:?} ", self.alloc,);
self.alloc.inner_alloc.reduce_all_in_place(
&self.scheduler,
self.counters.clone(),
src_and_dst,
op,
)
}
pub(crate) fn reduce(
&self,
op: ReduceOp,
index: usize,
len: usize,
root_pe: usize,
) -> CollectiveReduceOpHandle<T> {
trace!(
"reduce at root memregion {:?} root_pe: {:?}",
self.alloc,
root_pe
);
self.alloc.inner_alloc.reduce(
&self.scheduler,
self.counters.clone(),
op,
index,
len,
root_pe,
)
}
pub(crate) fn reduce_into_buffer<B: AsLamellarBuffer<T>>(
&self,
op: ReduceOp,
index: usize,
len: usize,
root_or_buffer: RootOrLamellarBuffer<T, B>,
) -> CollectiveReduceIntoBufferOpHandle<T, B> {
trace!("reduce at root memregion {:?}", self.alloc);
self.alloc.inner_alloc.reduce_into_buffer(
&self.scheduler,
self.counters.clone(),
op,
index,
len,
root_or_buffer,
)
}
pub(crate) fn gather_all(&self, index: usize, len: usize) -> CollectiveAllGatherOpHandle<T> {
trace!("gather_all memregion {:?} ", self.alloc,);
self.alloc
.inner_alloc
.gather_all(&self.scheduler, self.counters.clone(), index, len)
}
pub(crate) fn gather_all_into_buffer<B: AsLamellarBuffer<T>>(
&self,
index: usize,
len: usize,
buffer: LamellarBuffer<T, B>,
) -> CollectiveAllGatherIntoBufferOpHandle<T, B> {
trace!("gather_all into buffer memregion {:?} ", self.alloc,);
self.alloc.inner_alloc.gather_all_into_buffer(
&self.scheduler,
self.counters.clone(),
index,
len,
buffer,
)
}
pub(crate) fn gather(
&self,
index: usize,
len: usize,
root_pe: usize,
) -> CollectiveGatherOpHandle<T> {
trace!(
"gather at root memregion {:?} root_pe: {:?}",
self.alloc,
root_pe
);
self.alloc
.inner_alloc
.gather(&self.scheduler, self.counters.clone(), index, len, root_pe)
}
pub(crate) fn gather_into_buffer<B: AsLamellarBuffer<T>>(
&self,
index: usize,
len: usize,
root_or_buffer: RootOrLamellarBuffer<T, B>,
) -> CollectiveGatherIntoBufferOpHandle<T, B> {
trace!("gather at root memregion {:?}", self.alloc);
self.alloc.inner_alloc.gather_into_buffer(
&self.scheduler,
self.counters.clone(),
index,
len,
root_or_buffer,
)
}
pub(crate) fn alltoall(&self, index: usize, len: usize) -> CollectiveAllToAllOpHandle<T> {
trace!("alltoall memregion {:?} ", self.alloc,);
self.alloc
.inner_alloc
.alltoall(&self.scheduler, self.counters.clone(), index, len)
}
pub(crate) fn alltoall_into_buffer<B: AsLamellarBuffer<T>>(
&self,
index: usize,
len: usize,
buffer: LamellarBuffer<T, B>,
) -> CollectiveAllToAllIntoBufferOpHandle<T, B> {
trace!("alltoall into buffer memregion {:?} ", self.alloc,);
self.alloc.inner_alloc.alltoall_into_buffer(
&self.scheduler,
self.counters.clone(),
index,
len,
buffer,
)
}
pub(crate) fn broadcast(
&self,
src_or_root_pe: BroadcastInput,
len: usize,
) -> CollectiveBroadcastOpHandle<T> {
self.alloc.inner_alloc.broadcast(
&self.scheduler,
self.counters.clone(),
src_or_root_pe,
len,
)
}
pub(crate) fn broadcast_into_buffer<B: AsLamellarBuffer<T>>(
&self,
target: RootSrcOrLamellarBuffer<T, B>,
len: usize,
) -> CollectiveBroadcastIntoBufferOpHandle<T, B> {
trace!("broadcast into buffer memregion {:?}", self.alloc,);
self.alloc.inner_alloc.broadcast_into_buffer(
&self.scheduler,
self.counters.clone(),
target,
len,
)
}
pub(crate) fn scatter(
&self,
src_or_pe: ScatterInput,
len: usize,
) -> CollectiveScatterOpHandle<T> {
self.alloc
.inner_alloc
.scatter(&self.scheduler, self.counters.clone(), src_or_pe, len)
}
pub(crate) fn scatter_into_buffer<B: AsLamellarBuffer<T>>(
&self,
result: LamellarBuffer<T, B>,
src_or_pe: ScatterInput,
len: usize,
) -> CollectiveScatterIntoBufferOpHandle<T, B> {
trace!("scatter into buffer memregion {:?}", self.alloc,);
self.alloc.inner_alloc.scatter_into_buffer(
&self.scheduler,
self.counters.clone(),
result,
src_or_pe,
len,
)
}
pub(crate) fn reduce_scatter(
&self,
op: ReduceOp,
index: usize,
len: usize,
) -> CollectiveReduceScatterOpHandle<T> {
trace!("reduce_scatter memregion {:?} ", self.alloc,);
self.alloc.inner_alloc.reduce_scatter(
&self.scheduler,
self.counters.clone(),
op,
index,
len,
)
}
pub(crate) fn reduce_scatter_into_buffer<B: AsLamellarBuffer<T>>(
&self,
op: ReduceOp,
index: usize,
len: usize,
buffer: LamellarBuffer<T, B>,
) -> CollectiveReduceScatterIntoBufferOpHandle<T, B> {
trace!("reduce_scatter into buffer memregion {:?} ", self.alloc,);
self.alloc.inner_alloc.reduce_scatter_into_buffer(
&self.scheduler,
self.counters.clone(),
op,
index,
len,
buffer,
)
}
pub(crate) fn wait_all(&self) {
self.rdma.comm().wait_all();
}
pub(crate) fn addr(&self) -> MemResult<CommAllocAddr> {
if self.mode == Mode::Remote {
return Err(MemRegionError::MemNotLocalError);
}
Ok(self.alloc.inner_alloc.addr())
}
pub(crate) fn as_slice(&self) -> &[T] {
unsafe { self.as_mut_slice() }
}
pub(crate) unsafe fn as_mut_slice(&self) -> &mut [T] {
if self.mode == Mode::Remote {
return &mut [];
}
std::slice::from_raw_parts_mut(
self.alloc.as_mut_ptr(),
self.alloc.num_bytes() / std::mem::size_of::<T>(),
)
}
}
impl<T: Remote> MemoryRegion<T> {
pub(crate) unsafe fn as_casted_mut_slice<R: Remote>(&self) -> MemResult<&mut [R]> {
if self.mode == Mode::Remote {
return Ok(&mut []);
}
if self.alloc.num_bytes() % std::mem::size_of::<R>() != 0 {
return Err(MemRegionError::MemNotAlignedError);
}
Ok(std::slice::from_raw_parts_mut(
self.alloc.as_mut_ptr(),
self.alloc.num_bytes() / std::mem::size_of::<R>(),
))
}
pub(crate) fn as_casted_mut_ptr<R: Remote>(&self) -> MemResult<*mut R> {
if self.mode == Mode::Remote {
return Err(MemRegionError::MemNotLocalError);
}
unsafe { Ok(self.alloc.as_mut_ptr()) }
}
pub(crate) unsafe fn as_comm_slice(&self) -> MemResult<CommSlice<T>> {
if self.mode == Mode::Remote {
return Err(MemRegionError::MemNotLocalError);
}
Ok(self.alloc.as_comm_slice())
}
}
#[lamellar_prof::prof]
impl<T: Remote + PartialEq> MemoryRegion<T> {
pub(crate) fn atomic_compare_exchange(
&self,
pe: usize,
index: usize,
current: T,
new: T,
) -> crate::lamellae::AtomicCompareExchangeOpHandle<T> {
trace!(
"atomic_compare_exchange memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc.inner_alloc.atomic_compare_exchange(
&self.scheduler,
self.counters.clone(),
current,
new,
pe,
index,
)
}
pub(crate) fn atomic_compare_exchange_blocking(
&self,
pe: usize,
index: usize,
current: T,
new: T,
) -> Result<T, T> {
trace!(
"atomic_compare_exchange blocking memregion {:?} index: {:?}",
self.alloc,
index
);
self.alloc.inner_alloc.atomic_compare_exchange_blocking(
&self.scheduler,
current,
new,
pe,
index,
)
}
}
#[lamellar_prof::prof]
impl<T: Remote> MemRegionId for MemoryRegion<T> {
fn id(&self) -> usize {
self.alloc.inner_alloc.addr().into()
}
}
pub trait RemoteMemoryRegion {
#[doc(alias = "Collective")]
fn alloc_shared_mem_region<T: Remote + std::marker::Sized>(
&self,
size: usize,
) -> SharedMemoryRegionHandle<T>;
#[doc(alias = "Collective")]
fn try_alloc_shared_mem_region<T: Remote + std::marker::Sized>(
&self,
size: usize,
) -> FallibleSharedMemoryRegionHandle<T>;
#[doc(alias("One-sided", "onesided"))]
fn alloc_one_sided_mem_region<T: Remote + std::marker::Sized>(
&self,
size: usize,
) -> OneSidedMemoryRegion<T>;
#[doc(alias("One-sided", "onesided"))]
fn try_alloc_one_sided_mem_region<T: Remote + std::marker::Sized>(
&self,
size: usize,
) -> Result<OneSidedMemoryRegion<T>, anyhow::Error>;
}
impl<T: Remote> Drop for MemoryRegion<T> {
fn drop(&mut self) {
trace!(target: "lamellae_debug", "dropping memory region lamellae cnt: {:?}", Arc::strong_count(&self.rdma));
}
}
impl<T: Remote> std::fmt::Debug for MemoryRegion<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"addr {:#x} size {:?} backend {:?}", self.alloc.comm_addr(),
self.alloc.num_bytes(),
self.backend,
)
}
}