230 likes | 382 Views
Titulo. Introducción a MPI Clase 3. Marcelo Rozenberg (agradecimiento: Ruben Weht ruweht@cnea.gov.ar). Ejemplo. Ejemplo Quiero calcular como :. Pi.f-1/2. double precision mypi, pi, h, sum, x, f, a integer n, myid, size, i, rc, ierr, status c --- funcion a integrar
E N D
Titulo Introducción a MPI Clase 3 Marcelo Rozenberg (agradecimiento: Ruben Weht ruweht@cnea.gov.ar)
Ejemplo Ejemplo Quiero calcular como :
Pi.f-1/2 double precision mypi, pi, h, sum, x, f, a integer n, myid, size, i, rc, ierr, status c --- funcion a integrar f(a) = 4.d0 / (1.d0 + a*a) c --- Numero de intervalos read(5,*) n c --- tamaño del intervalo h = 1.0d0/n c --- realiza las sumas sum = 0.0d0 do i = 1, n x = h * (dble(i) - 0.5d0) sum = sum + f(x) enddo mypi = h * sum pi=mypi write(6, '(" pi es aproximadamente:", F18.16)') pi end
Pi.f-1/2 include 'mpif.h' double precision mypi, pi, h, sum, x, f, a integer n, myid, size, i, rc, ierr, status c --- funcion a 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, size, ierr ) print *, "Proceso ", myid, " de ", size, " funcionando" if(myid.eq.0) then read(5,*) n endif if(myid.eq.0) then do i=1,size-1 call MPI_SEND(n,1,MPI_INTEGER,i,1,MPI_COMM_WORLD,ierr) enddo else call MPI_RECV(n,1,MPI_INTEGER,0,1,MPI_COMM_WORLD,status,ierr) endif h = 1.0d0/n
Pi.f-2/2 sum = 0.0d0 do i = myid+1, n, size x = h * (dble(i) - 0.5d0) sum = sum + f(x) enddo mypi = h * sum if(myid.eq.0) then pi=mypi do i=1,size-1 call MPI_RECV(mypi,1,MPI_DOUBLE_PRECISION,MPI_ANY_SOURCE,MPI_ANY_TAG, MPI_COMM_WORLD,status,ierr) pi=pi+mypi enddo else call MPI_SEND(mypi,1,MPI_DOUBLE_PRECISION,0,99, MPI_COMM_WORLD,ierr) endif if (myid .eq. 0) then write(6, '(" pi es aproximadamente:", F18.16)') pi endif call MPI_FINALIZE(rc) end
Pi.f-2/2 0+1+1= 2+3+1= 0 0 1 2 1 3 0 6 1 5 3 7 0 4 2 En log2(p) pasos comunique el dato a los p-1 procesos. Si p=1024 gano un factor 10!
Comm. Colectivos Con las comunicaciones punto-a-punto puedo hacer (casi) todo!!!aunque se necesitaría algo mejor para hacerlo más sencillo... Comunicaciones colectivas Ejemplo: Broadcast Datos Procesos MPI_Bcast(datos, tamaño, tipo, origen, comm, error)
Broadcast En nuestro ejemplo para calcular : if(myid.eq.0) then do i=1,size-1 call MPI_SEND(n,1,MPI_INTEGER,i,1,MPI_COMM_WORLD,ierr) enddo else call MPI_RECV(n,1,MPI_INTEGER,0,1,MPI_COMM_WORLD,status,ierr) endif call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr)
Reduce A veces uno está interesado en calcular algo globalmente. En nuestro ejemplo de , quisieramos simplificar: ! collect all the partial sums if(myid.eq.0) then pi=0.d0 do i=1,size-1 call MPI_RECV(mypi,1,MPI_DOUBLE_PRECISION,MPI_ANY_SOURCE,,MPI_COMM_WORLD,status,ierr) pi=pi+mypi enddo else call MPI_SEND(mypi,1,MPI_DOUBLE_PRECISION,0,99,MPI_COMM_WORLD,ierr) endif MPI_Reduce (mypi, pi, 1, MPI_DOUBLE_PRECISION, MPI_SUM, 0, MPI_COMM_WORLD,ierr)
Pi.f-2/2 include 'mpif.h' double precision mypi, pi, h, sum, x, f, a integer n, myid, size, i, rc, ierr, status 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, size, ierr ) if(myid.eq.0) read(5,*) n call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr) h = 1.0d0/n sum = 0.0d0 do i = myid+1, n,size x = h * (dble(i) - 0.5d0) sum = sum + f(x) enddo mypi = h * sum call MPI_REDUCE > (mypi,pi,1,MPI_DOUBLE_PRECISION,MPI_SUM,0, MPI_COMM_WORLD,ierr) if (myid .eq. 0) write(6, '(" pi es aproximadamente:", F18.16)') pi call MPI_FINALIZE(rc) end
Comunicaciones Punto a Punto más comunes MPI_SEND(datos, tamaño, tipo_de_dato, destino, tag, comm, ierror) Ej: MPI_SEND(n,1,MPI_INTEGER,i,1,MPI_COMM_WORLD,ierr) envia 1 numero entero “n” al proceso i de comm_world MPI_SEND(a,5,MPI_REAL,4,1,MPI_COMM_WORLD,ierr) envia los 5 numeros reales del vector “a(5)” al proceso 4 de comm_world MPI_RECV(datos, tamaño, tipo_de_dato, origen, tag, comm, status,ierror) Ej: MPI_RECV(n,1,MPI_INTEGER,0,1,MPI_COMM_WORLD,status,ierr)
Comunic. Punto a Punto 2 Para recordar: MPI_SEND y MPI_RECV estándar son bloqueantes!! size es el tamaño de los datos threshold es el espacio de buffer disponible Cualquiera de las 2 Situaciones puede ocurrir
Que pasa si el proceso 1 no esta listo para recibir? Supongamos que: MPI_Send(n,0) MPI_Recv(n,1) • P0 para y espera hasta que P1 le da el OK • P0 guarda el dato en un buffer y continua y lo envia luego cuando P1 le da el OK • El programa falla
Comunic. Punto a Punto 3 3 variantes de Send (y Recv): Sincrónico:MPI_Ssend(.....) Permite hacer programas “seguros” ya que no utiliza espacios de buffer. Portabilidad del codigo. Buffered: MPI_Bsend(.....) S guarda en un buffer el mensaje y lo envia cuando R lo pida. Hay que reservar espacio de buffer con la rutina MPI_Buffer_attach(....) Ready: MPI_Rsend(.....) Puede usarse cuando S esta seguro que ya le enviaron el aviso que R esta listo. Si R no estaba listo el comportamiento esta indefinido y es un error de programacion
Comm. Colectivos 1 • Comunicaciones Colectivas • Involucran comunicación coordinada dentro de un grupo de procesos identificados por un comunicador • (ej. MPI_comm_world) • Todas las rutinas son bloqueantes • No hay tags involucrados
Comm. Colectivos 2 • Tres tipos de comunicaciones colectivas: • De sincronización • De transferencia de datos • De cálculo 1) Rutinas de sincronización: call MPI_Barrier(comm, ierror) Todos los procesos del comunicador comm esperan al llegar a la barrera hasta la llegada de todos. Luego continuan todos al mismo tiempo.
Broadcast 2) Rutinas de transferencia de datos: Broadcast, Gather, Gatherv, Scatter, ScattervAllgather, Allgatherv, Alltoall, Alltoallv Broadcast Datos Proces. MPI_Bcast(datos, tamaño, tipo, origen, comm, error)
Broadcast: ej. En nuestro ejemplo para calcular : if(myid.eq.0) then do i=1,size-1 call MPI_SEND(n,1,MPI_INTEGER,i,1,MPI_COMM_WORLD,ierr) enddo else call MPI_RECV(n,1,MPI_INTEGER,0,1,MPI_COMM_WORLD,status,ierr) endif call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr)
Scatter/gather Datos scatter Proces. gather MPI_Scatter(datos-o, tam-o, tipo-o, datos-r, tam-r, tipo-r, raíz, comm, error) MPI_Gather(datos-o, tam-o, tipo-o, datos-r, tam-r, tipo-r, raíz,comm, error)
Ejemplo de gather Ejemplo de MPI_Gather: multiplicación de una matriz por un vector C=A*B, A(100,00) B(100) C(100) con 4 procesos dimension aloc(25,100), b(100), cloc(25), ctotal(100) integer root data root/0/ do i=1,25 cloc(i)=0. do k=1,100 cloc(i)=cloc(i) + aloc(i,k)*b(k) enddo enddo call MPI_GATHER(cloc, 25, MPI_REAL, ctotal, 25, MPI_REAL, root, MPI_COMM_WORLD, ierr) Nota: sólo “root” junta (recibe) los datos
A B C P0 Aloc Cloc P1 P2 P3 MPI_Gather C P0 (root)
A P0 (root) P0 Aloc P1 P2 P3 MPI_Scatter P0 reparte (dispersa) la matriz A