1use std::any::Any;
7use std::collections::HashMap;
8use std::sync::atomic::{AtomicU32, Ordering};
9use std::sync::{Arc, Mutex};
10
11use crate::datatype::{Buffer, BufferMut, DatatypeRef};
12use crate::point_to_point::{AnyProcess, Process};
13use crate::transport;
14use crate::{Count, Rank, Tag};
15
16pub type Key = i32;
18
19pub(crate) const COLL_CONTEXT_BIT: u32 = 0x8000_0000;
22
23pub struct CommData {
28 pub(crate) context: u32,
29 pub(crate) rank: Rank,
30 pub(crate) size: Rank,
31 pub(crate) world_ranks: Vec<i32>,
33 pub(crate) child_seq: AtomicU32,
37 pub(crate) name: Mutex<Option<String>>,
39 pub(crate) attributes: Mutex<HashMap<i32, Box<dyn Any + Send + Sync>>>,
41}
42
43impl CommData {
44 fn world() -> CommData {
46 let rt = transport::runtime();
47 let size = rt.size;
48 CommData {
49 context: 0,
50 rank: rt.rank,
51 size,
52 world_ranks: (0..size).collect(),
53 child_seq: AtomicU32::new(0),
54 name: Mutex::new(Some("MPI_COMM_WORLD".to_string())),
55 attributes: Mutex::new(HashMap::new()),
56 }
57 }
58
59 pub(crate) fn coll_context(&self) -> u32 {
61 self.context | COLL_CONTEXT_BIT
62 }
63
64 pub(crate) fn world_rank(&self, comm_rank: Rank) -> i32 {
66 self.world_ranks[comm_rank as usize]
67 }
68
69 pub(crate) fn async_clone(&self, context: u32) -> CommData {
72 CommData {
73 context,
74 rank: self.rank,
75 size: self.size,
76 world_ranks: self.world_ranks.clone(),
77 child_seq: AtomicU32::new(0),
78 name: Mutex::new(None),
79 attributes: Mutex::new(HashMap::new()),
80 }
81 }
82
83 pub(crate) fn derive_context(&self, disc: u32) -> u32 {
87 let seq = self.child_seq.fetch_add(1, Ordering::SeqCst);
88 let mut h = self
90 .context
91 .wrapping_mul(0x9E37_79B1)
92 .wrapping_add(seq.wrapping_mul(0x85EB_CA77))
93 .wrapping_add(disc.wrapping_mul(0xC2B2_AE3D));
94 h ^= h >> 15;
95 h = h.wrapping_mul(0x2545_F491);
96 h ^= h >> 13;
97 h & !COLL_CONTEXT_BIT
99 }
100}
101
102#[derive(Copy, Clone, Debug, PartialEq, Eq)]
104pub enum CommunicatorRelation {
105 Identical,
107 Congruent,
109 Similar,
111 Unequal,
113}
114
115#[derive(Copy, Clone, Debug, PartialEq, Eq)]
117pub enum GroupRelation {
118 Identical,
120 Similar,
122 Unequal,
124}
125
126#[derive(Copy, Clone, Debug, PartialEq, Eq)]
129pub struct Color(Option<i32>);
130
131impl Color {
132 pub fn with_value(value: Rank) -> Color {
134 Color(Some(value))
135 }
136 pub fn undefined() -> Color {
138 Color(None)
139 }
140 fn value(&self) -> Option<i32> {
141 self.0
142 }
143}
144
145#[derive(Clone, Debug)]
148pub struct Group {
149 members: Vec<i32>,
151}
152
153pub type UserGroup = Group;
155
156impl Group {
157 pub(crate) fn from_world_ranks(mut members: Vec<i32>) -> Group {
158 members.dedup();
159 Group { members }
160 }
161
162 pub fn empty() -> Group {
164 Group {
165 members: Vec::new(),
166 }
167 }
168
169 pub fn size(&self) -> Rank {
171 self.members.len() as Rank
172 }
173
174 pub fn rank(&self) -> Option<Rank> {
176 let me = transport::runtime().rank;
177 self.members
178 .iter()
179 .position(|&w| w == me)
180 .map(|p| p as Rank)
181 }
182
183 pub fn translate_ranks(&self, ranks: &[Rank], other: &Group) -> Vec<Option<Rank>> {
186 ranks
187 .iter()
188 .map(|&r| {
189 let w = self.members.get(r as usize).copied()?;
190 other
191 .members
192 .iter()
193 .position(|&o| o == w)
194 .map(|p| p as Rank)
195 })
196 .collect()
197 }
198
199 pub fn union(&self, other: &Group) -> Group {
202 let mut m = self.members.clone();
203 for &w in &other.members {
204 if !m.contains(&w) {
205 m.push(w);
206 }
207 }
208 Group { members: m }
209 }
210
211 pub fn intersection(&self, other: &Group) -> Group {
213 let m = self
214 .members
215 .iter()
216 .copied()
217 .filter(|w| other.members.contains(w))
218 .collect();
219 Group { members: m }
220 }
221
222 pub fn difference(&self, other: &Group) -> Group {
224 let m = self
225 .members
226 .iter()
227 .copied()
228 .filter(|w| !other.members.contains(w))
229 .collect();
230 Group { members: m }
231 }
232
233 pub fn include(&self, ranks: &[Rank]) -> Group {
236 let m = ranks
237 .iter()
238 .filter_map(|&r| self.members.get(r as usize).copied())
239 .collect();
240 Group { members: m }
241 }
242
243 pub fn exclude(&self, ranks: &[Rank]) -> Group {
245 let drop: Vec<i32> = ranks
246 .iter()
247 .filter_map(|&r| self.members.get(r as usize).copied())
248 .collect();
249 let m = self
250 .members
251 .iter()
252 .copied()
253 .filter(|w| !drop.contains(w))
254 .collect();
255 Group { members: m }
256 }
257
258 pub fn compare(&self, other: &Group) -> GroupRelation {
260 if self.members == other.members {
261 GroupRelation::Identical
262 } else {
263 let mut a = self.members.clone();
264 let mut b = other.members.clone();
265 a.sort_unstable();
266 b.sort_unstable();
267 if a == b {
268 GroupRelation::Similar
269 } else {
270 GroupRelation::Unequal
271 }
272 }
273 }
274
275 pub(crate) fn members(&self) -> &[i32] {
276 &self.members
277 }
278}
279
280pub trait Communicator {
285 #[doc(hidden)]
288 fn comm_data(&self) -> &CommData;
289
290 fn size(&self) -> Rank {
292 self.comm_data().size
293 }
294
295 fn rank(&self) -> Rank {
297 self.comm_data().rank
298 }
299
300 fn target_size(&self) -> Rank {
303 self.comm_data().size
304 }
305
306 fn process_at_rank(&self, r: Rank) -> Process<'_> {
308 Process::new(self.comm_data(), r)
309 }
310
311 fn this_process(&self) -> Process<'_> {
313 Process::new(self.comm_data(), self.comm_data().rank)
314 }
315
316 fn any_process(&self) -> AnyProcess<'_> {
318 AnyProcess::new(self.comm_data())
319 }
320
321 fn group(&self) -> Group {
323 Group::from_world_ranks(self.comm_data().world_ranks.clone())
324 }
325
326 fn compare(&self, other: &dyn Communicator) -> CommunicatorRelation {
328 let a = self.comm_data();
329 let b = other.comm_data();
330 if a.context == b.context {
331 CommunicatorRelation::Identical
332 } else if a.world_ranks == b.world_ranks {
333 CommunicatorRelation::Congruent
334 } else {
335 let mut sa = a.world_ranks.clone();
336 let mut sb = b.world_ranks.clone();
337 sa.sort_unstable();
338 sb.sort_unstable();
339 if sa == sb {
340 CommunicatorRelation::Similar
341 } else {
342 CommunicatorRelation::Unequal
343 }
344 }
345 }
346
347 fn duplicate(&self) -> SimpleCommunicator {
350 let data = self.comm_data();
351 let ctx = data.derive_context(0xD00Du32);
352 SimpleCommunicator::from_parts(ctx, data.rank, data.size, data.world_ranks.clone())
353 }
354
355 fn split_by_color(&self, color: Color) -> Option<SimpleCommunicator> {
357 self.split_by_color_with_key(color, self.rank())
358 }
359
360 fn split_by_color_with_key(&self, color: Color, key: Key) -> Option<SimpleCommunicator> {
363 split_impl(self.comm_data(), color, key)
364 }
365
366 fn split_by_subgroup(&self, group: &Group) -> Option<SimpleCommunicator> {
369 let data = self.comm_data();
370 let me = transport::runtime().rank;
371 if !group.members().contains(&me) {
372 return None;
373 }
374 let disc = group
377 .members()
378 .iter()
379 .fold(0u32, |a, &w| a.wrapping_mul(31).wrapping_add(w as u32));
380 let ctx = data.derive_context(disc ^ 0x5EED);
381 let world_ranks: Vec<i32> = group.members().to_vec();
382 let rank = world_ranks.iter().position(|&w| w == me).unwrap() as Rank;
383 let size = world_ranks.len() as Rank;
384 Some(SimpleCommunicator::from_parts(ctx, rank, size, world_ranks))
385 }
386
387 fn abort(&self, errorcode: i32) -> ! {
390 eprintln!(
391 "MPI_Abort called on rank {} (code {})",
392 self.rank(),
393 errorcode
394 );
395 transport::abort_job(errorcode);
396 }
397
398 fn set_name(&self, name: &str) {
400 *self.comm_data().name.lock().unwrap() = Some(name.to_string());
401 }
402
403 fn get_name(&self) -> String {
405 self.comm_data()
406 .name
407 .lock()
408 .unwrap()
409 .clone()
410 .unwrap_or_default()
411 }
412
413 fn pack_size(&self, incount: Count, dt: DatatypeRef) -> Count {
416 incount * dt.size as Count
417 }
418
419 fn pack<Buf: Buffer + ?Sized>(&self, inbuf: &Buf) -> Vec<u8>
422 where
423 Self: Sized,
424 {
425 inbuf.as_bytes().to_vec()
426 }
427
428 fn pack_into<Buf: Buffer + ?Sized>(
431 &self,
432 inbuf: &Buf,
433 outbuf: &mut [u8],
434 position: Count,
435 ) -> Count
436 where
437 Self: Sized,
438 {
439 let bytes = inbuf.as_bytes();
440 let start = position as usize;
441 outbuf[start..start + bytes.len()].copy_from_slice(bytes);
442 position + bytes.len() as Count
443 }
444
445 unsafe fn unpack_into<Buf: BufferMut + ?Sized>(
453 &self,
454 inbuf: &[u8],
455 outbuf: &mut Buf,
456 position: Count,
457 ) -> Count
458 where
459 Self: Sized,
460 {
461 let dst = outbuf.as_bytes_mut();
462 let start = position as usize;
463 let n = dst.len().min(inbuf.len() - start);
464 dst[..n].copy_from_slice(&inbuf[start..start + n]);
465 position + n as Count
466 }
467
468 fn create_graph_communicator(
474 &self,
475 index: &[Count],
476 edges: &[Count],
477 ) -> Option<GraphCommunicator> {
478 let nnodes = index.len() as Count;
479 let color = if self.rank() < nnodes {
480 Color::with_value(0)
481 } else {
482 Color::undefined()
483 };
484 let sub = self.split_by_color(color)?;
485 Some(GraphCommunicator {
486 comm: sub,
487 index: index.to_vec(),
488 edges: edges.to_vec(),
489 })
490 }
491
492 fn create_dist_graph_adjacent(
496 &self,
497 sources: &[Rank],
498 destinations: &[Rank],
499 ) -> DistGraphCommunicator {
500 DistGraphCommunicator {
501 comm: self.duplicate(),
502 sources: sources.to_vec(),
503 destinations: destinations.to_vec(),
504 }
505 }
506
507 fn split_intercommunicator(&self, in_group_a: bool) -> InterCommunicator {
512 let data = self.comm_data();
513 let me = transport::runtime().rank;
514 let mut rec = Vec::with_capacity(5);
515 rec.push(in_group_a as u8);
516 rec.extend_from_slice(&me.to_le_bytes());
517 let table = allgather_bytes(data, &rec);
518
519 let mut group_a = Vec::new();
520 let mut group_b = Vec::new();
521 for r in &table {
522 let a = r[0] != 0;
523 let w = i32::from_le_bytes(r[1..5].try_into().unwrap());
524 if a {
525 group_a.push(w);
526 } else {
527 group_b.push(w);
528 }
529 }
530 let (local, remote) = if in_group_a {
531 (group_a, group_b)
532 } else {
533 (group_b, group_a)
534 };
535 let ctx = data.derive_context(0x1E7E_1C0D);
536 let my_local_rank = local.iter().position(|&w| w == me).unwrap() as Rank;
537 InterCommunicator::new(ctx, my_local_rank, local, remote)
538 }
539
540 fn create_cartesian_communicator(
547 &self,
548 dims: &[Count],
549 periods: &[bool],
550 _reorder: bool,
551 ) -> Option<CartesianCommunicator> {
552 assert_eq!(
553 dims.len(),
554 periods.len(),
555 "dims and periods length mismatch"
556 );
557 let total: Count = dims.iter().product();
558 let color = if self.rank() < total {
559 Color::with_value(0)
560 } else {
561 Color::undefined()
562 };
563 let sub = self.split_by_color(color)?;
564 Some(CartesianCommunicator {
565 comm: sub,
566 dims: dims.to_vec(),
567 periods: periods.to_vec(),
568 })
569 }
570
571 fn parent(&self) -> Option<InterCommunicator> {
575 let (ictx, paddrs) = transport::spawn_parent()?;
576 transport::runtime().register_context_peers(ictx, paddrs.clone());
577 let data = self.comm_data();
578 Some(InterCommunicator::new_spawned(
579 ictx,
580 data.rank,
581 data.world_ranks.clone(),
582 paddrs.len(),
583 ))
584 }
585}
586
587pub struct SimpleCommunicator {
590 inner: Arc<CommData>,
591}
592
593pub type SystemCommunicator = SimpleCommunicator;
595pub type UserCommunicator = SimpleCommunicator;
597
598impl SimpleCommunicator {
599 pub fn world() -> SimpleCommunicator {
601 SimpleCommunicator {
602 inner: Arc::new(CommData::world()),
603 }
604 }
605
606 fn from_parts(
607 context: u32,
608 rank: Rank,
609 size: Rank,
610 world_ranks: Vec<i32>,
611 ) -> SimpleCommunicator {
612 SimpleCommunicator {
613 inner: Arc::new(CommData {
614 context,
615 rank,
616 size,
617 world_ranks,
618 child_seq: AtomicU32::new(0),
619 name: Mutex::new(None),
620 attributes: Mutex::new(HashMap::new()),
621 }),
622 }
623 }
624}
625
626impl Communicator for SimpleCommunicator {
627 fn comm_data(&self) -> &CommData {
628 &self.inner
629 }
630}
631
632impl Clone for SimpleCommunicator {
633 fn clone(&self) -> Self {
634 SimpleCommunicator {
635 inner: Arc::clone(&self.inner),
636 }
637 }
638}
639
640fn split_impl(parent: &CommData, color: Color, key: Key) -> Option<SimpleCommunicator> {
642 let mut rec = Vec::with_capacity(16);
644 let c = color.value();
645 rec.extend_from_slice(&(c.is_some() as i32).to_le_bytes());
646 rec.extend_from_slice(&c.unwrap_or(0).to_le_bytes());
647 rec.extend_from_slice(&key.to_le_bytes());
648 rec.extend_from_slice(&transport::runtime().rank.to_le_bytes());
649
650 let table = allgather_bytes(parent, &rec);
651
652 struct Entry {
654 defined: bool,
655 color: i32,
656 key: i32,
657 world: i32,
658 }
659 let entries: Vec<Entry> = table
660 .iter()
661 .map(|r| Entry {
662 defined: i32::from_le_bytes(r[0..4].try_into().unwrap()) != 0,
663 color: i32::from_le_bytes(r[4..8].try_into().unwrap()),
664 key: i32::from_le_bytes(r[8..12].try_into().unwrap()),
665 world: i32::from_le_bytes(r[12..16].try_into().unwrap()),
666 })
667 .collect();
668
669 let my_world = transport::runtime().rank;
670 let my_color = color.value()?; let mut members: Vec<(&Entry, usize)> = entries
674 .iter()
675 .enumerate()
676 .filter(|(_, e)| e.defined && e.color == my_color)
677 .map(|(i, e)| (e, i))
678 .collect();
679 members.sort_by(|a, b| a.0.key.cmp(&b.0.key).then(a.1.cmp(&b.1)));
680
681 let world_ranks: Vec<i32> = members.iter().map(|(e, _)| e.world).collect();
682 let rank = world_ranks.iter().position(|&w| w == my_world).unwrap() as Rank;
683 let size = world_ranks.len() as Rank;
684
685 let ctx = parent.derive_context(my_color as u32);
688 Some(SimpleCommunicator::from_parts(ctx, rank, size, world_ranks))
689}
690
691const SPLIT_GATHER_TAG: Tag = 1;
692const SPLIT_BCAST_TAG: Tag = 2;
693
694pub(crate) fn allgather_bytes(comm: &CommData, mine: &[u8]) -> Vec<Vec<u8>> {
698 let rt = transport::runtime();
699 let ctx = comm.coll_context();
700 let n = comm.size;
701 let me = comm.rank;
702 let dt = crate::datatype::ids::U8;
703
704 if me == 0 {
705 let mut table: Vec<Vec<u8>> = vec![Vec::new(); n as usize];
706 table[0] = mine.to_vec();
707 for src in 1..n {
708 let (_s, _t, _c, _d, payload) = rt.recv(ctx, src, SPLIT_GATHER_TAG);
709 table[src as usize] = payload;
710 }
711 let mut blob = Vec::new();
713 blob.extend_from_slice(&(n as u32).to_le_bytes());
714 for rec in &table {
715 blob.extend_from_slice(&(rec.len() as u32).to_le_bytes());
716 blob.extend_from_slice(rec);
717 }
718 for dst in 1..n {
719 rt.send(
720 ctx,
721 0,
722 comm.world_rank(dst),
723 SPLIT_BCAST_TAG,
724 blob.len() as u64,
725 dt,
726 &blob,
727 )
728 .expect("split broadcast failed");
729 }
730 table
731 } else {
732 rt.send(
733 ctx,
734 me,
735 comm.world_rank(0),
736 SPLIT_GATHER_TAG,
737 mine.len() as u64,
738 dt,
739 mine,
740 )
741 .expect("split gather failed");
742 let (_s, _t, _c, _d, blob) = rt.recv(ctx, 0, SPLIT_BCAST_TAG);
743 decode_table(&blob)
744 }
745}
746
747fn decode_table(blob: &[u8]) -> Vec<Vec<u8>> {
748 let mut pos = 0;
749 let n = u32::from_le_bytes(blob[pos..pos + 4].try_into().unwrap()) as usize;
750 pos += 4;
751 let mut out = Vec::with_capacity(n);
752 for _ in 0..n {
753 let len = u32::from_le_bytes(blob[pos..pos + 4].try_into().unwrap()) as usize;
754 pos += 4;
755 out.push(blob[pos..pos + len].to_vec());
756 pos += len;
757 }
758 out
759}
760
761#[derive(Clone)]
765pub struct CartesianCommunicator {
766 comm: SimpleCommunicator,
767 dims: Vec<Count>,
768 periods: Vec<bool>,
769}
770
771impl Communicator for CartesianCommunicator {
772 fn comm_data(&self) -> &CommData {
773 self.comm.comm_data()
774 }
775}
776
777impl CartesianCommunicator {
778 pub fn num_dimensions(&self) -> usize {
780 self.dims.len()
781 }
782
783 pub fn dimensions(&self) -> &[Count] {
785 &self.dims
786 }
787
788 pub fn periods(&self) -> &[bool] {
790 &self.periods
791 }
792
793 pub fn coordinates(&self, rank: Rank) -> Vec<Count> {
795 let mut coords = vec![0; self.dims.len()];
796 let mut r = rank;
797 for i in (0..self.dims.len()).rev() {
798 coords[i] = r % self.dims[i];
799 r /= self.dims[i];
800 }
801 coords
802 }
803
804 pub fn my_coordinates(&self) -> Vec<Count> {
806 self.coordinates(self.rank())
807 }
808
809 pub fn rank_from_coordinates(&self, coords: &[Count]) -> Option<Rank> {
812 let mut rank = 0;
813 for ((&dim, &periodic), &coord) in self.dims.iter().zip(&self.periods).zip(coords) {
814 let mut c = coord;
815 if periodic {
816 c = c.rem_euclid(dim);
817 } else if c < 0 || c >= dim {
818 return None;
819 }
820 rank = rank * dim + c;
821 }
822 Some(rank)
823 }
824
825 pub fn shift(&self, direction: usize, disp: Count) -> (Option<Rank>, Option<Rank>) {
829 let coords = self.my_coordinates();
830 let mut dest = coords.clone();
831 dest[direction] += disp;
832 let mut source = coords;
833 source[direction] -= disp;
834 (
835 self.rank_from_coordinates(&source),
836 self.rank_from_coordinates(&dest),
837 )
838 }
839}
840
841#[derive(Clone)]
843pub struct GraphCommunicator {
844 comm: SimpleCommunicator,
845 index: Vec<Count>,
846 edges: Vec<Count>,
847}
848
849impl Communicator for GraphCommunicator {
850 fn comm_data(&self) -> &CommData {
851 self.comm.comm_data()
852 }
853}
854
855impl GraphCommunicator {
856 pub fn num_nodes(&self) -> Count {
858 self.index.len() as Count
859 }
860
861 pub fn num_edges(&self) -> Count {
863 self.edges.len() as Count
864 }
865
866 pub fn neighbor_count(&self, rank: Rank) -> Count {
868 let (s, e) = self.range(rank);
869 (e - s) as Count
870 }
871
872 pub fn neighbors(&self, rank: Rank) -> Vec<Rank> {
874 let (s, e) = self.range(rank);
875 self.edges[s..e].to_vec()
876 }
877
878 pub fn my_neighbors(&self) -> Vec<Rank> {
880 self.neighbors(self.rank())
881 }
882
883 pub fn neighbor_all_gather_into<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
887 where
888 S: Buffer + ?Sized,
889 R: BufferMut + ?Sized,
890 {
891 const TAG: Tag = 40;
892 let rt = transport::runtime();
893 let ctx = self.comm.comm_data().coll_context();
894 let me = self.comm.comm_data().rank;
895 let nbrs = self.my_neighbors();
896 let send = sendbuf.as_bytes();
897 let dt = sendbuf.as_datatype().id;
898 for &nb in &nbrs {
899 rt.send(
900 ctx,
901 me,
902 self.comm.comm_data().world_rank(nb),
903 TAG,
904 sendbuf.count() as u64,
905 dt,
906 send,
907 )
908 .expect("neighbor_all_gather send");
909 }
910 let out = recvbuf.as_bytes_mut();
911 let blk = send.len();
912 for (k, &nb) in nbrs.iter().enumerate() {
913 let (_s, _t, _c, _d, payload) = rt.recv(ctx, nb, TAG);
914 out[k * blk..k * blk + payload.len()].copy_from_slice(&payload);
915 }
916 }
917
918 pub fn neighbor_all_to_all_into<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
922 where
923 S: Buffer + ?Sized,
924 R: BufferMut + ?Sized,
925 {
926 const TAG: Tag = 41;
927 let rt = transport::runtime();
928 let ctx = self.comm.comm_data().coll_context();
929 let me = self.comm.comm_data().rank;
930 let nbrs = self.my_neighbors();
931 let send = sendbuf.as_bytes();
932 let dt = sendbuf.as_datatype().id;
933 let esize = sendbuf.as_datatype().size.max(1);
934 let blk = if nbrs.is_empty() {
935 0
936 } else {
937 send.len() / nbrs.len()
938 };
939 for (k, &nb) in nbrs.iter().enumerate() {
940 rt.send(
941 ctx,
942 me,
943 self.comm.comm_data().world_rank(nb),
944 TAG,
945 (blk / esize) as u64,
946 dt,
947 &send[k * blk..(k + 1) * blk],
948 )
949 .expect("neighbor_all_to_all send");
950 }
951 let out = recvbuf.as_bytes_mut();
952 for (k, &nb) in nbrs.iter().enumerate() {
953 let (_s, _t, _c, _d, payload) = rt.recv(ctx, nb, TAG);
954 out[k * blk..k * blk + payload.len()].copy_from_slice(&payload);
955 }
956 }
957
958 fn range(&self, rank: Rank) -> (usize, usize) {
959 let r = rank as usize;
960 let start = if r == 0 {
961 0
962 } else {
963 self.index[r - 1] as usize
964 };
965 let end = self.index[r] as usize;
966 (start, end)
967 }
968}
969
970pub struct InterCommunicator {
975 data: CommData,
979 local: Vec<i32>,
980 remote: Vec<i32>,
981}
982
983impl InterCommunicator {
984 fn new(context: u32, local_rank: Rank, local: Vec<i32>, remote: Vec<i32>) -> InterCommunicator {
985 let data = CommData {
986 context,
987 rank: local_rank,
988 size: local.len() as Rank,
989 world_ranks: remote.clone(),
990 child_seq: AtomicU32::new(0),
991 name: Mutex::new(None),
992 attributes: Mutex::new(HashMap::new()),
993 };
994 InterCommunicator {
995 data,
996 local,
997 remote,
998 }
999 }
1000
1001 pub(crate) fn new_spawned(
1006 context: u32,
1007 local_rank: Rank,
1008 local: Vec<i32>,
1009 remote_count: usize,
1010 ) -> InterCommunicator {
1011 let remote: Vec<i32> = (0..remote_count as i32).collect();
1012 let data = CommData {
1013 context,
1014 rank: local_rank,
1015 size: local.len() as Rank,
1016 world_ranks: remote.clone(),
1017 child_seq: AtomicU32::new(0),
1018 name: Mutex::new(None),
1019 attributes: Mutex::new(HashMap::new()),
1020 };
1021 InterCommunicator {
1022 data,
1023 local,
1024 remote,
1025 }
1026 }
1027
1028 pub fn local_size(&self) -> Rank {
1030 self.local.len() as Rank
1031 }
1032
1033 pub fn remote_size(&self) -> Rank {
1035 self.remote.len() as Rank
1036 }
1037
1038 pub fn rank(&self) -> Rank {
1040 self.data.rank
1041 }
1042
1043 pub fn local_group(&self) -> Group {
1045 Group::from_world_ranks(self.local.clone())
1046 }
1047
1048 pub fn remote_group(&self) -> Group {
1050 Group::from_world_ranks(self.remote.clone())
1051 }
1052
1053 pub fn merge(&self) -> SimpleCommunicator {
1056 let mut all = self.local.clone();
1057 all.extend_from_slice(&self.remote);
1058 all.sort_unstable();
1059 all.dedup();
1060 let mut ctx = 0x4D_4552u32; for &w in &all {
1063 ctx = ctx.wrapping_mul(31).wrapping_add(w as u32);
1064 }
1065 ctx &= !COLL_CONTEXT_BIT;
1066 let me = transport::runtime().rank;
1067 let rank = all.iter().position(|&w| w == me).unwrap() as Rank;
1068 let size = all.len() as Rank;
1069 SimpleCommunicator::from_parts(ctx, rank, size, all)
1070 }
1071}
1072
1073impl Communicator for InterCommunicator {
1074 fn comm_data(&self) -> &CommData {
1075 &self.data
1076 }
1077
1078 fn size(&self) -> Rank {
1080 self.local.len() as Rank
1081 }
1082}
1083
1084#[derive(Clone)]
1088pub struct DistGraphCommunicator {
1089 comm: SimpleCommunicator,
1090 sources: Vec<Rank>,
1091 destinations: Vec<Rank>,
1092}
1093
1094impl Communicator for DistGraphCommunicator {
1095 fn comm_data(&self) -> &CommData {
1096 self.comm.comm_data()
1097 }
1098}
1099
1100impl DistGraphCommunicator {
1101 pub fn in_degree(&self) -> usize {
1103 self.sources.len()
1104 }
1105
1106 pub fn out_degree(&self) -> usize {
1108 self.destinations.len()
1109 }
1110
1111 pub fn sources(&self) -> &[Rank] {
1113 &self.sources
1114 }
1115
1116 pub fn destinations(&self) -> &[Rank] {
1118 &self.destinations
1119 }
1120
1121 pub fn neighbor_all_gather_into<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
1124 where
1125 S: Buffer + ?Sized,
1126 R: BufferMut + ?Sized,
1127 {
1128 const TAG: Tag = 42;
1129 let comm = self.comm.comm_data();
1130 let ctx = comm.coll_context();
1131 let me = comm.rank;
1132 let send = sendbuf.as_bytes();
1133 let dt = sendbuf.as_datatype().id;
1134 for &d in &self.destinations {
1135 transport::runtime()
1136 .send(
1137 ctx,
1138 me,
1139 comm.world_rank(d),
1140 TAG,
1141 sendbuf.count() as u64,
1142 dt,
1143 send,
1144 )
1145 .expect("dist-graph neighbor_all_gather send");
1146 }
1147 let out = recvbuf.as_bytes_mut();
1148 let blk = send.len();
1149 for (k, &s) in self.sources.iter().enumerate() {
1150 let (_s, _t, _c, _d, payload) = transport::runtime().recv(ctx, s, TAG);
1151 out[k * blk..k * blk + payload.len()].copy_from_slice(&payload);
1152 }
1153 }
1154}