Aula 5 Computação Distribuída de Alto Desempenho

Texto

(1)

Aula 5

Computação Distribuída de Alto Desempenho

Marcelo Giovanni Marcelo Giovanni Nilton Alves

Nilton Alves

Marcelo Portes de Albuquerque Marcelo Portes de Albuquerque

Centro Brasileiro de Pesquisas Físicas

VI Escola do CBPF – Rio de Janeiro

17 a 28 de julho de 2006

(2)

Sumário Aula 05

1. 1. Programa C++ (Orienta Programa C++ (Orienta ç ç ão Objeto) ão Objeto)

2. 2. Laborat Laborat ó ó rios MPI rios MPI

BBáásico e Avansico e Avanççadoado

3. 3. Charm Charm ++ ++

(3)

3

Exemplo em C++

// classe contador class contador{

private:

unsigned int valor;

public:

contador( ){ // ---Æ Construtor valor = 0;

}

void inicializa(unsigned int val){

valor = val;

}

void incremento( ){

if (valor < 65535) valor++;

}

void decremento( ) {

if (valor > 0) valor--;

}

unsigned int get_valor( ){

return valor;

} };

// classe contador class contador{

private:

unsigned int valor;

public:

contador( ){ // ---Æ Construtor valor = 0;

}

void inicializa(unsigned int val){

valor = val;

}

void incremento( ){

if (valor < 65535) valor++;

}

void decremento( ) {

if (valor > 0) valor--;

}

unsigned int get_valor( ){

return valor;

} };

// Programa principal void main(){

contador cont;

unsigned int x;

cout << “\nValor inicial:"; cin >> x;

cont.inicializa(x);

cont.incremento();

cont.incremento();

cout << “\nValor final:“ <<

cont.get_valor();

}

// Programa principal void main(){

contador cont;

unsigned int x;

cout << “\nValor inicial:"; cin >> x;

cont.inicializa(x);

cont.incremento();

cont.incremento();

cout << “\nValor final:“ <<

cont.get_valor();

}

VI Escola do CBPF – Rio de Janeiro

OK!

(4)

Como Utilizar o MPI?

Bibliotecas

Adicione em seus programas o seguintes include para programas em C #include “mpi.h”

Rotinas MPI

Escreva seu programa fazendo chamadas às rotinas MPI

Para a compilação e linkedição utilizar os comandos:

mpicc [fonte.c] -o [executável] [parâmetros]

– Obs: O comando mpicc aceita os argumentos de compilação do compilador C

Execução

mpirun -[argumentos] [executável]

Exemplo: mpirun -np 5 a.out (executa a.out em 5 processadores)

Nomenclatura das Rotinas MPI

rc = MPI_Xxxxx(parâmetros, ...);

– rc é uma variável inteira que recebe um código de erro

(5)

5

MPI_Init

#include <stdio.h>

#include "mpi.h“

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

int ret;

ret = MPI_Init(&argc, &argv);

if (ret < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else ...

}

#include <stdio.h>

#include "mpi.h“

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

int ret;

ret = MPI_Init(&argc, &argv);

if (ret < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else ...

}

Inicia um processo MPI

Inicializa o processo MPI no processador

Deve ser a primeira rotina a ser chamada por cada processo Estabelece o ambiente necessário para executar o MPI Sincroniza a inicialização de todos os processos

Sintaxe (em C):

int MPI_Init (int *argc, char *argv[]) Parâmetros:

– argc – Quantidade de parâmetros da linha de comando – argv – ponteiro para os parâmetros da linha de comando

(6)

MPI_Comm_rank

Identifica um processo MPI dentro de um determinado grupo

Retorna sempre um valor inteiro entre 0 e n-1, onde n é o número de processos

Sintaxe (em C) : int MPI_Comm_rank (MPI_Comm comm, int *rank) Parâmetros:

comm - Comunicador do MPI

rank - Variável inteira com o número de identificação do processo

#include <stdio.h>

#include "mpi.h"

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

int mpierr, rank;

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

#include <stdio.h>

#include "mpi.h"

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

int mpierr, rank;

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

(7)

7

MPI_Comm_Size

Retorna o número de processos dentro de um grupo

