paulistrings/collectives.rs
1//! [`Collectives`], the group operations a partition's truncation and layer loop issue besides the exchange.
2
3/// Seals [`Collectives`] and, through it, [`Transport`](crate::Transport).
4pub(crate) mod sealed {
5 pub trait Sealed {}
6}
7
8/// The group operations a partition needs besides the exchange: its rank, the reductions, and a barrier.
9///
10/// Every partition must issue the identical sequence of collective and transport calls, and every reduction must return the identical value on every partition.
11/// Sealed: implemented only by the in-process, solo and `mpi::MpiTransport` transports.
12pub trait Collectives: sealed::Sealed + Send + Sync {
13 /// This partition's index in the group, `0 <= rank < size`.
14 fn rank(&self) -> u32;
15 /// Number of partitions in the group.
16 fn size(&self) -> u32;
17 /// Maximum of `v` over the group.
18 fn allreduce_max_u8(&self, v: u8) -> u8;
19 /// Element-wise wrapping sum of `buffer` over the group, in place; every partition passes the same length.
20 fn allreduce_sum_u64(&self, buffer: &mut [u64]);
21 /// Element-wise sum of `buffer` over the group, in place, bitwise identical on every partition.
22 ///
23 /// The combination order is the implementation's, so the result may differ by rounding from a serial sum; a slot only one partition fills is exact.
24 fn allreduce_sum_f64(&self, buffer: &mut [f64]);
25 /// Block until every partition has arrived.
26 fn barrier(&self);
27
28 /// Panic unless every partition passed the same `fingerprint`; one collective.
29 fn check_consistency(&self, fingerprint: u64) {
30 // Per bit, how many partitions set it: an agreeing group answers 0 or `size` for every bit.
31 let mut counts = [0u64; 64];
32 for (i, count) in counts.iter_mut().enumerate() {
33 *count = (fingerprint >> i) & 1;
34 }
35 self.allreduce_sum_u64(&mut counts);
36 let size = u64::from(self.size());
37 for (bit, &count) in counts.iter().enumerate() {
38 assert!(
39 count == 0 || count == size,
40 "the partitions disagree about the run: partition {} offered fingerprint \
41 {fingerprint:#018x}, and {count} of {size} partitions set bit {bit} of theirs. \
42 Every partition must be driven through the same circuit, in the same direction, \
43 under the same policy and options — a group that is not stays in step only by \
44 luck.",
45 self.rank(),
46 );
47 }
48 }
49}