MPIEjemplos. Integración numérica Problema de integración numérica
The example application is to integrate cosine(x) from a to b numerically. There are various ways to perform numerical integrations of this type. Among them, the Mid-point rule is the least accurate but is chosen nevertheless for its simplicity. Essentially, the integrand, cox(x), is assumed to be constant within the upper and lower limit of integration and is taken to be the mid-point between the limits.
Normally, the integration range need only be divided into a series of smaller intervals so that the mid-point rule can be applied. Here, the integration range is first divided into a series of "partitions", each of which is assigned to a processor. Each processor will then subdivide its own sub-range into smaller segments for mid-point rule integration. The final integral sum is obtained by adding the integral sums from all processors. For single processor, the number of partitions is set to unity and the sub-range is the full range, from a to b.
MPIEjemplos. Integración numérica
MPIEjemplos. Integración numérica SECUENCIAL
#include #include float integral(float ai, float h, int n);
void main(void) { int n, p, i, j, ierr; float h, integral_sum, a, ai, b, pi, my_int;
pi = acos(-1.0); /* = 3.14159… */ a = 0.; /*lower limit of integration */ b = pi*1./2.; /*upper limit of integration */ p = 4; /*number of processes (partitions) */ n = 500; /*number of increment within each process */ h = (b-a)/n/p; /*length of increment */ integral_sum = 0.0; /*sum of integrals over all processes */
MPIEjemplos. Integración numérica SECUENCIAL
for (i=0; i #include #include
float integral(float ai, float h, int n);
void main(int argc, char* argv[]) { int n, p, myid, tag, proc, ierr; float h, integral_sum, a, b, ai, pi, my_int; int master = 0; /* processor performing total sum */ MPI_Comm comm; MPI_Status status; comm = MPI_COMM_WORLD;
ierr = MPI_Init(&argc,&argv); MPI_Comm_rank(comm, &myid); MPI_Comm_size(comm, &p);
MPIEjemplos. Integración numérica PARALELO. Comunicación bloqueante
pi = acos(-1.0); /* = 3.14159… */ a = 0.; /* lower limit of integration */ b = pi*1./2.; /* upper limit of integration */ n = 500; /* number of increment within each process */ tag = 123; /* set the tag to identify this particular job */ h = (b-a)/n/p; /* length of increment */ ai = a + myid*n*h; /* lower limit of integration for partition myid */ my_int = integral(ai, h, n); /* 0<=myid<=p-1 */
MPIEjemplos. Integración numérica PARALELO. Comunicación bloqueante
printf("Process %d has the partial integral of %fn", myid,my_int); MPI_Send(&my_int, 1, MPI_FLOAT, master, tag, comm); if(myid == master) { /* Receives serialized */ integral_sum = 0.0; for (proc=0;proc #include #include void other_work(int myid); float integral(float ai, float h, int n); int main(int argc, char* argv[]){ int n, p, myid, tag, master, proc, ierr; float h, integral_sum, a, b, ai, pi, my_int; MPI_Comm comm; MPI_Request request; MPI_Status status;
comm = MPI_COMM_WORLD; ierr = MPI_Init(&argc,&argv); MPI_Comm_rank(comm, &myid); MPI_Comm_size(comm, &p);
MPIEjemplos. Integración numérica PARALELO. Comunicación con Send (no bloqueante) y Recev
pi = acos(-1.0); /* = 3.14159… */ a = 0.; /* lower limit of integration */ b = pi*1./2.; /* upper limit of integration */ n = 500; /* number of increment within each process */ tag = 123; /* set the tag to identify this particular job */ h = (b-a)/n/p; /* length of increment */ ai = a + myid*n*h; /* lower limit of integration for partition myid */ my_int = integral(ai, h, n); /* 0<=myid<=p-1 */
printf("Process %d has the partial integral of %fn", myid,my_int);
MPIEjemplos. Integración numérica PARALELO. Comunicación con Send (no bloqueante) y Recev
if(myid == master) { integral_sum = my_int; for (proc=1;proc #include #include /* Ejecutar con dos procesos */
void main(intargc, char *argv[]) { int rank, i, count; float data[100],value[200]; MPI_Status status; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPIEjemplos. getcount.c if(rank==1) { for(i=0;i<100;++i) data[i]=i; MPI_Send(data,100,MPI_FLOAT,0,55,MPI_COMM_WORLD); } else { MPI_Recv(value,200,MPI_FLOAT,MPI_ANY_SOURCE,55, MPI_COMM_WORLD,&status); printf("P:%dGot data from processor %d n",rank, status.MPI_SOURCE); MPI_Get_count(&status,MPI_FLOAT,&count); printf("P:%dGot %d elements n",rank,count); printf("P:%dvalue[5]=%f n",rank,value[5]); } MPI_Finalize(); }
MPIEjemplos. Buffer.c #include #include #define TAM 100 #define BUFTAM 1000 /*Con 2 procesos*/
main(int argc, char* argv[]){ int p, my_rank; int tag=42; MPI_Status status; int x[TAM]; int buff[BUFTAM]; int tambuff=BUFTAM;
MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&p); MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);
MPIEjemplos. Buffer.c MPI_Buffer_attach(buff, tambuff);
if(my_rank ==0){ printf(“Proceso 0: mando al proceso 1n”); MPI_Bsend(&x,TAM,MPI_INT,1,tag,MPI_COMM_WORLD); printf(“Proceso 0: vuelta de la operación de envion”); } else{ printf(“Proceso 1: recibiendo del proceso 0n”); MPI_Recv(&c,TAM,MPI_INT,0,tag,MPI_COMM_WORLD,&status); printf(“Proceso 1: recibidos %d elementosn”,TAM); }
MPI_Buffer_detach(&buff,&tambuff); MPI_Finalize(); }
MPIComunicación punto a punto. Buffer Problema del envío básico: el programador NO tiene control sobre cuánto tiempo va a tardar en completarse la operación: Puede que apenas tarde, si es que el sistema se limita a hacer una copia del mensaje en un buffer, que saldrá más tarde hacia su destino; Puede que mantenga al proceso bloqueado un largo tiempo, esperando a que el receptor acepte el mensaje.
MPI_Bsend() solicita explícitamente que la comunicación se complete copiando el mensaje en un buffer, que tendrá que asignar al efecto el propio proceso.
int MPI_Bsend(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm);
MPIComunicación punto a punto. Buffer Para que se pueda usar el envío con buffer es necesario que el programador asigne un buffer de salida. Para ello hay reservar previamente una zona de memoria (de forma estática o con malloc()) y luego indicarle al sistema que la emplee como buffer.
Esta última operación la hace MPI_Buffer_attach().
Ese buffer se puede recuperar usando MPI_Buffer_detach().
int MPI_Buffer_attach(void* buffer, int size); int MPI_Buffer_detach(void* buffer, int* size);
Problema de los envíos con buffer: fracasan en el caso de que el buffer no tenga suficiente espacio como para contener un mensaje, y el resultado es que el programa aborta.
MPIComunicación punto a punto. Recepción por encuesta Las funciones de recepción de mensajes engloban en una operación la sincronización con el emisor (esperar a que haya un mensaje disponible) con la de comunicación (copiar ese mensaje).
A veces, sin embargo, conviene separar ambos conceptos. Por ejemplo, podemos estar a la espera de mensajes de tres clases, cada una asociada a un tipo de datos diferente, y la clase nos viene dada por el valor de la etiqueta.
Por lo tanto, nos gustaría saber el valor de la etiqueta antes de leer el mensaje.
También puede ocurrir que nos llegue un mensaje de longitud desconocida, y resulte necesario averiguar primero el tamaño para así asignar dinámicamente el espacio de memoria requerido por el mensaje.
MPIComunicación punto a punto. Recepción por encuesta Las funciones MPI_Probe() y MPI_Iprobe() nos permiten saber si tenemos un mensaje recibido y listo para leer, pero sin leerlo.
A partir de la información de estado obtenida con cualquiera de estas “sondas”, podemos averiguar la identidad del emisor del mensaje, la etiqueta del mismo y su longitud.
Una vez hecho esto, podemos proceder a la lectura real del mensaje con la correspondiente llamada a MPI_Recv() o MPI_Irecv().
int MPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status);
int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status);
MPIComunicación punto a punto. Recepción por encuesta MPI_Probe() es bloqueante: sólo devuelve el control al proceso cuando hay un mensaje listo.
MPI_Iprobe() es no bloqueante: nos indica en el argumento flag si hay un mensaje listo o no, es decir, realiza una encuesta.
MPIComunicación punto a punto. Modos de comunicación Envio Bloqueante No bloqueante Estándar. MPI_Send MPI_Isend Con Buffer: Usa un buffer para copiar los datos a enviar. No se requiere recepción para iniciar ni finalizar. MPI_Bsend MPI_Ibsend Síncrono: Debe sincronizarse con alguna recepción para poder finalizar. No la requiere para arrancar. MPI_Ssend MPI_Issend Listo: Requiere una recepción para arrancar. MPI_Rsend MPI_Irsend
MPIComunicación punto a punto. Modos de comunicación Recepción Bloqueante No bloqueante Estándar. MPI_Recv MPI_Irecv
MPITipo de datos elementales Los mensajes gestionados por MPI son secuencias de count elementos del tipo datatype.
MPI define una colección de tipos de datos primitivos, correspondientes a los tipos de datos existentes en C. Hay otra colección, distinta, para FORTRAN.
MPITipo de datos elementales Aunque una aplicación desarrollada en C trabaja con los tipos de datos habituales, cuando se realice un paso de mensajes habrá que facilitar a MPI un descriptor del tipo equivalente, tal como lo define MPI.
La idea de fondo es la siguiente: los procesadores que participan en una aplicación MPI no tienen por qué ser todos iguales. Es posible que existan diferencias en la representación de los datos en las distintas máquinas. Para eliminar los problemas que puedan surgir, MPI realiza, si son necesarias, transformaciones de sintaxis que posibilitan la comunicación en entornos heterogéneos. La excepción la constituyen los datos de tipo MPI_BYTE, que se copian sin más de una máquina a otra.
Aparte de los tipos simples definidos de forma primitiva por MPI, se permite la definición de tipos de usuario, más complejos.
Página anterior | Volver al principio del trabajo | Página siguiente |