// Deep Dive ยท HPC Programming

MPI โ€” Message Passing Interface

๐Ÿ“… Updated: June 2026 โฑ 10 min read ๐Ÿท Parallel Programming ยท Distributed Memory ยท Supercomputing
OpenMPI MPICH Collective Ops RDMA InfiniBand MPI-4 Hybrid MPI/OpenMP

What is MPI?

The Message Passing Interface (MPI) is the de facto standard for parallel programming on distributed-memory systems โ€” meaning HPC clusters where each compute node has its own private memory. Processes running on different nodes communicate by explicitly sending and receiving messages over the network.

MPI is not a language or a compiler โ€” it is a library specification defining over 400 functions. Programs written in C, C++, or Fortran call MPI routines to coordinate parallel work. The first standard (MPI-1) was released in 1994; the current standard is MPI-4.1 (2023).

// Why MPI dominates HPC

Every major supercomputer on the TOP500 runs MPI workloads. Its explicit communication model gives programmers precise control over data movement โ€” critical when squeezing performance from 10,000+ node systems where even microseconds of latency matter.

The Core Concept: Ranks and Communicators

When an MPI program launches, it starts N processes simultaneously. Each process gets a unique integer identifier called a rank (0 to N-1). Processes are organized into communicators โ€” groups that can exchange messages. The default communicator MPI_COMM_WORLD contains all processes.

// Minimal MPI program โ€” every process prints its rank #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(&argc, &argv); // Initialize MPI int rank, size; MPI_Comm_rank(MPI_COMM_WORLD, &rank); // My rank (0..N-1) MPI_Comm_size(MPI_COMM_WORLD, &size); // Total processes printf("Hello from rank %d of %d\n", rank, size); MPI_Finalize(); // Clean up MPI return 0; }

Run on 4 nodes with 32 processes each: mpirun -np 128 ./hello โ€” 128 independent processes each knowing their own rank and the total count.

Point-to-Point Communication

The fundamental MPI operations are send and receive between pairs of processes:

FunctionTypeBehavior
MPI_SendBlockingReturns when buffer can be reused โ€” may buffer internally
MPI_RecvBlockingReturns only when message is fully received
MPI_IsendNon-blockingReturns immediately; use MPI_Wait to confirm completion
MPI_IrecvNon-blockingPosts receive buffer; use MPI_Wait to confirm arrival
MPI_SendrecvBlockingSend and receive simultaneously โ€” avoids deadlock in ring patterns
// Deadlock warning

If process 0 calls MPI_Send to process 1 and process 1 calls MPI_Send to process 0 simultaneously โ€” both block waiting for a receive that never comes. Always use non-blocking or MPI_Sendrecv for bidirectional exchanges.

Collective Operations

Collectives coordinate all processes in a communicator simultaneously โ€” they are the backbone of parallel algorithms. Every process must call the collective, making them implicit synchronization points.

MPI_Bcast
One process sends identical data to all others. Used to distribute parameters, configuration, or model weights.
MPI_Scatter
Root distributes different chunks of an array to each process. Essential for data parallelism.
MPI_Gather
All processes send data to root, which assembles the complete result.
MPI_Reduce
Combines values from all processes (sum, max, min, etc.) into a single result on root.
MPI_Allreduce
Reduce + broadcast to all โ€” the most critical collective for distributed AI training (gradient averaging).
MPI_Alltoall
Every process sends unique data to every other process โ€” used in FFTs and matrix transposes.
MPI_Barrier
Synchronization point โ€” all processes wait until every process has reached the barrier.
MPI_Scan
Prefix reduction โ€” process i receives the reduction of values from ranks 0 through i.

MPI_Allreduce in AI Training

MPI_Allreduce is arguably the single most important HPC communication pattern for modern AI. During distributed training, each GPU computes gradients on its local data batch. Before the weight update, gradients must be averaged across all GPUs โ€” this is an Allreduce operation. At scale (thousands of GPUs), the efficiency of this operation directly determines training throughput.

// Distributed gradient averaging โ€” simplified double local_gradient = compute_gradient(my_batch); double global_gradient; MPI_Allreduce( &local_gradient, // Send buffer &global_gradient, // Receive buffer 1, // Count MPI_DOUBLE, // Datatype MPI_SUM, // Operation MPI_COMM_WORLD // Communicator ); global_gradient /= num_processes; update_weights(global_gradient);

MPI Implementations

ImplementationMaintained byKey strengthsCommon use
OpenMPIOpen-source consortiumBroad hardware support, modular, excellent InfiniBandMost university/research clusters
MPICHArgonne National LabReference implementation, tight MPI standard conformanceNational labs, basis for other MPIs
Intel MPIIntel (oneAPI)Highly optimized for Intel Xeon, Omni-Path fabricIntel-based enterprise HPC
MVAPICH2Ohio State UniversityBest-in-class InfiniBand/RDMA optimizationInfiniBand clusters, GPU-aware MPI
Cray MPICHHPE/CrayOptimized for Slingshot interconnectFrontier, Perlmutter, HPE Cray systems

Hybrid MPI + OpenMP

Modern HPC nodes have 64โ€“256 CPU cores sharing memory. Running one MPI process per core wastes memory (each process has independent address space and MPI overhead). The best practice is hybrid programming: one MPI process per socket or per node, with OpenMP threads filling the cores.

#!/bin/bash โ€” SLURM hybrid job script #SBATCH --nodes=16 #SBATCH --ntasks-per-node=2 # 2 MPI ranks per node (1 per socket) #SBATCH --cpus-per-task=64 # 64 OpenMP threads per rank export OMP_NUM_THREADS=64 export OMP_PLACES=cores export OMP_PROC_BIND=close mpirun ./simulation

This launches 32 MPI processes total across 16 nodes, each with 64 threads โ€” fully utilizing a dual-socket node with 128 cores while minimizing MPI overhead.

GPU-Aware MPI

Traditional MPI requires data to be in CPU memory before sending. GPU-aware MPI (supported by MVAPICH2, OpenMPI with UCX, Cray MPICH) allows direct GPU-to-GPU transfers over InfiniBand using GPUDirect RDMA โ€” bypassing the CPU entirely and dramatically reducing latency for AI training communication.

// Performance impact

GPUDirect RDMA reduces the latency of GPU-to-GPU transfers across nodes from ~50ยตs (via host memory) to ~5ยตs, and increases bandwidth from ~10 GB/s to the full InfiniBand line rate (~25 GB/s for HDR). For large-scale AI training, this translates directly into faster iteration times.

MPI-4: What's New (2021โ€“2023)

Performance Tuning Tips

Key Takeaways