Descargar

Programación con Paso de Mensajes (MPI) (página 3)

Enviado por Pablo Turmero


Partes: 1, 2, 3, 4
edu.red MPIComunicación punto a punto. MPI define un envío como finalizado cuando el emisor puede reutilizar, sin problemas de causar interferencias, el buffer de emisión que tenía el mensaje.

Se puede entender que tras hacer un send (envío) bloqueante podemos reutilizar el buffer asociado sin problemas.

Pero tras hacer un send no bloqueante tenemos que ser muy cuidadosos con las manipulaciones que se realizan sobre el buffer, bajo el riesgo de alterar inadvertidamente la información que se está enviando.

edu.red MPIComunicación punto a punto. Al margen de si la función invocada es bloqueante o no, el programador puede tener un cierto control sobre la forma en la que se realiza y completa un envío. MPI define, en relación a este aspecto, 4 modos de envío:

básico(basic) con buffer (buffered) síncrono (synchronous) listo (ready).

edu.red MPIComunicación punto a punto. Cuando se hace un envío con buffer se guarda inmediatamente, en un buffer al efecto en el emisor, una copia del mensaje. La operación se da por completa en cuanto se ha efectuado esta copia. Si no hay espacio en el buffer, el envío fracasa.

Si se hace un envío síncrono, la operación se da por terminada sólo cuando el mensaje ha sido recibido en destino.

El modo de envío básico no especifica la forma en la que se completa la operación: es algo dependiente de la implementación. Normalmente equivale a un envío con buffer para mensajes cortos y a un envío síncrono para mensajes largos. Se intenta así agilizar el envío de mensajes cortos a la vez que se procura no perder demasiado tiempo realizando copias de la información.

En cuanto al envío en modo listo, sólo se puede hacer si antes el otro extremo está preparado para una recepción inmediata. No hay copias adicionales del mensaje (como en el caso del modo con buffer), y tampoco podemos confiar en bloquearnos hasta que el receptor esté preparado.

edu.red MPIComunicación punto a punto. Básica El resultado de la combinación de dos modelos y cuatro modos de comunicación nos da 8 diferentes funciones de envío.

Funciones de recepción sólo hay dos, una por modelo.

MPI_Send() y MPI_Recv() que son, respectivamente, las funciones de envío y recepción básicas bloqueantes.

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);

edu.red MPIComunicación punto a punto. Básica Enviando y recibiendo mensajes

Preguntas: ¿Donde está la info? ¿Que tipo de info se envía? ¿Que cantidad de info se envía? ¿A quién se envía la info? ¿Como identifica el receptor el mensaje?

edu.red MPIComunicación punto a punto. Básica En MPI se especifica con address, datatype y count: count copias de un dato del tipo datatype que se encuentran (o se van a dejar) en memoria a partir de la dirección indicada por buf.

Dest es el identificador del proceso destinatario del mensaje.

Source es el identificador del emisor del cual esperamos un mensaje. Si no nos importa el origen del mensaje, podemos poner MPI_ANY_SOURCE.

Tag es una etiqueta que se puede poner al mensaje. Suele emplearse para distinguir entre diferentes clases de mensajes. El receptor puede elegir entre recibir sólo los mensajes que tengan una etiqueta dada, o aceptar cualquier etiqueta (MPI_ANY_TAG).

Comm es un comunicador (comunicador universal MPI_COMM_WORLD).

Status es un resultado que se obtiene cada vez que se completa una recepción, y nos informa de aspectos tales como el tamaño del mensaje recibido, la etiqueta del mensaje y el emisor del mismo.

edu.red MPIComunicación punto a punto. Básica Si queremos saber el tamaño de un mensaje, lo haremos con la función MPI_Get_count():

int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count);

MPI_Isend() y MPI_Irecv() son las funciones de emisión/recepción básicas no bloqueantes.

int MPI_Isend(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request); int MPI_Irecv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request);

edu.red MPIComunicación punto a punto. Básica Asociadas a MPI_Isend() y MPI_Irecv() existen otras tres funciones:

int MPI_Wait(MPI_Request *request, MPI_Status *status); int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status); int MPI_Cancel(MPI_Request *request);

MPI_Wait() toma como entrada un recibo (request), y bloquea al proceso hasta que la operación correspondiente termina.

Hacer un MPI_Isend() seguido de un MPI_Wait() equivale a hacer un envío bloqueante.

Sin embargo, entre la llamada a la función de envío y la llamada a la función de espera el proceso puede haber estado haciendo cosas útiles, es decir, consigue solapar parte de cálculo de la aplicación con la comunicación.

edu.red MPIComunicación punto a punto. Básica Asociadas a MPI_Isend() y MPI_Irecv() existen otras tres funciones:

