Introducción a MPI Clase 5 Marcelo Rozenberg (agradecimiento: Ruben Weht [email protected])...
-
Upload
catalina-rojo-rojas -
Category
Documents
-
view
216 -
download
0
Transcript of Introducción a MPI Clase 5 Marcelo Rozenberg (agradecimiento: Ruben Weht [email protected])...
Tipos de datos derivados
• Tipo contiguo (bloques simples)
• Tipo vector (bloques equiespaceados)
• Tipo indexado (bloques y espaceados variables)
MPI_Type_contiguous(…)
MPI_Type_vector(…)
MPI_Type_indexed(cuantos, vec-largobloque, vec-desplazamiento,
oldtype, newtype, ierr)
1. Obtener un conjunto de IDs de un comunicador existente
2. Crear un grupo como un subconjunto de un dado grupo
3. Definir un nuevo comunicador para el grupo.
Definir y manipular comunicadores
1. MPI_Comm_group ( comm, group, ierr)
2.1 MPI_Group_incl ( oldgrp, count, ranks, newgrp, ierr)2.2 MPI_Group_excl ( oldgrp, count, ranks, newgrp, ierr)
3. MPI_Comm_create ( comm, newgrp, newcomm, ierr)
• Permite crear de una vez varios comunicadoresEj: una llamada crea q nuevos comunicadores (todos con el
mismo nombre mi_fila_comm)
MPI_Comm mi_fila_comm
int mi_fila
C mi_rank es rank en MPI_Comm_world
C q*q = p
mi_fila = mi_rank/q
MPI_Comm_split(MPI_COMM_WORLD, mi_fila , mi_rank , mi_fila_comm)
Una rutina útil: MPI_Comm_split
out
P0 P1 P2
P3 P4 P5
P6 P7 P8
q = 3p = 9
Para el P5 los procs del comunicador mi_fila_comm son el {3,4,5}
Topologías virtuales:
•MPI tiene rutinas que permiten definir una grilla de procesos que se adaptan bien a la geometría particular del cálculo.
•El concepto de topología virtual es una característica de MPI que permite manejar una grilla de procesos.
•El objetivo es obtener códigos mas concisos y simples, permitiendo también optimizar la comunicación entre los nodos.
•Una topología virtual se asocia con un comunicador.
Topologías virtuales
Ejemplos típicos
P0
P1
P2
P3
Grilla 1-d
Ejemplos típicos
P4
P5
P6
P7
Grilla 2-dP0
P1
P2
P3
P8
P9
P10
P11
P4
P5
P6
P7
Grilla 2-dP0
P1
P2
P3
P8
P9
P10
P11
Definir una matriz de procesos!
1,1 1,2 1,3
2,1 2,2 2,3
3,1 3,2 3,3
4,1 4,2 4,3
y definir comunicadores fila y comunicadores columna
Hay dos tipos de topologías Cartesianas Graph (generales)Cart_create
Las topologías cartesianas son grillas cartesianas uni o bi-dimensionales
Son un caso particular de las generales, pero como son muy utilizadas, hay subrutinas dedicadas
Para asociar un punto de la grilla virtual a cada procesador es precisoespecificar la siguiente información:
1. Numero de dimensiones de la grilla (1 o 2)2. Largo de cada dimension (# de procs por fila y/o columna)3. Periodicidad de la dimensión (condiciones de contorno: anillos, toros)4. Opción de optimización (reordenar los procesadores físicos)
Topología cartesiana
MPI_CART_CREATE(old_comm, ndims, dims, periods,reorder, comm_cart, ierr)
ndims: dimensión de la grilladims: vector con la dimensión de cada eje de coordenadasperiods: vector lógico que indica si existe periodicidad o no
en cada ejereorder: .false. Si los datos ya fueron distribuidos. Usa los ranks
del comunicador original .true. Si los datos todavia no fueron distribuidos. Reordena
los procesos para optimizar la comunicación
Cart_create
Ejemplo:
MPI_Comm grid_comm
int dim_sizes(2), wrap_around(2), reorder
reorder = 1
dim_sizes(1) = q
dim_sizes(2) = q
wrap_around(1) = 1
wrap_around(2) = 1
MPI_Cart_create( MPI_COMM_WORLD , 2 , dim_sizes , wrap_around , reorder , grid_comm )
Crear una topología cartesiana bidimensional de q x q,con condiciones de contorno periodicas (toro) y permitiendo al sistema reordenar procesadores
Ejemplo (cont):
MPI_Comm grid_comm
int dim_sizes(2), wrap_around(2), reorder, coord(2), mi_grid_rank
reorder = 1
dim_sizes(1) = q
dim_sizes(2) = q
wrap_around(1) = 1
wrap_around(2) = 1
MPI_Cart_create( MPI_COMM_WORLD , 2 , dim_sizes , wrap_around , reorder , grid_comm )
MPI_Comm_rank( grid_comm , mi_grid_rank )
MPI_Cart_coord( grid_comm , mi_grid_rank , 2 , coord )
Cómo obtener las coordenadas?
Otras rutinas de la clase MPI_Cart:
MPI_Cart_rank( grid_comm , coord , grid_rank )
Es el “inverso” de MPI_Cart_coord
MPI_Cart_sub( grid_comm , var_coords , fila_comm )
Crea subgrillas (nuevos comunicadores de filas)
Ej:
MPI_comm fila_comm
int var_coords(2)
var_coords(1) = 0 ( 0 porque la coord “x” no varia en cada fila)
var_coords(2) = 1 ( 1 porque la coord “y” varia en cada fila)
MPI_Cart_sub( grid_comm , var_coords , fila_comm)
Otras rutinas de la clase MPI_Cart:
MPI_Cart_get( grid_comm , 2 , dim_sizes , wrap_around , coord )
Obtiene las coordenadas del proceso ademas de los tamaños de las dimensiones y la periodicidad de un dado comunicador cartsiano.
vectores de salida: dim_sizes(2) , wrap_around(2) , coord(2)
MPI_Cart_shift( grid_comm , dir, disp , rank_source, rank_dest )
Obtine el rank del proceso de origen y el de destino (para usar en un send/recv) entre procesos separados por disp procesos en la dirección dir. “Averigua quiénes son los vecinos”
Un código de ejemplo (típico):
• Método de Jacobi para la solución del Problema de Poisson (ecuación en derivadas parciales PDE)
Problema de Poisson u = f(x,y) en el interioru(x,y) = g(x,y) en el borde
ui-1,j + ui,j+1 + ui,j-1 + ui+1,j – 4ui,j
h2= fi,j
ui,j = ¼ (ui-1,j + ui,j+1 + ui,j-1 + ui+1,j – h2 fi,j)
uk+1i,j = ¼ (uki-1,j + uki,j+1 + uki,j-1 + uki+1,j – h2 fi,j) iteración
i,j+1
i+1,j
i,j-1
i-1,j
i,j
xi = i / (n+1), i = 0,1,..., n+1 yj = j / (n+1), j = 0,1,..., n+1
n+2 x n+2 puntos, h = 1/(n+1)
Discretización
interior borde
c*******************************************************************c oned.f - a solution to the Poisson problem using Jacobi c interation on a 1-d decompositionc c The size of the domain is read by processor 0 and broadcast toc all other processors. The Jacobi iteration is run until the c change in successive elements is small or a maximum number of c iterations is reached. The difference is printed out at each c step.c******************************************************************* program main C include "mpif.h" integer maxn parameter (maxn = 128) double precision a(maxn,maxn), b(maxn,maxn), f(maxn,maxn) integer nx, ny integer myid, numprocs, ierr integer comm1d, nbrbottom, nbrtop, s, e, it double precision diff, diffnorm, dwork double precision t1, t2 double precision MPI_WTIME external MPI_WTIME external diff
call MPI_INIT( ierr ) call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr ) call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr )
1/3
c if (myid .eq. 0) thencc Get the size of the problemcc print *, 'Enter nx'c read *, nx nx = 110 endif call MPI_BCAST(nx,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr) ny = nxcc Get a new communicator for a decomposition of the domainc call MPI_CART_CREATE( MPI_COMM_WORLD, 1, numprocs, .false., $ .true., comm1d, ierr )cc Get my position in this communicator, and my neighborsc call MPI_COMM_RANK( comm1d, myid, ierr ) call MPI_Cart_shift( comm1d, 0, 1, nbrbottom, nbrtop, ierr )cc Compute the actual decompositionc call MPE_DECOMP1D( ny, numprocs, myid, s, e )cc Initialize the right-hand-side (f) and the initial solution guess (a)c call onedinit( a, b, f, nx, s, e )
2/3
crea la topología: una dimensióncon reordenamientocada procs obtiene su rank y averigua quienes son sus vecinos
asigna bloques de puntos (x,y) a los procesos
Topología virtual 1-d para el Problema de Poisson
i,j+1
i+1,j
i,j-1
i-1,j
i,j
xi = i / (n+1), i = 0,1,..., n+1 yj = j / (n+1), j = 0,1,..., n+1
n+2 x n+2 puntos, h = 1/(n+1)
Discretización
interior borde
rank=2
rank=1
rank=0
1-dDebo definir bloques:
double precision u(0:n+1, s:e)s:e indica los valores de j de cada bloque. Cómo obtengo s y e?
Problema con los bordes!
Topología virtual 1-d para el Problema de Poisson (cont)
i,j+1
i+1,j
i,j-1
i-1,j
i,j
rank=2
rank=1
rank=0
double precision u(0:n+1, s:e)s:e indica los valores de j de cada bloqueEsto se hace con la rutinaMPE_DECOMP1D( ny, numprocs, myid, s, e )
Es una extension de MPI, freeware no forma parte del standard MPI
puntos fantasmas
Agrando los bloques
Detalles sobre MPE_DECOMP1DMPE_DECOMP1D( ny, numprocs, myid, s, e )
ny es el tamaño del sistema en el eje verticalnumprocs es el numero de procesosmyid es el rank de la coordenada cartesiana
• Si ny y nprocs son divisibles es fácil:s = 1+ myid * (ny /nprocs)e = s + (ny/nprocs) – 1
• Si no lo son la elección obvia es:s= 1+ myid * piso(ny /nprocs)if (myid .eq. nprocs – 1) then
e = nyelse
e = s + piso(ny/nprocs) – 1endif
Donde piso(x) da el mayor entero que no es mayor que x. Pero si nprocs = 64 y ny = 127 .... Da 63 de 1 y 1 de 64!!!!
MPE_DECOMP1DEs más inteligente !
c if (myid .eq. 0) thencc Get the size of the problemcc print *, 'Enter nx'c read *, nx nx = 110 endif call MPI_BCAST(nx,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr) ny = nxcc Get a new communicator for a decomposition of the domainc call MPI_CART_CREATE( MPI_COMM_WORLD, 1, numprocs, .false., $ .true., comm1d, ierr )cc Get my position in this communicator, and my neighborsc call MPI_COMM_RANK( comm1d, myid, ierr ) call MPI_Cart_shift( comm1d, 0, 1, nbrbottom, nbrtop, ierr )cc Compute the actual decompositionc call MPE_DECOMP1D( ny, numprocs, myid, s, e )cc Initialize the right-hand-side (f) and the initial solution guess (a)c call onedinit( a, b, f, nx, s, e )
2/3
crea la topología: una dimensióncon reordenamiento
cada procs obtiene su rank y averigua quiénes son sus vecinos
asigna bloques de puntos (x,y) a los procesos
inicializa
subroutine onedinit( a, b, f, nx, s, e ) integer nx, s, e, i, j double precision a(0:nx+1, s-1:e+1), b(0:nx+1, s-1:e+1),f(0:nx+1, s-1:e+1)c do 10 j=s-1,e+1 do 10 i=0,nx+1 a(i,j) = 0.0d0 b(i,j) = 0.0d0 f(i,j) = 0.0d0 10 continuec c Handle boundary conditionsc do 20 j=s,e a(0,j) = 1.0d0 b(0,j) = 1.0d0 a(nx+1,j) = 0.0d0 b(nx+1,j) = 0.0d0 20 continuec if (s .eq. 1) then do 30 i=1,nx a(i,0) = 1.0d0 b(i,0) = 1.0d0 30 continue endif return end
limpia las matrices
fija las condiciones de contorno
u(0,y) = 1
u(1,y) = 0
u(x,0) = 1
u(x,1) = 0
Subrutina onedinit
cc Actually do the computation. Note the use of a collective operation toc check for convergence, and a do-loop to bound the number of iterations.c call MPI_BARRIER( MPI_COMM_WORLD, ierr ) t1 = MPI_WTIME() do 10 it=1, 100c do 10 it=1, 2
call exchng1( a, nx, s, e, comm1d, nbrbottom, nbrtop )call sweep1d( a, f, nx, s, e, b )call exchng1( b, nx, s, e, comm1d, nbrbottom, nbrtop )call sweep1d( b, f, nx, s, e, a )dwork = diff( a, b, nx, s, e )call MPI_Allreduce( dwork, diffnorm, 1, MPI_DOUBLE_PRECISION,
$ MPI_SUM, comm1d, ierr ) if (diffnorm .lt. 1.0e-5) goto 20c if (myid .eq. 0) print *, 2*it, ' Difference is ', diffnorm10 continue if (myid .eq. 0) print *, 'Failed to converge'20 continue t2 = MPI_WTIME() if (myid .eq. 0) then print *, 'Converged after ', 2*it, ' Iterations in ', t2 - t1, $ ' secs ' endifc call MPI_FINALIZE(ierr) end
3/3
sincroniza y mide el tiempo
pasa los puntos fantasma
subroutine exchng1( a, nx, s, e, comm1d, nbrbottom, nbrtop )include 'mpif.h'integer nx, s, edouble precision a(0:nx+1,s-1:e+1)integer comm1d, nbrbottom, nbrtopinteger status(MPI_STATUS_SIZE), ierr
ccall MPI_SENDRECV(
& a(1,e), nx, MPI_DOUBLE_PRECISION, nbrtop, 0, & a(1,s-1), nx, MPI_DOUBLE_PRECISION, nbrbottom, 0, & comm1d, status, ierr )
call MPI_SENDRECV( & a(1,s), nx, MPI_DOUBLE_PRECISION, nbrbottom, 1, & a(1,e+1), nx, MPI_DOUBLE_PRECISION, nbrtop, 1, & comm1d, status, ierr )
returnend
Subrutina exchng1
cc Actually do the computation. Note the use of a collective operation toc check for convergence, and a do-loop to bound the number of iterations.c call MPI_BARRIER( MPI_COMM_WORLD, ierr ) t1 = MPI_WTIME() do 10 it=1, 100c do 10 it=1, 2
call exchng1( a, nx, s, e, comm1d, nbrbottom, nbrtop )call sweep1d( a, f, nx, s, e, b )call exchng1( b, nx, s, e, comm1d, nbrbottom, nbrtop )call sweep1d( b, f, nx, s, e, a )dwork = diff( a, b, nx, s, e )call MPI_Allreduce( dwork, diffnorm, 1, MPI_DOUBLE_PRECISION,
$ MPI_SUM, comm1d, ierr ) if (diffnorm .lt. 1.0e-5) goto 20c if (myid .eq. 0) print *, 2*it, ' Difference is ', diffnorm10 continue if (myid .eq. 0) print *, 'Failed to converge'20 continue t2 = MPI_WTIME() if (myid .eq. 0) then print *, 'Converged after ', 2*it, ' Iterations in ', t2 - t1, $ ' secs ' endifc call MPI_FINALIZE(ierr) end
3/3
sincroniza y mide el tiempo
pasa los puntos fantasmabarrida por toda la red
cc Perform a Jacobi sweep for a 1-d decomposition.c Sweep from a into bc subroutine sweep1d( a, f, nx, s, e, b ) integer nx, s, e double precision a(0:nx+1,s-1:e+1), f(0:nx+1,s-1:e+1), + b(0:nx+1,s-1:e+1)c integer i, j double precision hc h = 1.0d0 / dble(nx+1) do 10 j=s, e do 10 i=1, nx b(i,j) = 0.25 * (a(i-1,j)+a(i,j+1)+a(i,j-1)+a(i+1,j)) - + h * h * f(i,j) 10 continue return end
Subrutina sweep
uk+1i,j = ¼ (uki-1,j + uki,j+1 + uki,j-1 + uki+1,j – h2 fi,j) iteración
cc Actually do the computation. Note the use of a collective operation toc check for convergence, and a do-loop to bound the number of iterations.c call MPI_BARRIER( MPI_COMM_WORLD, ierr ) t1 = MPI_WTIME() do 10 it=1, 100c do 10 it=1, 2
call exchng1( a, nx, s, e, comm1d, nbrbottom, nbrtop )call sweep1d( a, f, nx, s, e, b )call exchng1( b, nx, s, e, comm1d, nbrbottom, nbrtop )call sweep1d( b, f, nx, s, e, a )dwork = diff( a, b, nx, s, e )call MPI_Allreduce( dwork, diffnorm, 1, MPI_DOUBLE_PRECISION,
$ MPI_SUM, comm1d, ierr ) if (diffnorm .lt. 1.0e-5) goto 20c if (myid .eq. 0) print *, 2*it, ' Difference is ', diffnorm10 continue if (myid .eq. 0) print *, 'Failed to converge'20 continue t2 = MPI_WTIME() if (myid .eq. 0) then print *, 'Converged after ', 2*it, ' Iterations in ', t2 - t1, $ ' secs ' endifc call MPI_FINALIZE(ierr) end
3/3
sincroniza y mide el tiempo
pasa los puntos fantasmabarrida por toda la red
check de convergencia
Notas finalesqué quedó afuera?
• Bibliotecas (2 buenas y documentadas): – ScaLAPACK (Scalable LAPACK) - originada en F77
• PBLAS (Parallel BLAS)
– PETSc (Portable Extensible Toolkit for Sci. Comp.) - diseñada para C
• Profiling (medición de performance)– No hay un standard. La medición afecta el tiempo de cálculo!– Problemas de buffering– Balanceo de carga
• Debugging (www.lam-mpi.org/software/xmpi/)
• Bibliografia y links– Using MPI (W. Gropp, E. Lusk y A. Skjellum)– Parallel Programming with MPI– www.mpi-forum.org/; www.mcs.anl.gov/mpi; www.erc.msstate.edu/mpi