• Nenhum resultado encontrado

Programação Paralela com Troca de Mensagens. Profa Andréa Schwertner Charão DLSC/CT/UFSM

N/A
N/A
Protected

Academic year: 2021

Share "Programação Paralela com Troca de Mensagens. Profa Andréa Schwertner Charão DLSC/CT/UFSM"

Copied!
30
0
0

Texto

(1)

Profa Andréa Schwertner Charão

DLSC/CT/UFSM

Programação Paralela

(2)

Modelo de programa MPI

Comunicação em MPI

Comunicadores

Mensagens

Comunicação ponto-a-ponto

Comunicação coletiva

Sumário

(3)

Padrão MPI (Message Passing Interface)

Implementações: OpenMPI, MPICH, LAM,

etc.

Alternativas: sockets, ZeroMQ, PVM (Parallel

Virtual Machine), etc.

Funcionalidades

Bibliotecas para troca de mensagens

processos

Criação, identificação, etc.

comunicação

Ponto-a-ponto, em grupo,

global, etc.

sincronização

Barreiras, comunicação

síncrona

(4)

API padrão para troca de mensagens

(versões MPI1, MPI2, MPI3)

Programas escritos em C, C++, Fortran,

Python, etc.

Implementações

open-source: OpenMPI, MPICH, LAM, ...

proprietárias

Mais de 120 chamadas

diferentes modos de comunicação

muitos programas usam menos de 10

chamadas!

(5)

Processos em MPI

Criação e execução de processos

MPI versão 1

Criação estática de processos: processos devem

ser definidos antes da execução e inicializados

juntos

Utiliza o modelo de programação SPMD

MPI versão 2

Criação dinâmica de processos

Permite utilizar um modelo MPMD

(6)

Modelos SPMD e MPMD

Single

Program

Multiple

Data

Multiple

Program

Multiple

Data

código fonte

executável

P0

P1

código fonte

executável

P0

P1

executável

seleção de código

conforme id.

do processo

código que ativa

outros processos

(7)

Modelo SPMD

#include "mpi.h"

int main (int argc, char *argv[])

{

MPI_Init(&argc, &argv);

.

.

MPI_Comm_Rank(MPI_COMM_WORLD, &myrank);

if (myrank ==0)

...;

else

...;

.

.

MPI_Finalize();

}

(8)

Comunicação em MPI

Contextos/grupos de comunicação

(communicators)

MPI_COMM_WORLD: contexto/grupo

contendo todos os processos lançados

Processos de um grupo são numerados

de 0 a NP-1

Operações básicas com grupos

MPI_Comm_rank: id do processo no grupo

MPI_Comm_size: número de processos no

(9)

Mensagens em MPI

Tamanho (quantidade de dados)

Tipo do dado (MPI_INT, MPI_DOUBLE, etc.)

Identificação de processo (origem, destino,

etc.)

MPI_ANY_SOURCE para recepção de

qualquer processo

Índice (tag)

MPI_ANY_TAG para recepção de qualquer

tag

Comunicator (ex.: MPI_COMM_WORLD)

(10)

Comunicação em MPI

Comunicação ponto-a-ponto (local)

com bloqueio

sem bloqueio

modos de envio: padrão, bufferizado,

síncrono, ready

Comunicação coletiva (global)

processo raiz

operações: difusão, redução,

(11)

Comunicação ponto-a-ponto

Com bloqueio

MPI_Send/MPI_Recv: bloqueiam até

que dados da mensagem possam ser

utilizados

Sem bloqueio

MPI_Isend/MPI_Irecv: envio/recepção

com retorno imediato (sem bloqueio)

Possuem MPI_Request associado

MPI_Wait/MPI_Test: espera/verifica se

(12)

Olá, mundo!

Processos 1 a P-1 enviam “Olá”

Processo 0 recebe as mensagens

Processo 1

Processo 3

Processo 0

Processo 2

Processo 4

(13)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

cabeçalho MPI

(14)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

inicialização do

ambiente

finalização do

ambiente

(15)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

“quem sou eu?”

conjunto default

MPI_COMM_WORLD

0

2

3

(16)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

quantos

processos fazem

parte do

“comunicador”?

(17)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

processos 1 a p-1

executam esse

código

(18)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

mensagem

(19)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

envia

mensagem

(20)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

 int MPI_Send(

void *buf, 

// ptr para msg

int count,

// tamanho da msg

MPI_Datatype dtype, 

// tipo de dados na msg

int dest,

// destinatário

int tag, 

// identificador da msg

MPI_Comm comm)

// conjunto “comunicador”

(21)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

processo 0

recebe p-1

mensagens

(22)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

 int MPI_Recv(

void *buf, 

// ptr para msg

int count,

// tamanho máximo da msg

MPI_Datatype dtype, 

// tipo de dados na msg

int source,

// remetente

int tag, 

// identificador da msg

MPI_Comm comm,

// conjunto “comunicador”

MPI_STATUS *stat)

