#mpi #parallel #cluster

msgpass

Thin wrapper to a Message Passing Interface (MPI)

7 releases (4 breaking)

0.5.0 Apr 30, 2024
0.4.0 Jan 18, 2024
0.3.0 Jan 17, 2024
0.2.2 Jan 15, 2024
0.1.0 Jan 14, 2024

#104 in Science

MIT license

97KB
2K SLoC

Rust 1.5K SLoC // 0.0% comments C 160 SLoC // 0.1% comments BASH 75 SLoC // 0.1% comments

Thin wrapper to a Message Passing Interface (MPI)

Test on macOS Test on Linux Test on Linux with Intel MPI

documentation

Contents

Introduction

MsgPass (Message Passing) is a thin Rust wrapper to MPI. We consider a small subset of MPI functions. This subset will grow as our projects require more functionality. We implement (by hand) C functions that Rust can easily call using the FFI (in the c_code directory).

We try to test all functions as much as possible, but test coverage could be better. The tests must be called with mpiexec, thus it is easy to use the run-tests.bash script.

documentation

Note: We can communicate strings by converting them to an array of bytes. For instance:

let mut bytes = vec![0_u8; MAX];
str_to_bytes(&mut bytes, "Hello World 😊");
comm.broadcast_bytes(0, &mut bytes)?;

Installation

Debian/Ubuntu Linux

First, install OpenMPI, MPICH, or Intel MPI. For instance,

sudo apt install libopenmpi-dev

or

sudo apt install libmpich-dev

or

bash ./zscripts/install-intel-mpi-debian.bash

The use the corresponding feature:

  • intel: use Intel MPI
  • mpich: use MPICH
  • (default): use OpenMPI

For Intel MPI, remember to call setvars.sh first:

source /opt/intel/oneapi/setvars.sh

macOS

On macOS, install the following packages:

brew install llvm open-mpi

Also, export the following environment variable:

export echo TMPDIR=/tmp

Setting Cargo.toml

Crates.io

👆 Check the crate version and update your Cargo.toml accordingly:

[dependencies]
msgpass = "*"

Or, considering the optional features:

[dependencies]
msgpass = { version = "*", features = ["intel"] }

Examples

See also:

The example below (available in the examples directory) will send an array from ROOT to all the other processors.

use msgpass::*;

fn main() -> Result<(), StrError> {
    mpi_init()?;

    let mut comm = Communicator::new()?;
    let rank = comm.rank()?;
    let size = comm.size()?;

    const ROOT: i32 = 0;
    const TAG: i32 = 70;

    if rank == ROOT as usize {
        let x = vec![1.0, 2.0, 3.0];
        for to in 1..size {
            comm.send_f64(&x, to, TAG)?;
        }
        println!("{}: x = {:?}", rank, x);
    } else {
        let mut y = vec![0.0, 0.0, 0.0];
        comm.receive_f64(&mut y, ROOT, TAG)?;
        println!("{}: y = {:?}", rank, y);
    }

    mpi_finalize()
}

Running the code above with mpiexec -np 4 ex_send_receive (see run-examples.bash), we get an output similar to the one below:

### ex_send_receive ######################################################
2: y = [1.0, 2.0, 3.0]
0: x = [1.0, 2.0, 3.0]
3: y = [1.0, 2.0, 3.0]
1: y = [1.0, 2.0, 3.0]

Roadmap

  • Implement basic functionality
    • Initialize and finalize
    • Abort and barrier
  • Wrap more MPI functions
    • Implement send/receive
    • Implement reduce/allreduce
    • Implement scatter/gather/allgather
  • Handle complex numbers

Dependencies

~205–490KB