Sintaxe (em C): int MPI_Comm_size (MPI_Comm comm, int *size)

Parâmetros:

comm: Comunicador do MPI

size: Variável interna que retorna o número de processos iniciados pelo MPI

#include <stdio.h>

#include "mpi.h"

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

int mpierr, rank, size;

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

printf ("Minha identificação no MPI e':%d\n",rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

printf("O numero de processos e': %d\n",size);

...

} }

#include <stdio.h>

#include "mpi.h"

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

int mpierr, rank, size;

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

printf ("Minha identificação no MPI e':%d\n",rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

printf("O numero de processos e': %d\n",size);

...

} }

(8)

MPI_Send

Rotina para envio de mensagens no MPI

utiliza o modo de comunicação "blocking send" (envio bloqueante), o que traz maior segurança na transmissão da mensagem

Sintaxe (em C): int MPI_Send (void *sndbuf, int count, MPI_Datatype dtype, int dest, int tag, MPI_Comm comm)

Parâmetros:

Sndbuf - Identificação do buffer (endereço de onde os dados serão enviados) count - Número de elementos a serem enviados

dtype - Tipo de dado

dest - Identificação do processo destino tag - Rótulo (label) da mensagem

comm - MPI Communicator

(9)

9

MPI_Send

#include <stdio.h>

#include "mpi.h"

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

int mpierr, rank, size, tag=100, i;

char message[20];

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

}

else {

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

printf ("Minha identificação no MPI e':%d\n",rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

printf("O numero de processos e': %d\n",size);

if (rank == 0){

strcpy(message,"Ola', Mundo!\n");

for (i=1; i<size; i++)

MPI_Send(message, 13, MPI_CHAR, i, tag, MPI_COMM_WORLD);

} else

...

} }

#include <stdio.h>

#include "mpi.h"

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

int mpierr, rank, size, tag=100, i;

char message[20];

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

}

else {

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

printf ("Minha identificação no MPI e':%d\n",rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

printf("O numero de processos e': %d\n",size);

if (rank == 0){

strcpy(message,"Ola', Mundo!\n");

for (i=1; i<size; i++)

MPI_Send(message, 13, MPI_CHAR, i, tag, MPI_COMM_WORLD);

} else

...

} }

int MPI_Send (void *sndbuf, int count, MPI_Datatype dtype, int dest, int tag, MPI_Comm comm) // 1234567890123

(10)

MPI_Recv

Rotina para recepção de mensagens no MPI

– utiliza o modo de comunicação "blocking receive" (recepção bloqueante), de forma que o processo espera até que a mensagem tenha sido recebida

Sintaxe (em C):

int MPI_Recv (void *sendbuf, int count, MPI_Datatype dtype,

int source, int tag, MPI_Comm comm, MPI_Status status)

Parâmetros:

sndbuf - Identificação do buffer de onde os dados serão armazenados count - Número de elementos a serem recebidos

dtype - Tipo de dado

source - Identificação do processo emissor tag - Rótulo (label) da mensagem

comm - MPI Communicator

status - Vetor de informações envolvendo os parâmetros source e tag

(11)

11

MPI_Recv

#include <stdio.h>

#include "mpi.h“

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

int mpierr, rank, size, tag=100, i;

MPI_Status status;

char message[20];

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

printf ("Minha identificação no MPI e':%d\n",rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

printf("O numero de processos e': %d\n",size);

if (rank == 0){

strcpy(message,"Ola', Mundo!\n");

for (i=1; i < size; i++)

MPI_Send(message, 13, MPI_CHAR, i, tag, MPI_COMM_WORLD);

} else{

MPI_Recv(message, 20, MPI_CHAR, 0, tag, MPI_COMM_WORLD, &status);

printf("Mensagem do no' %d : %s\n", rank, message);

...

} }

#include <stdio.h>

#include "mpi.h“

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

int mpierr, rank, size, tag=100, i;

MPI_Status status;

char message[20];

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

printf ("Minha identificação no MPI e':%d\n",rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

printf("O numero de processos e': %d\n",size);

if (rank == 0){

strcpy(message,"Ola', Mundo!\n");

for (i=1; i < size; i++)

MPI_Send(message, 13, MPI_CHAR, i, tag, MPI_COMM_WORLD);

} else{

MPI_Recv(message, 20, MPI_CHAR, 0, tag, MPI_COMM_WORLD, &status);

printf("Mensagem do no' %d : %s\n", rank, message);

...

} }

