Message Passing Interface (MPI) é um padrão para comunicação de dados em computação paralela. Existem várias modalidades de computação paralela, e dependendo do problema que se está tentando resolver, pode ser necessário passar informações entre os vários processadores ou nós de um cluster, e o MPI oferece uma infraestrutura para essa tarefa.
Para iniciarmos o nosso estudo de MPI, implemente os desafios abaixo, entendendo como encadear sends e receives, e o impacto nos resultados.
Ping-pong¶
A ideia é medir a latência de comunicação ponto a ponto.
Implemente o ping-pong: rank 0 envia uma mensagem ao rank 1, que responde. Faça duas versões:
- Bloqueante (
MPI_Send/MPI_Recv
) - Não-bloqueante (
MPI_Isend/Irecv + MPI_Wait
)
Rode os testes:
- Mensagens de 16 B, 1 KB, 64 KB, 1 MB
- Em 2, 3 e 4 nós
Dica!
Lembre-se, cada double ocupa 8 bytes, cada float ocupa 4 bytes, cada int ocupa 4 bytes, cada char, 1 byte.
Analise:
- Para mensagens pequenas, o que domina: latência fixa ou tamanho da mensagem?
- A partir de que tamanho de mensagem o gargalo passa a ser a largura de banda da rede?
Código base:
#include <mpi.h> // Biblioteca principal do MPI para comunicação entre processos
#include <iostream>
#include <cstring>
int main(int argc, char** argv) {
int rank; // Variável que armazenará o "rank" (identificador) do processo
MPI_Status status; // Estrutura que armazenará o status da comunicação MPI
char mensagem[100]; // Vetor de caracteres para armazenar a mensagem a ser enviada/recebida
// Inicializa o ambiente MPI (todos os processos são iniciados)
MPI_Init(&argc, &argv);
// Descobre o "rank" do processo atual dentro do comunicador global (MPI_COMM_WORLD)
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Se este for o processo de rank 0 (emissor inicial)
if (rank == 0) {
// Copia a string "Olá" para a variável mensagem
std::strcpy(mensagem, "Olá");
// Envia a mensagem para o processo de rank 1
// Parâmetros: buffer, tamanho, tipo, destino, tag, comunicador
MPI_Send(mensagem, std::strlen(mensagem) + 1, MPI_CHAR, 1, 0, MPI_COMM_WORLD);
// Imprime no terminal que a mensagem foi enviada
std::cout << "Processo 0 enviou: " << mensagem << std::endl;
// Aguarda a resposta do processo 1
// Parâmetros: buffer, tamanho máximo, tipo, origem, tag, comunicador, status
MPI_Recv(mensagem, 100, MPI_CHAR, 1, 0, MPI_COMM_WORLD, &status);
// Imprime a mensagem recebida
std::cout << "Processo 0 recebeu: " << mensagem << std::endl;
}
// Se este for o processo de rank 1 (receptor inicial)
else if (rank == 1) {
// Recebe a mensagem enviada pelo processo 0
MPI_Recv(mensagem, 100, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &status);
// Imprime a mensagem recebida
std::cout << "Processo 1 recebeu: " << mensagem << std::endl;
// Prepara a resposta "Oi"
std::strcpy(mensagem, "Oi");
// Envia a resposta de volta ao processo 0
MPI_Send(mensagem, std::strlen(mensagem) + 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
// Imprime que a mensagem foi enviada
std::cout << "Processo 1 enviou: " << mensagem << std::endl;
}
else {
// Todos os outros processos apenas informam que estão ociosos
std::cout << "Processo " << rank << " está ocioso neste exercício." << std::endl;
}
// Finaliza o ambiente MPI (todos os processos encerram)
MPI_Finalize();
return 0;
}
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
Script 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
Submeta o job com SLURM:¶
sbatch SeuSlurm.slurm
Você deve ver algo como isso:¶
[liciascl@head-node mpi]$ cat saida.txt
/usr/bin/id: cannot find name for user ID 1018
/var/spool/slurmd/job06957/slurm_script: line 15: /opt/spack/share/spack/setup-env.sh: No such file or directory
Lmod has detected the following error: The following module(s) are unknown:
"openmpi/5.0.8-gcc-14.2.0"
Please check the spelling or version number. Also try "module spider ..."
It is also possible your cache file is out-of-date; it may help to try:
$ module --ignore_cache load "openmpi/5.0.8-gcc-14.2.0"
Also make sure that all modulefiles written in TCL start with the string
Processo 2 está ocioso neste exercício.
Processo 3 está ocioso neste exercício.
Processo 0 enviou: Olá
Processo 0 recebeu: Oi
Processo 1 recebeu: Olá
Processo 1 enviou: Oi
Processo 4 está ocioso neste exercício.
Ignore os warnings, o ponto é que o Rank0 está conversando com o Rank1 conforme o código exemplo, agora é a sua vez! Faça as alterações no código exemplo e implemente as outras formas de comunicação entre nós usando MPI
Token em anel¶
A ideia é perceber o custo de coletar informações sequencialmente.
Implemente o token em anel: cada rank adiciona uma informação nova ao vetor e passa adiante.
Execute em 2, 3 e 4 nós .
Compare com o mesmo problema usando MPI_Gather
.
Analise:
- Como cresce o tempo do anel com o número de processos?
- Qual o gargalo de percorrer todos em sequência?
- Qual a vantagem de usar
MPI_Gather
?
Alternância¶
A ideia é entender como funciona uma distribuição de tarefas.
Rank 0 possui 13 tarefas cada uma com diferentes niveis de complexidade. Implemente uma distribuição dinâmica de tarefas, o worker que terminar primeiro recebe a próxima tarefa.
O que acontece quando as tarefas variam muito de custo?
O que você deve entregar:¶
Para cada exercício:
- Código (disponível no repositório do github).
- Tabela de resultados (parâmetros usados, tempos medidos).
- Discussão: Análise dos resultados
Envie o seu relatório com as suas análises até as 23h59 de 08/09 pelo GitHub Classroom