int MPI_Wait(MPI_Request *request, MPI_Status *status); int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status); int MPI_Cancel(MPI_Request *request);

Cuando no interesa bloquearse, sino simplemente saber si la operación ha terminado o no, podemos usar MPI_Test(). Esta función actualiza un flag que se le pasa como segundo parámetro. Si la función ha terminado, este flag toma el valor 1, y si no ha terminado pasa a valer 0.

Por último, MPI_Cancel() nos sirve para cancelar una operación de comunicación pendiente, siempre que ésta aún no se haya completado.

edu.red MPIEjemplos Calcular el valor de la integral usando una suma de rectángulos:

edu.red MPIEjemplos. program main include 'mpif.h'

double precision PI25DT parameter (PI25DT = 3.141592653589793238462643d0) double precision mypi,pi,h,suma,x,f,a double precision startime,endtime integer n,myid,numprocs,i,ierr

! FUNCION PARA INTEGRAR

f(a)=4.d0/(1.d0+a*a)

call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)

edu.red MPIEjemplos. 10 if(myid .eq. 0) then print *, 'Introduzca el numero de intervalos (0 salir)' read(*,*) n print *, 'lo he leido y es ', n endif

! BROADCAST N

startime=MPI_WTIME() call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr)

! CHEQUEAR POR POSIBLE SALIDA

if (n .le. 0) goto 30

edu.red MPIEjemplos. ! CALCULAR EL TAMANO DEL INTERVALO

h=1.0d0/n suma=0.0d0

do 20 i=myid+1,n,numprocs x=h*(dble(i)-0.5d0) suma=suma+f(x) 20 continue mypi=h*suma

! RECOLECTAR TODAS LAS SUMAS PARCIALES call MPI_REDUCE(mypi,pi,1,MPI_DOUBLE_PRECISION,MPI_SUM,0, MPI_COMM_WORLD,ierr)

edu.red MPIEjemplos. ! EL NODO 0 IMPRIMIRA LA RESPUESTA

entime=MPI_WTIME() if(myid .eq. 0) then print *, 'pi es', pi, 'Error es ', abs(pi-PI25DT) print *, 'tiempo es ', (endtime-starttime), 'segundos' endif ! goto 10

30 call MPI_FINALIZE(ierr)

stop end

edu.red MPIEjemplos. #include using namespace std; int main(int argc, char **argv) { int sum = 0; for(int i=1;i<=1000;i=i+1) sum = sum + i; cout << "The sum from 1 to 1000 is: "<< sum << endl; }

Resultado: The sum from 1 to 1000 is: 500500 SUMA. Algoritmo secuencial

edu.red MPIEjemplos. #include #include “mpi.h” using namespace std; int main(int argc, char ** argv) { int mynode, totalnodes; int sum = 0,startval,endval,accum; MPI_Status status; MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD, &totalnodes); MPI_Comm_rank(MPI_COMM_WORLD, &mynode); startval = 1000*mynode/totalnodes+1; endval = 1000*(mynode+1)/totalnodes; SUMA. Algoritmo paralelo

edu.red MPIEjemplos. for(int i=startval;i<=endval;i=i+1) sum = sum + i; if(mynode!=0) MPI_Send(&sum, 1, MPI_INT, 0, 1, MPI_COMM_WORLD); else for(int j=1;j<< "The sum from 1 to 1000 is: "<< sum << endl; MPI_Finalize(); } SUMA. Algoritmo paralelo

edu.red MPIEjemplos. SUMA. Algoritmo paralelo

Compilación: mpicxx –o sumaparalelo sumaParalelo.cpp

Ejecución: mpiexec -n 4 ./suma_para Resultado: The sum from 1 to 1000 is: 500500

edu.red MPIEjemplos. Programa greetings

/* Envío de un mensaje desde todos los procesos con rank!= 0 al proceso 0. El proces 0 imprime los mensajes */

#include #include #include "mpi.h" main(int argc, char* argv[]) { int my_rank; int p; int source; /* origen */ int dest; /* destino */ int tag = 0; char message[100]; MPI_Status status;

MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD, &p); MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

edu.red MPIEjemplos. if (my_rank != 0) { /* Creamos el mensaje */ sprintf(message, "Greetings from process %d!", my_rank); dest = 0; /* Longitud strlen+1 porque en C se añade al final de una cadena '' */ MPI_Send(message, strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD); } else { /* my_rank == 0 */ for (source = 1; source < p; source++) { MPI_Recv(message, 100, MPI_CHAR, source, tag, MPI_COMM_WORLD, &status); printf("%sn", message); } } MPI_Finalize(); }

Partes: 1, 2, 3, 4
 Página anterior Volver al principio del trabajoPágina siguiente