use crate::{
active_messaging::{
batching::{
simple_batcher::io_task_stats, BATCHER_AM_PE_RECV_CNTS, BATCHER_AM_PE_SEND_CNTS,
},
handle::AmHandleInner,
*,
},
barrier::{Barrier, BarrierHandle},
env_var::config,
lamellae::{AllocationType, CommProgress, Lamellae, LamellaeShutdown, LamellaeUtil, Remote},
lamellar_arch::{GlobalArch, IdError, LamellarArch, LamellarArchEnum, LamellarArchRT},
lamellar_env::LamellarEnv,
lamellar_request::*,
lamellar_world::LamellarWorld,
memregion::{
handle::{FallibleSharedMemoryRegionHandle, SharedMemoryRegionHandle},
one_sided::OneSidedMemoryRegion,
shared::SharedMemoryRegion,
Dist, LamellarMemoryRegion, MemoryRegion, RemoteMemoryRegion,
},
scheduler::{
work_stealing::{task_finished_to_string, task_launched_to_string},
LamellarTask, ReqId, Scheduler,
},
utils::print_stats,
warnings::RuntimeWarning,
Darc,
};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use futures_util::future::join_all;
use futures_util::Future;
use parking_lot::{Mutex, RwLock};
use std::collections::HashMap;
use std::marker::PhantomPinned;
use std::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
use std::sync::Arc; use std::time::{Duration, Instant};
use tracing::{debug, trace};
use std::cell::Cell;
use std::marker::PhantomData;
pub struct LamellarTeam {
pub(crate) world: Option<Arc<LamellarTeam>>,
pub(crate) team: Darc<LamellarTeamRT>,
pub(crate) am_team: bool,
pub(crate) panic: Arc<AtomicU8>,
}
impl LamellarTeam {
pub(crate) fn new(
world: Option<Arc<LamellarTeam>>,
team: Darc<LamellarTeamRT>,
am_team: bool,
) -> Arc<LamellarTeam> {
let panic = team.panic.clone();
let the_team = Arc::new(LamellarTeam {
world,
team,
am_team,
panic,
});
the_team
}
#[doc(alias("One-sided", "onesided"))]
#[allow(dead_code)]
pub fn get_pes(&self) -> Vec<usize> {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.arch.team_iter().collect::<Vec<usize>>()
}
#[doc(alias("One-sided", "onesided"))]
pub fn num_pes(&self) -> usize {
assert!(self.panic.load(Ordering::SeqCst) == 0);
trace!(
"num_pes called 0x{:x} {:?}",
self.team.darc_addr(),
self.team.arch
);
self.team.arch.num_pes()
}
pub fn num_threads_per_pe(&self) -> usize {
self.team.scheduler.num_workers()
}
#[doc(alias("One-sided", "onesided"))]
pub fn world_pe_id(&self) -> usize {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.world_pe
}
#[doc(alias("One-sided", "onesided"))]
pub fn team_pe_id(&self) -> Result<usize, IdError> {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.arch.team_pe(self.team.world_pe)
}
#[doc(alias = "Collective")]
pub fn create_subteam_from_arch<L>(
parent: Arc<LamellarTeam>,
arch: L,
) -> Option<Arc<LamellarTeam>>
where
L: LamellarArch + std::hash::Hash + 'static,
{
assert!(parent.panic.load(Ordering::SeqCst) == 0);
let world = if let Some(world) = &parent.world {
world.clone()
} else {
parent.clone()
};
if let Some(team) =
LamellarTeamRT::create_subteam_from_arch(world.team.clone(), parent.team.clone(), arch)
{
let team = LamellarTeam::new(Some(world), team.clone(), parent.am_team);
Some(team)
} else {
None
}
}
#[doc(alias("One-sided", "onesided"))]
pub fn print_arch(&self) {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.print_arch()
}
#[doc(alias = "Collective")]
pub fn barrier(&self) {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.barrier()
}
#[doc(alias = "Collective")]
pub fn async_barrier(&self) -> BarrierHandle {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.async_barrier()
}
#[doc(hidden)]
pub fn exec_am_group_pe<F, O>(&self, pe: usize, am: F) -> AmHandle<O>
where
F: RemoteActiveMessage + LamellarAM + crate::Serialize + 'static,
O: AmDist + 'static,
{
self.team.am_group_exec_am_pe_tg(pe, am, None)
}
#[doc(hidden)]
pub fn exec_am_group_all<F, O>(&self, am: F) -> MultiAmHandle<O>
where
F: RemoteActiveMessage + LamellarAM + crate::Serialize + 'static,
O: AmDist + 'static,
{
self.team.am_group_exec_am_all_tg(am, None)
}
#[doc(alias("One-sided", "onesided"))]
pub fn exec_am_local_thread<F>(&self, am: F, thread: usize) -> LocalAmHandle<F::Output>
where
F: LamellarActiveMessage + LocalAM + 'static,
{
self.team.exec_am_local_tg(am, None, Some(thread))
}
#[doc(alias("One-sided", "onesided"))]
pub fn spawn_am_all<F>(&self, am: F) -> MultiAmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + Serde + AmDist + 'static,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.spawn_am_all_tg(am, None)
}
#[doc(alias("One-sided", "onesided"))]
pub fn spawn_am_pe<F>(&self, pe: usize, am: F) -> AmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + Serde + AmDist + 'static,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.spawn_am_pe_tg(pe, am, None)
}
#[doc(alias("One-sided", "onesided"))]
pub fn spawn_am_local<F>(&self, am: F) -> LocalAmHandle<F::Output>
where
F: LamellarActiveMessage + LocalAM + 'static,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.spawn_am_local_tg(am, None, None)
}
}
impl LamellarEnv for Arc<LamellarTeam> {
fn my_pe(&self) -> usize {
self.team
.arch
.team_pe(self.team.world_pe)
.expect("PE is apart of team")
}
fn num_pes(&self) -> usize {
trace!(
"num_pes called {:x} {:?} {:?} {:?}",
self.team.darc_addr(),
self.team.arch,
self.team.num_pes(),
self.team.arch.num_pes()
);
self.team.arch.num_pes()
}
fn num_threads_per_pe(&self) -> usize {
self.team.num_threads()
}
fn world(&self) -> Arc<LamellarTeam> {
if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
}
}
fn team(&self) -> Arc<LamellarTeam> {
self.clone()
}
}
impl std::fmt::Debug for LamellarTeam {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"pes: {:?}",
self.team.arch.team_iter().collect::<Vec<usize>>()
)
}
}
impl ActiveMessaging for Arc<LamellarTeam> {
type SinglePeAmHandle<R: AmDist> = AmHandle<R>;
type MultiAmHandle<R: AmDist> = MultiAmHandle<R>;
type LocalAmHandle<L> = LocalAmHandle<L>;
fn exec_am_all<F>(&self, am: F) -> Self::MultiAmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + Serde + AmDist,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.exec_am_all_tg(am, None)
}
fn exec_am_pe<F>(&self, pe: usize, am: F) -> AmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + Serde + AmDist,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.exec_am_pe_tg(pe, am, None)
}
fn exec_am_local<F>(&self, am: F) -> LocalAmHandle<F::Output>
where
F: LamellarActiveMessage + LocalAM + 'static,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.exec_am_local_tg(am, None, None)
}
fn wait_all(&self) {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.wait_all();
}
fn await_all(&self) -> impl Future<Output = ()> + Send {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.await_all()
}
fn barrier(&self) {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.barrier();
}
fn async_barrier(&self) -> BarrierHandle {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.async_barrier()
}
fn spawn<F>(&self, task: F) -> LamellarTask<F::Output>
where
F: Future + Send + 'static,
F::Output: Send,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.scheduler.spawn_task(
task,
Some(Arc::from([
self.team.world_counters.clone(),
self.team.team_counters.clone(),
])),
)
}
fn block_on<F: Future>(&self, f: F) -> F::Output {
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team.scheduler.block_on(f)
}
fn block_on_all<I>(&self, iter: I) -> Vec<<<I as IntoIterator>::Item as Future>::Output>
where
I: IntoIterator,
<I as IntoIterator>::Item: Future + Send + 'static,
<<I as IntoIterator>::Item as Future>::Output: Send,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.team
.scheduler
.block_on(join_all(iter.into_iter().map(|task| {
self.team.scheduler.spawn_task(
task,
Some(Arc::from([
self.team.world_counters.clone(),
self.team.team_counters.clone(),
])),
)
})))
}
}
impl RemoteMemoryRegion for Arc<LamellarTeam> {
fn try_alloc_shared_mem_region<T: Remote>(
&self,
size: usize,
) -> FallibleSharedMemoryRegionHandle<T> {
assert!(self.panic.load(Ordering::SeqCst) == 0);
let mr = if self.team.num_world_pes == self.team.num_pes {
SharedMemoryRegion::try_new(size, self.team.clone(), AllocationType::Global)
} else {
SharedMemoryRegion::try_new(
size,
self.team.clone(),
AllocationType::Sub(self.team.arch.team_iter().collect::<Vec<usize>>()),
)
};
mr
}
fn alloc_shared_mem_region<T: Remote>(&self, size: usize) -> SharedMemoryRegionHandle<T> {
assert!(self.panic.load(Ordering::SeqCst) == 0);
let mr = if self.team.num_world_pes == self.team.num_pes {
SharedMemoryRegion::new(size, self.team.clone(), AllocationType::Global)
} else {
SharedMemoryRegion::new(
size,
self.team.clone(),
AllocationType::Sub(self.team.arch.team_iter().collect::<Vec<usize>>()),
)
};
mr
}
fn try_alloc_one_sided_mem_region<T: Remote>(
&self,
size: usize,
) -> Result<OneSidedMemoryRegion<T>, anyhow::Error> {
assert!(self.panic.load(Ordering::SeqCst) == 0);
OneSidedMemoryRegion::try_new(size, &self.team)
}
fn alloc_one_sided_mem_region<T: Remote>(&self, size: usize) -> OneSidedMemoryRegion<T> {
assert!(self.panic.load(Ordering::SeqCst) == 0);
let mut lmr = OneSidedMemoryRegion::try_new(size, &self.team);
while let Err(_err) = lmr {
std::thread::yield_now();
let alloc_fut = self
.team
.lamellae
.request_new_alloc(size * std::mem::size_of::<T>());
self.team.scheduler.block_on(alloc_fut);
lmr = OneSidedMemoryRegion::try_new(size, &self.team);
}
lmr.expect("out of memory")
}
}
#[derive(Debug)]
pub struct IntoLamellarTeam {
pub(crate) team: Darc<LamellarTeamRT>,
}
impl Drop for IntoLamellarTeam {
fn drop(&mut self) {
trace!(target: "drop", "drop IntoLamellarTeam");
}
}
impl From<Darc<LamellarTeamRT>> for IntoLamellarTeam {
fn from(team: Darc<LamellarTeamRT>) -> Self {
IntoLamellarTeam { team: team.clone() }
}
}
impl From<&Darc<LamellarTeamRT>> for IntoLamellarTeam {
fn from(team: &Darc<LamellarTeamRT>) -> Self {
IntoLamellarTeam { team: team.clone() }
}
}
impl From<Arc<LamellarTeam>> for IntoLamellarTeam {
fn from(team: Arc<LamellarTeam>) -> Self {
IntoLamellarTeam {
team: team.team.clone(),
}
}
}
impl From<&Arc<LamellarTeam>> for IntoLamellarTeam {
fn from(team: &Arc<LamellarTeam>) -> Self {
IntoLamellarTeam {
team: team.team.clone(),
}
}
}
impl From<&LamellarWorld> for IntoLamellarTeam {
fn from(world: &LamellarWorld) -> Self {
IntoLamellarTeam {
team: world.team_rt.deref().clone(),
}
}
}
impl From<LamellarWorld> for IntoLamellarTeam {
fn from(world: LamellarWorld) -> Self {
IntoLamellarTeam {
team: (*world.team_rt.deref()).clone(),
}
}
}
#[doc(hidden)]
pub struct ArcLamellarTeam {
pub team: Arc<LamellarTeam>,
}
impl From<Arc<LamellarTeam>> for ArcLamellarTeam {
fn from(team: Arc<LamellarTeam>) -> Self {
ArcLamellarTeam { team }
}
}
impl From<&Arc<LamellarTeam>> for ArcLamellarTeam {
fn from(team: &Arc<LamellarTeam>) -> Self {
ArcLamellarTeam { team: team.clone() }
}
}
impl From<&LamellarWorld> for ArcLamellarTeam {
fn from(world: &LamellarWorld) -> Self {
ArcLamellarTeam { team: world.team() }
}
}
impl From<LamellarWorld> for ArcLamellarTeam {
fn from(world: LamellarWorld) -> Self {
ArcLamellarTeam { team: world.team() }
}
}
pub(crate) struct LamellarTeamRT {
#[allow(dead_code)]
pub(crate) world: Option<Darc<LamellarTeamRT>>,
parent: Option<Darc<LamellarTeamRT>>,
sub_teams: RwLock<HashMap<usize, Darc<LamellarTeamRT>>>,
mem_regions: RwLock<HashMap<usize, Box<LamellarMemoryRegion<u8>>>>,
pub(crate) scheduler: Arc<Scheduler>,
pub(crate) arch: Arc<LamellarArchRT>,
pub(crate) world_pe: usize,
pub(crate) num_world_pes: usize,
pub(crate) team_pe: Result<usize, IdError>,
pub(crate) num_pes: usize,
pub(crate) team_counters: Arc<AMCounters>,
pub(crate) world_counters: Arc<AMCounters>, pub(crate) id: usize,
sub_team_id_cnt: AtomicUsize,
pub(crate) barrier: Barrier,
dropped: MemoryRegion<usize>,
pub(crate) team_hash: u64,
pub(crate) panic: Arc<AtomicU8>,
pub(crate) tid: std::thread::ThreadId,
pub(crate) lamellae: Arc<Lamellae>, _pin: std::marker::PhantomPinned,
}
unsafe impl Send for LamellarTeamRT {}
impl Darc<LamellarTeamRT> {
pub(crate) fn rt_num_threads_per_pe(&self) -> usize {
self.num_threads()
}
pub(crate) fn user_world(&self) -> Arc<LamellarTeam> {
let world = if let Some(world) = self.world.clone() {
world
} else {
self.clone()
};
let world = LamellarTeam::new(None, world, false);
world
}
pub(crate) fn user_team(&self) -> Arc<LamellarTeam> {
let world = if self.world.is_some() {
Some(self.world())
} else {
None
};
let team = LamellarTeam::new(world, self.clone(), false);
team
}
}
impl std::fmt::Debug for LamellarTeamRT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"pes: {:?}",
self.arch.team_iter().collect::<Vec<usize>>()
)
}
}
impl Hash for LamellarTeamRT {
fn hash<H: Hasher>(&self, state: &mut H) {
self.team_hash.hash(state);
}
}
impl PartialEq for LamellarTeamRT {
fn eq(&self, other: &Self) -> bool {
self.team_hash == other.team_hash
}
}
impl Eq for LamellarTeamRT {}
#[lamellar::prof]
impl LamellarTeamRT {
pub(crate) fn new(
num_pes: usize,
world_pe: usize,
scheduler: Arc<Scheduler>,
world_counters: Arc<AMCounters>,
lamellae: Arc<Lamellae>,
panic: Arc<AtomicU8>,
) -> Darc<LamellarTeamRT> {
let arch = Arc::new(LamellarArchRT {
parent: None,
arch: LamellarArchEnum::GlobalArch(GlobalArch::new(num_pes)),
num_pes,
});
lamellae.comm().barrier();
trace!(target: "lamellae_debug", "creating barrier for team lamellae cnt: {:?}", Arc::strong_count(&lamellae));
let barrier = Barrier::new(
world_pe,
num_pes,
lamellae.clone(),
arch.clone(),
scheduler.clone(),
panic.clone(),
);
trace!(target: "lamellae_debug", "barrier created lamellae cnt: {:?}", Arc::strong_count(&lamellae));
let alloc = AllocationType::Global;
let team_counters = Arc::new(AMCounters::new());
let dropped = MemoryRegion::new(
num_pes,
&scheduler,
Some(Arc::from([team_counters.clone(), world_counters.clone()])),
&lamellae,
alloc.clone(),
);
trace!(target: "lamellae_debug", "dropped memory region created lamellae cnt: {:?}", Arc::strong_count(&lamellae));
unsafe { dropped.as_mut_slice().fill(0) };
let team = LamellarTeamRT {
world: None,
parent: None,
sub_teams: RwLock::new(HashMap::new()),
mem_regions: RwLock::new(HashMap::new()),
scheduler: scheduler.clone(),
lamellae: lamellae.clone(),
arch: arch.clone(),
world_pe,
team_pe: Ok(world_pe),
num_world_pes: num_pes,
num_pes: num_pes,
team_counters,
world_counters: world_counters,
id: 0,
team_hash: 0, sub_team_id_cnt: AtomicUsize::new(0),
barrier: barrier,
dropped: dropped,
panic: panic.clone(),
tid: std::thread::current().id(),
_pin: PhantomPinned,
};
trace!(target: "lamellae_debug", "team created lamellae cnt: {:?}", Arc::strong_count(&lamellae));
lamellae.comm().barrier(); scheduler
.block_on(Darc::async_try_new_team_darc(team))
.expect("Failed to create team Darc")
}
pub(crate) fn force_shutdown(&self) {
let first = self
.panic
.compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst)
.is_ok();
if self.tid == std::thread::current().id() {
self.panic.store(2, Ordering::SeqCst);
}
self.scheduler.force_shutdown();
if first {
self.lamellae.force_shutdown();
}
if self.tid == std::thread::current().id() {
self.mem_regions.write().clear();
self.sub_teams.write().clear();
self.lamellae.force_deinit();
}
}
pub(crate) fn destroy(&self) {
trace!(target: "drop","destroying team? {:?}", self.mem_regions.read().len());
if self.panic.load(Ordering::SeqCst) == 0 {
self.wait_all();
}
self.mem_regions.write().clear();
self.sub_teams.write().clear(); self.lamellae.comm().wait_all(); self.lamellae.comm().barrier();
if self.panic.load(Ordering::SeqCst) == 0 {
if let None = &self.parent {
trace!(target: "drop","shutdown lamellae, going to shutdown scheduler");
self.scheduler.begin_shutdown();
self.put_dropped();
self.drop_barrier();
trace!(target: "drop","barrier dropped, now shutting down lamellae and scheduler");
self.lamellae.shutdown();
trace!(target: "drop","lamellae shutdown cnt: {:?}, now shutting down scheduler cnt: {:?}",Arc::strong_count(&self.lamellae), Arc::strong_count(&self.scheduler));
self.scheduler.shutdown();
trace!(target: "drop","scheduler shutdown");
}
}
trace!(target: "drop","Tasks Launched: {:?} Tasks Completed: {:?}", task_launched_to_string(),
task_finished_to_string(),);
trace!(target: "lamellae_debug", "team destroyed lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
}
#[allow(dead_code)]
pub(crate) fn get_pes(&self) -> Vec<usize> {
self.arch.team_iter().collect::<Vec<usize>>()
}
pub(crate) fn team_pe_id(&self) -> Result<usize, IdError> {
self.arch.team_pe(self.world_pe)
}
pub(crate) fn counters(&self) -> Option<Arc<[Arc<AMCounters>]>> {
Some(Arc::from([
self.world_counters.clone(),
self.team_counters.clone(),
]))
}
pub(crate) fn create_subteam_from_arch<L>(
world: Darc<LamellarTeamRT>,
parent: Darc<LamellarTeamRT>,
arch: L,
) -> Option<Darc<LamellarTeamRT>>
where
L: LamellarArch + std::hash::Hash + 'static,
{
if parent.team_pe_id().is_ok() {
let id = parent.sub_team_id_cnt.fetch_add(1, Ordering::SeqCst);
let mut hasher = DefaultHasher::new();
parent.hash(&mut hasher);
id.hash(&mut hasher);
arch.hash(&mut hasher);
let hash = hasher.finish();
let archrt = Arc::new(LamellarArchRT::new(parent.arch.clone(), arch));
trace!("subteam arch: {:?}", archrt);
parent.barrier();
let parent_alloc = AllocationType::Sub(parent.arch.team_iter().collect::<Vec<usize>>());
let team_counters = Arc::new(AMCounters::new());
trace!("subteam allocating hash_buf");
let dropped = MemoryRegion::<usize>::new(
parent.num_pes,
&parent.scheduler,
Some(Arc::from([
team_counters.clone(),
parent.world_counters.clone(),
])),
&parent.lamellae,
parent_alloc.clone(),
);
trace!(target: "lamellae_debug", "subteam hash_buf created lamellae cnt: {:?}", Arc::strong_count(&parent.lamellae));
unsafe { dropped.as_mut_slice().fill(0) };
let s = Instant::now();
parent.barrier();
let timeout = Instant::now() - s;
trace!("subteam putting hash vals {:?}", hash);
if let Ok(parent_world_pe) = parent.arch.team_pe(parent.world_pe) {
for world_pe in parent.arch.team_iter() {
unsafe {
dropped
.put(world_pe, parent_world_pe, hash as usize)
.block();
}
}
}
trace!("subteam done putting hash, now gonna check hash vals");
parent.check_hash_vals(hash as usize, &dropped, timeout);
trace!("subteam passed check hash vals");
let num_pes = archrt.num_pes();
parent.barrier();
trace!("subteam passed barrier, creating RT team");
let team = LamellarTeamRT {
world: Some(world.clone()),
parent: Some(parent.clone()),
sub_teams: RwLock::new(HashMap::new()),
mem_regions: RwLock::new(HashMap::new()),
scheduler: parent.scheduler.clone(),
lamellae: parent.lamellae.clone(),
arch: archrt.clone(),
world_pe: parent.world_pe,
num_world_pes: parent.num_world_pes,
team_pe: archrt.team_pe(parent.world_pe),
num_pes: num_pes,
team_counters,
world_counters: parent.world_counters.clone(),
id,
sub_team_id_cnt: AtomicUsize::new(0),
barrier: Barrier::new(
parent.world_pe,
parent.num_world_pes,
parent.lamellae.clone(),
archrt,
parent.scheduler.clone(),
parent.panic.clone(),
),
team_hash: hash,
dropped,
panic: parent.panic.clone(),
tid: parent.tid,
_pin: PhantomPinned,
};
trace!(target: "lamellae_debug", "subteam RT team created lamellae cnt: {:?}", Arc::strong_count(&parent.lamellae));
unsafe {
team.dropped.as_mut_slice().fill(0);
}
let team = parent
.scheduler
.block_on(Darc::async_try_new_with_drop(
parent.clone(),
team,
crate::darc::DarcMode::Darc,
None,
))
.expect("Failed to create team");
trace!("team created in {:?}", s.elapsed());
let mut sub_teams = parent.sub_teams.write();
sub_teams.insert(team.id, team.clone());
parent.barrier();
team.barrier();
parent.barrier();
trace!("subteam created successfully");
Some(team)
} else {
None
}
}
pub(crate) fn num_pes(&self) -> usize {
trace!("num_pes called {:p} {:?}", self, self.arch);
self.arch.num_pes()
}
pub(crate) fn num_threads(&self) -> usize {
self.scheduler.num_workers()
}
#[cfg_attr(test, allow(unreachable_code), allow(unused_variables))]
fn check_hash_vals(&self, hash: usize, hash_buf: &MemoryRegion<usize>, timeout: Duration) {
#[cfg(test)]
return;
let mut s = Instant::now();
let mut cnt = 0;
for (pe, hash_val) in hash_buf.as_slice().iter().enumerate() {
if pe != self.team_pe.unwrap() {
while *hash_val == 0 {
self.lamellae.comm().thread_wait();
std::thread::yield_now();
if s.elapsed().as_secs_f64() > config().deadlock_warning_timeout {
let status = hash_buf
.as_slice()
.iter()
.enumerate()
.map(|(i, elem)| (i, *elem == hash))
.collect::<Vec<_>>();
println!("[WARNING] Potential deadlock detected when trying construct a new LamellarTeam.\n\
Creating a team is a collective operation requiring all PEs associated with the Parent Team (or LamellarWorld) to enter the call, not just the PEs that will be part of the new team.\n\
The following indicates which PEs have not entered the call: {:?}\n\
The deadlock timeout can be set via the LAMELLAR_DEADLOCK_WARNING_TIMEOUT environment variable, the current timeout is {} seconds\n\
To view backtrace set RUST_LIB_BACKTRACE=1\n\
{}",status,config().deadlock_warning_timeout,std::backtrace::Backtrace::capture()
);
trace!(
"[{:?}] ({:?}) hash: {:?}",
self.world_pe,
hash,
hash_buf.as_slice()
);
s = Instant::now();
}
}
if *hash_val != hash && Instant::now() - s > timeout {
println!(
"[{:?}] ({:?}) hash: {:?}",
self.world_pe,
hash,
hash_buf.as_slice()
);
panic!("team creating mismatch! Ensure teams are constructed in same order on every pe");
} else {
std::thread::yield_now();
cnt = cnt + 1;
}
}
}
}
fn put_dropped(&self) {
if self.panic.load(Ordering::SeqCst) == 0 {
if let Some(parent) = &self.parent {
let my_index = parent
.arch
.team_pe(self.world_pe)
.expect("invalid parent pe");
for world_pe in self.arch.team_iter() {
unsafe {
let _ = self.dropped.put_unmanaged(world_pe, my_index, 1usize);
}
}
} else {
for world_pe in self.arch.team_iter() {
unsafe {
let _ = self.dropped.put_unmanaged(world_pe, self.world_pe, 1usize);
}
}
}
self.wait_all();
}
}
fn drop_barrier(&self) {
let mut s = Instant::now();
if self.panic.load(Ordering::SeqCst) == 0 {
for pe in self.dropped.as_slice().iter() {
while *pe != 1 {
if s.elapsed().as_secs_f64() > config().deadlock_warning_timeout {
println!("[WARNING] Potential deadlock detected when trying to drop a LamellarTeam.\n\
The following indicates the dropped status on each PE: {:?}\n\
The deadlock timeout can be set via the LAMELLAR_DEADLOCK_WARNING_TIMEOUT environment variable, the current timeout is {} seconds\n\
To view backtrace set RUST_LIB_BACKTRACE=1\n\
{}",
self.dropped.as_slice(),
config().deadlock_warning_timeout,
std::backtrace::Backtrace::capture());
s = Instant::now();
}
}
}
}
}
pub(crate) fn print_arch(&self) {
println!("-----mapping of team pe ids to parent pe ids-----");
let mut parent = format!("");
let mut team = format!("");
for i in 0..self.arch.num_pes() {
let mut width = (i as f64).log10() as usize + 1;
if let Ok(id) = self.arch.world_pe(i) {
width = std::cmp::max(width, (id as f64).log10() as usize + 1);
parent = format!("{} {:width$}", parent, id, width = width);
}
team = format!("{} {:width$}", team, i, width = width);
}
println!(" team pes: {}", team);
println!("global pes: {}", parent);
println!("-----mapping of parent pe ids to team pe ids-----");
parent = format!("");
team = format!("");
for i in 0..self.num_world_pes {
let mut width = (i as f64).log10() as usize + 1;
if let Ok(id) = self.arch.team_pe(i) {
width = std::cmp::max(width, (id as f64).log10() as usize + 1);
team = format!("{} {:width$}", team, id, width = width);
} else {
team = format!("{} {:width$}", team, "", width = width);
}
parent = format!("{} {:width$}", parent, i, width = width);
}
println!("global pes: {}", parent);
println!(" team pes: {}", team);
println!("-------------------------------------------------");
}
pub(crate) fn inc_outstanding(&self, cnt: usize) {
self.team_counters.inc_outstanding(cnt);
self.world_counters.inc_outstanding(cnt);
}
pub(crate) fn dec_outstanding(&self, cnt: usize) {
self.team_counters.dec_outstanding(cnt);
self.world_counters.dec_outstanding(cnt);
}
pub(crate) fn spawn<F>(&self, task: F) -> LamellarTask<F::Output>
where
F: Future + Send + 'static,
F::Output: Send,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.scheduler.spawn_task(
task,
Some(Arc::from([
self.world_counters.clone(),
self.team_counters.clone(),
])),
)
}
pub(crate) fn wait_all(&self) {
RuntimeWarning::BlockingCall("wait_all", "await_all().await").print();
self.lamellae.comm().wait_all();
let mut temp_now = Instant::now();
let mut orig_reqs = self.team_counters.send_req_cnt.load(Ordering::SeqCst);
let mut orig_launched = self.team_counters.launched_req_cnt.load(Ordering::SeqCst);
let mut world_orig_reqs = self.world_counters.send_req_cnt.load(Ordering::SeqCst);
let mut world_orig_launched = self.world_counters.launched_req_cnt.load(Ordering::SeqCst);
debug!(
target: "barrier",
my_pe = self.world_pe,
send_req_cnt = self.team_counters.send_req_cnt.load(Ordering::SeqCst),
send_req_cnt_addr = ?(&self.team_counters.send_req_cnt as *const _),
outstanding_reqs = self.team_counters.outstanding_reqs.load(Ordering::SeqCst),
outstanding_reqs_addr = ?Arc::as_ptr(&self.team_counters.outstanding_reqs),
launched_req_cnt = self.team_counters.launched_req_cnt.load(Ordering::SeqCst),
launched_req_cnt_addr = ?(&self.team_counters.launched_req_cnt as *const _),
"team wait_all: entering poll loop"
);
let mut done = false;
while !done {
while self.panic.load(Ordering::SeqCst) == 0
&& ((self.team_counters.outstanding_reqs.load(Ordering::SeqCst) > 0
|| orig_reqs != self.team_counters.send_req_cnt.load(Ordering::SeqCst)
|| orig_launched != self.team_counters.launched_req_cnt.load(Ordering::SeqCst))
|| (self.parent.is_none()
&& (self.world_counters.outstanding_reqs.load(Ordering::SeqCst) > 0
|| world_orig_reqs
!= self.world_counters.send_req_cnt.load(Ordering::SeqCst)
|| world_orig_launched
!= self.world_counters.launched_req_cnt.load(Ordering::SeqCst))))
{
orig_reqs = self.team_counters.send_req_cnt.load(Ordering::SeqCst);
orig_launched = self.team_counters.launched_req_cnt.load(Ordering::SeqCst);
world_orig_reqs = self.world_counters.send_req_cnt.load(Ordering::SeqCst);
world_orig_launched = self.world_counters.launched_req_cnt.load(Ordering::SeqCst);
if std::thread::current().id() == *crate::MAIN_THREAD {
self.scheduler.exec_task()
}; if temp_now.elapsed().as_secs_f64() > config().deadlock_warning_timeout {
debug!(
target: "counters",
mype = ?self.world_pe,
send_req_cnt = self.team_counters.send_req_cnt.load(Ordering::SeqCst),
send_req_cnt_addr = ?(&self.team_counters.send_req_cnt as *const _),
outstanding_reqs = self.team_counters.outstanding_reqs.load(Ordering::SeqCst),
outstanding_reqs_addr = ?Arc::as_ptr(&self.team_counters.outstanding_reqs),
launched_req_cnt = self.team_counters.launched_req_cnt.load(Ordering::SeqCst),
launched_req_cnt_addr = ?(&self.team_counters.launched_req_cnt as *const _),
send_cnts = ?print_stats!(&*BATCHER_AM_PE_SEND_CNTS),
recv_cnts = ?print_stats!(&*BATCHER_AM_PE_RECV_CNTS),
launched_tasks = ?task_launched_to_string(),
finished_tasks = ?task_finished_to_string(),
io_task_stats = ?io_task_stats(),
"in team wait_all"
);
self.lamellae.wait_all_print();
temp_now = Instant::now();
}
}
if self.team_counters.send_req_cnt.load(Ordering::SeqCst)
!= self.team_counters.launched_req_cnt.load(Ordering::SeqCst)
|| (self.parent.is_none()
&& self.world_counters.send_req_cnt.load(Ordering::SeqCst)
!= self.world_counters.launched_req_cnt.load(Ordering::SeqCst))
{
if (self.team_counters.outstanding_reqs.load(Ordering::SeqCst) > 0
|| orig_reqs != self.team_counters.send_req_cnt.load(Ordering::SeqCst)
|| orig_launched != self.team_counters.launched_req_cnt.load(Ordering::SeqCst))
|| (self.parent.is_none()
&& (self.world_counters.outstanding_reqs.load(Ordering::SeqCst) > 0
|| world_orig_reqs
!= self.world_counters.send_req_cnt.load(Ordering::SeqCst)
|| world_orig_launched
!= self.world_counters.launched_req_cnt.load(Ordering::SeqCst)))
{
continue;
}
println!(
"in team wait_all mype: {:?} cnt: {:?} {:?} {:?}",
self.world_pe,
self.team_counters.send_req_cnt.load(Ordering::SeqCst),
self.team_counters.outstanding_reqs.load(Ordering::SeqCst),
self.team_counters.launched_req_cnt.load(Ordering::SeqCst)
);
RuntimeWarning::UnspawnedTask(
"`wait_all` before all tasks/active messages have been spawned",
)
.print();
}
done = true;
}
debug!(
target: "barrier",
my_pe = self.world_pe,
send_req_cnt = self.team_counters.send_req_cnt.load(Ordering::SeqCst),
outstanding_reqs = self.team_counters.outstanding_reqs.load(Ordering::SeqCst),
launched_req_cnt = self.team_counters.launched_req_cnt.load(Ordering::SeqCst),
"team wait_all: leaving poll loop"
);
}
pub(crate) async fn await_all(&self) {
self.lamellae.comm().wait_all(); let mut temp_now = Instant::now();
let mut orig_reqs = self.team_counters.send_req_cnt.load(Ordering::SeqCst);
let mut orig_launched = self.team_counters.launched_req_cnt.load(Ordering::SeqCst);
let mut world_orig_reqs = self.world_counters.send_req_cnt.load(Ordering::SeqCst);
let mut world_orig_launched = self.world_counters.launched_req_cnt.load(Ordering::SeqCst);
let mut done = false;
while !done {
while self.panic.load(Ordering::SeqCst) == 0
&& ((self.team_counters.outstanding_reqs.load(Ordering::SeqCst) > 0
|| orig_reqs != self.team_counters.send_req_cnt.load(Ordering::SeqCst)
|| orig_launched != self.team_counters.launched_req_cnt.load(Ordering::SeqCst))
|| (self.parent.is_none()
&& (self.world_counters.outstanding_reqs.load(Ordering::SeqCst) > 0
|| world_orig_reqs
!= self.world_counters.send_req_cnt.load(Ordering::SeqCst)
|| world_orig_launched
!= self.world_counters.launched_req_cnt.load(Ordering::SeqCst))))
{
orig_reqs = self.team_counters.send_req_cnt.load(Ordering::SeqCst);
orig_launched = self.team_counters.launched_req_cnt.load(Ordering::SeqCst);
world_orig_reqs = self.world_counters.send_req_cnt.load(Ordering::SeqCst);
world_orig_launched = self.world_counters.launched_req_cnt.load(Ordering::SeqCst);
async_std::task::yield_now().await;
if temp_now.elapsed().as_secs_f64() > config().deadlock_warning_timeout {
println!(
"in team wait_all mype: {:?} cnt: {:?} {:?}",
self.world_pe,
self.team_counters.send_req_cnt.load(Ordering::SeqCst),
self.team_counters.outstanding_reqs.load(Ordering::SeqCst),
);
temp_now = Instant::now();
}
}
if self.team_counters.send_req_cnt.load(Ordering::SeqCst)
!= self.team_counters.launched_req_cnt.load(Ordering::SeqCst)
|| (self.parent.is_none()
&& self.world_counters.send_req_cnt.load(Ordering::SeqCst)
!= self.world_counters.launched_req_cnt.load(Ordering::SeqCst))
{
if (self.team_counters.outstanding_reqs.load(Ordering::SeqCst) > 0
|| orig_reqs != self.team_counters.send_req_cnt.load(Ordering::SeqCst)
|| orig_launched != self.team_counters.launched_req_cnt.load(Ordering::SeqCst))
|| (self.parent.is_none()
&& (self.world_counters.outstanding_reqs.load(Ordering::SeqCst) > 0
|| world_orig_reqs
!= self.world_counters.send_req_cnt.load(Ordering::SeqCst)
|| world_orig_launched
!= self.world_counters.launched_req_cnt.load(Ordering::SeqCst)))
{
continue;
}
println!(
"in team await_all mype: {:?} cnt: {:?} {:?} {:?}",
self.world_pe,
self.team_counters.send_req_cnt.load(Ordering::SeqCst),
self.team_counters.outstanding_reqs.load(Ordering::SeqCst),
self.team_counters.launched_req_cnt.load(Ordering::SeqCst)
);
RuntimeWarning::UnspawnedTask(
"`await_all` before all tasks/active messages have been spawned",
)
.print();
}
done = true;
}
}
pub(crate) fn block_on<F>(&self, f: F) -> F::Output
where
F: Future + Send + 'static,
F::Output: Send,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.scheduler.block_on(f)
}
pub(crate) fn block_on_all<I>(
&self,
iter: I,
) -> Vec<<<I as IntoIterator>::Item as Future>::Output>
where
I: IntoIterator,
<I as IntoIterator>::Item: Future + Send + 'static,
<<I as IntoIterator>::Item as Future>::Output: Send,
{
assert!(self.panic.load(Ordering::SeqCst) == 0);
self.scheduler
.block_on(join_all(iter.into_iter().map(|task| {
self.scheduler.spawn_task(
task,
Some(Arc::from([
self.world_counters.clone(),
self.team_counters.clone(),
])),
)
})))
}
pub(crate) fn barrier(&self) {
self.barrier.barrier();
}
pub(crate) fn tasking_barrier(&self) {
self.barrier.tasking_barrier();
}
pub(crate) fn async_barrier(&self) -> BarrierHandle {
self.barrier.barrier_handle()
}
}
impl Darc<LamellarTeamRT> {
pub(crate) fn exec_am_all<F>(&self, am: F) -> MultiAmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + AmDist,
{
self.exec_am_all_tg(am, None)
}
pub(crate) fn exec_am_all_tg<F>(
&self,
am: F,
task_group_cnts: Option<Arc<AMCounters>>,
) -> MultiAmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + crate::Serialize + 'static,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_send_req(self.num_pes);
}
let req = Arc::new(MultiAmHandleInner {
cnt: AtomicUsize::new(self.num_pes),
arch: self.arch.clone(),
data: Mutex::new(HashMap::new()),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::MultiAm(req.clone()));
let req_ptr = Arc::into_raw(req_result);
for _ in 0..(self.num_pes - 1) {
unsafe { Arc::increment_strong_count(req_ptr) } }
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_send_req(self.num_pes);
self.team_counters.inc_send_req(self.num_pes);
let func: LamellarArcAm = Arc::new(am);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let req_data = ReqMetaData {
src: self.world_pe,
dst: None,
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "exec_am_all_tg submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
MultiAmHandle {
inner: req,
am: Some((Am::All(req_data, func), self.num_pes)),
_phantom: PhantomData,
}
}
pub(crate) fn spawn_am_all_tg<F>(
&self,
am: F,
task_group_cnts: Option<Arc<AMCounters>>,
) -> MultiAmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + crate::Serialize + 'static,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_outstanding(self.num_pes);
task_group_cnts.inc_launched(self.num_pes);
task_group_cnts.inc_send_req(self.num_pes);
}
let req = Arc::new(MultiAmHandleInner {
cnt: AtomicUsize::new(self.num_pes),
arch: self.arch.clone(),
data: Mutex::new(HashMap::new()),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::MultiAm(req.clone()));
let req_ptr = Arc::into_raw(req_result);
for _ in 0..(self.num_pes - 1) {
unsafe { Arc::increment_strong_count(req_ptr) } }
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_outstanding(self.num_pes);
self.world_counters.inc_launched(self.num_pes);
self.world_counters.inc_send_req(self.num_pes);
self.team_counters.inc_outstanding(self.num_pes);
self.team_counters.inc_launched(self.num_pes);
self.team_counters.inc_send_req(self.num_pes);
let func: LamellarArcAm = Arc::new(am);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let req_data = ReqMetaData {
src: self.world_pe,
dst: None,
id: id,
lamellae: self.lamellae.clone(),
world: world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "spawn_am_all_tg submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
self.scheduler.submit_am(Am::All(req_data, func.clone()));
MultiAmHandle {
inner: req,
am: None,
_phantom: PhantomData,
}
}
pub(crate) fn am_group_exec_am_all_tg<F, O>(
&self,
am: F,
task_group_cnts: Option<Arc<AMCounters>>,
) -> MultiAmHandle<O>
where
F: RemoteActiveMessage + LamellarAM + crate::Serialize + 'static,
O: AmDist + 'static,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_send_req(self.num_pes);
}
let req = Arc::new(MultiAmHandleInner {
cnt: AtomicUsize::new(self.num_pes),
arch: self.arch.clone(),
data: Mutex::new(HashMap::new()),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::MultiAm(req.clone()));
let req_ptr = Arc::into_raw(req_result);
for _ in 0..(self.num_pes - 1) {
unsafe { Arc::increment_strong_count(req_ptr) } }
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_send_req(self.num_pes);
self.team_counters.inc_send_req(self.num_pes);
let func: LamellarArcAm = Arc::new(am);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let req_data = ReqMetaData {
src: self.world_pe,
dst: None,
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "am_group_exec_am_all_tg submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
MultiAmHandle {
inner: req,
am: Some((Am::All(req_data, func), self.num_pes)),
_phantom: PhantomData,
}
}
#[allow(dead_code)]
pub(crate) fn exec_am_pe<F>(&self, pe: usize, am: F) -> AmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + AmDist,
{
self.exec_am_pe_tg(pe, am, None)
}
pub(crate) fn exec_am_pe_tg<F>(
&self,
pe: usize,
am: F,
task_group_cnts: Option<Arc<AMCounters>>,
) -> AmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + crate::Serialize + 'static,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_send_req(1);
}
trace!(
"[{:?}- 0x{:x}] team exec am pe request to pe {:?} {:?}",
self.world_pe,
self.darc_addr(),
pe,
self.arch
);
assert!(pe < self.arch.num_pes());
let req = Arc::new(AmHandleInner {
ready: AtomicBool::new(false),
data: Cell::new(None),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::Am(req.clone()));
let req_ptr = Arc::into_raw(req_result);
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_send_req(1);
self.team_counters.inc_send_req(1);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let func: LamellarArcAm = Arc::new(am);
let req_data = ReqMetaData {
src: self.world_pe,
dst: Some(self.arch.world_pe(pe).expect("pe not member of team")),
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "exec_am_pe_tg submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
AmHandle {
inner: req,
am: Some((Am::Remote(req_data, func), 1)),
_phantom: PhantomData,
}
.into()
}
pub(crate) fn spawn_am_pe_tg<F>(
&self,
pe: usize,
am: F,
task_group_cnts: Option<Arc<AMCounters>>,
) -> AmHandle<F::Output>
where
F: RemoteActiveMessage + LamellarAM + crate::Serialize + 'static,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_outstanding(1);
task_group_cnts.inc_launched(1);
task_group_cnts.inc_send_req(1);
}
assert!(pe < self.arch.num_pes());
let req = Arc::new(AmHandleInner {
ready: AtomicBool::new(false),
data: Cell::new(None),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::Am(req.clone()));
let req_ptr = Arc::into_raw(req_result);
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_outstanding(1);
self.world_counters.inc_launched(1);
self.world_counters.inc_send_req(1);
self.team_counters.inc_outstanding(1);
self.team_counters.inc_launched(1);
self.team_counters.inc_send_req(1);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let func: LamellarArcAm = Arc::new(am);
let req_data = ReqMetaData {
src: self.world_pe,
dst: Some(self.arch.world_pe(pe).expect("pe not member of team")),
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "spawn_am_pe_tg submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
self.scheduler.submit_am(Am::Remote(req_data, func));
AmHandle {
inner: req,
am: None,
_phantom: PhantomData,
}
.into()
}
pub(crate) fn am_group_exec_am_pe_tg<F, O>(
&self,
pe: usize,
am: F,
task_group_cnts: Option<Arc<AMCounters>>,
) -> AmHandle<O>
where
F: RemoteActiveMessage + LamellarAM + crate::Serialize + 'static,
O: AmDist + 'static,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_send_req(1);
}
assert!(pe < self.arch.num_pes());
let req = Arc::new(AmHandleInner {
ready: AtomicBool::new(false),
data: Cell::new(None),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::Am(req.clone()));
let req_ptr = Arc::into_raw(req_result);
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_send_req(1);
self.team_counters.inc_send_req(1);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let func: LamellarArcAm = Arc::new(am);
let req_data = ReqMetaData {
src: self.world_pe,
dst: Some(self.arch.world_pe(pe).expect("pe not member of team")),
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "am_group_exec_am_pe_tg submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
AmHandle {
inner: req,
am: Some((Am::Remote(req_data, func), 1)),
_phantom: PhantomData,
}
}
pub(crate) fn exec_arc_am_all<F>(
&self,
am: LamellarArcAm,
task_group_cnts: Option<Arc<AMCounters>>,
) -> MultiAmHandle<F>
where
F: AmDist,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_send_req(self.num_pes);
}
let req = Arc::new(MultiAmHandleInner {
cnt: AtomicUsize::new(self.num_pes),
arch: self.arch.clone(),
waker: Mutex::new(None),
data: Mutex::new(HashMap::new()),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::MultiAm(req.clone()));
let req_ptr = Arc::into_raw(req_result);
for _ in 0..(self.num_pes - 1) {
unsafe { Arc::increment_strong_count(req_ptr) } }
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_send_req(self.num_pes);
self.team_counters.inc_send_req(self.num_pes);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let req_data = ReqMetaData {
src: self.world_pe,
dst: None,
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "exec_arc_am_all submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
MultiAmHandle {
inner: req,
am: Some((Am::All(req_data, am), self.num_pes)),
_phantom: PhantomData,
}
}
pub(crate) fn exec_arc_am_pe<F>(
&self,
pe: usize,
am: LamellarArcAm,
task_group_cnts: Option<Arc<AMCounters>>,
) -> AmHandle<F>
where
F: AmDist,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_send_req(1);
}
assert!(pe < self.arch.num_pes());
let req = Arc::new(AmHandleInner {
ready: AtomicBool::new(false),
data: Cell::new(None),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::Am(req.clone()));
let req_ptr = Arc::into_raw(req_result);
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_send_req(1);
self.team_counters.inc_send_req(1);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let req_data = ReqMetaData {
src: self.world_pe,
dst: Some(self.arch.world_pe(pe).expect("pe not member of team")),
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "exec_arc_am_pe submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
AmHandle {
inner: req,
am: Some((Am::Remote(req_data, am), 1)),
_phantom: PhantomData,
}
.into()
}
#[allow(dead_code)]
pub(crate) async fn exec_arc_am_pe_immediately<F>(
&self,
pe: usize,
am: LamellarArcAm,
task_group_cnts: Option<Arc<AMCounters>>,
) -> AmHandle<F>
where
F: AmDist,
{
self.scheduler.increment_stall_mark();
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_send_req(1);
}
assert!(pe < self.arch.num_pes());
let req = Arc::new(AmHandleInner {
ready: AtomicBool::new(false),
data: Cell::new(None),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::Am(req.clone()));
let req_ptr = Arc::into_raw(req_result);
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_send_req(1);
self.team_counters.inc_send_req(1);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let req_data = ReqMetaData {
src: self.world_pe,
dst: Some(self.arch.world_pe(pe).expect("pe not member of team")),
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "exec_arc_am_pe_immediately submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
self.scheduler.exec_am(Am::Remote(req_data, am)).await;
AmHandle {
inner: req,
am: None,
_phantom: PhantomData,
}
.into()
}
pub(crate) fn exec_am_local<F>(&self, am: F) -> LocalAmHandle<F::Output>
where
F: LamellarActiveMessage + LocalAM + 'static,
{
self.exec_am_local_tg(am, None, None)
}
pub(crate) fn exec_am_local_tg<F>(
&self,
am: F,
task_group_cnts: Option<Arc<AMCounters>>,
thread: Option<usize>,
) -> LocalAmHandle<F::Output>
where
F: LamellarActiveMessage + LocalAM + 'static,
{
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_send_req(1);
}
let req = Arc::new(AmHandleInner {
ready: AtomicBool::new(false),
data: Cell::new(None),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::Am(req.clone()));
let req_ptr = Arc::into_raw(req_result);
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_send_req(1);
self.team_counters.inc_send_req(1);
let func: LamellarArcLocalAm = Arc::new(am);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let req_data = ReqMetaData {
src: self.world_pe,
dst: Some(self.world_pe),
id,
lamellae: self.lamellae.clone(),
world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "exec_am_local_tg submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
LocalAmHandle {
inner: req,
am: Some((Am::Local(req_data, func), 1)),
_phantom: PhantomData,
thread: thread,
}
}
pub(crate) fn spawn_am_local_tg<F>(
&self,
am: F,
task_group_cnts: Option<Arc<AMCounters>>,
thread: Option<usize>,
) -> LocalAmHandle<F::Output>
where
F: LamellarActiveMessage + LocalAM + 'static,
{
if let Some(task_group_cnts) = task_group_cnts.as_ref() {
task_group_cnts.inc_outstanding(1);
task_group_cnts.inc_launched(1);
task_group_cnts.inc_send_req(1);
}
let req = Arc::new(AmHandleInner {
ready: AtomicBool::new(false),
data: Cell::new(None),
waker: Mutex::new(None),
team_counters: self.team_counters.clone(),
world_counters: self.world_counters.clone(),
tg_counters: task_group_cnts,
user_handle: AtomicU8::new(1),
scheduler: self.scheduler.clone(),
});
let req_result = Arc::new(LamellarRequestResult::Am(req.clone()));
let req_ptr = Arc::into_raw(req_result);
let id = ReqId {
id: req_ptr as usize,
sub_id: 0,
};
self.world_counters.inc_outstanding(1);
self.world_counters.inc_launched(1);
self.world_counters.inc_send_req(1);
self.team_counters.inc_outstanding(1);
self.team_counters.inc_launched(1);
self.team_counters.inc_send_req(1);
let func: LamellarArcLocalAm = Arc::new(am);
let world = if let Some(world) = &self.world {
world.clone()
} else {
self.clone()
};
let req_data = ReqMetaData {
src: self.world_pe,
dst: Some(self.world_pe),
id: id,
lamellae: self.lamellae.clone(),
world: world,
team: self.clone(),
};
trace!(target: "lamellae_debug", "spawn_am_local_tg submitting am to scheduler lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
self.scheduler
.submit_am(Am::Local(req_data.clone(), func.clone()));
LocalAmHandle {
inner: req,
am: None,
_phantom: PhantomData,
thread: thread,
}
}
pub(crate) fn alloc_one_sided_mem_region<T: Dist>(
&self,
size: usize,
) -> OneSidedMemoryRegion<T> {
let mut lmr = OneSidedMemoryRegion::try_new(size, self);
while let Err(_err) = lmr {
std::thread::yield_now();
let alloc_fut = self
.lamellae
.request_new_alloc(size * std::mem::size_of::<T>());
self.scheduler.block_on(alloc_fut);
lmr = OneSidedMemoryRegion::try_new(size, self);
}
trace!(target: "lamellae_debug", "allocated one sided mem region lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
lmr.expect("out of memory")
}
pub(crate) fn try_alloc_one_sided_mem_region<T: Remote>(
&self,
size: usize,
) -> Option<OneSidedMemoryRegion<T>> {
let lmr = OneSidedMemoryRegion::try_new(size, self);
if lmr.is_ok() {
trace!(target: "lamellae_debug", "allocated one sided mem region lamellae cnt: {:?}", Arc::strong_count(&self.lamellae));
}
lmr.ok()
}
}
impl Drop for LamellarTeamRT {
fn drop(&mut self) {
trace!(target: "drop", "begin drop LamellarTeamRT");
debug!("LamellarTeamRT dropped");
trace!(target: "drop", "end drop LamellarTeamRT lamellae cnt: {:?} scheduler cnt: {:?} arch cnt: {:?} world_counters cnt: {:?} team_counters cnt: {:?}",
Arc::strong_count(&self.lamellae),
Arc::strong_count(&self.scheduler),
Arc::strong_count(&self.arch),
Arc::strong_count(&self.world_counters),
Arc::strong_count(&self.team_counters),
);
trace!(target: "lamellae_debug", "end drop LamellarTeamRT lamellae cnt: {:?} scheduler cnt: {:?} arch cnt: {:?} world_counters cnt: {:?} team_counters cnt: {:?}",
Arc::strong_count(&self.lamellae),
Arc::strong_count(&self.scheduler),
Arc::strong_count(&self.arch),
Arc::strong_count(&self.world_counters),
Arc::strong_count(&self.team_counters),
);
}
}
impl Drop for LamellarTeam {
fn drop(&mut self) {
trace!(target: "drop", "begin drop LamellarTeam");
if self.panic.load(Ordering::SeqCst) == 0 {
if !self.am_team {
if let Some(parent) = &self.team.parent {
self.team.wait_all();
self.team.barrier();
self.team.put_dropped();
if self.team.team_pe.is_ok() {
self.team.drop_barrier();
}
parent.sub_teams.write().remove(&self.team.id);
trace!(
"removed team {:?} from parent {:?}",
self.team.team_hash,
parent.team_hash
);
}
}
} else {
assert!(self.panic.load(Ordering::SeqCst) == 2);
}
trace!("team handle dropped, RT Team: {:?}", self.team);
trace!(target: "drop", "end drop LamellarTeam lamellae cnt: {:?} scheduler cnt: {:?} arch cnt: {:?} world_counters cnt: {:?} team_counters cnt: {:?}",
Arc::strong_count(&self.team.lamellae),
Arc::strong_count(&self.team.scheduler),
Arc::strong_count(&self.team.arch),
Arc::strong_count(&self.team.world_counters),
Arc::strong_count(&self.team.team_counters),
);
trace!(target: "lamellae_debug", "end drop LamellarTeam lamellae cnt: {:?} scheduler cnt: {:?} arch cnt: {:?} world_counters cnt: {:?} team_counters cnt: {:?}",
Arc::strong_count(&self.team.lamellae),
Arc::strong_count(&self.team.scheduler),
Arc::strong_count(&self.team.arch),
Arc::strong_count(&self.team.world_counters),
Arc::strong_count(&self.team.team_counters),
);
}
}