La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Teo. 5: Paradigma "Message Passing"

Presentaciones similares


Presentación del tema: "Teo. 5: Paradigma "Message Passing""— Transcripción de la presentación:

1 Teo. 5: Paradigma "Message Passing"
Algoritmos paralelos Glen Rodríguez

2 Introducción El paradigma de paso de mensajes es uno de los más viejos en computación paralela. Su adopción es amplia, debido a su antigüedad y al hecho que no exige mayores demandas del hardware, sólo que haya algún tipo de comunicación entre CPUs.

3 Principios del "Message-Passing"
Atributos clave: Espacio de memoria particionado (no usa memoria compartida) Sólo soporta paralelización explícita (programada directamente por el programador) Vista lógica: “p” nodos o CPUs corriendo “p” procesos, cada uno con su espacio propio de memoria.

4 Principios del "Message-Passing"
 Cada variable básica debe pertenecer a una de esas memorias: partición explícita de la data. Hay que aprovechar localidad de la data  Todas las interacciones (read-only o read/write) necesitan la cooperación de 2 procesos, uno que envía y otro que recibe data. El proceso que envía a veces no tiene mayor relación de cómputo con la data que envía: Patrones de uso de data no naturales. Especialmente en programas dinámicos y/o no estructurados. Pero el programador siempre sabe el costo de comunicación del programa.

5 Estructura de programas con paso de mensajes
Paradigma asíncrono o débilmente síncrono. En el asíncrono, todas las tareas concurrentes se ejecutan asíncronamente. Fácil de programar, pero riesgo de "race conditions" y comportamiento no predecible. Los débilmente síncronos son un poco más tediosos de programar, pero con mucho menos desventajas. las tareas se sincronizan para interactuar. Salvo eso, son asíncronas. Seguir y predecir el programa es más fácil.

6 Estructura de programas con paso de mensajes
Más flexible Menos escalable (modificar a mano el programa) Se adecua al modelo SPMD.

7 Operaciones Send y Receive
Esquema general: send(void *sendbuf, int nelems, int dest) receive(void *recvbuf, int nelems, int source) Donde sendbuf apunta a una o más variables (array) que serán enviadas, y recvbuf a las que se reciben, nelems es el número de variables, dest y source identifican al proceso destino y origen.

8 Operaciones Send y Receive
Se envía de verdad la(s) variable(s) en sendbuf? Mire estos procesos: P P1 a = 100; receive(&a, 1, 0) send(&a, 1, 1); printf("%d\n", a); a=0; Se debe enviar a=100, no a=0. Si bloqueo en send: OK. Pero si no bloqueo, tengo que copiar a a una var. temporal ! Si hay soporte de DMA, send puede trabajar mientras ejecuto a=0.

9 Operaciones con bloqueo
Send/receive con bloqueo y sin buffers

10 Operaciones con bloqueo
En (a) y (c) se puede observar tiempos ociosos (por que send y receive no coinciden en el tiempo) OJO: Deadlock (bloqueo mutuo) P P1 send(&a, 1, 1); send(&a, 1, 0); receive(&b, 1, 1); receive(&b, 1, 0);

11 Operaciones con bloqueo
Send/receive con bloqueo y con buffers (a) Con soporte de HW para los buffers (b) Sin soporte de HW para buffers

12 Operaciones con bloqueo
Menos tiempo ocioso pero más administración (de buffers). Espacio de memoria para buffers no es infinito. Impacto: P P1 for (i = 0; i < 1000; i++) { for (i = 0; i < 1000; i++) { produce_data(&a); receive(&a, 1, 0); send(&a, 1, 1); consume_data(&a); } } Analizar: Si son simultaneos vs. P1 se atrasa. Se llenará el buffer? Que pasa si se llena?

13 Operaciones con bloqueo
Bloqueos mutuos: si hay buffer, aún podrían haber deadlocks, por que los receive aún son bloqueantes. P P1 receive(&a, 1, 1); receive(&a, 1, 0); send(&b, 1, 1); send(&b, 1, 0); Por qué receive es bloqueante? Qué pasaría si ejecute este receive y luego pido x=a+1?  consistencia semántica

14 Operaciones no bloqueantes
No aseguran consistencia semántica, pero son potencialmente más rápidos. Se acompañan de operaciones check-status, para saber si se puede violar la consistencia de un send o receive ya ejecutado. Después se puede verificar si la comunicación de datos se llevó a cabo y/o esperar que acaben.

