pub struct SystemOperation { /* private fields */ }Expand description
A built-in reduction operation (MPI_SUM, MPI_MAX, …). Mirrors rsmpi’s
SystemOperation.
Implementations§
Source§impl SystemOperation
impl SystemOperation
Sourcepub fn sum() -> SystemOperation
pub fn sum() -> SystemOperation
MPI_SUM.
Examples found in repository?
examples/cluster.rs (line 38)
12fn main() {
13 let universe = mpi::initialize().unwrap();
14 let world = universe.world();
15 let rank = world.rank();
16 let size = world.size();
17
18 println!(
19 "rank {rank}/{size}: os={} arch={}",
20 std::env::consts::OS,
21 std::env::consts::ARCH
22 );
23
24 // Ring send/receive across nodes.
25 let next = (rank + 1) % size;
26 let prev = (rank - 1 + size) % size;
27 let msg = rank * 1000;
28 let (got, status): (i32, _) = mpi::point_to_point::send_receive(
29 &msg,
30 &world.process_at_rank(next),
31 &world.process_at_rank(prev),
32 );
33 assert_eq!(got, prev * 1000, "ring mismatch");
34 assert_eq!(status.source_rank(), prev);
35
36 // All-reduce sum of ranks.
37 let mut sum = 0i32;
38 world.all_reduce_into(&rank, &mut sum, SystemOperation::sum());
39 assert_eq!(sum, (0..size).sum::<i32>(), "allreduce mismatch");
40
41 // Broadcast from rank 0.
42 let mut buf = if rank == 0 {
43 vec![42i32; 3]
44 } else {
45 vec![0; 3]
46 };
47 world.process_at_rank(0).broadcast_into(&mut buf[..]);
48 assert_eq!(buf, vec![42, 42, 42], "broadcast mismatch");
49
50 world.barrier();
51 println!("rank {rank}: cross-node comm OK (sum of ranks = {sum})");
52 if rank == 0 {
53 println!("CLUSTER PASS: {size} ranks communicated across hosts.");
54 }
55}More examples
examples/reduce.rs (line 17)
6fn main() {
7 let universe = mpi::initialize().unwrap();
8 let world = universe.world();
9 let rank = world.rank();
10 let size = world.size();
11 let root_rank = 0;
12 let root = world.process_at_rank(root_rank);
13
14 // Sum of all ranks lands on the root.
15 if rank == root_rank {
16 let mut sum = 0i32;
17 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
18 let expected = (0..size).sum::<i32>();
19 println!("Sum of ranks = {sum} (expected {expected})");
20 assert_eq!(sum, expected);
21 } else {
22 root.reduce_into(&rank, SystemOperation::sum());
23 }
24
25 // Every rank learns the maximum rank via all-reduce.
26 let mut max = 0i32;
27 world.all_reduce_into(&rank, &mut max, SystemOperation::max());
28 assert_eq!(max, size - 1);
29
30 // Element-wise all-reduce over a vector.
31 let local = [rank as f64, (rank * rank) as f64];
32 let mut total = vec![0.0f64; 2];
33 world.all_reduce_into(&local[..], &mut total[..], SystemOperation::sum());
34 let expected0: f64 = (0..size).map(|r| r as f64).sum();
35 let expected1: f64 = (0..size).map(|r| (r * r) as f64).sum();
36 assert!((total[0] - expected0).abs() < 1e-9);
37 assert!((total[1] - expected1).abs() < 1e-9);
38
39 world.barrier();
40 if rank == root_rank {
41 println!("Reductions verified. vector all-reduce = {total:?}");
42 }
43}examples/rma.rs (line 50)
8fn main() {
9 let universe = mpi::initialize().unwrap();
10 let world = universe.world();
11 let rank = world.rank();
12 let size = world.size();
13
14 // ---- put: rank 0 writes distinct data into every other rank's window ----
15 let win = Window::<i32>::allocate(4, &world);
16 win.fence();
17 if rank == 0 {
18 for r in 1..size {
19 win.put(r, 0, &[r * 10, r * 10 + 1, r * 10 + 2, r * 10 + 3]);
20 }
21 win.with_local_mut(|m| {
22 for (i, v) in m.iter_mut().enumerate() {
23 *v = i as i32;
24 }
25 });
26 }
27 win.fence();
28 if rank != 0 {
29 win.with_local(|m| {
30 assert_eq!(
31 m,
32 [rank * 10, rank * 10 + 1, rank * 10 + 2, rank * 10 + 3],
33 "put mismatch"
34 );
35 });
36 }
37 win.fence();
38
39 // ---- get: every rank reads rank 0's window (0,1,2,3) ----
40 if rank != 0 {
41 let mut buf = [0i32; 4];
42 win.get(0, 0, &mut buf);
43 assert_eq!(buf, [0, 1, 2, 3], "get mismatch");
44 }
45 win.fence();
46
47 // ---- accumulate: every rank sums [1;4] into rank 0's window ----
48 let win2 = Window::<i32>::allocate(4, &world);
49 win2.fence();
50 win2.accumulate(0, 0, &[1, 1, 1, 1], SystemOperation::sum());
51 win2.fence();
52 if rank == 0 {
53 win2.with_local(|m| assert_eq!(m, [size, size, size, size], "accumulate mismatch"));
54 }
55 win2.fence();
56
57 if rank == 0 {
58 println!("RMA PASS: put/get/accumulate verified on {size} ranks.");
59 }
60}examples/bigmsg.rs (line 35)
7fn main() {
8 let universe = mpi::initialize().unwrap();
9 let world = universe.world();
10 let rank = world.rank();
11 let size = world.size();
12
13 // ---- point-to-point: 4 MB round trip (well above the 64 KiB threshold) ----
14 let n: i32 = 1_000_000;
15 if size >= 2 {
16 if rank == 0 {
17 let data: Vec<i32> = (0..n).collect();
18 world.process_at_rank(1).send(&data[..]);
19 let (back, _) = world.process_at_rank(1).receive_vec::<i32>();
20 assert_eq!(back.len(), n as usize, "echo length");
21 assert_eq!(back[n as usize - 1], n - 1, "echo tail");
22 } else if rank == 1 {
23 let (data, _) = world.process_at_rank(0).receive_vec::<i32>();
24 assert_eq!(data.len(), n as usize, "bigmsg length");
25 assert_eq!(data[0], 0);
26 assert_eq!(data[n as usize - 1], n - 1, "bigmsg content");
27 world.process_at_rank(0).send(&data[..]);
28 }
29 }
30
31 // ---- large all-reduce (400 KB per rank -> rendezvous inside the tree) ----
32 {
33 let local = vec![rank; 100_000];
34 let mut sum = vec![0i32; 100_000];
35 world.all_reduce_into(&local[..], &mut sum[..], SystemOperation::sum());
36 let expected: i32 = (0..size).sum();
37 assert!(
38 sum.iter().all(|&x| x == expected),
39 "big all_reduce mismatch"
40 );
41 }
42
43 world.barrier();
44 if rank == 0 {
45 println!(
46 "BIGMSG PASS: {} MB round-trip + large all-reduce via rendezvous on {size} ranks.",
47 n * 4 / 1_000_000
48 );
49 }
50}examples/pingpong.rs (line 66)
8fn main() {
9 let universe = mpi::initialize().unwrap();
10 let world = universe.world();
11 let rank = world.rank();
12 let size = world.size();
13
14 if size >= 2 {
15 let latency_iters = 2000;
16 let bw_iters = 100;
17 let bw_bytes = 1 << 20; // 1 MiB
18
19 if rank == 0 {
20 // ---- latency: 8-byte round trip ----
21 let small = [0u8; 8];
22 // warm up
23 for _ in 0..100 {
24 world.process_at_rank(1).send(&small[..]);
25 let _ = world.process_at_rank(1).receive_vec::<u8>();
26 }
27 let t0 = mpi::time();
28 for _ in 0..latency_iters {
29 world.process_at_rank(1).send(&small[..]);
30 let _ = world.process_at_rank(1).receive_vec::<u8>();
31 }
32 let dt = mpi::time() - t0;
33 let lat_us = dt / latency_iters as f64 / 2.0 * 1e6;
34 println!("latency: {lat_us:.2} µs (8 B, half round-trip, {latency_iters} iters)");
35
36 // ---- bandwidth: 1 MiB round trip ----
37 let big = vec![0u8; bw_bytes];
38 let t0 = mpi::time();
39 for _ in 0..bw_iters {
40 world.process_at_rank(1).send(&big[..]);
41 let _ = world.process_at_rank(1).receive_vec::<u8>();
42 }
43 let dt = mpi::time() - t0;
44 let mb = bw_bytes as f64 * bw_iters as f64 * 2.0 / 1e6;
45 println!("bandwidth: {:.1} MB/s (1 MiB, {bw_iters} iters)", mb / dt);
46 } else if rank == 1 {
47 let small = [0u8; 8];
48 for _ in 0..latency_iters + 100 {
49 let _ = world.process_at_rank(0).receive_vec::<u8>();
50 world.process_at_rank(0).send(&small[..]);
51 }
52 for _ in 0..bw_iters {
53 let (v, _) = world.process_at_rank(0).receive_vec::<u8>();
54 world.process_at_rank(0).send(&v[..]);
55 }
56 }
57 }
58
59 // ---- collective timing: all-reduce over all ranks ----
60 world.barrier();
61 let coll_iters = 1000;
62 let x = rank;
63 let mut acc = 0i32;
64 let t0 = mpi::time();
65 for _ in 0..coll_iters {
66 world.all_reduce_into(&x, &mut acc, SystemOperation::sum());
67 }
68 let dt = mpi::time() - t0;
69 if rank == 0 {
70 println!(
71 "all_reduce: {:.2} µs/op over {size} ranks ({coll_iters} iters), result {acc}",
72 dt / coll_iters as f64 * 1e6
73 );
74 }
75 world.barrier();
76}examples/selftest.rs (line 115)
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcepub fn product() -> SystemOperation
pub fn product() -> SystemOperation
MPI_PROD.
Sourcepub fn max() -> SystemOperation
pub fn max() -> SystemOperation
MPI_MAX.
Examples found in repository?
examples/reduce.rs (line 27)
6fn main() {
7 let universe = mpi::initialize().unwrap();
8 let world = universe.world();
9 let rank = world.rank();
10 let size = world.size();
11 let root_rank = 0;
12 let root = world.process_at_rank(root_rank);
13
14 // Sum of all ranks lands on the root.
15 if rank == root_rank {
16 let mut sum = 0i32;
17 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
18 let expected = (0..size).sum::<i32>();
19 println!("Sum of ranks = {sum} (expected {expected})");
20 assert_eq!(sum, expected);
21 } else {
22 root.reduce_into(&rank, SystemOperation::sum());
23 }
24
25 // Every rank learns the maximum rank via all-reduce.
26 let mut max = 0i32;
27 world.all_reduce_into(&rank, &mut max, SystemOperation::max());
28 assert_eq!(max, size - 1);
29
30 // Element-wise all-reduce over a vector.
31 let local = [rank as f64, (rank * rank) as f64];
32 let mut total = vec![0.0f64; 2];
33 world.all_reduce_into(&local[..], &mut total[..], SystemOperation::sum());
34 let expected0: f64 = (0..size).map(|r| r as f64).sum();
35 let expected1: f64 = (0..size).map(|r| (r * r) as f64).sum();
36 assert!((total[0] - expected0).abs() < 1e-9);
37 assert!((total[1] - expected1).abs() < 1e-9);
38
39 world.barrier();
40 if rank == root_rank {
41 println!("Reductions verified. vector all-reduce = {total:?}");
42 }
43}More examples
examples/selftest.rs (line 125)
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcepub fn min() -> SystemOperation
pub fn min() -> SystemOperation
MPI_MIN.
Sourcepub fn logical_and() -> SystemOperation
pub fn logical_and() -> SystemOperation
MPI_LAND.
Sourcepub fn logical_or() -> SystemOperation
pub fn logical_or() -> SystemOperation
MPI_LOR.
Sourcepub fn logical_xor() -> SystemOperation
pub fn logical_xor() -> SystemOperation
MPI_LXOR.
Sourcepub fn bitwise_and() -> SystemOperation
pub fn bitwise_and() -> SystemOperation
MPI_BAND.
Sourcepub fn bitwise_or() -> SystemOperation
pub fn bitwise_or() -> SystemOperation
MPI_BOR.
Sourcepub fn bitwise_xor() -> SystemOperation
pub fn bitwise_xor() -> SystemOperation
MPI_BXOR.
Trait Implementations§
Source§impl Clone for SystemOperation
impl Clone for SystemOperation
Source§fn clone(&self) -> SystemOperation
fn clone(&self) -> SystemOperation
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreimpl Copy for SystemOperation
Source§impl Debug for SystemOperation
impl Debug for SystemOperation
impl Eq for SystemOperation
Source§impl Operation for SystemOperation
impl Operation for SystemOperation
Source§fn is_commutative(&self) -> bool
fn is_commutative(&self) -> bool
Whether the operation is commutative (
MPI_Op_commutative).Source§impl PartialEq for SystemOperation
impl PartialEq for SystemOperation
Source§fn eq(&self, other: &SystemOperation) -> bool
fn eq(&self, other: &SystemOperation) -> bool
Tests for
self and other values to be equal, and is used by ==.impl StructuralPartialEq for SystemOperation
Auto Trait Implementations§
impl Freeze for SystemOperation
impl RefUnwindSafe for SystemOperation
impl Send for SystemOperation
impl Sync for SystemOperation
impl Unpin for SystemOperation
impl UnsafeUnpin for SystemOperation
impl UnwindSafe for SystemOperation
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more