Skip to content

Commit 20b44e8

Browse files
committed
mpi
1 parent 86439f2 commit 20b44e8

File tree

3 files changed

+267
-1
lines changed

3 files changed

+267
-1
lines changed

material/aulas/aula07/index.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
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.
2+
3+
Para iniciarmos o nosso estudo de MPI, implemente os desafios abaixo, entendendo como encadear sends e receives, e o impacto nos resultados.
4+
5+
6+
## **Ping-pong**
7+
8+
A ideia é medir a **latência de comunicação ponto a ponto**.
9+
10+
Implemente o ping-pong: rank 0 envia uma mensagem ao rank 1, que responde.
11+
Faça duas versões:
12+
13+
* **Bloqueante** (`MPI_Send/MPI_Recv`)
14+
* **Não-bloqueante** (`MPI_Isend/Irecv + MPI_Wait`)
15+
16+
Rode os testes:
17+
18+
* Mensagens de **16 B, 1 KB, 64 KB, 1 MB**
19+
* Em 2, 3 e 4 nós
20+
21+
Analise:
22+
23+
* Para mensagens pequenas, o que domina: **latência fixa** ou **tamanho da mensagem**?
24+
* A partir de que tamanho de mensagem o gargalo passa a ser a **largura de banda** da rede?
25+
26+
Código base:
27+
```cpp
28+
#include <mpi.h> // Biblioteca principal do MPI para comunicação entre processos
29+
#include <iostream>
30+
#include <cstring>
31+
32+
int main(int argc, char** argv) {
33+
int rank; // Variável que armazenará o "rank" (identificador) do processo
34+
MPI_Status status; // Estrutura que armazenará o status da comunicação MPI
35+
char mensagem[100]; // Vetor de caracteres para armazenar a mensagem a ser enviada/recebida
36+
37+
// Inicializa o ambiente MPI (todos os processos são iniciados)
38+
MPI_Init(&argc, &argv);
39+
40+
// Descobre o "rank" do processo atual dentro do comunicador global (MPI_COMM_WORLD)
41+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
42+
43+
// Se este for o processo de rank 0 (emissor inicial)
44+
if (rank == 0) {
45+
// Copia a string "Olá" para a variável mensagem
46+
std::strcpy(mensagem, "Olá");
47+
48+
// Envia a mensagem para o processo de rank 1
49+
// Parâmetros: buffer, tamanho, tipo, destino, tag, comunicador
50+
MPI_Send(mensagem, std::strlen(mensagem) + 1, MPI_CHAR, 1, 0, MPI_COMM_WORLD);
51+
52+
// Imprime no terminal que a mensagem foi enviada
53+
std::cout << "Processo 0 enviou: " << mensagem << std::endl;
54+
55+
// Aguarda a resposta do processo 1
56+
// Parâmetros: buffer, tamanho máximo, tipo, origem, tag, comunicador, status
57+
MPI_Recv(mensagem, 100, MPI_CHAR, 1, 0, MPI_COMM_WORLD, &status);
58+
59+
// Imprime a mensagem recebida
60+
std::cout << "Processo 0 recebeu: " << mensagem << std::endl;
61+
}
62+
63+
// Se este for o processo de rank 1 (receptor inicial)
64+
else if (rank == 1) {
65+
// Recebe a mensagem enviada pelo processo 0
66+
MPI_Recv(mensagem, 100, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &status);
67+
68+
// Imprime a mensagem recebida
69+
std::cout << "Processo 1 recebeu: " << mensagem << std::endl;
70+
71+
// Prepara a resposta "Oi"
72+
std::strcpy(mensagem, "Oi");
73+
74+
// Envia a resposta de volta ao processo 0
75+
MPI_Send(mensagem, std::strlen(mensagem) + 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
76+
77+
// Imprime que a mensagem foi enviada
78+
std::cout << "Processo 1 enviou: " << mensagem << std::endl;
79+
}
80+
81+
else {
82+
// Todos os outros processos apenas informam que estão ociosos
83+
std::cout << "Processo " << rank << " está ocioso neste exercício." << std::endl;
84+
}
85+
86+
// Finaliza o ambiente MPI (todos os processos encerram)
87+
MPI_Finalize();
88+
89+
return 0;
90+
}
91+
```
92+
93+
94+
## **Token em anel**
95+
96+
A ideia é perceber o custo de **coletar informações sequencialmente**.
97+
98+
Implemente o token em anel: cada rank adiciona uma informação nova ao vetor e passa adiante.
99+
Execute em 2, 3 e 4 nós .
100+
Compare com o mesmo problema usando `MPI_Gather`.
101+
102+
Analise:
103+
104+
* Como cresce o tempo do anel com o número de processos?
105+
* Qual o gargalo de percorrer todos em sequência?
106+
* Qual a vantagem de usar `MPI_Gather`?
107+
108+
---
109+
110+
111+
## **Alternância**
112+
113+
A ideia é entender como funciona uma **distribuição de tarefas**.
114+
115+
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.
116+
117+
O que acontece quando as tarefas variam muito de custo?
118+
119+
120+
121+
122+
# O que você deve entregar:
123+
124+
Para cada exercício:
125+
126+
1. **Código** (disponível no repositório do github).
127+
2. **Tabela de resultados** (parâmetros usados, tempos medidos).
128+
3. **Gráficos**: tempo × P, tempo × tamanho, throughput × blocos, etc.
129+
4. **Discussão**: Análise dos resultados
130+
131+
**Envie o seu relatório com as suas análises até as 23h59 de 04/09 pelo [GitHub Classroom](https://classroom.github.com/a/ilH4AsH_)**

material/teoria/MPI.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
## Conceitos básicos de MPI
2+
3+
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`).
4+
5+
## Comunicação ponto a ponto
6+
7+
### Envio e recebimento **bloqueantes**
8+
9+
```cpp
10+
MPI_Send(buffer, count, MPI_CHAR, destino, tag, MPI_COMM_WORLD);
11+
MPI_Recv(buffer, count, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);
12+
```
13+
14+
* `buffer`: ponteiro para os dados.
15+
* `count`: número de elementos.
16+
* `MPI_CHAR`, `MPI_INT`, `MPI_DOUBLE` etc.
17+
* `destino` / `origem`: rank do processo de envio/recebimento.
18+
* `tag`: identificador da mensagem (permite diferenciar mensagens).
19+
* `status`: metadados sobre a recepção.
20+
21+
### Envio e recebimento **não-bloqueantes**
22+
23+
```cpp
24+
MPI_Request req;
25+
MPI_Isend(buffer, count, MPI_INT, destino, tag, MPI_COMM_WORLD, &req);
26+
MPI_Wait(&req, MPI_STATUS_IGNORE);
27+
```
28+
29+
```cpp
30+
MPI_Request req;
31+
MPI_Irecv(buffer, count, MPI_INT, origem, tag, MPI_COMM_WORLD, &req);
32+
MPI_Wait(&req, MPI_STATUS_IGNORE);
33+
```
34+
35+
* Permitem **sobrepor comunicação e computação**.
36+
* Precisa sempre de `MPI_Wait` (ou `MPI_Test`).
37+
38+
39+
## Comunicação coletiva
40+
41+
* **Broadcast**
42+
43+
```cpp
44+
MPI_Bcast(buffer, count, MPI_INT, root, MPI_COMM_WORLD);
45+
```
46+
47+
Envia `buffer` do processo `root` para todos.
48+
49+
* **Scatter**
50+
51+
```cpp
52+
MPI_Scatter(sendbuf, count, MPI_INT, recvbuf, count, MPI_INT, root, MPI_COMM_WORLD);
53+
```
54+
55+
Distribui partes de um vetor do root para todos.
56+
57+
* **Gather**
58+
59+
```cpp
60+
MPI_Gather(sendbuf, count, MPI_INT, recvbuf, count, MPI_INT, root, MPI_COMM_WORLD);
61+
```
62+
63+
Cada processo envia dados para o root.
64+
65+
* **Reduce**
66+
67+
```cpp
68+
MPI_Reduce(&valor_local, &valor_total, 1, MPI_INT, MPI_SUM, root, MPI_COMM_WORLD);
69+
```
70+
71+
Combina valores de todos os processos (soma, máximo, mínimo, etc.).
72+
73+
* **Barrier**
74+
75+
```cpp
76+
MPI_Barrier(MPI_COMM_WORLD);
77+
```
78+
79+
Todos os processos param até que todos cheguem aqui.
80+
81+
---
82+
83+
## Medição de tempo
84+
85+
```cpp
86+
double t0 = MPI_Wtime();
87+
// ... código ...
88+
double t1 = MPI_Wtime();
89+
if(rank==0) std::cout << "Tempo = " << (t1-t0) << " segundos\n";
90+
```
91+
92+
---
93+
94+
## Estruturas úteis
95+
96+
* **MPI\_Status** → contém informações de mensagens recebidas (como rank origem).
97+
98+
```cpp
99+
MPI_Status status;
100+
MPI_Recv(buf, n, MPI_INT, origem, tag, MPI_COMM_WORLD, &status);
101+
int origem_real; MPI_Get_count(&status, MPI_INT, &origem_real);
102+
```
103+
104+
* **Tags** → permitem diferenciar mensagens diferentes em paralelo.
105+
106+
107+
## Compilação e execução
108+
109+
Compilar:
110+
111+
```bash
112+
mpic++ programa.cpp -o programa
113+
```
114+
115+
Executar com SLURM (arquivo `job.slurm`):
116+
117+
```bash
118+
#!/bin/bash
119+
#SBATCH --job-name=mpi_job
120+
#SBATCH --ntasks=4
121+
#SBATCH --time=00:05:00
122+
#SBATCH --partition=normal
123+
srun ./programa arg1 arg2
124+
```
125+
126+
Submit:
127+
128+
```bash
129+
sbatch job.slurm
130+
```
131+
132+
133+
Documentação:
134+
[https://www.physics.rutgers.edu/~haule/509/MPI_Guide_C++.pdf](https://www.physics.rutgers.edu/~haule/509/MPI_Guide_C++.pdf)

mkdocs.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ nav:
3838
- "Aula 04 - Heurísticas e Aleatoriedade": aulas/aula04/index.md
3939
- "Aula 05 - Programação paralela em CPU": aulas/aula05/index.md
4040
- "Aula 06 - Efeitos colaterais do paralelismo": aulas/aula06/index.md
41-
#- "Aula 07 - Programação Distribuída": aulas/aula07/index.md
41+
- "Aula 07 - Programação Distribuída": aulas/aula07/index.md
4242
#- "Aula 08 - Programação Paralela e Distribuída": aulas/aula08/index.md
4343
#- "Aula 09 - Programação Paralela em GPU": aulas/aula09/index.md
4444

@@ -49,6 +49,7 @@ nav:
4949
- "Lista de Comandos" : teoria/comandos.md
5050
- "Heurísticas" : teoria/heuristicas.md
5151
- "OpenMP" : teoria/openmp.md
52+
- "MPI" : teoria/MPI.md
5253
extra_javascript:
5354
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML
5455
- https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.0.0/js-yaml.min.js

0 commit comments

Comments
 (0)