Presentacion Taller de Introducción a Linux SFD2010
Operaciones Colectivas en MPI
1. Operaciones Colectivas en MPI
Manuel Martín Salvador
draxus@correo.ugr.es
http://draxus.org
Programación Concurrente
I.T. Informática de Sistemas
Granada, 16 enero 2007
2. Operaciones colectivas
Operaciones en las que participan todos los
procesos de un comunicador
- Barreras de sincronización
- Broadcast (difusión)
- Gather (recolección)
- Scatter (distribución)
- Operaciones de reducción (suma, mínimo...)
- Combinaciones de todas ellas
3. Barrier (barerra)
int MPI_Barrier(MPI_Comm comm)
Bloquea a los procesos de un comunicador hasta que todos ellos
han llegado a la barrera.
int main()
{ ...
rank = MPI_Rank();
if(rank==0){
a[0][0] = b[0][0] + c[0][0];
a[0][1] = b[0][1] + c[0][1];
}else{
a[1][0] = b[1][0] + c[1][0];
a[1][1] = b[1][1] + c[1][1];
}
MPI_Barrier(MPI_COMMWORLD);
if(MPI_Rank()==0)
//Imprimo matriz a
}
15. Scatter (distribución)
Ejemplo: distribuir 100 enteros desde el raíz a todos los procesos
int main(){
MPI_Comm comm;
int gsize,*sendbuf;
int root, rbuf[100], i, *displs, *scounts;
...
MPI_Comm_size(comm, &gsize);
sendbuf = (int *)malloc(gsize*stride*sizeof(int));
...
displs = (int *)malloc(gsize*sizeof(int));
scounts = (int *)malloc(gsize*sizeof(int));
for (i=0; i<gsize; ++i) {
displs[i] = i*stride;
scounts[i] = 100;
}
MPI_Scatterv(sendbuf, scounts, displs, MPI_INT, rbuf, 100, MPI_INT,
root, comm);
...
}
16. Comunicación todos con todos
int MPI_Alltoall(void *sendbuf, int sendcount, MPI_Datatype
sendtype, void *recvbuf, int recvcount, MPI_Datatype
recvtype, MPI_Comm comm)
int MPI_Alltoall(void *sendbuf, int *sendcounts, int
*sdispls, MPI_Datatype sendtype, void *recvbuf, int
*recvcounts, MPI_Datatype recvtype, int *rdispls, MPI_Comm
comm)
Cada proceso tiene un vector con tantos elementos como
procesos hay en el comunicador. Sean i, j y k entre 0 y N-1 (siendo
N=nº procesos). Cada proceso i envía una copia de sendbuf[j] al
proceso j, y recibe del proceso k un elemento que almacena en
recvbuf[k].
18. Reduce (reducción)
En ocasiones resulta útil que el resultado de una
reducción esté disponible para todos los procesos.
int MPI_Allreduce(void *sendbuf, void *recvbuf, int
count, MPI_Datatype datatype, MPI_Op op, MPI_Comm
comm)
Si el resultado es un vector que hay que distribuir entre todos los
procesos, usaremos:
int MPI_Reduce_scatter(void *sendbuf, void *recvbuf,
int *recvcounts, MPI_Datatype datatype, MPI_Op op,
MPI_Comm comm)
Si queremos que cada proceso reciba un resultado parcial:
int MPI_Scan(void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
21. Ejemplo: cálculo de Pi
double f( double a ){ if (n == 0)
return (4.0 / (1.0 + a*a)); done = 1;
} else{
h = 1.0 / (double) n;
int main( int argc, char *argv[]){ sum = 0.0;
int done = 0, n, myid, numprocs, i; for (i = myid + 1; i <= n; i +=
double PI25DT = 3.141592653589793238462643; numprocs){
double mypi, pi, h, sum, x; x = h * ((double)i 0.5);
double startwtime = 0.0, endwtime; sum += f(x);
int namelen; }
char processor_name[MPI_MAX_PROCESSOR_NAME]; mypi = h * sum;
MPI_Init(&argc,&argv); MPI_Reduce(&mypi, &pi, 1,
MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
MPI_Get_processor_name(processor_name,&namelen); if (myid == 0){
printf("pi is approximately
fprintf(stderr,"Proceso %d en %sn", myid, %.16f, Error is %.16fn", pi, fabs(pi
processor_name); PI25DT));
endwtime = MPI_Wtime();
n = 0; printf("wall clock time = %fn",
while (!done){ endwtimestartwtime);
if (myid == 0){ }
if (n==0) n=100; else n=0; }
startwtime = MPI_Wtime(); }
} MPI_Finalize();
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
return 0;
}
22. Referencias
● MPI: The Complete Reference
http://www.netlib.org/utk/papers/mpi-book/mpi-book.html
● Parallel programming with MPI - Peter S. Pacheco
● Cálculo de PI
http://www.ace.ual.es/~jamartin/Multi_2005_2006_html/practica1.html
● Especificación de MPI http://www-unix.mcs.anl.gov/mpi/www/
● Servidor público de MPI ftp://ftp.mcs.anl.gov/pub/mpi/