15 Operaciones no bloqueantes
Se postean mensajes de “data lista para enviar” o “lista para recibir”

16 Operaciones no bloqueantes sin buffer

17 MPI (Message Passing Interface)
Es una interfaz estándar (1993) para la programación usando el paradigma de paso de mensajes. Sirve tanto para grandes computadores de memoria compartida, como para clusters o redes de ordenadores heterogéneos (incluido el grid computing). Definida para C, C++ y FORTRAN. Comprende una gran cantidad de funciones (más de 120), macros, etc. Pero con 6 funciones básicas se puede empezar a programar usando MPI.

18 Implementaciones de MPI
Existen bastantes implementaciones del estándar MPI. Algunas son debidas a proveedores de hardware que las proporcionan (optimizadas) paras sus máquinas (IBM, HP, SGI…), otras son desarrolladas en el ámbito académico. Algunas implementaciones son: MPICH (MPICH 2 implementa MPI2) Disponible para múltiples devices incluido globus2. LAM/MPI OpenMPI unión de varios proyectos (FT-MPI, LA-MPI, LAM/MPI, y PACX-MPI) .

19 Uso de MPI Se puede usar MPI para: Cuando no usar MPI:
Programas paralelos “portables”. Librerías paralelas. Programas que no se ajusten a un modelo de paralelismo en los datos. Cuando no usar MPI: Si se puede usar HPF o un programa paralelo Fortran 90. Si se pueden usar librerías de más alto nivel (que pueden haber sido escritas usando MPI). Si se usa 1 sola computadora con SMP (varios CPUs o cores) podrías usarse OpenMP

20 MPI tipos de datos Se definen los siguientes tipos de datos MPI:
MPI_CHAR char MPI_SHORT short int MPI_INT int MPI_LONG long int MPI_UNSIGNED_CHAR MPI_UNSIGNED_SHORT MPI_UNSIGNED MPI_UNSIGNED_LONG MPI_FLOAT float MPI_DOUBLE double MPI_LONG_DOUBLE long double MPI_BYTE MPI_PACKED Corresponde a los de C, pero se añaden el tipo byte, y el empaquetado, que permite enviar simultáneamente datos de distintos tipos.

21 MPI Funciones básicas Funciones básicas: Referencia del estándar en
MPI_Init => Inicialización de MPI. MPI_Finalize => Termina MPI. MPI_Comm_size => Para averiguar el número de procesos. MPI_Comm_rank => Identifica el proceso. MPI_Send => Envía un mensaje. MPI_Recv => Recibe un mensaje. Referencia del estándar en

22 MPICH MPICH es una implementación gratuita de MPI 1.2
Implementa parte del nuevo estándar MPI-2 MPICH 2 implementa MPI-2 Es una implementación muy “portable”: Supercomputadores de memoria distribuida Sistemas de memoria compartida Clusters Grid Esta se puede compilar para distintos “devices” de comunicación. Consideraremos dos: Ch3:nemesis Usa meoria compartida, Myrinet o sockets según convenga. Ch3:sock Usa sockets

23 Escribiendo programas MPI
De las seis funciones básicas que mencionamos antes MPI_Init y MPI_Finalize son imprescindibles para que haya un programa MPI. Veamos un ejemplo trivial (hello.c) #include "mpi.h" #include <stdio.h> int main( int argc, char **argv ) { MPI_Init( &argc, &argv ); printf( "Hola Mundo\n" ); MPI_Finalize(); return 0; }

24 Programas MPI (compilación)
El programa anterior solo inicializa y termina el entorno MPI. Entre tanto cada proceso imprime un mensaje por pantalla. Para un programa pequeño como este podemos hacer una llamada directamente al comando de compilación: mpicc (para programas C) mpif77 (Fortran 77). mpif90 (Fortran 90) mpicxx (C++) Para aplicaciones más complicadas conviene usar un Makefile. En nuestro caso anterior: mpicc –o hello hello.c

25 Ejecución de un programa MPI con MPICH
El comando mpiexec se usa para ejecutar los programas MPI en MPICH. mpiexec admite diversas opciones. Destacaremos las siguientes: -n N: N indica el número de procesos que se quiere en la ejecución del programa. -machinefile mfile: fichero de máquinas para correr en lugar del estándar (se usa en combinación con –n). Si queremos correr nuestro programa en dos máquinas de la lista estándar machinefile: mpiexec -n 2 hello

