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
(ouMPI_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