int MPI_Recv (void *sendbuf, int count, MPI_Datatype dtype,

int source, int tag, MPI_Comm comm, MPI_Status status)

(12)

MPI_Finalize

Finaliza um processo MPI

– Última rotina a ser chamada por cada processo.

– Sincroniza todos os processos na finalização de uma aplicação MPI

Sintaxe (em C)

int MPI_Finalize (void)

Parâmetros:

(Nenhum)

(13)

13

MPI_Finalize

#include <stdio.h>

#include "mpi.h“

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

int mpierr, rank, size, tag=100, i;

MPI_Status status;

char message[20];

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

printf ("Minha identificação no MPI e':%d\n",rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

printf("O numero de processos e': %d\n",size);

if (rank == 0){

strcpy(message,"Ola', Mundo!\n");

for (i=1; i < size; i++)

MPI_Send(message, 13, MPI_CHAR, i, tag, MPI_COMM_WORLD);

} else

MPI_Recv(message, 20, MPI_CHAR, 0, tag, MPI_COMM_WORLD, &status);

printf("Mensagem do no' %d : %s\n", rank, message);

MPI_Finalize();

} }

#include <stdio.h>

#include "mpi.h“

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

int mpierr, rank, size, tag=100, i;

MPI_Status status;

char message[20];

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

printf ("Minha identificação no MPI e':%d\n",rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

printf("O numero de processos e': %d\n",size);

if (rank == 0){

strcpy(message,"Ola', Mundo!\n");

for (i=1; i < size; i++)

MPI_Send(message, 13, MPI_CHAR, i, tag, MPI_COMM_WORLD);

} else

MPI_Recv(message, 20, MPI_CHAR, 0, tag, MPI_COMM_WORLD, &status);

printf("Mensagem do no' %d : %s\n", rank, message);

MPI_Finalize();

} }

OK!

(14)

MPI_Finalize

Job started at Mon Jul 17 16:56:31 BRST 2006 Minha identificação no MPI e':1

O numero de processos e': 4

Mensagem do no' 1 : Ola', Mundo!

Minha identificação no MPI e':3 O numero de processos e': 4

Mensagem do no' 3 : Ola', Mundo!

Minha identificação no MPI e':2 O numero de processos e': 4

Mensagem do no' 2 : Ola', Mundo!

Minha identificação no MPI e':0 O numero de processos e': 4

Mensagem do no' 0 : Ola', Mundo!

Job ended at Mon Jul 17 16:56:31 BRST 2006 Job started at Mon Jul 17 16:56:31 BRST 2006 Minha identificação no MPI e':1

O numero de processos e': 4

Mensagem do no' 1 : Ola', Mundo!

Minha identificação no MPI e':3 O numero de processos e': 4

Mensagem do no' 3 : Ola', Mundo!

Minha identificação no MPI e':2 O numero de processos e': 4

Mensagem do no' 2 : Ola', Mundo!

Minha identificação no MPI e':0 O numero de processos e': 4

Mensagem do no' 0 : Ola', Mundo!

Job ended at Mon Jul 17 16:56:31 BRST 2006

Output OK!

(15)

15

MPI_Bcast

Enviando dados para todos os processos

Diferentemente da comunicação ponto-a-ponto, na comunicação coletiva é possível enviar/receber dados simultaneamente de/para vários processos.

Sintaxe (em C) int MPI_Bcast (void *buf, int count,

MPI_Datatype datatype, int root, MPI_Comm comm)

Parâmetros:

buffer - Endereço do dado a ser enviado

count - Número de elementos a serem enviados datatype - Tipo do dado

root - Identifica o processo que irá efetuar o broadcast (origem) tag - Variável inteira com o rótulo da mensagem

comm - Identifica o Communicator

A0

processadores

Dados

Bcast

A0 A0

A0 A0

processadores

Dados

(16)

MPI_Bcast

#include <stdio.h>

#include "mpi.h"

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

int mpierr, rank, size, *index;

char message[20];

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

if (rank==0)