26 Ejemplo de machinefile
grid073.pepe.edu.pe:2 grid074.pepe.edu.pe:2 grid075.pepe.edu.pe:4 grid076.pepe.edu.pe:2 grid077.pepe.edu.pe:1 grid078.pepe.edu.pe:2 :2 :1 :1 :4 :2

27 Delimitación del alcance de la comunicación
Grupos separados de subprocesos trabajando en diferentes subprogramas. Invocación paralela de librerías paralelas: Los mensajes propios de la aplicación deben mantenerse separados de los de la librería. MPI proporciona grupos de procesos Inicialmente el grupo “all”. Se proporcionan rutinas para la administración de los grupos. Todas las comunicaciones, no solo las colectivas, tienen lugar en grupos. Un grupo (group) y un contexto (context) se combinan en un comunicador (communicator). Fuente y destino en una operación send o receive se refieren al rank en el grupo asociado con un comunicador dado. Se puede usar MPI_ANY_SOURCE en una operación receive.

28 MPI tipos de comunicación
La comunicación MPI entre procesos puede ser de dos tipos: Punto a punto: el proceso “origen” conoce el identificador del proceso “destino” y envía un mensaje dirigido solo a él. Se usan las funciones MPI_Send y MPI_Recv. Colectiva: Operaciones en las que participan todos los procesos de un operador. Ejemplo: “Broadcast”: El proceso origen manda el mensaje a todos los demas (que pertenezcan al mismo comunicador). Esto es típico de un esquema “master-slave”. Se usa la función MPI_Bcast. Las funciones MPI de recepción de datos son por lo general “bloqueantes”, es decir, un proceso que debe recibir un mensaje espera hasta que de hecho lo ha recibido completo.

