Skip to content

MPI

Conceitos básicos de MPI

MPI (Message Passing Interface) é um padrão para programação paralela em memória compartilhada, o seja, em vários nós de computação. Cada processo é identificado por um rank (um número de 0 até size-1), todos os processos de um programa MPI formam um comunicador (por padrão MPI_COMM_WORLD).

Comunicação ponto a ponto

Envio e recebimento bloqueantes

MPI_Send(buffer, count, MPI_CHAR, destino, tag, MPI_COMM_WORLD);
MPI_Recv(buffer, count, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);
  • buffer: ponteiro para os dados.
  • count: número de elementos.
  • MPI_CHAR, MPI_INT, MPI_DOUBLE etc.
  • destino / origem: rank do processo de envio/recebimento.
  • tag: identificador da mensagem (permite diferenciar mensagens).
  • status: metadados sobre a recepção.

Envio e recebimento não-bloqueantes

MPI_Request req;
MPI_Isend(buffer, count, MPI_INT, destino, tag, MPI_COMM_WORLD, &req);
MPI_Wait(&req, MPI_STATUS_IGNORE);
MPI_Request req;
MPI_Irecv(buffer, count, MPI_INT, origem, tag, MPI_COMM_WORLD, &req);
MPI_Wait(&req, MPI_STATUS_IGNORE);
  • Permitem sobrepor comunicação e computação.
  • Precisa sempre de MPI_Wait (ou MPI_Test).

Comunicação coletiva

  • Broadcast
MPI_Bcast(buffer, count, MPI_INT, root, MPI_COMM_WORLD);

Envia buffer do processo root para todos.

  • Scatter
MPI_Scatter(sendbuf, count, MPI_INT, recvbuf, count, MPI_INT, root, MPI_COMM_WORLD);

Distribui partes de um vetor do root para todos.

  • Gather
MPI_Gather(sendbuf, count, MPI_INT, recvbuf, count, MPI_INT, root, MPI_COMM_WORLD);

Cada processo envia dados para o root.

  • Reduce
MPI_Reduce(&valor_local, &valor_total, 1, MPI_INT, MPI_SUM, root, MPI_COMM_WORLD);

Combina valores de todos os processos (soma, máximo, mínimo, etc.).

  • Barrier
MPI_Barrier(MPI_COMM_WORLD);

Todos os processos param até que todos cheguem aqui.


Medição de tempo

double t0 = MPI_Wtime();
// ... código ...
double t1 = MPI_Wtime();
if(rank==0) std::cout << "Tempo = " << (t1-t0) << " segundos\n";

Estruturas úteis

  • MPI_Status → contém informações de mensagens recebidas (como rank origem).
MPI_Status status;
MPI_Recv(buf, n, MPI_INT, origem, tag, MPI_COMM_WORLD, &status);
int origem_real; MPI_Get_count(&status, MPI_INT, &origem_real);
  • Tags → permitem diferenciar mensagens diferentes em paralelo.

Carregue o modulo

spack load openmpi

Teste para ver se o modulo foi carregado corretamente

mpicc --version

Deve aparecer algo como:

gcc (GCC) 14.2.0
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Compile o programa:

mpic++ -FlagdeOtimização seu_codigo.cpp -o seu_binario

Executar com SLURM (arquivo job.slurm):

#!/bin/bash
#SBATCH --job-name=mpi_hello
#SBATCH --output=saida%j.txt
#SBATCH --partition=express
#SBATCH --mem=1GB
#SBATCH --nodes=2
#SBATCH --ntasks=5
#SBATCH --cpus-per-task=1
#SBATCH --time=00:02:00
#SBATCH --export=ALL


# Faça load nos módulos dentro do nó de computação
source /etc/profile
. /opt/spack/share/spack/setup-env.sh
module use /opt/spack/share/spack/lmod/linux-rocky9-x86_64/Core
module --ignore_cache load openmpi/5.0.8-gcc-14.2.0

# Execute o seu binário com o MPI
mpirun -np $SLURM_NTASKS ./seu_binario

Submit:

sbatch job.slurm

Documentação: https://www.physics.rutgers.edu/~haule/509/MPI_Guide_C++.pdf