Jan 31, 2016
Ejemplo
Quiero calcular como :
dxx
1
021
4
Ejemplo
double precision mypi, pi, h, sum, x, f, a integer n, myid, size, i, rc, ierr, statusc --- 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-1/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
Pi.f-2/2
0
10
10
3
73516240
2
En log2(p) pasos comunique el dato a los p-1 procesos. Si p=1024 gano un factor 10!
0+1+1=
2+3+1=
Con las comunicaciones punto-a-punto puedo hacer (casi) todo!!! aunque se necesitaría algo mejor para hacerlo más sencillo...
Comunicaciones colectivas
Ao
Datos
Pro
ceso
s
Ao
Ao
Ao
Ao
Ejemplo: Broadcast
MPI_Bcast(datos, tamaño, tipo, origen, comm, error)
Comm. Colectivos
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)
En nuestro ejemplo para calcular :Broadcast
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)
Reduce
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
Pi.f-2/2
Comunicaciones en más detalle
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)
Para recordar:
MPI_SEND y MPI_RECV estándar son bloqueantes!! Comunic. Punto a Punto 2
size es el tamaño de los datos
threshold es el espacio de buffer disponible
Cualquiera de las 2Situaciones puede ocurrir
• 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
Que pasa si el proceso 1 no esta listo para recibir?
Supongamos que:MPI_Send(n,0)MPI_Recv(n,1)
3 variantes de Send (y Recv):
Comunic. Punto a Punto 3
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
Sincrónico:MPI_Ssend(.....)
Permite hacer programas “seguros” ya que no utiliza espacios de buffer. Portabilidad del codigo.
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 1
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.
Comm. Colectivos 2
2) Rutinas de transferencia de datos:
Broadcast, Gather, Gatherv, Scatter, ScattervAllgather, Allgatherv, Alltoall, Alltoallv
Ao
Datos
Pro
ces.
Ao
Ao
Ao
Ao
Broadcast
MPI_Bcast(datos, tamaño, tipo, origen, comm, error)
Broadcast
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)
En nuestro ejemplo para calcular :Broadcast: ej.
Ao A1 A2 A3
DatosP
roce
s.
Ao
A1
A2
A3
MPI_Scatter(datos-o, tam-o, tipo-o, datos-r, tam-r, tipo-r,
raíz, comm, error)
scatter
gather
MPI_Gather(datos-o, tam-o, tipo-o, datos-r, tam-r, tipo-r, raíz,comm, error)
Scatter/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 rootdata root/0/
do i=1,25 cloc(i)=0. do k=1,100 cloc(i)=cloc(i) + aloc(i,k)*b(k) enddoenddocall MPI_GATHER(cloc, 25, MPI_REAL, ctotal, 25, MPI_REAL, root, MPI_COMM_WORLD, ierr)
Ejemplo de gather
Nota: sólo “root” junta (recibe) los datos
A BC
P0
P1
P2
P3
Cloc Aloc
CP0 (root)
MPI_Gather
A
P0
P1
P2
P3
Aloc
P0 (root)
MPI_Scatter
P0 reparte (dispersa) la matriz A