29 Obteniendo información de MPI
Usaremos ahora dos más de las seis funciones básicas: MPI_Comm_size y MPI_Comm_rank. Así averiguaremos desde el programa el número de procesos que participan y la identificación de cada uno. int main( argc, argv ) { int rank, size; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); printf( “Hola Mundo! Soy el proceso %d de %d\n", rank, size ); MPI_Finalize(); return 0; }

30 Funciones de comunicación MPI
A continuación veremos un poco más en detalle las funciones básicas de envío y recepción de mensajes punto a punto y broadcast. MPI_Send MPI_Recv MPI_Bcast MPI_Reduce

31 Sintaxis de MPI_Send y MPI_Recv
La operación básica de envío (bloqueante) es: MPI_Send( start, count, datatype, dest, tag, comm ) start: puntero a los datos a enviar count: número de elementos a enviar datatype: tipo de dato dest: Identificación del proceso destino tag: etiqueta de la comunicación comm: Identificación del comunicador La operación básica de recepción correspondiente: MPI_Recv(start, count, datatype, source, tag, comm, status) start: puntero para la recepción de los datos count: número de elementos datatype: tipo de dato source: Identificación del proceso origen tag: etiqueta de la comunicación comm: Identificación del comunicador status: puntero para acceso a información sobre mensaje

32 Ejemplo MPI_Send/MPI_Recv
char msg[100]; if(my_rank==0) { sprintf(msg,"\n\n\t Esto es un mensaje del proceso %d al proceso %d",source,dest); MPI_Send(msg,100,MPI_CHAR,dest,TAG,MPI_COMM_WORLD); printf("\n Mensaje enviado a %d",dest); } else if(my_rank==1) { MPI_Recv(msg,100,MPI_CHAR,source,TAG,MPI_COMM_WORLD,&status); printf("\n Mensaje recibido en %d",dest); printf(msg);

33 Adquiriendo información sobre un mensaje
MPI_TAG y MPI_SOURCE son usados principalmente cuando hay MPI_ANY_TAG y/o MPI_ANY_SOURCE en la llamada MPI_Recv. MPI_Get_count se usa para determinar la cantidad de datos de un tipo dado que se han recibido. MPI_Status status; MPI_Recv( ..., &status ); ... status.MPI_TAG; ... status.MPI_SOURCE; MPI_Get_count( &status, datatype, &count );

34 Status Para saber que paso con un receive typedef struct MPI_Status {
int MPI_SOURCE; int MPI_TAG; int MPI_ERROR; };

35 Ojo con los tags Que pasa si no se usan buffers?:
int a[10], b[10], myrank; MPI_Status status; ... MPI_Comm_rank(MPI_COMM_WORLD, &myrank); if (myrank == 0) { MPI_Send(a, 10, MPI_INT, 1, 1, MPI_COMM_WORLD); MPI_Send(b, 10, MPI_INT, 1, 2, MPI_COMM_WORLD); } else if (myrank == 1) { MPI_Recv(b, 10, MPI_INT, 0, 2, MPI_COMM_WORLD); MPI_Recv(a, 10, MPI_INT, 0, 1, MPI_COMM_WORLD);

36 Mejor así (impares envían primero)
int a[10], b[10], npes, myrank; MPI_Status status; ... MPI_Comm_size(MPI_COMM_WORLD, &npes); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); if (myrank%2 == 1) { MPI_Send(a, 10, MPI_INT, (myrank+1)%npes, 1, MPI_COMM_WORLD); MPI_Recv(b, 10, MPI_INT, (myrank-1+npes)%npes, 1, MPI_COMM_WORLD); } else {

37 Enviando y recibiendo a la vez
MPI_Sendrecv envía y recibe a la vez. MPI_Sendrecv no tiene los problemas de bloqueo mutuo circular como MPI_Send y el MPI_Recv: int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype senddatatype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvdatatype, int source, int recvtag, MPI_Comm comm, MPI_Status *status)

38 Ejemplo int a[10], b[10], npes, myrank; MPI_Status status; …
MPI_Comm_size(MPI_COMM_WORLD, &npes); MPI_Comm_rank(MPI_COMM_WORLD, &myrank); MPI_SendRecv(a, 10, MPI_INT, (myrank+1)%npes, 1, b, 10, MPI_INT, (myrank-1+npes)%npes, 1, MPI_COMM_WORLD, &status); ...

39 Overlapping de Comunicación y Computación: No bloqueantes
MPI_Send y MPI_Recv son bloqueantes con buffer. Versiones No Bloqueantes: MPI_Isend(start, count, datatype, dest, tag, comm, request) MPI_Irecv(start, count, datatype, dest, tag, comm, request) MPI_Wait(request, status) MPI_Test(MPI_Request *request, int *flag, MPI_Status *status)

40 Ejemplo int a[10], b[10], myrank; MPI_Status status;
MPI_Request requests[2]; ... MPI_Comm_rank(MPI_COMM_WORLD, &myrank); if (myrank == 0) { MPI_Send(a, 10, MPI_INT, 1, 1, MPI_COMM_WORLD); MPI_Send(b, 10, MPI_INT, 1, 2, MPI_COMM_WORLD); } else if (myrank == 1) { MPI_Irecv(b, 10, MPI_INT, 0, 2, &requests[0], MPI_COMM_WORLD); MPI_Irecv(a, 10, MPI_INT, 0, 1, &requests[1], MPI_COMM_WORLD);

41 Operaciones colectivas
Comunicación colectiva: envío de un mensaje de uno a muchos. Se hace con MPI_Bcast (Broadcast) Típicamente un master envía los mismos datos a sus esclavos. Por ejemplo, en la paralelización del entrenamiento de una red neuronal enviamos a todos los esclavos los nuevos pesos al final de cada época de entrenamiento. Operaciones colectivas: se realiza una operación matemática distribuida y se devuelve el resultado al root de la operación También es típico en un esquema master-slave. En la neura se utiliza por ejemplo en la suma de los errores de todos los esclavos. Operaciones definidas: Aritméticas: suma, multiplicación… Lógicas: AND, OR…

42 Operaciones colectivas

43 Sintaxis de Broadcast y Reduce
MPI_Bcast(start, count, datatype, root, comm) start: puntero a los datos a enviar count: número de elementos a enviar datatype: tipo de dato root: identificación del proceso origen comm: Identificación del comunicador Reduce: MPI_Reduce(start, result, count, datatype, operation, root, comm) start: puntero a los datos a enviar result: puntero para almacenar el resultado count: número de elementos a enviar datatype: tipo de dato operation: identificación de la operación colectiva root: identificación del proceso origen comm: Identificación del comunicador

44 Operaciones de Reduce MPI_MAX maximum integer, float, real, complex
MPI_MIN minimum integer, float, real, complex MPI_SUM sum integer, float, real, complex MPI_PROD product integer, float, real, complex MPI_LAND logical AND integer logical MPI_BAND bit-wise AND integer, MPI_BYTE MPI_LOR logical OR integer logical MPI_BOR bit-wise OR integer, MPI_BYTE MPI_LXOR logical XOR integer logical MPI_BXOR bit-wise XOR integer, MPI_BYTE MPI_MAXLOC max value and location MPI_MINLOC min value and location

45 Ejemplo BroadCast Char msg[100]; if(my_rank==source) {
sprintf(msg,"\n Esto es un mensaje del proceso %d a todos los demás",sourc e); MPI_Bcast(msg,100,MPI_CHAR,source,MPI_COMM_WORLD); printf("\n Mensaje enviado a todos desde %d",source); } else printf("\n Mensaje recibido en %d desde %d",my_rank,source); printf(msg);

46 Ejemplo Reduce int value; int result; value = my_rank;
MPI_Reduce(&value,&result,1,MPI_INT,MPI_SUM,source,MPI_COMM_WORLD); if(my_rank==source) { printf("\n Resultado de la suma colectiva %d", result); }

47 Topologías y Embedding
Topología por default en MPI: lineal (0,1,2,…) Se pueden crear topología virtuales o cartesianas (1D, 2D, 3D, etc)

48 Creando topología int MPI_Cart_create(MPI_Comm comm_old, int ndims, int *dims, int *periods, int reorder, MPI_Comm *comm_cart) Ejemplo (a) con reorden MPI_Comm comm_2d; dims[0] = dims[1] = 4; reorden=1; /* periods 0 si plano, 1 si vuelta al mundo */ periods[0] = periods[1] = 1; MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, reorden, &comm_2d);

49 Otro ejemplo

50 Nombrando procesos en una topología
Hay dos IDs: Coordenadas, rango Dado las coordenadas, obtener rango: int MPI_Cart_rank(MPI_Comm comm_cart, int *coords, int *rank) Dado rango, obtener coordenadas: int MPI_Cart_coords(MPI_Comm comm_cart, int rank, int maxdims, int *coords)

51 Ejemplos int rang; coord[0]=3; coord[1]=1;
MPI_Cart_rank(comm_2d, coord, &rang) printf(“El CPU en posicion (%d, %d) tiene el rango %d\n",coord[0],coord[1],rang) MPI_Cart_coords(comm_2d,10,2,coord); printf(“El proc. 10 tiene coordenadas (%d , %d)\n", coord[0],coord[1]);

52 Proces. vecinos Muchas veces hay que mover o intercambiar data a lo largo de una dimensión de la topología. MPI tiene la función MPI_Cart_shift, que puede usarse para computar el rango de otro proceso para enviarle o recibirle data: int MPI_Cart_shift(MPI_Comm comm_cart, int dir, int s_step, int *rank_source, int *rank_dest) dir: dimensión; s_step: desplazamiento en esa dimensión

53 Grupos y Comunicadores
En varios algoritmos paralelos, las operaciones de comunicación deben ser restringindas a un subconjunto de procesos. MPI tiene mecanismos para particionar un grupo de procesos que pertenecen a un comunicador en subgrupos que se aoscian a nuevos comunicadores: int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm) Todos los porcesos del mismo “color” pertenecen al mismo comunicador nuevo

54 Ejemplo

55 En topologías Si quiero hacer subgrupos de procesos en una topología:
int MPI_Cart_sub(MPI_Comm comm_cart, int *keep_dims, MPI_Comm *comm_subcart) Si keep_dims[i] es “true” (1 en C) entonces la i-esima dimensión es parte de la nueva sub-topología.

56 Topología: 2x4x7

57 Lecturas 1PC Teoría Load Balancing for Term-Distributed Parallel Retrieval A Heterogeneous Parallel System Running Open MPI on a Broadband Network of Embedded Set-Top Devices FPGA ACCELERATION OF MONTE-CARLO BASED CREDIT DERIVATIVE PRICING Speed-up of Monte Carlo simulations by sampling of rejected states


Descargar ppt "Teo. 5: Paradigma "Message Passing""

Presentaciones similares


Anuncios Google