// status da operação

(23)

#include <stdio.h> #include <string.h> #include "mpi.h" int main(int argc, char* argv[]) {   int meu_rank;       // "rank" do processo (0 a P­1)   int p;      // número de processos   int origem;         // "rank" do processo remetente   int destino;        // "rank" do processo destinatário   int tag = 0;        // "etiqueta" da mensagem   char msg[100];      // a mensagem   MPI_Status status;  // "status" de uma operação efetuada   // MPI_Init deve ser invocado antes de qualquer outra chamada MPI   MPI_Init(&argc, &argv);   // Descobre o "rank" do processo   MPI_Comm_rank(MPI_COMM_WORLD, &meu_rank);   // Descobre o número de processos   MPI_Comm_size(MPI_COMM_WORLD, &p);   if (meu_rank != 0) {     sprintf(msg, "Processo %d disse Ola!", meu_rank);     // envia mensagem ao processo 0     destino = 0;     MPI_Send(msg, strlen(msg)+1, MPI_CHAR, destino, tag, MPI_COMM_WORLD);   } else {     for(origem = 1; origem < p; origem++) {       // recebe P­1 mensagens       MPI_Recv(msg, 100, MPI_CHAR, origem, tag, MPI_COMM_WORLD, &status);       printf("%s\n", msg); // mostra mensagem     }   }   MPI_Finalize(); // finaliza MPI   return 0; }

(24)

Comunicação coletiva

Realizada em um conjunto de processadores

definido por um communicator

Não usa índices (tags)

Todos processos usam a mesma função

MPI_Bcast: envio do processo raiz para todos

os outros

MPI_Gather: coleta valores para um grupo de

processos

MPI_Scatter: espalha buffer de dados em

partes para um grupo de processos

MPI_Alltoall: envia dados de todos os

(25)

Comunicação coletiva

MPI_Reduce: combina valores de todos os

processos em um único valor no processo raiz

MPI_Allreduce: combina valores e difunde

resultados

MPI_Reduce_scatter: combina valores e

(26)

MPI_Bcast

Envio da mesma mensagem para todos os

processos

bcast();

Processo 0

dado

buf

bcast();

Processo 1

dado

bcast();

Processo n-1

dado

Código

Ação

(27)

MPI_Scatter

Envio de cada elemento de uma matriz de

dados do processo raiz para outros processos;

o conteúdo da i-ésima localização da

matriz é

enviado para o i-ésimo processo

scatter();

Processo 0

dado

buf

scatter();

Processo 1

dado

scatter()

;

Processo n-1

dado

Código

Ação

(28)

MPI_Gather

Coleta de dados de um conjunto de processos,

com armazenamento no processo raiz

gather();

Processo 0

dado

buf

gather();

Processo 1

dado

gather();

Processo n-1

dado

Código

Ação

(29)

MPI_Reduce

Operação MPI_Gather combinada com uma

operação lógica ou aritmética específica. Ex:

valores coletados e somados pelo processo

raiz

reduce()

;

Processo 0

dado

buf

reduce()

;

Processo 1

dado

reduce()

;

Processo n-1

dado

Código

Ação

+

(30)

Sincronização com barreira (barrier)

Em todos os sistemas de passagem de

mensagens existe uma maneira de sincronizar

os processos

MPI_Barrier(): processos ficam bloqueados

até todos os processos terem atingido essa

instrução no programa

Referências

Documentos relacionados

O objetivo do curso foi oportunizar aos participantes, um contato direto com as plantas nativas do Cerrado para identificação de espécies com potencial

Na lancha testada, haviam 8 caixas O Cat190 já vem de série com guincho elétrico para âncora, instalado na proa, entre os dois cascos O camarote principal é enorme.Tem mais de

Comparando os carcinomas com os adenomas funcionantes com síndrome de Cushing, foram observadas diferenças significativas na percentagem de área marcada e score

A peptide fraction isolated from the Polybia paulista wasp venom increases latency for the onset of seizures and protects 60% of the animals from tonic-clonic seizures induced by PTZ

(2004) deconstruction approach to investigate the effects of “current climate” vs. “historic climate” hypotheses on South American tree species gradients. More specifically,

The aim of this study was to evaluate the effect of short 3 mm long glass fiber addiction in flexural strength and flexural modulus of photopolymerizable 30%(wt) silica filled

Ainda assim, com essa vasta gama de estudos, sua química não é tão dominada em relação a outros metais.[47] Ainda que o uso do nióbio e seus óxidos esteja aumentando

decumbens apresenta efeito alelopático positivo sobre a soja, já que proporcionou uma maior porcentagem de germinação, um maior comprimento de parte aérea e maior