Post on 17-Apr-2015
MPI – Comunicações
Com. Colectiva esquecida
Barrier não há troca de dados, apenas sincroniza os processos
int MPI_Barrier( MPI_Comm, comm)
Tcom
= Tlat
+ Bandwidth*tamanho mensagem
~10s 1000Mb/s
Menor número de comunicações
Medidas de Performance
Parallel Speedup Razão entre o tempo de execução sequencial T(N,1)
e o tempo de execução do algoritmo paralelo em P
processadores
N = tamanho do problema
S N ,P=T N ,1
T N , P
S(N,P) = P speedup linear ou perfect speedup
S(N,P) > P superlinear speedu
GRANULARIDADEDe um conjunto de tarefas paralelas é o trabalho
da mais pequena tarefa que pode ser realizado
independentemente de todas as outras tarefas
Sequencial
A=∑ i=1
Nai
Paralelo
N = k*P
k = granularidade
Aj=∑ i= j−1∗k1
j∗kai
A=∑ i=1
NAi
T1 = N T(N,P)= C*P + N/P
S(N,P) = 1 / [ (1/P) + C*P/N ] = P/[ 1 + C*P2/N ]
P
1P2
1000
S'(N,P) = 0
S(N,P)max
=
P= NC1
2 NC
Eficiência Paralela Speedup por processador
E(N,P) = S(N,P) / P
Limitações à Performance
Lei de Amdahl
T1 = tempo de execução em 1 processador
f = fracção do código que não pode ser paralelizado
f T1 = tempo de execução da fracção sequencial não paralizável
(1-f) T1 = tempo de execução da restante parte do código
TP f T
1 + (1-f) T
1 / P ( f + (1-f) / P ) S
P
SP < 1 / [ f + (1-f) / P ] < 1/f
Algoritmos Nem sempre é possível paralelizar o melhor algoritmo
Comunicações TP = T
Com + T
Cal
T1 < P*T
Cal
SP < P*T
Cal / [ T
Com + T
Cal ] = 1 / [ 1 + (T
Com / T
Cal )]
Load Balance TP proporcional tempo de execução do processador com
mais trabalho
Sincronização Falta de sincronização pode levar a que alguns processadores
fiquem à espera (idle), levando ao aumento do tempo de
execução
Algoritmo Escalável Um algoritmo diz-se escalável se existir uma
eficiência mínima tal que, para qualquer tamanho
do problema N, há um número de processadores
que cresce com N, P(N), tal que
E( N, P(N) ) >=
para N suficientemente grande
S(N,P) = P/[ 1 + C*P2/N] P = N1/2
S(N,P) = N1/2 / [ 1 + C] = P / [ 1 + C]
Álgebra Linear I
Multiplicação Matriz-Vector Yi = A
ij X
j
Solução I
> X cópia em todos os processos
> cada processo tem uma ou
várias linhas inteiras da matriz
N multiplicações + (N-1) somas
2N-1 operações vírgula flutante
N = k*P
Y calculado em
2(N-1) Tvf
N / P
~ 2N2 Tvf / P
Matriz * Vector (master/slave)
Slave:
i) Recebe X
ii) while (não fim programa)
recebe linha A;
multiplica Aij Xj;
devolve resultado;
Master:
i) Ler matriz A e vector X
ii) Broadcast X
iii) Envia linha da matriz A
cada processo MPI
iv) for (i=nproc; i < linhas; i++)
recebe linha de slave;
envia nova linha
v) envia mensagem finalização
Um processo (master) coordena o trabalho realizado pelos
outros processos (slaves)
int MPI_Bcast(void *buf, int count, MPI_Datatype datatype,
int root, MPI_Comm comm)
int MPI_Send(void *buf, int count, MPI_Datatype datatype,
int dest, int tag, MPI_Comm comm)
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag,
MPI_Comm comm, MPI_Status *status)
typedef struct MPI_Status {
int count;
int cancelled;
int MPI_SOURCE;
int MPI_TAG;
int MPI_ERROR;
} MPI_Status;
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
main( int argc, char *argv[] )
{
int master, nprocs, myid, linhas, colunas, emissor, tipo_resposta, nova_linha, i, j;
static int NLINHAS = 300, NCOLUNAS = 400;
double A[NLINHAS][NCOLUNAS],
buffer[NCOLUNAS], X[NCOLUNAS], B[NCOLUNAS], resposta;
MPI_Status status;
master = 0;
MPI_Init( &argc, &argv);
MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
MPI_Comm_rank( MPI_COMM_WORLD, &myid );
if (myid == master) { /* ======================= MASTER */
printf("Introduza o número linhas e colunas ");
scanf("%ld %ld",&linhas,&colunas);
printf("%ld %ld\n\n",linhas, colunas);
}
MPI_Bcast( &linhas, 1, MPI_INT, master, MPI_COMM_WORLD );
MPI_Bcast( &colunas, 1, MPI_INT, master, MPI_COMM_WORLD );
if (linhas > NLINHAS){
printf(" ERRO: linhas excedem o maximo permitido (%ld) \n", NLINHAS);
MPI_Abort( MPI_COMM_WORLD, i);
return 1;
}
if (colunas > NCOLUNAS){
printf(" ERRO: colunas excedem o maximo permitido (%ld) \n", NCOLUNAS);
MPI_Abort( MPI_COMM_WORLD, i);
return 2;
}
if (myid == master) { /* ======================= MASTER */
}
else { /* ============================================= Slave */
}
if (myid == 0){
for (i=0; i<linhas; i++)
printf(" %ld %lf \n",i,B[i]);
}
MPI_Finalize();
return 0;
}
Mas
ter
I printf(" \n Numero de linhas e colunas dentro dos limites \n");
for (i=0; i<linhas; i++){ /* ======================== Inicializa */
for (j=0; j<colunas; j++){
A[i][j] = i*j + 1.0;
X[j] = j + 2.0;
}
}
MPI_Bcast( &X, colunas, MPI_DOUBLE, master, MPI_COMM_WORLD );
for (i=0; i<nprocs-1; i++){ /* ======= Uma linha para cada processo */
for (j=0; j<colunas; j++)
buffer[j] = A[i][j];
MPI_Send( &buffer, colunas, MPI_DOUBLE, i+1, i, MPI_COMM_WORLD );
}
printf(" Enviou primeira linha para cada processador \n");
Mas
ter
II for (i=nprocs-1; i<linhas+1; i++){
MPI_Recv( &resposta, 1, MPI_DOUBLE, MPI_ANY_SOURCE,
MPI_ANY_TAG, MPI_COMM_WORLD, &status );
emissor = status.MPI_SOURCE;
tipo_resposta = status.MPI_TAG;
B[tipo_resposta] = resposta;
for (j=0; j<colunas; j++)
buffer[j] = A[i][j];
MPI_Send( &buffer, colunas, MPI_DOUBLE, emissor, i, MPI_COMM_WORLD);
}
printf(" Finaliza Ciclo \n"); /* ============== FINALIZA */
for (i=1; i<nprocs; i++)
MPI_Send( &resposta, 1, MPI_DOUBLE, i, linhas, MPI_COMM_WORLD );
Sla
veMPI_Bcast( &X, colunas, MPI_DOUBLE, master, MPI_COMM_WORLD );
while ( status.MPI_TAG < linhas ){
MPI_Recv( &buffer, colunas, MPI_DOUBLE, master,
MPI_ANY_TAG, MPI_COMM_WORLD, &status );
if (status.MPI_TAG < linhas ){
resposta = 0.0;
for (i=0; i<colunas; i++)
resposta = resposta + buffer[i]*X[i];
nova_linha = status.MPI_TAG;
MPI_Send( &resposta, 1, MPI_DOUBLE,
master, nova_linha, MPI_COMM_WORLD);
}
}
Exercício
Escreva um código paralelo para a multiplicação de uma matriz por
um vector sem usar o paradigma Master/Slave, isto é distribuindo o
cálculo por todos os processadores.
Multiplicação Matriz-Vector Yi = A
ij X
j
Solução II
> A divida por colunas
> X dividido por blocos
N ( N/P multiplicações + (N/P-1) somas )
Soma Colectiva
N = k*P
Y calculado em
~ 2N2 Tvf / P
+ comunicações0 1 2 3 4=
Exercício
Implemente a multiplicação de uma matriz por um vector usando a
decomposição discutida no slide anterior.
int MPI_Allreduce ( void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype,
MPI_Op op,
MPI_Comm comm )
Multiplicação Matriz -Vector Yi = A
ij X
j
Solução III
> A (e X divididos) por blocos
> cada processo tem um só bloco
N/P multiplicações + (N/P-1) somas
2N/P - 1 operações vírgula flutuante
N = k*P
Y calculado em
~ 2N3 Tvf / P3
+ comunicações
1 C
omm
Mu
ltip
le C
omm