MPL is a message passing library written in C++17 based on the Message Passing Interface (MPI) standard. Since the C++ API has been dropped from the MPI standard in version 3.1, it is the aim of MPL to provide a modern C++ message passing library for high performance computing.
MPL will neither bring all functions of the C language MPI-API to C++ nor provide a direct mapping of the C API to some C++ functions and classes. The library's focus lies on the MPI core message passing functions, ease of use, type safety, and elegance. The aim of MPL is to provide an idiomatic C++ message passing library without introducing a significant overhead compared to utilizing MPI via its plain C-API. This library is most useful for developers who have at least some basic knowledge of the Message Passing Interface standard and would like to utilize it via a more user-friendly interface in modern C++. Unlike Boost.MPI, MPL does not rely on an external serialization library and has a negligible run-time overhead.
MPL requires an MPI 4.1 implementation and uses its large-count interfaces.
MPL gives currently access via a convenient C++ interface to the following features of the Message Passing Interface standard:
- environmental management (implicit initialization and finalization and timers),
- point-to-point communication (blocking and non-blocking),
- collective communication (blocking and non-blocking),
- derived data types (happens automatically for many custom data types or via the
base_struct_builderhelper class and the layout classes of MPL), - communicator- and group-management,
- process topologies (cartesian and graph topologies),
- inter-communicators,
- dynamic process creation and
- file i/o.
Currently, the following MPI features are not yet supported by MPL:
- one-sided communication.
Although MPL covers a subset of the MPI functionality only, it has probably the largest MPI-feature coverage among all alternative C++ interfaces to MPI.
MPL is built on top of the Message Passing Interface (MPI) standard. Therefore, MPL shares many concepts known from the MPI standard, e.g., the concept of a communicator. Communicators manage the message exchange between different processes, i.e., messages are sent and received with the help of a communicator.
The MPL environment provides a global default communicator comm_world, which will
be used in the following Hello-World program. The program prints out some information
about each process:
- its rank,
- the total number of processes and
- the computer's name the process is running on.
If there are two or more processes, a message is sent from process 0 to process 1, which is also printed.
#include <cstdlib>
#include <iostream>
// include MPL header file
#include <mpl/mpl.hpp>
int main() {
// get a reference to communicator "world"
const mpl::communicator &comm_world{mpl::environment::comm_world()};
// each process prints a message containing the processor name, the rank
// in communicator world and the size of communicator world
// output may depend on the underlying MPI implementation
std::cout << "Hello world! I am running on \"" << mpl::environment::processor_name()
<< "\". My rank is " << comm_world.rank() << " out of " << comm_world.size()
<< " processes.\n";
// if there are two or more processes send a message from process 0 to process 1
if (comm_world.size() >= 2) {
if (comm_world.rank() == 0) {
std::string message{"Hello world!"};
comm_world.send(message, 1); // send message to rank 1
} else if (comm_world.rank() == 1) {
std::string message;
comm_world.recv(message, 0); // receive message from rank 0
std::cout << "got: \"" << message << "\"\n";
}
}
return EXIT_SUCCESS;
}When a checked MPI call returns an error, MPL reports it as mpl::mpi_error (derived from mpl::error), carrying its code, class and message. Recognized I/O error classes become mpl::io_failure, including outside file operations; other classes from file operations remain mpl::mpi_error.
MPL installs MPI_ERRORS_RETURN when it initializes its environment and wraps MPI_COMM_WORLD and MPI_COMM_SELF, and when it creates or wraps communicators. With external MPI initialization, earlier operations do not initialize the MPL environment or change those handlers; a fatal handler may abort before a call returns. Borrowed mpi_communicator and mpi_inter_communicator adapters change the original handle's handler without restoring it or taking ownership. MPI file and objectless operations can use different handlers; exceptions are possible only if MPI returns an error to MPL.
Error reporting does not guarantee recovery: MPI may not permit continued execution, and other ranks may remain blocked. Cleanup and destructors are best-effort and do not throw. See the error handling documentation for request completion details.
MPL can be built and tested using standard CMake commands:
cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DMPL_BUILD_EXAMPLES=ON
cmake --build build -j
ctest --test-dir build --output-on-failureWhen running unit tests or executables directly via mpirun or mpiexec under MPICH on systems with libhwloc GL plugins installed (hwloc_gl.so), MPI initialization may hang in remote, headless, or containerized environments if an unreachable $DISPLAY socket endpoint is queried via XOpenDisplay.
While CTest targets in MPL configure this automatically, when executing binaries directly under MPICH, disable the hwloc OpenGL discovery component by setting:
export HWLOC_COMPONENTS=-gl
# or prepend to direct mpiexec invocations:
HWLOC_COMPONENTS=-gl mpiexec -n 2 ./build/test/test_communicator_send_recvFor further documentation see the documentation, the blog posts
the presentation
- Message Passing mit modernem C++ (German only),
the book
- Parallel Programming for Science and Engineering by Victor Eijkhout, or
the workshop material
and the files in the examples directory of the source package.