strcpy(message,"Mensagem do no 0\n");

MPI_Bcast(message, 20, MPI_CHAR, 0, MPI_COMM_WORLD);

printf("A mensagem recebida pelo rank (%d) foi: %s", rank, message);

MPI_Finalize();

#include <stdio.h>

#include "mpi.h"

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

int mpierr, rank, size, *index;

char message[20];

mpierr = MPI_Init(&argc, &argv);

if (mpierr < 0){

printf ("Nao foi possivel inicializar o processo MPI!\n");

return;

} else{

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

if (rank==0)

strcpy(message,"Mensagem do no 0\n");

MPI_Bcast(message, 20, MPI_CHAR, 0, MPI_COMM_WORLD);

printf("A mensagem recebida pelo rank (%d) foi: %s", rank, message);

MPI_Finalize();

OK!

Rank 0 define a mensagem a ser enviada Rank 0 define a mensagem a ser enviada

(17)

17

MPI_Bcast

Job started at Mon Jul 17 18:29:40 BRST 2006

A mensagem recebida pelo rank (1) foi: Mensagem do no 0 A mensagem recebida pelo rank (3) foi: Mensagem do no 0 A mensagem recebida pelo rank (0) foi: Mensagem do no 0 A mensagem recebida pelo rank (2) foi: Mensagem do no 0 Job ended at Mon Jul 17 18:29:40 BRST 2006

Job started at Mon Jul 17 18:29:40 BRST 2006

A mensagem recebida pelo rank (1) foi: Mensagem do no 0 A mensagem recebida pelo rank (3) foi: Mensagem do no 0 A mensagem recebida pelo rank (0) foi: Mensagem do no 0 A mensagem recebida pelo rank (2) foi: Mensagem do no 0 Job ended at Mon Jul 17 18:29:40 BRST 2006

Output OK!

r3 r2 r1 r0

message []

message []

message []

message []

“”

“”

“”

“Mensagem do no 0\n”

processadores

Broadcast

Dados

r3 r2 r1 r0

message []

message []

message []

message []

“Mensagem do no 0\n”

“Mensagem do no 0\n”

“Mensagem do no 0\n”

“Mensagem do no 0\n”

processadores

Dados

(18)

MPI_Scatter

Envia mensagens coletivamente

Envio de mensagens para um subgrupo de processos.

A mensagem pode ser segmentada e enviada para processos diferentes

Sintaxe (em C):

int MPI_Scatter (void *sbuf,int scount,MPI_Datatype stype, void *rbuf, int rcount,MPI_Datatype rtype,int root, MPI_Comm comm)

Parâmetros:

sbuf - Endereço dos dados a serem distribuídos

scount - Número de elementos enviados para cada processo stype - Tipo do dado a ser enviado

rbuf - Endereço onde os dados serão armazenados rcount - Quantidade de dados recebidos

rtype - Tipo do dado recebido

root - Identifica o processo que irá distribuir os dados comm - Identifica o Communicator

A3 A1 A2

A0

Dados

A0

Dados

(19)

19

MPI_Scatter

#include "mpi.h"

#include <stdio.h>

#define SIZE 4

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

int numtasks, rank, sendcount, recvcount, source;

float sendbuf[SIZE][SIZE] = {

{1.0, 2.0, 3.0, 4.0}, {5.0, 6.0, 7.0, 8.0}, {9.0, 10.0, 11.0, 12.0}, {13.0, 14.0, 15.0, 16.0}};

float recvbuf[SIZE];

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

if (numtasks == SIZE){

source = 0;

sendcount = SIZE;

recvcount = SIZE;

MPI_Scatter(sendbuf, sendcount, MPI_FLOAT, recvbuf, recvcount, MPI_FLOAT, source, MPI_COMM_WORLD);

printf(" Results (%d): %3.0f %3.0f %3.0f %3.0f\n",rank, recvbuf[0], recvbuf[1], recvbuf[2], recvbuf[3]);

} else

printf("Must specify %d processors. Terminating.\n",SIZE);

MPI_Finalize();

}

#include "mpi.h"

#include <stdio.h>

#define SIZE 4

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

int numtasks, rank, sendcount, recvcount, source;

