reduce/
reduce.rs

1#![deny(warnings)]
2#![allow(clippy::many_single_char_names)]
3#![allow(clippy::needless_pass_by_value)]
4extern crate mpi_fork_fnsp as mpi;
5
6use std::os::raw::{c_int, c_void};
7
8#[cfg(feature = "user-operations")]
9use mpi::collective::UserOperation;
10use mpi::collective::{self, SystemOperation, UnsafeUserOperation};
11use mpi::ffi::MPI_Datatype;
12use mpi::topology::Rank;
13use mpi::traits::*;
14
15#[cfg(feature = "user-operations")]
16fn test_user_operations<C: Communicator>(comm: C) {
17    let rank = comm.rank();
18    let size = comm.size();
19    let mut h = 0;
20    comm.all_reduce_into(
21        &(rank + 1),
22        &mut h,
23        &UserOperation::commutative(|x, y| {
24            let x: &[Rank] = x.downcast().unwrap();
25            let y: &mut [Rank] = y.downcast().unwrap();
26            for (&x_i, y_i) in x.iter().zip(y) {
27                *y_i += x_i;
28            }
29        }),
30    );
31    assert_eq!(h, size * (size + 1) / 2);
32}
33
34#[cfg(not(feature = "user-operations"))]
35fn test_user_operations<C: Communicator>(_: C) {}
36
37#[cfg(not(all(msmpi, target_arch = "x86")))]
38unsafe extern "C" fn unsafe_add(
39    invec: *mut c_void,
40    inoutvec: *mut c_void,
41    len: *mut c_int,
42    _datatype: *mut MPI_Datatype,
43) {
44    use std::slice;
45
46    let x: &[Rank] = slice::from_raw_parts(invec as *const Rank, *len as usize);
47    let y: &mut [Rank] = slice::from_raw_parts_mut(inoutvec as *mut Rank, *len as usize);
48    for (&x_i, y_i) in x.iter().zip(y) {
49        *y_i += x_i;
50    }
51}
52
53#[cfg(all(msmpi, target_arch = "x86"))]
54unsafe extern "stdcall" fn unsafe_add(
55    invec: *mut c_void,
56    inoutvec: *mut c_void,
57    len: *mut c_int,
58    _datatype: *mut MPI_Datatype,
59) {
60    use std::slice;
61
62    let x: &[Rank] = slice::from_raw_parts(invec as *const Rank, *len as usize);
63    let y: &mut [Rank] = slice::from_raw_parts_mut(inoutvec as *mut Rank, *len as usize);
64    for (&x_i, y_i) in x.iter().zip(y) {
65        *y_i += x_i;
66    }
67}
68
69fn main() {
70    let universe = mpi::initialize().unwrap();
71    let world = universe.world();
72    let rank = world.rank();
73    let size = world.size();
74    let root_rank = 0;
75
76    if rank == root_rank {
77        let mut sum: Rank = 0;
78        world
79            .process_at_rank(root_rank)
80            .reduce_into_root(&rank, &mut sum, SystemOperation::sum());
81        assert_eq!(sum, size * (size - 1) / 2);
82    } else {
83        world
84            .process_at_rank(root_rank)
85            .reduce_into(&rank, SystemOperation::sum());
86    }
87
88    let mut max: Rank = -1;
89
90    world.all_reduce_into(&rank, &mut max, SystemOperation::max());
91    assert_eq!(max, size - 1);
92
93    let a: u16 = 0b0000_1111_1111_0000;
94    let b: u16 = 0b0011_1100_0011_1100;
95
96    let mut c = b;
97    collective::reduce_local_into(&a, &mut c, SystemOperation::bitwise_and());
98    assert_eq!(c, 0b0000_1100_0011_0000);
99
100    let mut d = b;
101    collective::reduce_local_into(&a, &mut d, SystemOperation::bitwise_or());
102    assert_eq!(d, 0b0011_1111_1111_1100);
103
104    let mut e = b;
105    collective::reduce_local_into(&a, &mut e, SystemOperation::bitwise_xor());
106    assert_eq!(e, 0b0011_0011_1100_1100);
107
108    let f = (0..size).collect::<Vec<_>>();
109    let mut g: Rank = 0;
110
111    world.reduce_scatter_block_into(&f[..], &mut g, SystemOperation::product());
112    assert_eq!(g, rank.wrapping_pow(size as u32));
113
114    test_user_operations(universe.world());
115
116    let mut i = 0;
117    let op = unsafe { UnsafeUserOperation::commutative(unsafe_add) };
118    world.all_reduce_into(&(rank + 1), &mut i, &op);
119    assert_eq!(i, size * (size + 1) / 2);
120}