Kahibaro
Discord Login Register

Introduction to MPI

What MPI Is (and What It Is Not)

MPI (Message Passing Interface) is a standardized API for writing distributed-memory parallel programs, typically in C, C++, and Fortran.

Key points:

MPI is designed to be:

MPI is not:

Basic MPI Programming Model

MPI follows a SPMD (Single Program, Multiple Data) style by default:

Core ideas:

Because processes do not share memory, all inter-process cooperation happens through explicit message passing:

This chapter focuses on the basic MPI concepts you need to understand the rest of the MPI-related chapters.

Setting Up and Running MPI Programs

You normally compile and run MPI programs using wrappers and launchers provided by the MPI implementation.

Typical commands (names may vary slightly per MPI library):

These wrapper compilers:

You do not normally run MPI programs with ./myprog directly. Instead, you launch multiple processes with an MPI launcher. On many systems:

On HPC clusters, this is often integrated with the batch scheduler (e.g., SLURM). There you may use:

Details of interaction with job schedulers are handled in the job scheduling chapters; here the main concept is that the MPI runtime is responsible for starting the requested number of processes and connecting them.

Minimal Structure of an MPI Program

Almost every MPI program in C/C++/Fortran has the same basic skeleton:

  1. Initialize MPI
  2. Query the environment (number of processes, rank, etc.)
  3. Perform communication and computation
  4. Finalize MPI

Initialization and Finalization

In C-style pseudocode:

#include <mpi.h>
int main(int argc, char *argv[]) {
    MPI_Init(&argc, &argv);   // 1. Initialize
    // ... your MPI code here ...
    MPI_Finalize();           // 4. Finalize
    return 0;
}

Key points:

In Fortran, the pattern is similar (with call MPI_INIT(ierr) and call MPI_FINALIZE(ierr)).

Discovering the Parallel Environment

You typically begin by asking:

In C:

int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);

These two queries are enough to let you:

A First MPI Program: "Hello, World"

A classic first example is a parallel "Hello, world" where each process identifies itself.

C example:

#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
    MPI_Init(&argc, &argv);
    int world_size;
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
    printf("Hello from rank %d out of %d processes\n",
           world_rank, world_size);
    MPI_Finalize();
    return 0;
}

Key observations:

Basic MPI Data Types and Messages (High-Level View)

MPI functions often need to know:

  1. Buffer address: Where the data is in memory.
  2. Count: How many items.
  3. Datatype: What kind of items.
  4. Destination/source: Which rank to send to or receive from.
  5. Tag: A small integer label to help match messages.
  6. Communicator: The group of processes involved in this communication.

For example, most point-to-point operations take arguments of the general form:

MPI provides its own datatypes (e.g., MPI_INT, MPI_DOUBLE, MPI_CHAR) to stay portable across machines where the size and representation of C and Fortran types may differ.

Basic Point-to-Point Communication Concepts

Details of point-to-point functions are covered in the corresponding chapter; here the aim is to introduce the ideas in abstract terms.

Core concepts:

Typical operations (names only, not full explanation here):

Example pattern (conceptual):

Correctness depends on matching:

Basic Collective Operations (Conceptual Overview)

MPI also defines collective communication routines, which involve all processes in a communicator.

These are higher-level than point-to-point operations. Examples (to be covered in detail in their own chapter):

At this stage, you only need to recognize that:

Communicators and Groups: The Context for Communication

All MPI communications happen within communicators. Conceptually:

Reasons communicators are important:

Later chapters will cover:

For now, you just need to recognize that nearly every MPI call asks you for a communicator, and MPI_COMM_WORLD is the simplest and most common choice in small examples.

Basic Error Handling and Return Codes

Most MPI routines return an integer error code:

In C, you typically write:

int err = MPI_SomeCall(...);
if (err != MPI_SUCCESS) {
    // handle error (or abort)
}

For small educational codes, you might ignore error codes, but in real applications, checking them helps diagnose issues such as:

MPI also provides ways to change error handlers on communicators (e.g., to abort all processes on error), which is covered more thoroughly in advanced usage.

MPI Standards and Versions (High-Level)

The MPI standard has evolved:

For introductory usage:

On many HPC systems, you can check the version of MPI by running:

Typical Development Workflow with MPI

To summarize how MPI fits into a basic workflow:

  1. Write code:
    • Include MPI headers (e.g., #include <mpi.h>).
    • Add MPI_Init and MPI_Finalize.
    • Use MPI_Comm_size and MPI_Comm_rank to discover the environment.
    • Insert appropriate MPI communication calls (to be learned in following chapters).
  2. Compile with MPI wrappers:
    • Use mpicc, mpicxx, or mpif90.
  3. Run with an MPI launcher:
    • On a workstation: mpirun -np N ./a.out
    • On a cluster: via the job scheduler (using srun, mpirun inside job scripts, etc.).
  4. Debug and profile:
    • Use standard debugging techniques plus MPI-specific tools (covered in later chapters).

What You Should Be Able to Do After This Chapter

After studying this introduction, you should be able to:

Subsequent chapters will build on this foundation to cover point-to-point communication, collectives, communicators, process topologies, and performance aspects in much more detail.

Views: 13

Comments

Please login to add a comment.

Don't have an account? Register now!