float sendbuf[SIZE][SIZE] = {

{1.0, 2.0, 3.0, 4.0}, {5.0, 6.0, 7.0, 8.0}, {9.0, 10.0, 11.0, 12.0}, {13.0, 14.0, 15.0, 16.0}};

float recvbuf[SIZE];

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

if (numtasks == SIZE){

source = 0;

sendcount = SIZE;

recvcount = SIZE;

MPI_Scatter(sendbuf, sendcount, MPI_FLOAT, recvbuf, recvcount, MPI_FLOAT, source, MPI_COMM_WORLD);

printf(" Results (%d): %3.0f %3.0f %3.0f %3.0f\n",rank, recvbuf[0], recvbuf[1], recvbuf[2], recvbuf[3]);

} else

printf("Must specify %d processors. Terminating.\n",SIZE);

MPI_Finalize();

} int MPI_Scatter (void *sbuf,int scount,MPI_Datatype stype, void *rbuf, int rcount,MPI_Datatype rtype,int root, MPI_Comm comm)

OK!

buffer de envio buffer de envio

Rank 0 distribui para todos Rank 0 distribui para todos

buffer de recepção buffer de recepção

(20)

MPI_Scatter

Job started at Mon Jul 17 18:38:05 BRST 2006 Results (1): 5 6 7 8

Results (3): 13 14 15 16 Results (2): 9 10 11 12 Results (0): 1 2 3 4

Job ended at Mon Jul 17 18:38:05 BRST 2006 Job started at Mon Jul 17 18:38:05 BRST 2006 Results (1): 5 6 7 8

Results (3): 13 14 15 16 Results (2): 9 10 11 12 Results (0): 1 2 3 4

Job ended at Mon Jul 17 18:38:05 BRST 2006

Output OK!

sendbuf

r1

r0 9 10 11 12

16 15

14 13

8 7

6 5

4

2 3

1

Dados

adores

Dados

Scatter

recvbuf recvbuf

r1 r0

12 11

10 9

8 7

6 5

4 3

2 1

(21)

21

MPI_Gather

Coleta mensagens dos processos Sintaxe:

int MPI_Gather (void *sbuf, int scount, MPI_Datatype stype, void *rbuf, int rcount, MPI_Datatype rtype, int root, MPI_Comm comm)

Parâmetros:

sbuf - Endereço inicial do dado a ser coletado scount - Número de dados a serem coletados stype - Tipo do dado a ser coletado

rbuf - Endereço onde os dados serão armazenados rcount - Número de elementos recebidos por processo rtype - Tipo do dado recebido

root - Identifica o processo que irá efetuar a coleta comm - Identifica o Communicator

A2 A1

A3 A0

processadores

Dados

Gather

A3 A1 A2

A0

processadores

Dados

(22)

MPI_Gather

#include <stdio.h>

#include "mpi.h"

#define SIZE 4

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

int numtasks, rank, sendcount, recvcount, source, i;

float recvbuf[SIZE][SIZE];

float sendbuf[SIZE];

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

