use std::marker::PhantomData;
use crate::datatype::{Buffer, BufferMut, DatatypeRef, Equivalence};
use crate::request::{Request, Scope};
use crate::topology::CommData;
use crate::transport::{self, ANY_SOURCE, ANY_TAG};
use crate::{Count, Rank, Tag};
pub const DEFAULT_TAG: Tag = 0;
pub(crate) fn elem_from_bytes<T: Equivalence>(bytes: &[u8]) -> T {
assert!(
bytes.len() >= std::mem::size_of::<T>(),
"received message smaller than expected scalar"
);
unsafe { std::ptr::read_unaligned(bytes.as_ptr() as *const T) }
}
pub(crate) fn vec_from_bytes<T: Equivalence>(bytes: &[u8]) -> Vec<T> {
let size = std::mem::size_of::<T>();
let count = bytes.len().checked_div(size).unwrap_or(0);
let mut v: Vec<T> = Vec::with_capacity(count);
unsafe {
std::ptr::copy_nonoverlapping(bytes.as_ptr(), v.as_mut_ptr() as *mut u8, count * size);
v.set_len(count);
}
v
}
pub(crate) fn copy_into_buffer<Buf: BufferMut + ?Sized>(buf: &mut Buf, bytes: &[u8]) {
buf.scatter_from(bytes);
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Status {
source: Rank,
tag: Tag,
count: Count,
byte_len: usize,
}
impl Status {
pub(crate) fn new(source: Rank, tag: Tag, count: Count, byte_len: usize) -> Status {
Status {
source,
tag,
count,
byte_len,
}
}
pub fn source_rank(&self) -> Rank {
self.source
}
pub fn tag(&self) -> Tag {
self.tag
}
pub fn count(&self, dt: DatatypeRef) -> Count {
self.byte_len.checked_div(dt.size).unwrap_or(0) as Count
}
pub fn is_cancelled(&self) -> bool {
false
}
pub fn is_canceled(&self) -> bool {
false
}
}
pub struct Message {
source: Rank,
tag: Tag,
count: Count,
payload: Vec<u8>,
}
impl Message {
pub fn matched_receive_vec<Msg: Equivalence>(self) -> (Vec<Msg>, Status) {
let status = Status::new(self.source, self.tag, self.count, self.payload.len());
(vec_from_bytes::<Msg>(&self.payload), status)
}
pub fn matched_receive_into<Buf: BufferMut + ?Sized>(self, buf: &mut Buf) -> Status {
let status = Status::new(self.source, self.tag, self.count, self.payload.len());
copy_into_buffer(buf, &self.payload);
status
}
}
pub trait Source {
#[doc(hidden)]
fn src_comm(&self) -> &CommData;
fn source_rank(&self) -> Rank;
fn receive<Msg: Equivalence>(&self) -> (Msg, Status) {
self.receive_with_tag(ANY_TAG)
}
fn receive_with_tag<Msg: Equivalence>(&self, tag: Tag) -> (Msg, Status) {
let comm = self.src_comm();
let (src, t, count, _dt, payload) =
transport::runtime().recv(comm.context, self.source_rank(), tag);
let val = elem_from_bytes::<Msg>(&payload);
(val, Status::new(src, t, count as Count, payload.len()))
}
fn receive_vec<Msg: Equivalence>(&self) -> (Vec<Msg>, Status) {
self.receive_vec_with_tag(ANY_TAG)
}
fn receive_vec_with_tag<Msg: Equivalence>(&self, tag: Tag) -> (Vec<Msg>, Status) {
let comm = self.src_comm();
let (src, t, count, _dt, payload) =
transport::runtime().recv(comm.context, self.source_rank(), tag);
let v = vec_from_bytes::<Msg>(&payload);
(v, Status::new(src, t, count as Count, payload.len()))
}
fn receive_into<Buf: BufferMut + ?Sized>(&self, buf: &mut Buf) -> Status {
self.receive_into_with_tag(buf, ANY_TAG)
}
fn receive_into_with_tag<Buf: BufferMut + ?Sized>(&self, buf: &mut Buf, tag: Tag) -> Status {
let comm = self.src_comm();
let (src, t, count, _dt, payload) =
transport::runtime().recv(comm.context, self.source_rank(), tag);
copy_into_buffer(buf, &payload);
Status::new(src, t, count as Count, payload.len())
}
fn probe(&self) -> Status {
self.probe_with_tag(ANY_TAG)
}
fn probe_with_tag(&self, tag: Tag) -> Status {
let comm = self.src_comm();
let (src, t, count, _dt, len) =
transport::runtime().probe_blocking(comm.context, self.source_rank(), tag);
Status::new(src, t, count as Count, len)
}
fn immediate_probe(&self) -> Option<Status> {
self.immediate_probe_with_tag(ANY_TAG)
}
fn immediate_probe_with_tag(&self, tag: Tag) -> Option<Status> {
let comm = self.src_comm();
transport::runtime()
.probe(comm.context, self.source_rank(), tag)
.map(|(src, t, count, _dt, len)| Status::new(src, t, count as Count, len))
}
fn matched_probe(&self) -> (Message, Status) {
self.matched_probe_with_tag(ANY_TAG)
}
fn matched_probe_with_tag(&self, tag: Tag) -> (Message, Status) {
let comm = self.src_comm();
let (src, t, count, _dt, payload) =
transport::runtime().recv(comm.context, self.source_rank(), tag);
let status = Status::new(src, t, count as Count, payload.len());
(
Message {
source: src,
tag: t,
count: count as Count,
payload,
},
status,
)
}
fn immediate_matched_probe(&self) -> Option<(Message, Status)> {
self.immediate_matched_probe_with_tag(ANY_TAG)
}
fn immediate_matched_probe_with_tag(&self, tag: Tag) -> Option<(Message, Status)> {
if self.immediate_probe_with_tag(tag).is_some() {
Some(self.matched_probe_with_tag(tag))
} else {
None
}
}
fn immediate_receive<Msg: Equivalence>(&self) -> ReceiveFuture<Msg> {
self.immediate_receive_with_tag(ANY_TAG)
}
fn immediate_receive_with_tag<Msg: Equivalence>(&self, tag: Tag) -> ReceiveFuture<Msg> {
let comm = self.src_comm();
ReceiveFuture {
ctx: comm.context,
source: self.source_rank(),
tag,
_p: PhantomData,
}
}
fn immediate_receive_into<'a, Sc, Buf>(
&self,
scope: Sc,
buf: &'a mut Buf,
) -> Request<'a, Buf, Sc>
where
Buf: 'a + BufferMut + ?Sized,
Sc: Scope<'a>,
{
self.immediate_receive_into_with_tag(scope, buf, ANY_TAG)
}
fn immediate_receive_into_with_tag<'a, Sc, Buf>(
&self,
scope: Sc,
buf: &'a mut Buf,
tag: Tag,
) -> Request<'a, Buf, Sc>
where
Buf: 'a + BufferMut + ?Sized,
Sc: Scope<'a>,
{
let ctx = self.src_comm().context;
let source = self.source_rank();
let bytes = buf.as_bytes_mut();
let ptr = bytes.as_mut_ptr();
let len = bytes.len();
Request::pending_recv(scope, ptr, len, ctx, source, tag)
}
fn receive_init<'a, Buf: BufferMut + ?Sized>(
&self,
buf: &'a mut Buf,
) -> crate::request::PersistentRequest<'a> {
let ctx = self.src_comm().context;
let source = self.source_rank();
let bytes = buf.as_bytes_mut();
let ptr = bytes.as_mut_ptr();
let len = bytes.len();
crate::request::PersistentRequest::new_recv(ctx, source, DEFAULT_TAG, ptr, len)
}
}
pub trait Destination {
#[doc(hidden)]
fn dst_comm(&self) -> &CommData;
fn destination_rank(&self) -> Rank;
#[doc(hidden)]
fn do_try_send<Buf: Buffer + ?Sized>(
&self,
buf: &Buf,
tag: Tag,
) -> Result<(), crate::MpiError> {
let comm = self.dst_comm();
let dt = buf.as_datatype();
transport::runtime()
.send(
comm.context,
comm.rank,
comm.world_rank(self.destination_rank()),
tag,
buf.count() as u64,
dt.id,
buf.as_bytes(),
)
.map_err(|e| crate::MpiError::Other(format!("send failed: {e}")))
}
#[doc(hidden)]
fn do_send<Buf: Buffer + ?Sized>(&self, buf: &Buf, tag: Tag) {
self.do_try_send(buf, tag).expect("MPI send failed");
}
fn send<Buf: Buffer + ?Sized>(&self, buf: &Buf) {
self.do_send(buf, DEFAULT_TAG);
}
fn send_with_tag<Buf: Buffer + ?Sized>(&self, buf: &Buf, tag: Tag) {
self.do_send(buf, tag);
}
fn try_send<Buf: Buffer + ?Sized>(&self, buf: &Buf) -> Result<(), crate::MpiError> {
self.do_try_send(buf, DEFAULT_TAG)
}
fn try_send_with_tag<Buf: Buffer + ?Sized>(
&self,
buf: &Buf,
tag: Tag,
) -> Result<(), crate::MpiError> {
self.do_try_send(buf, tag)
}
fn buffered_send<Buf: Buffer + ?Sized>(&self, buf: &Buf) {
self.do_send(buf, DEFAULT_TAG);
}
fn buffered_send_with_tag<Buf: Buffer + ?Sized>(&self, buf: &Buf, tag: Tag) {
self.do_send(buf, tag);
}
fn synchronous_send<Buf: Buffer + ?Sized>(&self, buf: &Buf) {
self.do_send(buf, DEFAULT_TAG);
}
fn synchronous_send_with_tag<Buf: Buffer + ?Sized>(&self, buf: &Buf, tag: Tag) {
self.do_send(buf, tag);
}
unsafe fn ready_send<Buf: Buffer + ?Sized>(&self, buf: &Buf) {
self.do_send(buf, DEFAULT_TAG);
}
unsafe fn ready_send_with_tag<Buf: Buffer + ?Sized>(&self, buf: &Buf, tag: Tag) {
self.do_send(buf, tag);
}
fn immediate_send<'a, Sc, Buf>(&self, scope: Sc, buf: &'a Buf) -> Request<'a, Buf, Sc>
where
Buf: 'a + Buffer + ?Sized,
Sc: Scope<'a>,
{
self.immediate_send_with_tag(scope, buf, DEFAULT_TAG)
}
fn immediate_send_with_tag<'a, Sc, Buf>(
&self,
scope: Sc,
buf: &'a Buf,
tag: Tag,
) -> Request<'a, Buf, Sc>
where
Buf: 'a + Buffer + ?Sized,
Sc: Scope<'a>,
{
self.do_send(buf, tag);
Request::completed(scope)
}
fn immediate_buffered_send<'a, Sc, Buf>(&self, scope: Sc, buf: &'a Buf) -> Request<'a, Buf, Sc>
where
Buf: 'a + Buffer + ?Sized,
Sc: Scope<'a>,
{
self.immediate_send_with_tag(scope, buf, DEFAULT_TAG)
}
fn immediate_synchronous_send<'a, Sc, Buf>(
&self,
scope: Sc,
buf: &'a Buf,
) -> Request<'a, Buf, Sc>
where
Buf: 'a + Buffer + ?Sized,
Sc: Scope<'a>,
{
self.immediate_send_with_tag(scope, buf, DEFAULT_TAG)
}
fn send_init<'a, Buf: Buffer + ?Sized>(
&self,
buf: &'a Buf,
) -> crate::request::PersistentRequest<'a> {
let comm = self.dst_comm();
let bytes = buf.as_bytes();
crate::request::PersistentRequest::new_send(
comm.context,
comm.rank,
comm.world_rank(self.destination_rank()),
DEFAULT_TAG,
buf.as_datatype().id,
buf.count() as u64,
bytes.as_ptr(),
bytes.len(),
)
}
}
pub struct ReceiveFuture<T> {
ctx: u32,
source: Rank,
tag: Tag,
_p: PhantomData<T>,
}
impl<T: Equivalence> ReceiveFuture<T> {
pub fn get(self) -> (T, Status) {
let (src, t, count, _dt, payload) =
transport::runtime().recv(self.ctx, self.source, self.tag);
(
elem_from_bytes::<T>(&payload),
Status::new(src, t, count as Count, payload.len()),
)
}
}
pub fn send_receive<R, M, D, S>(msg: &M, destination: &D, source: &S) -> (R, Status)
where
M: Equivalence,
R: Equivalence,
D: Destination,
S: Source,
{
destination.send(msg);
source.receive::<R>()
}
pub fn send_receive_into_with_tags<M, D, B, S>(
msg: &M,
destination: &D,
sendtag: Tag,
buf: &mut B,
source: &S,
receivetag: Tag,
) -> Status
where
M: Buffer + ?Sized,
D: Destination,
B: BufferMut + ?Sized,
S: Source,
{
destination.send_with_tag(msg, sendtag);
source.receive_into_with_tag(buf, receivetag)
}
pub fn send_receive_into<M, D, B, S>(msg: &M, destination: &D, buf: &mut B, source: &S) -> Status
where
M: Buffer + ?Sized,
D: Destination,
B: BufferMut + ?Sized,
S: Source,
{
send_receive_into_with_tags(msg, destination, DEFAULT_TAG, buf, source, ANY_TAG)
}
pub fn send_receive_replace_into_with_tags<B, D, S>(
buf: &mut B,
destination: &D,
sendtag: Tag,
source: &S,
receivetag: Tag,
) -> Status
where
B: Buffer + BufferMut + ?Sized,
D: Destination,
S: Source,
{
let saved = buf.as_bytes().to_vec();
destination.send_with_tag(&saved[..], sendtag);
source.receive_into_with_tag(buf, receivetag)
}
pub fn send_receive_replace_into<B, D, S>(buf: &mut B, destination: &D, source: &S) -> Status
where
B: Buffer + BufferMut + ?Sized,
D: Destination,
S: Source,
{
send_receive_replace_into_with_tags(buf, destination, DEFAULT_TAG, source, ANY_TAG)
}
#[derive(Copy, Clone)]
pub struct Process<'a> {
pub(crate) comm: &'a CommData,
pub(crate) rank: Rank,
}
impl<'a> Process<'a> {
pub(crate) fn new(comm: &'a CommData, rank: Rank) -> Process<'a> {
Process { comm, rank }
}
pub fn rank(&self) -> Rank {
self.rank
}
pub fn is_self(&self) -> bool {
self.rank == self.comm.rank
}
}
impl Source for Process<'_> {
fn src_comm(&self) -> &CommData {
self.comm
}
fn source_rank(&self) -> Rank {
self.rank
}
}
impl Destination for Process<'_> {
fn dst_comm(&self) -> &CommData {
self.comm
}
fn destination_rank(&self) -> Rank {
self.rank
}
}
#[derive(Copy, Clone)]
pub struct AnyProcess<'a> {
comm: &'a CommData,
}
impl<'a> AnyProcess<'a> {
pub(crate) fn new(comm: &'a CommData) -> AnyProcess<'a> {
AnyProcess { comm }
}
}
impl Source for AnyProcess<'_> {
fn src_comm(&self) -> &CommData {
self.comm
}
fn source_rank(&self) -> Rank {
ANY_SOURCE
}
}