if (numtasks == SIZE){

for (i=0;i<SIZE;i++)

sendbuf[i]=(float) rank * SIZE + i;

source = 0;

sendcount = SIZE; recvcount = SIZE;

MPI_Gather(sendbuf, sendcount, MPI_FLOAT, recvbuf, recvcount, MPI_FLOAT, source, MPI_COMM_WORLD);

if (rank==source)

for (i=0;i<SIZE;i++)

printf("Results (%d): %3.0f %3.0f %3.0f %3.0f\n", rank,

#include <stdio.h>

#include "mpi.h"

#define SIZE 4

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

int numtasks, rank, sendcount, recvcount, source, i;

float recvbuf[SIZE][SIZE];

float sendbuf[SIZE];

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

if (numtasks == SIZE){

for (i=0;i<SIZE;i++)

sendbuf[i]=(float) rank * SIZE + i;

source = 0;

sendcount = SIZE; recvcount = SIZE;

MPI_Gather(sendbuf, sendcount, MPI_FLOAT, recvbuf, recvcount, MPI_FLOAT, source, MPI_COMM_WORLD);

if (rank==source)

for (i=0;i<SIZE;i++)

printf("Results (%d): %3.0f %3.0f %3.0f %3.0f\n", rank,

recvbuf[i][0], recvbuf[i][1], recvbuf[i][2], recvbuf[i][3]);

OK!

Rank 0 recebe de todos Rank 0 recebe de todos

Prepara buffer de envio Prepara buffer de envio

(23)

23

MPI_Gather

Job started at Mon Jul 17 19:24:01 BRST 2006 Results (0): 0 1 2 3

Results (0): 4 5 6 7 Results (0): 8 9 10 11 Results (0): 12 13 14 15

Job ended at Mon Jul 17 19:24:02 BRST 2006 Job started at Mon Jul 17 19:24:01 BRST 2006 Results (0): 0 1 2 3

Results (0): 4 5 6 7 Results (0): 8 9 10 11 Results (0): 12 13 14 15

Job ended at Mon Jul 17 19:24:02 BRST 2006

Output OK!

recvbuf

r3 r2 r1 r0

11 10

9 8

15 14

13 12

7 6

5 4

3

1 2

0

processadores

Dados

processadores

Dados Gather

sendbuf Sendbuf Sendbuf Sendbuf

15 14

13 12

r3

11 10

9 8

r2

7 6

5 4

r1

3 2

1 0

r0

(24)

MPI_Reduce

Realiza uma computação de todos os processos

– Todos os processos executam uma operação, onde o resultado parcial de cada processo é combinado e retornado para um processo específico

Sintaxe (em C)

int MPI_Reduce (void *sbuf, void *rbuf, int count,

MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)

Parâmetros

sbuf - Endereço do dado a ser enviado;

rbuf - Endereço do dado a ser recebido;

count - Número de elementos a serem distribuídos;

datatype - Tipo do dado a ser computado;

op - Operaçâo a ser executada;

root - Processo que irá receber o resultado da operação;

comm - Identifica o Communicator;

(25)

25

MPI_Reduce

int, float Valor mínimo de menor índice

MPI_MINLOC

int, float Valor máximo de maior índice

MPI_MAXLOC

OU-EXCLUSIVO (XOR) lógico a nível de BIT int MPI_BXOR

OU-EXCLUSIVO (XOR) lógico int MPI_LXOR

OU (OR) lógico a nível de BIT int MPI_BOR

OU (OR) lógico int MPI_LOR

E (AND) lógico a nível de BIT int MPI_BAND

E (AND) lógico int MPI_LAND

int, float Produtório dos valores

MPI_PROD

int, float Somatório dos valores

MPI_SUM

int, float Valor mínimo

MPI_MIN

int, float Valor máximo

MPI_MAX

C Significado

Função

Operações Possíveis

(26)

MPI_Reduce

#include "mpi.h"

#include <stdio.h>

#define SIZE 4

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

int numtasks, rank;

int recvbuf, sendbuf;

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

sendbuf=rank;

if (numtasks == SIZE){

MPI_Reduce(&sendbuf, &recvbuf, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);

if (rank==0)

printf("Maior = %d\n", recvbuf);

} else

printf("Especifique %d processadores. Abortado.\n",SIZE);

#include "mpi.h"

#include <stdio.h>

#define SIZE 4

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

int numtasks, rank;

int recvbuf, sendbuf;

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

sendbuf=rank;

if (numtasks == SIZE){

MPI_Reduce(&sendbuf, &recvbuf, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);

if (rank==0)

printf("Maior = %d\n", recvbuf);

} else

printf("Especifique %d processadores. Abortado.\n",SIZE);

OK!

Rank 0 recebe o valor máximo Rank 0 recebe o valor máximo Em cada processo sendbuf

recebe o valor de rank Em cada processo sendbuf

recebe o valor de rank

(27)

27

MPI_Reduce

Job started at Mon Jul 17 19:21:59 BRST 2006 Maior = 3

Job ended at Mon Jul 17 19:21:59 BRST 2006 Job started at Mon Jul 17 19:21:59 BRST 2006 Maior = 3

Job ended at Mon Jul 17 19:21:59 BRST 2006

Output OK!

recvbuf recvbuf recvbuf recvbuf

sendbuf sendbuf sendbuf sendbuf

r3 r2 r1 r0

?

?

?

?

2 1

3 0

processadores

Reduce

Dados

3 2 1 0 MAX

recvbuf recvbuf recvbuf recvbuf

sendbuf sendbuf sendbuf sendbuf

r3 r2 r1 r0

?

?

? 3

2 1

3 0

processadores

Dados

(28)

Outras Rotinas Avançadas

MPI_Wtime

– Retorna (em precisão numérica dupla) o número de segundos decorridos desde algum tempo no passado

MPI_Wtick

– Retorna (em valor real) a precisão de tempo computada pelo comando MPI_Wtime

MPI_Get_processor_name

Retorna o nome da máquina onde um dado processo está executando

...

(29)

29

Organização dos Labs

Local: Prédio Min. João Alberto, 4º Andar, Laboratórios 1 e 3 Divisão da Turma em 2 Grupos

Grupo 1: 14h – 15h – “A até J”

Grupo 2: 15h – 16h – “L até Z”

Cluster dedicado à VI Escola: 6 CPUs

Login: esc1 Password: cbpf

Quinta (19/07)

Equação do segundo grau Compilação

Script pbs

Sexta (19/07)

MPI básico MPI avançado Integral em mpi charm++

Cluster do CBPF – andar térreo do prédio anexo

(30)

Integração Numérica

O conceito de integral está ligado ao problema da determinação da área de uma figura plana qualquer

Integral de uma função f(x) no intervalo [a,b]

f(x) F(x) =

ab f (x) dx Em determinados casos não podemos calcular F(x) ou a sua

obtenção não é simples

Em situações práticas nem sempre se tem a forma analítica da função f(x) a

ser integrada, mas sim uma tabela de pontos que descreve o comportamento da função

Em determinados casos não podemos calcular F(x) ou a sua

obtenção não é simples

Em situações práticas nem sempre se tem a forma analítica da função f(x) a

ser integrada, mas sim uma tabela de pontos que descreve o comportamento da função

(31)

31

Regra dos Trapézios

A idéia básica é a substituição da função f(x) por uma aproximação no intervalo [a,b]

Integrando no intervalo [x0 , x1] teremos

x1

f(x)

x0 x

O que é a fórmula da área do trapézio, como mostrado na figura

onde h = x1 x0

A = (B + b) * h / 2

[

( ) ( )

]

) 2

( 0 1

1

0

x f x

h f dx

x

x f

x +

B b

h

(32)

Regra dos Trapézios ...

Quanto maior for o intervalo, maior será o erro do método

O que se utiliza é subdividir o intervalo em vários pedaços, calcular a área de cada um deles e em seguida somar todos

[ ]

)) ( ) ( 2( ...

)) ( ) ( 2( )) ( ) ( 2( ) (

) ( ) 2 (

) (

1 2

1 1

0 1

0

1

n n

n

i

i i

x f x

h f x

f x

h f x

f x

h f x F

x f x h f

x F

+ +

+ +

+ +

+

= +

f(x)

n = 8

(33)

33

Implementação em MPI

x4 x x0 x1 x2 x3

f(x)

Passo p

rank 1

rank 1 rank 2rank 2 rank 3rank 3 rank 4rank 4

+ ResultadoFinal rank 0 rank 0

Cálculos parciais

result_parcial=0;

for ( i = (rank-1)*delta; i+p-precisao < (rank)*delta; i+=p ){

result_parcial += p * 0.5 * ( f(i)+ f(i+INC-precisao) );

}

result_parcial=0;

for ( i = (rank-1)*delta; i+p-precisao < (rank)*delta; i+=p ){

result_parcial += p * 0.5 * ( f(i)+ f(i+INC-precisao) );

}

P

#

0

4 x

x

=

... ...

x0 x0 + p precisão

Atenção

Σ r4 Σ r3 Σ r2 Σ r1

(34)

Cálculo da integral com f(x) = x no intervalo [ 0,10 ]

) 2

...

2 2 (

) (

)) 1 ( 9

, 0 ( 2 ...

) 1 , 0 ( 2 )

0 ( 2 (

) (

1 , 10 0

1 9

, 0 1

, 0

0 + + + +

+ +

+ +

=

=

e e

e h e

x F

f f

f h f

x F

a h b

Exemplo

1 50

0 =

=

x dx

Cálculo da integral com f(x) = ex no intervalo [ 0,1 ]

(35)

35

Hello

Hello

SayHi(int n) Hello

SayHi(int n)

# processadores = 6 2 Classes – Main e Hello

nElements = 10 objetos Hello (array objetos)

Main

Main done Main done

arr[0]

Hello

SayHi(n) SayHi(n)

Main

Main done Main done

arr[1]

Hello

SayHi(n) SayHi(n)

arr[9]

Hello

SayHi(n) SayHi(n)

...

arr[0].SayHi(17) arr[1].SayHi(17+1) arr[9].SayHi(17+9)

Main.done()

Hello Charm++ (Objects Array)

(36)

Charm++ Hello with Array Obj

#include <stdio.h>

#include "hello.decl.h"

CProxy_Main mainProxy; /*readonly*/

int nElements; /*readonly*/

class Main : public Chare{ /*mainchare*/

public:

--- Main(CkArgMsg* m) {

nElements=5; //Process command-line arguments if(m->argc >1 ) nElements=atoi(m->argv[1]);

delete m;

//Start the computation

CkPrintf("Running Hello on %d processors

for %d elements\n", CkNumPes(),nElements);

mainProxy = thishandle;

CProxy_Hello arr = CProxy_Hello::ckNew(nElements);

arr[0].SayHi(17);

};

#include <stdio.h>

#include "hello.decl.h"

CProxy_Main mainProxy; /*readonly*/

int nElements; /*readonly*/

class Main : public Chare{ /*mainchare*/

public:

--- Main(CkArgMsg* m) {

nElements=5; //Process command-line arguments if(m->argc >1 ) nElements=atoi(m->argv[1]);

delete m;

//Start the computation

CkPrintf("Running Hello on %d processors

for %d elements\n", CkNumPes(),nElements);

mainProxy = thishandle;

CProxy_Hello arr = CProxy_Hello::ckNew(nElements);

arr[0].SayHi(17);

};

/*array [1D]*/

class Hello : public CBase_Hello{

public:

--- Hello(){

CkPrintf("Hello %d created\n",thisIndex);

}

--- Hello(CkMigrateMessage *m) {}

--- void SayHi(int hiNo){

CkPrintf("Hi[%d] from element (%d)\n",hiNo,thisIndex);

if (thisIndex < nElements-1) //Pass the hello on:

thisProxy[thisIndex+1].SayHi(hiNo+1);

else

//We've been around once-- we're done.

mainProxy.done();

/*array [1D]*/

class Hello : public CBase_Hello{

public:

--- Hello(){

CkPrintf("Hello %d created\n",thisIndex);

}

--- Hello(CkMigrateMessage *m) {}

--- void SayHi(int hiNo){

CkPrintf("Hi[%d] from element (%d)\n",hiNo,thisIndex);

if (thisIndex < nElements-1) //Pass the hello on:

thisProxy[thisIndex+1].SayHi(hiNo+1);

else

//We've been around once-- we're done.

mainProxy.done();

(37)

37

Charm++ Hello with Array Obj

Compilando: > charmc -c hello.ci hello.C -o a.out -language charm++

Executando: > charmrun ++p3 a.out 10 Job started at Mon Aug 15 11:27:23 BRST 2005 Running Hello on 3 processors for 10 elements Hello 0 created

Hello 3 created Hello 6 created Hello 9 created

Hi[17] from element 0 Hello 2 created

Hello 5 created Hello 8 created Hello 1 created Hello 4 created Hello 7 created

Hi[18] from element 1 Hi[19] from element 2 Hi[20] from element 3 Hi[21] from element 4 Hi[22] from element 5 Hi[23] from element 6 Hi[24] from element 7 Hi[25] from element 8 Hi[26] from element 9 All done

Job ended at Mon Aug 15 11:27:25 BRST 2005

>

(38)

Aula 5

Computação Distribuída de Alto Desempenho

Marcelo Giovanni Marcelo Giovanni Nilton Alves

Nilton Alves

Marcelo Portes de Albuquerque Marcelo Portes de Albuquerque

Centro Brasileiro de Pesquisas Físicas

Imagem

Referências

temas relacionados :