programaciÓn con mpi y openmp en el cluster euler

270
PROGRAMACIÓN CON MPI Y OPENMP EN EL CLUSTER EULER _________________________________________ ___ Angelines Alberto Morillas Telf. +34 91 346 6025 Divisón de Supercomputación y Desarrollo Grid CIEMAT Avenida Complutense, 22 28040 Madrid _________________________________________ ___

Upload: dunn

Post on 11-Jan-2016

87 views

Category:

Documents


7 download

DESCRIPTION

PROGRAMACIÓN CON MPI Y OPENMP EN EL CLUSTER EULER. ____________________________________________ Angelines Alberto Morillas Telf. +34 91 346 6025 Divisón de Supercomputación y Desarrollo Grid CIEMAT Avenida Complutense, 22 28040 Madrid ____________________________________________. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

PROGRAMACIÓN CON MPI Y OPENMP

EN EL CLUSTER EULER

____________________________________________Angelines Alberto MorillasTelf. +34 91 346 6025Divisón de Supercomputación y Desarrollo GridCIEMATAvenida Complutense, 2228040 Madrid____________________________________________

Page 2: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

i. PROGRAMACIÓN EN ENTORNO CLUSTER EULER

ii. PROGRAMACIÓN CON PASO DE MENSAJES (MPI)

iii. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OpenMP)

Page 3: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

i. PROGRAMACIÓN EN ENTORNO CLUSTER EULER

ii. PROGRAMACIÓN CON PASO DE MENSAJES (MPI)

iii. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OpenMP)

Page 4: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

I. PROGRAMACIÓN EN ENTORNO CLUSTER EULER Características Conexión a EULER Software en EULER Compiladores Optimización Depuración de Errores Programación paralela Ejecución paralela

Page 5: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERCaracterísticas.

En su configuración actual dispone de 146 nodos Intel(R) Xeon(R) CPU E5450@ 3.0GHz.

Cada nodo tiene 8 procesadores o “cores”, lo que hace un total de 1152.

Cada nodo tiene 16 GB de memoria, ó 2 GB por core.

Además dispone de dos nodos para acceso interactivo y dos nodos de gestión

Todos los nodos se han interconectado a una red de alta velocidad Infiniband que se utilizará para la comunicación entre los procesos que colaboran en los trabajos paralelos MPI.

Page 6: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERCaracterísticas.

El cluster está basado en el sistema operativo linux (Red Hat Enterprise).

Dispone las herramientas habituales de software libre.

Existen dos nodos que actúan como frontend para que los usuarios puedan conectarse en forma interactiva.

El resto de los nodos actúan como servidores de cálculo accesibles sólo a través del entorno batch.

Page 7: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERConexión a EULER.

Para conectarse desde un desktop basado en MS Windows/CENIT se dispone de un cliente ssh llamado PUTTY (Z:\P32\PUTTY\PUTTY.EXE)

También se puede utilizar el emulador de ventanas X llamado Exceed. (http://intranet.ciemat.es/ICIEMATportal/portal.do?TR=A&IDR=1&identificador=1679)

En desktop basado en Linux basta utilizar el cliente habitual ssh. Ejemplos:

ssh eulerssh -f -X euler gnome-terminal

Page 8: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERSoftware en EULER.

Sistema Operativo– Red Hat Enterprise Linux AS release 4 (64 bits). Dispone de

herramientas gráficas de administración, planificador de procesamiento paralelo, distribución dinámica de procesos, etc.

Compiladores– Se han instalado los dos grupos de compiladores más usuales

en estas plataformas:o GNU: Compiladores de Fortran 90, C y C++ .

Se han instalado dos versiones de los compiladores: la versión 3.4 (comandos gcc, g++ y g77) la versión 4.1 (comandos gcc4, g++4 y gfortran).

o Intel: Compiladores de Fortran, C y C++ versión 10.1.

Page 9: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERSoftware en EULER.

Herramientas para desarrollo de aplicaciones paralelas:– MPI: (Message Passing Interface), el estándar de facto para

programación con paso de mensajes explícitos.– OpenMP: Es una API (Application Program Interface) basada en

directivas, rutinas y variables de entorno que facilita la paralelización en arquitecturas de memoria compartida. Está integrada en los compiladores de Intel, y se accede con un simple flag.

Utilidades de software público:– La mayor parte de la colección de software de GNU. Se instalará

en el futuro cualquier paquete que pueda necesitar un usuario del centro.

Sistema de gestión de bach y planificación basado en Torque/Moab.

Page 10: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERCompiladores.

La máquina dispone de compiladores de Fortran, C y C++, tanto de Intel como de GNU, que se pueden invocar con los siguientes comandos:

ifort -o prog prog.f90 (Fortran 90, compilador de Intel)

g77 -o prog prog.f (Fortran 77, compilador de GNU)

gfortran -o prog prog.f90 (Fortran 90, compilador de GNU)

icc -o prog prog.c (C, compilador de Intel)

gcc/gcc4 -o prog prog.c (C, compilador de GNU)

icpc -o prog prog.cc (C++, compilador de Intel)

g++/g++4 -o prog prog.cc (C++, compilador de GNU)

Page 11: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERCompiladores.

En caso de utilizar los compiladores de Intel es necesario añadir los directorios correspondientes al “PATH” y al “LD_LIB RARY_PATH”. Esto puede hacerse con los scripts siguientes:

– Si se usa bash

source /opt/intel/cce/10.1.015/bin/iccvars.sh

source /opt/intel/fce/10.1.015/bin/ifortvars.sh

– Si se usa tcsh

source /opt/intel/cce/10.1.015/bin/iccvars.csh

source /opt/intel/fce/10.1.015/bin/ifortvars.csh

Page 12: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULEROptimización de Intel

Los flags (opciones) más comunmente utilizados al invocar el compilador de Fortran de Intel, en general para optimizar código y conseguir que se ejecute más rápidamente, son los siguientes

– Flags para optimización:o -O0: Sin optimización.o -O1: Optimización local.o -O2,-O: Optimización extensiva. Es el defecto.o -O3: Ejecuta más SWP, prefetching, reogarnización de loop, etc.o -ip: intra-file/inter-file interprocedural optimization.o -prof_gen/-prof_use: optimización con feedback; útil si se tienen un buen

conjunto de pruebas.o -fno-alias, -fno-fnalias: Mejor optimización al indicar el uso de punteros sin

utilizar aliasing.o -opt_report: Genera un reporte de la optimización.o -ftz: fija underflows a cero, evitando traps del kernel (habilitado por defecto

en -03).

Page 13: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULER Optimización de Intel

Una regla práctica a seguir es Intentar al menos "-O2" en todas las rutinas. Tratar de compilar las rutinas que más tiempo consuman con “ -O3".

En este último caso, sin embargo, debe tenerse en cuenta que los resultados pueden cambiar ligeramente debido a diferencias en los redondeos. Además aumentará el tiempo de compilación, por lo que no conviene utilizar estos flags cuando se está desarrollando.

Page 14: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULER Optimización de Intel

– Flags de paralelización:o parallel: AutoParalelización. Convierte de forma a utomática código

secuencial en paralelo por medio de directivas.o openmp: Hace que el compilador reconozca las directivas OpenMP.

– Flags para facilitar el porting y debug de códigos:o -posixlib: Funciones de IEEE* POSIX FORTRAN-77 Language

bindings, como específicado en IEEE Standard 1003.9-1992.o -i8: Representación interna de enteros en 64 bits (8 bytes).o -r8: Representación interna de reales y complejos en 64 bits.o -zero: Inicializa variables a 0.o -g: Genera código apto para depurar (debug).o -save: Colocación de variables en memoria estática.

Page 15: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERDepuración de errores

Para el "debugging" de código disponemos de diferentes herramientas que nos ayudan a encontrar fallos en el código fuente:

– Debugger de Intel (idb): Soporta Fortran, C y C++. Tiene una interface basada en línea de

comandos. Se invocacon el comando “idb” seguido del nombre del ejecutable. Además, idb cuenta con una interfaz gráfica, para ello, se invoca con el flag “-gui”. Ejemplos:

idb a.out (modo línea)idb -gui a.out (modo gráfico en X window)

– Debugger de GNU (gdb): GNU debugger. Soporta C y C++ y Fortran. También es un

depurador en modo línea, y por lo tanto se utiliza poco.

Page 16: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERDepuración de errores

– Data Display Debugger (ddd):o Es uninterfaz gráfico para gdb y otros debuggers (incluido el de

intel).o Funciona bajo X Window ya que se trata de una herramienta gráfica.o Para iniciar un ciclo de depuración (debug) se debe compilar el

código con el flag "-g", que inhibe parcialmente la optimización y genera información simbólica en el código ejecutable para el debugger, esencialmente los números de líneas correspondientes entre fuente y ejecutable:

ifort -g -o prog.exe prog.f (Fortran)icc -g -o prog.exe prog.c (C)

o A continuación se invoca al debugger:ddd prog.exe

o Aparecerá una ventana X en la q ue podemos realizar las operaciones necesarias para la depuración de nuestro código. Una forma sencilla de empezar consiste en pisar el botón "Run" que inicia la ejecución y esperar a ver en qué línea se muere nuestro programa.

Page 17: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERProgramación paralela

OpenMP– Se pueden compilar y ejecutar programas que utilicen directivas

OpenMP, utilizando los compiladores de Intel. – Se dene compilar el código con el flag " -openmp". – Antes de ejecutar se debe declarar la variable de entorno

"OMP_NUM_THREADS" con el número de procesadores que deseemos:

ifort -openmp prog.f -o prog.exesetenv OMP_NUM_THREADS 4 (csh)export OMP_NUM_THREADS=4 (sh)prog.exe

Page 18: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERProgramación paralela

MPI– La máquina dispone de varias implementaciones de la librería

MPI que pueden utilizarse según conveniencia. – La motivación de tener varias implementaciones es ayudar a los

usuarios en los problemas relacionados con la portabilidad de códigos.

– Existen códigos de cálculo basados en MPI fáciles de portar a la plataforma con una determinada implementación y no con otras. El usuario debe elegir cual de ellas es mejor para su código.

– Las implementaciones de la librería MPI disponibles en nuestro cluster son MPICH, MPICH2, LAM, OPENMPI y MVAPICH.

Page 19: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERProgramación paralela

MPI– OPENMPI parece ser la implementación dominante últimamente.– Otras implementaciones como MPICH2 y LAM/MPI ofrecen la

ventaja de menores tiempos de latencia.– Las tres implementaciones de la librería que soportan

comunicaciones a través de la red infiniband son MVAPICH, MVAPICH2 y OPENMPI.

– La mayoría de las aplicaciones paralelas pueden potencialmente obtener mejores resultados en cuanto a velocidad y escalado utilizando infiniband.

– Las otras implementaciones darán menor rendimiento en la mayor parte de los casos, pero están instaladas por motivos de portabilidad de software.

Page 20: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERProgramación paralela

MPI– Para ver la lista de implementaciones de MPI disponibles

ejecutar el comando:

switcher mpi --list– En el momento de escribir este manual las opciones son las

siguientes:lam-X.X.Xlam-intel-X.X.Xmpich-ch_p4-gcc-X.X.Xmpich-ch_p4-intel-X.X.Xopenmpi-X.X.Xopenmpi-intel-X.X.X

ib-mvapich-X.X.X-gccib-mvapich-X.X.X-intelib-mvapich2-X.X.X-gccib-mvapich2-X.X.X-intelib-openmpi-X.X.X-gccib-openmpi-X.X.X-intel

Page 21: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERProgramación paralela

MPI– Se puede averiguar el módulo cargado en en el perfil del usuario

con el siguiente comando:

switcher mpi– Para compilar y ejecutar programas con MPI, tendremos que

tener en el “path” los comandos adecuados y en el “library path” las librerías correspondientes.

– El programador puede hacerlo del modo usual en UNIX, modificando las variables de entorno “PATH” y

“LD_LIBRARY_PATH”, o con la utilidad “switcher”.

Page 22: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERProgramación paralela

MPI– Ejemplo: si se desea cambiar al entorno LAM con compilador

intel: switcher mpi = lam-intel-7.1.2

switcher_reload

– El primer comando cambia el fichero de configuración y el segundo lo carga para actualizar las variables de entorno.

– Una vez elegida la implementación de MPI que se va a utilizar, ya se dispone en el PATH de las utilidades necesarias para compilar y ejecutar aplicaciones.

– Actualmente es necesario ejecutar también el comando:

mpi-selector-menu (elegir la opción adecuada)

Page 23: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULERProgramación paralela

MPI– La compilación se realiza utilizando los comandos “mpif90”,

“mpìcc” y “mpicxx” que se encargan de invocar a los compiladores y añadir los flags para las librerías propias de MPI.

– Ejemplos:mpif90 -o prog.exe prog.f90 (Fortran)mpicc -o prog.exe prog.c (C)mpicxx -o prog.exe prog.cc (C++)

– La ejecución de una aplicación MPI depende de la implementación que se haya utilizado para compilarla. Lo usual es utilizar los comandos “mpirun” o “mpiexec”.

– Ejemplos:mpirun -np 8 prog.exempiexec -n 8 prog.exe

– En la práctica estos comandos se utilizan en el entorno batch.

Page 24: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULEREjecución paralela

La ejecución de los programas de cálculo se debe realizarse utilizando el sistema de batch.

Para ello, lo usual es crear un “script” o fichero de comandos de shell que contenga en las primeras líneas los “flags” para el sistema batch.

A continuación se ofrece un ejemplo sencillo:

#PBS -l nodes=8cd ${PBS_O_WORKDIR}NUMPROC=`wc -l ${PBS_NODEFILE} | awk ' {print $1} ' `mpirun -np $NUMPROC -machinefile ${PBS_NODEFILE} prog.exe

Page 25: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

I. CLUSTER EULEREjecución paralela

La sintaxis de la última línea es válida en el caso de utilizar las implementaciones MPICH y OPENMPI.

En caso de utilizar MVAPICH2 debe cambiarse por estas dos:

mpdboot -n $NUMPROC -f $PBS_NODEFILEmpiexec -n $NUMPROC prog.exe

Esto es así porque antes de ejecutar con “mpiexec” es necesario arrancar el demonio con el comando “lamboot”.

Por último, si se utiliza la implementación LAM entonces debe cambiarse por estas líneas:

lamboot -d -f $PBS_NODEFILEmpiexec -n $NUMPROC prog.exelamcleanup

Page 26: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

i. PROGRAMACIÓN EN ENTORNO CLUSTER

ii. PROGRAMACIÓN CON PASO DE MENSAJES (MPI)

iii. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OpenMP)

Page 27: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones bloqueantes y no bloqueantes Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos Topologías vituales Introducción a MPI-2

Page 28: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones bloqueantes y no bloqueantes Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos Topologías vituales Introducción a MPI-2

Page 29: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Paralelismo

Paralelismo:– Significa realizar múltiples cosas al mismo tiempo, de tal manera que

se hace más trabajo en el mismo lapso de tiempo.

Uso de múltiples unidades de procesamiento para resolver un problema. Las unidades de procesamiento son:

– Procesos lógicos.– Procesadores físicos (cores).

Uso de múltiples unidades de procesamiento operando concurrentemente sobre diferentes partes de un problema. Estas partes pueden ser:

– Diferentes tareas– La misma tarea sobre diferentes piezas de datos.

Page 30: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Tipos de paralelismo

Tipos de paralelismo– Memoria compartida (Shared).– Memoria distribuida (Distributed).– Híbrido (Shared/Distributed).

Hilos, Procesos, Multi-hilos, Multi-procesos– Hilos (Threads): secuencias de ejecución que comparten un

área de memoria (address space).– procesos (Processes): secuencias de ejecución son su

propia memoria independiente.– Multi-hilos (Multi-threading): paralelismo vía multiples hilos.– Multi-procesamiento (Multi-processing): paralelismo vía

multiples procesos.

Page 31: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Reglas generales

Reglas generales– Paralelismo de memoria compartida => hilos.– Paralelismo distribuido => procesos.– Cuantas más unidades de procesamiento se tengan se puede

reducir el tiempo de ejecución.– Cuantas más unidades de procesamiento se tengan se

pueden resolver problemas más grandes.– En la práctica algunos términos se usan indistintamente:

o Paralelismoo Concurrenciao Multihiloso Multiprocesamiento

Page 32: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Memoria compartida

Un computadora de memoria compartida provee de hardware que soporta acceso (lectura/escritura) a un espacio de memoria para varios procesadores (Multiprocessors).

Los procesadores interactúan modificando datos almacenados en este espacio.

El mayor problema en este tipo de arquitecturas es el ancho de banda del bus de acceso a memoria.

Además, en cada lectura/escritura, cada procesador debe pasar por múltiples etapas.

Una solución es añadir una memoria local a cada procesador.– UMA (Uniform Memory Access), NUMA, Cache-coherence.

Page 33: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Memoria compartida

Memoria compartida. Arquitectura básica

Page 34: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Memoria compartida

Memoria compartida. Arquitectura básica

Page 35: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Memoria distribuida

En este tipo de arquitectura cada procesador tiene su propia memoria local (Multicomputer).

Beneficios:– No hay bus de memoria compartida (evita problemas de ancho de

banda).– No hay límite para el número de procesadores, esto depende de la red

de interconexión.– No hay problemas de cache-coherency.

Desventajas:– Las tareas que se ejecutan en cada procesador solo operan sobre datos

locales, por lo que si se requieren datos remotos, se debe realizar una comunicación con otros procesadores.

o Tiempo para construir y enviar un mensaje.o Tiempo para recibir y desempaquetar el mensaje.

Page 36: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Memoria distribuida

Memoria distribuida. Arquitectura básica

Page 37: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Memoria distribuida

Memoria distribuida. Ring

Page 38: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Taxonomías

Una taxonomía es un modelo basado en un conjunto de características que provee una información condensada que es útil cuando se comparan cosas.

La taxonmía más famosa en cómputo paralelo es la de Flynn que se basa en el flujo de información (instrucciones y datos) en una

computadora.– Esta información solo tiene dos valores: uno(single) o

varios(multiple).– Instruction stream: se refiere a la progresión de instrucciones

que se ejecutan en la computadora.– Data stream: se refiere a la progresión de los valores de los

datos que son llevados a la memoria del CPU.

Page 39: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Taxonomía de Flynn

Taxonomía de Flynn– SISD (Single Instruction, Single Data) : Computadora de von

Neumann.– SIMD (Single Instruction, Multiple Data) : En estas computadoras se

aplica una instrucción a un grupo de datos simultáneamente.– MISD (Multiple Instruction, Single Data) : Ningún tipo de arquitectura

cae dentro de este tipo.– MIMD (Multiple Instruction, Multiple Data) : Los procesadores

obedecen automáticamente sus propias secuencias de instrucciones y las aplican a sus propios datos.

Page 40: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Taxonomía de Flynn

Flujo de información

Page 41: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Taxonomía de Flynn

Memoria

Page 42: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. Taxonomía de Flynn

Memoria y procesadores

Page 43: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. ¿Qué es MPI?

Biblioteca estándar para programación paralela bajo el paradigma de comunicación de procesos mediante pasaje de mensajes.

Biblioteca, no lenguaje. Proporciona funciones.

Propuesta por un comité conformado de especialistas, vendedores y usuarios de HPC:

– IBM, Intel, TMC, Meiko, Cray, Convex, Ncube– PVM, p4, Zipcode, TCGMSG, Chameleon, Express, Linda– Especialistas: ARCO, ANL, UC Santa Barbara, Convex, GMD, Syracuse

University, Cray Research, LANL, Michigan State University, IBM, Oregon Grad Inst, Intel, NOAA, University of New Mexico, KAI, NSF, Mississippi State University, Meiko, ORNL, U of Southampton, NAG, PNL, Univeristy of Colorado, nCUBE, Sandia, Yale U, ParaSoft, SDSC, University of Tennessee, Shell, SRC, University of Maryland, TMC, Western Michigan Univeristy, University of Edinburgh, Cornell University, Rice University, University of San Francisco

Objetivo: desarrollar un estándar portable y eficiente, para programación paralela.

Page 44: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. ¿Qué es MPI?

Fue diseñado para HPC sobre computadoras masivamente paralelas y clusters.( Memoria distribuida).

Paralelismo explícito ( definido y controlado en su totalidad por el programador)

Modelo de programa: SPMD

Único mecanismo de comunicación: MP.

Existen implementaciones libres y algunas particulares para ciertas plataformas.

– MPICH, LAM, OpenMPI, winmpich.

MPI se puede usar con: C, C++, Fortran 77/90/95.

Java(?), más información : mpiJava, Java grande.

Page 45: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. ¿Qué es MPI?

Actualmente es muy maduro, fácil de entender, eficiente y existe mucho software alrededor de MPI.

Características de MPI-1.1 (1995)– Modular, portable, heterogeneo, comunicaciones seguras, subgrupos,

topologías, herramientas para medición de desempeño, comunicación punto a punto, comunicación colectiva.

Características de MPI-1.2 y MPI-2 (1997)– Extensiones, aclaraciones y correcciones de MPI-1.1.– MPI-2: manejo y creación de procesos, operaciones colectivas

extendidas, interfases externas, entrada/salida, language bindings.

MPICH2 (http://www.mcs.anl.gov/research/projects/mpich2)

Page 46: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción. ¿Qué es MPI?

¿Cuando usar MPI?– Si se requiere un programa paralelo, portable y de buen

desempeño.

¿Cuando NO usar MPI?– No se requiere paralelismo.– Cuando se puede usar HPF, OpenMP, Threads (POSIX, Java,

etc.).

Page 47: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones bloqueantes y no bloqueantes Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos Topologías vituales Introducción a MPI-2

Page 48: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started

C : Los nombres de todas las funciones de MPI comienzan con el prefijo MPI_. Los tipos y funciones definidas en MPI tienen una letra mayúscula después del prefijo; las letras siguientes son minúsculas.

C++ : Todas las funciones y clases estan en el espacio de nombres MPI, de tal manera que para referirnos a una función de MPI se usa MPI::Xxxxx.

Fortran : Los nombres de todas las funciones de MPI comienzan con el prefijo MPI_ y todas las demás letras son mayúsculas.

Page 49: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started

mpi.h y mpif.h proveen de las definiciones básicas de MPI (funciones y tipos).

Para iniciar MPI se usa:– int MPI_Init(int *argc, char **argv); (C)– void MPI::Init(int& argc, char**& argv); (C++)– INTEGER IERR y MPI_INIT(IERR) (Fortran)

Para finalizar MPI se usa:– int MPI_Finalize(void); (C)– void MPI::Finalize(); (C++)– INTEGER IERR y MPI_FINALIZE(IERR) (Fortran)

Page 50: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started. Hello world con C

#include <stdio.h>#include <mpi.h>int main(int argc, char *argv[]){

int rank, size,tam; char Name[MPI_MAX_PROCESSOR_NAME];

MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &rank);MPI_Comm_size(MPI_COMM_WORLD, &size);MPI_Get_processor_name(Name,&tam);printf("Hello world from %s! I am %d of %d\n", Name, rank, size);MPI_Finalize();return 0;

}

Page 51: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started. Hello world con C++

#include <iostream>#include <mpi.h>using namespace std;int main(int argc, char *argv[]){

int rank, size;MPI::Init(argc, argv);rank = MPI::COMM_WORLD.Get_rank();size = MPI::COMM_WORLD.Get_size();cout << "Hello world! I am " << rank << " of "<< size << endl;MPI::Finalize();return 0;}

Page 52: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started. Hello world con F

program main

include ’mpif.h’

integer rank, size, ierr

call MPI_INIT(ierr)

call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)

call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr)

print *, ’Hello world! I am ’, rank , ’ of ’, size

call MPI_FINALIZE(ierr)

stop

end

Page 53: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started.

MPI_INIT : La versión de C/C++ acepta los argumentos argc y argv que proveen de argumentos main().

Casi todas las rutinas de Fortran tienen un código entero de error como su último argumento.

En el caso de C/C++ dichas funciones regresan un entero como código de error.

No se garantiza interoperabilidad entre lenguajes.

Programas que mezclan lenguajes funcionarán siempre y cuando solo uno de ellos use MPI.

Todas las funciones que no son de MPI corren de manera local:– Por ejemplo: printf() se ejecuta sobre cada procesador

Page 54: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started.

Al momento de correr el programa una copia del programa empieza a ejecutarse en cada uno de los nodos seleccionados.

En la figura corre en size=3 nodos. Cada proceso obtiene un número de rank individual, entre 0 y

size-1. En general podría haber más de un “proceso” en cada

“procesador”.

Page 55: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started.

¿Cuantos procesadores hay?– MPI_COMM_SIZE

¿Quién soy yo?– MPI_COMM_RANK– El rango está en [0,SIZE - 1]

MPI_COMM_WORLD– La comunicación en MPI toma lugar con respecto a grupos de

procesos (comunicadores).– El grupo MPI_COMM_WORLD se crea cuando se inicia MPI y

contiene todos los procesos de MPI.– MPI_COMM_WORLD es el grupo de procesos por omisión.– Puede haber subgrupos de procesos.

Page 56: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIGetting started.

/* Iniciar MPI */

MPI_Init(&argc, &argv);

/* Saber el número que tengo de proceso*/

MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

/* Saber el número de procesos totales */

MPI_Comm_size(MPI_COMM_WORLD, &p);

Page 57: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones bloqueantes y no bloqueantes Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos Topologías vituales Introducción a MPI-2

Page 58: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto.

Un buen número de funciones de MPI están dedicadas a la comunicación entre pares de procesos (comunicación punto a punto).

Existen múltiples formas distintas de intercambiar un mensaje entre dos procesos, en función del modelo y el modo de comunicación elegido

Page 59: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto.

MPI define dos modelos de comunicación: bloqueante (blocking) y no bloqueante (nonblocking).

El modelo de comunicación tiene que ver con el tiempo que un proceso pasa bloqueado tras llamar a una función de comunicación, sea ésta de envío o de recepción.

– Una función bloqueante mantiene a un proceso bloqueado hasta que la operación solicitada finalice.

– Una función no bloqueante supone simplemente “encargar” al sistema la realización de una operación, recuperando el control inmediatamente. El proceso tiene que preocuparse, más adelante, de averiguar si la operación ha finalizado o no.

Page 60: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto.

MPI define un envío como finalizado cuando el emisor puede reutilizar, sin problemas de causar interferencias, el buffer de emisión que tenía el mensaje.

Se puede entender que tras hacer un send (envío) bloqueante podemos reutilizar el buffer asociado sin problemas.

Pero tras hacer un send no bloqueante tenemos que ser muy cuidadosos con las manipulaciones que se realizan sobre el buffer, bajo el riesgo de alterar inadvertidamente la información que se está enviando.

Page 61: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto.

Al margen de si la función invocada es bloqueante o no, el programador puede tener un cierto control sobre la forma en la que se realiza y completa un envío. MPI define, en relación a este aspecto, 4 modos de envío:

– básico(basic)– con buffer (buffered)– síncrono (synchronous)– listo (ready).

Page 62: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto.

Cuando se hace un envío con buffer se guarda inmediatamente, en un buffer al efecto en el emisor, una copia del mensaje. La operación se da por completa en cuanto se ha efectuado esta copia. Si no hay espacio en el buffer, el envío fracasa.

Si se hace un envío síncrono, la operación se da por terminada sólo cuando el mensaje ha sido recibido en destino.

El modo de envío básico no especifica la forma en la que se completa la operación: es algo dependiente de la implementación. Normalmente equivale a un envío con buffer para mensajes cortos y a un envío síncrono para mensajes largos. Se intenta así agilizar el envío de mensajes cortos a la vez que se procura no perder demasiado tiempo realizando copias de la información.

En cuanto al envío en modo listo, sólo se puede hacer si antes el otro extremo está preparado para una recepción inmediata. No hay copias adicionales del mensaje (como en el caso del modo con buffer), y tampoco podemos confiar en bloquearnos hasta que el receptor esté preparado.

Page 63: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto. Básica

El resultado de la combinación de dos modelos y cuatro modos de comunicación nos da 8 diferentes funciones de envío.

Funciones de recepción sólo hay dos, una por modelo.

MPI_Send() y MPI_Recv() que son, respectivamente, las funciones de envío y recepción básicas bloqueantes.

int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm);

int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status);

Page 64: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto. Básica

Enviando y recibiendo mensajes

Preguntas:– ¿Donde está la info?– ¿Que tipo de info se envía?– ¿Que cantidad de info se envía?– ¿A quién se envía la info?– ¿Como identifica el receptor el mensaje?

Page 65: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto. Básica

En MPI se especifica con address, datatype y count: count copias de un dato del tipo datatype que se encuentran (o se van a dejar) en memoria a partir de la dirección indicada por buf.

Dest es el identificador del proceso destinatario del mensaje.

Source es el identificador del emisor del cual esperamos un mensaje. Si no nos importa el origen del mensaje, podemos poner MPI_ANY_SOURCE.

Tag es una etiqueta que se puede poner al mensaje. Suele emplearse para distinguir entre diferentes clases de mensajes. El receptor puede elegir entre recibir sólo los mensajes que tengan una etiqueta dada, o aceptar cualquier etiqueta (MPI_ANY_TAG).

Comm es un comunicador (comunicador universal MPI_COMM_WORLD).

Status es un resultado que se obtiene cada vez que se completa una recepción, y nos informa de aspectos tales como el tamaño del mensaje recibido, la etiqueta del mensaje y el emisor del mismo.

Page 66: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto. Básica

Si queremos saber el tamaño de un mensaje, lo haremos con la función MPI_Get_count():

int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count);

MPI_Isend() y MPI_Irecv() son las funciones de emisión/recepción básicas no bloqueantes.

int MPI_Isend(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request);

int MPI_Irecv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request

*request);

Page 67: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto. Básica

Asociadas a MPI_Isend() y MPI_Irecv() existen otras tres funciones:

int MPI_Wait(MPI_Request *request, MPI_Status *status);int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status);int MPI_Cancel(MPI_Request *request);

MPI_Wait() toma como entrada un recibo (request), y bloquea al proceso hasta que la operación correspondiente termina.

Hacer un MPI_Isend() seguido de un MPI_Wait() equivale a hacer un envío bloqueante.

Sin embargo, entre la llamada a la función de envío y la llamada a la función de espera el proceso puede haber estado haciendo cosas útiles, es decir, consigue solapar parte de cálculo de la aplicación con la comunicación.

Page 68: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto. Básica

Asociadas a MPI_Isend() y MPI_Irecv() existen otras tres funciones:

int MPI_Wait(MPI_Request *request, MPI_Status *status);int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status);int MPI_Cancel(MPI_Request *request);

Cuando no interesa bloquearse, sino simplemente saber si la operación ha terminado o no, podemos usar MPI_Test(). Esta función actualiza un flag que se le pasa como segundo parámetro. Si la función ha terminado, este flag toma el valor 1, y si no ha terminado pasa a valer 0.

Por último, MPI_Cancel() nos sirve para cancelar una operación de comunicación pendiente, siempre que ésta aún no se haya completado.

Page 69: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos

Calcular el valor de la integral usando una suma de rectángulos:

Page 70: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

program maininclude 'mpif.h'

double precision PI25DTparameter (PI25DT = 3.141592653589793238462643d0)double precision mypi,pi,h,suma,x,f,adouble precision startime,endtimeinteger n,myid,numprocs,i,ierr

! FUNCION PARA 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,numprocs,ierr)

Page 71: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

10 if(myid .eq. 0) then print *, 'Introduzca el numero de intervalos (0 salir)' read(*,*) n print *, 'lo he leido y es ', n endif

! BROADCAST N

startime=MPI_WTIME()call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr)

! CHEQUEAR POR POSIBLE SALIDA

if (n .le. 0) goto 30

Page 72: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

! CALCULAR EL TAMANO DEL INTERVALO

h=1.0d0/nsuma=0.0d0

do 20 i=myid+1,n,numprocs x=h*(dble(i)-0.5d0) suma=suma+f(x)20 continuemypi=h*suma

! RECOLECTAR TODAS LAS SUMAS PARCIALEScall MPI_REDUCE(mypi,pi,1,MPI_DOUBLE_PRECISION,MPI_SUM,0,

MPI_COMM_WORLD,ierr)

Page 73: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

! EL NODO 0 IMPRIMIRA LA RESPUESTA

entime=MPI_WTIME()if(myid .eq. 0) then print *, 'pi es', pi, 'Error es ', abs(pi-PI25DT) print *, 'tiempo es ', (endtime-starttime), 'segundos'endif! goto 10

30 call MPI_FINALIZE(ierr)

stopend

Page 74: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

#include <iostream>using namespace std;

int main(int argc, char **argv){

int sum = 0;for(int i=1;i<=1000;i=i+1)

sum = sum + i;cout << "The sum from 1 to 1000 is: "<< sum << endl;

}

Resultado: The sum from 1 to 1000 is: 500500

SUMA. Algoritmo secuencial

Page 75: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

#include <iostream>#include “mpi.h”using namespace std;

int main(int argc, char ** argv){

int mynode, totalnodes;int sum = 0,startval,endval,accum;MPI_Status status;MPI_Init(&argc,&argv);MPI_Comm_size(MPI_COMM_WORLD, &totalnodes);MPI_Comm_rank(MPI_COMM_WORLD, &mynode);startval = 1000*mynode/totalnodes+1;endval = 1000*(mynode+1)/totalnodes;

SUMA. Algoritmo paralelo

Page 76: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

for(int i=startval;i<=endval;i=i+1)sum = sum + i;

if(mynode!=0) MPI_Send(&sum, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);elsefor(int j=1;j<totalnodes;j=j+1){

MPI_Recv(&accum, 1, MPI_INT, j, 1,MPI_COMM_WORLD, &status);

sum = sum + accum;}if(mynode == 0)

cout << "The sum from 1 to 1000 is: "<< sum << endl;MPI_Finalize();

}

SUMA. Algoritmo paralelo

Page 77: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

SUMA. Algoritmo paralelo

– Compilación: mpicxx –o sumaparalelo sumaParalelo.cpp

– Ejecución: mpiexec -n 4 ./suma_para– Resultado: The sum from 1 to 1000 is: 500500

Page 78: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

Programa greetings /* Envío de un mensaje desde todos los procesos con rank!= 0 al proceso 0. El proces 0 imprime los mensajes */

#include <stdio.h>#include <string.h>#include "mpi.h"main(int argc, char* argv[]) { int my_rank; int p; int source; /* origen */ int dest; /* destino */ int tag = 0; char message[100]; MPI_Status status;

MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD, &p); MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

Page 79: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

if (my_rank != 0) {

/* Creamos el mensaje */

sprintf(message, "Greetings from process %d!", my_rank);

dest = 0;

/* Longitud strlen+1 porque en C se añade al final de una cadena '\0' */

MPI_Send(message, strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD);

}

else { /* my_rank == 0 */

for (source = 1; source < p; source++) {

MPI_Recv(message, 100, MPI_CHAR, source, tag, MPI_COMM_WORLD, &status);

printf("%s\n", message);

}

}

MPI_Finalize();

}

Page 80: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos.

Compilarmpicc –o greetings greetings.c

Ejecutar mpirun -np 2 greetings

El programa corrido con 2 procesos, genera el outputGreetings from process 1!

El programa corrido con 4 procesos, genera el outputGreetings from process 1!Greetings from process 2!Greetings from process 3!

Page 81: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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.

Page 82: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

Page 83: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

SECUENCIAL

#include <math.h>#include <stdio.h> 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 */

Page 84: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

SECUENCIAL

for (i=0; i<p; i++) {

ai = a + i*n*h; /* lower limit of integration for partition i */ integral_sum += integral(ai,h,n);

}printf("The integral sum =%f\n",integral_sum);

}

Page 85: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

SECUENCIAL

float integral(float ai, float h, int n){

int j; float aij, integ; integ = 0.0; /* initialize */ for (j=0;j<n;j++) { /* sum integrals */

aij = ai + (j+0.5)*h; /* mid-point */ integ += cos(aij)*h;

} return integ;

}

Page 86: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

PARALELO. Comunicación bloqueante

#include <mpi.h>#include <math.h> #include <stdio.h>

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);

Page 87: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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 */

Page 88: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

PARALELO. Comunicación bloqueante

printf("Process %d has the partial integral of %f\n", 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<p;proc++) {

MPI_Recv( &my_int, 1, MPI_FLOAT, proc, tag, comm,&status); integral_sum += my_int; }printf("The Integral =%f\n",integral_sum);

}MPI_Finalize();

}

Page 89: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

PARALELO. Comunicación bloqueante

float integral(float ai, float h, int n){

int j; float aij, integ; integ = 0.0; /* initialize */ for (j=0;j<n;j++) { /* sum integrals */

aij = ai + (j+0.5)*h; /* mid-point */ integ += cos(aij)*h;

} return integ;

}

Page 90: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

PARALELO. Comunicación con Send (no bloqueante) y Recev

#include <mpi.h>#include <math.h> #include <stdio.h> 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);

Page 91: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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 %f\n", myid,my_int);

Page 92: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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<p;proc++){ MPI_Recv( &my_int, 1, MPI_FLOAT, MPI_ANY_SOURCE,

MPI_ANY_TAG, comm, &status); integral_sum += my_int;

}printf("The Integral =%f\n",integral_sum);

} else {

MPI_Isend(&my_int, 1, MPI_FLOAT, master, tag, comm, &request); other_work(myid); MPI_Wait(&request, &status); * block until Isend is done */

} MPI_Finalize();

}

Page 93: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Integración numérica

PARALELO. Comunicación con Send (no bloqueante) y Recev

void other_work(int myid) {

printf("more work on process %d\n", myid); } float integral(float ai, float h, int n){

int j; float aij, integ; integ = 0.0; /* initialize */ for (j=0;j<n;j++) { /* sum integrals */

aij = ai + (j+0.5)*h; /* mid-point */ integ += cos(aij)*h;

} return integ;

}

Page 94: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. getcount.c

#include <stdio.h>#include <stdlib.h>#include <mpi.h>/* 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);

Page 95: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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();

}

Page 96: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Buffer.c

#include <stdio.h>

#include <mpi.h>

#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);

Page 97: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Buffer.c

MPI_Buffer_attach(buff, tambuff);

if(my_rank ==0){

printf(“Proceso 0: mando al proceso 1\n”);

MPI_Bsend(&x,TAM,MPI_INT,1,tag,MPI_COMM_WORLD);

printf(“Proceso 0: vuelta de la operación de envio\n”);

}

else{

printf(“Proceso 1: recibiendo del proceso 0\n”);

MPI_Recv(&c,TAM,MPI_INT,0,tag,MPI_COMM_WORLD,&status);

printf(“Proceso 1: recibidos %d elementos\n”,TAM);

}

MPI_Buffer_detach(&buff,&tambuff);

MPI_Finalize();

}

Page 98: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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);

Page 99: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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.

Page 100: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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.

Page 101: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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);

Page 102: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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.

Page 103: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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

Page 104: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicación punto a punto. Modos de comunicación

Recepción Bloqueante No bloqueante

Estándar.

MPI_Recv MPI_Irecv

Page 105: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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.

Page 106: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. 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.

Page 107: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos Topologías vituales Introducción a MPI-2

Page 108: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas

Muchas aplicaciones requieren de la comunicación entre más de dos procesos.

Esto se puede hacer combinando operaciones punto a punto, pero para que le resulte más cómodo al programador, y para posibilitar implementaciones optimizadas, MPI incluye una serie de operaciones colectivas:

– Barreras de sincronización– Broadcast (difusión)– Gather (recolección)– Scatter (distribución)– Operaciones de reducción (suma, multiplicación, mínimo, etc.)– Combinaciones de todas ellas

Page 109: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas

Una operación colectiva tiene que ser invocada por todos los participantes, aunque los roles que juegen no sean los mismos.

La mayor parte de las operaciones requieren la designación de un proceso como root, o raíz de la operación.

Page 110: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Barreras y broadcast

Dos de las operaciones colectivas más comunes son las barreras de sincronización (MPI_Barrier()) y el envío de información en modo difusión (MPI_Broadcast()).

En MPI_Barrier no exige ninguna clase de intercambio de información. Es una operación puramente de sincronización, que bloquea a los procesos de un comunicador hasta que todos ellos han pasado por la barrera. Suele emplearse para dar por finalizada una etapa del programa, asegurándose de que todos han terminado antes de dar comienzo a la siguiente.

int MPI_Barrier(MPI_Comm comm);

Page 111: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Barreras y broadcast

MPI_Broadcast() sirve para que un proceso, el raíz, envíe un mensaje a todos los miembros del comunicador.

Esta función ya muestra una característica peculiar de las operaciones colectivas de MPI: todos los participantes invocan la misma función, designando al mismo proceso como raíz de la misma.

Una implementación alternativa sería tener una función de envío especial, en modo broadcast, y usar las funciones de recepción normales para leer los mensajes.

int MPI_Bcast(void* buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm);

Page 112: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Barreras y broadcast

Este esquema representa el significado de un broadcast.

En las filas representamos los procesos de un comunicador, y en las columnas los datos que posee cada proceso.

Antes del broadcast, el procesador raíz (suponemos que es el 0) tiene el dato A. Tras realizar el broadcast, todos los procesos (incluyendo el raíz) tienen una copia de A0.

Page 113: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Recolección (gather)

MPI_Gather realiza una recolección de datos en el proceso raíz.

Este proceso recopila un vector de datos, al que contribuyen todos los procesos del comunicador con la misma cantidad de datos.

El proceso raíz almacena las contribuciones de forma consecutiva.

int MPI_Gather(void* sendbuf, int sendcount,

MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm);

Page 114: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Recolección (gather)

Sólo el proceso raíz tiene que preocuparse de los parámetros

recbuf, recvcount y recvtype.

Sin embargo, todos los procesos (raíz incluido) tienen que facilitar valores válidos para sendbuf, sendcount y sendtype.

Page 115: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Recolección (gather)

Existe una versión de la función de recolección, llamada MPI_Gatherv(), que permite almacenar los datos recogidos en forma no consecutiva, y que cada proceso contribuya con bloques de datos de diferente tamaño .

int MPI_Gatherv(void* sendbuf, int sendcount,

MPI_Datatype sendtype, void* recvbuf, int *recvcounts,

int *displs, MPI_Datatype recvtype, int root, MPI_Comm comm);

La tabla recvcounts establece el tamaño del bloque de datos aportado por cada proceso, y displs indica cuál es el desplazamiento entre bloque y bloque

Page 116: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Recolección (gather)

Muchas veces interesa distribuir a todos los procesos el resultado de una recolección previa. (Esto se puede hacer concatenando una recolección con un broadcast).

Existen funciones que se encargan de hacer todo esto en un único paso: MPI_Allgather() (si los bloques de datos son de tamaño fijo y se almacenan consecutivamete) y MPI_Allgatherv() (si los tamaños de los datos son variables y/o se almacenan de forma no consecutiva).

int MPI_Allgather(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm);

int MPI_Allgatherv(void* sendbuf, int sendcount, MPI_Datatype sendtype,void* recvbuf, int *recvcounts, int *displs, MPI_Datatype recvtype, MPI_Comm comm);

Page 117: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Recolección (gather)

Page 118: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplo. Integración numérica

#include <mpi.h>#include <math.h>#include <stdio.h>/*Gather.c*/

float integral(float ai, float h, int n);

int main(int argc, char* argv[]) {int n, p, myid, tag, proc, ierr, i; float h, integral_sum, a, b, ai, pi, my_int, buf[50]; int master = 0; /* processor performing total sum */ MPI_Comm comm;

comm = MPI_COMM_WORLD; ierr = MPI_Init(&argc, &argv); MPI_Comm_rank(comm, &myid);MPI_Comm_size(comm, &p);

Page 119: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplo. Integración numérica

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 */

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);

printf("Process %d has the partial sum of %f\n", myid,my_int);

MPI_Gather( &my_int, 1, MPI_FLOAT, buf, 1, MPI_FLOAT, master, comm);

Page 120: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplo. Integración numérica

if(myid == master)

{

integral_sum = 0.0;

for (i=0; i<p; i++)

{

integral_sum += buf[i];

}

printf("The Integral =%f\n",integral_sum);

}

MPI_Finalize();

}

Page 121: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplo. Integración numérica

float integral(float ai, float h, int n)

{

int j; float aij, integ;

integ = 0.0;

/* initialize */

for (j=0;j<n;j++)

{ /* sum integrals */

aij = ai + (j+0.5)*h; /* mid-point */

integ += cos(aij)*h;

}

return integ;

}

Page 122: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Distribución (scatter)

MPI_Scatter() realiza la operación simétrica a MPI_Gather().

El proceso raíz posee un vector de elementos, uno por cada proceso del comunicador. Tras realizar la distribución, cada proceso tiene una copia del vector inicial.

Recordemos que MPI permite enviar bloques de datos, no sólo datos individuales.

int MPI_Scatter(void* sendbuf, int sendcount,

MPI_Datatype sendtype, void* recvbuf, int recvcount,

MPI_Datatype recvtype, int root, MPI_Comm comm);

Page 123: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Distribución (scatter)

Page 124: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Distribución (scatterv)

Si los datos a enviar no están almacenados de forma consecutiva en memoria, o los bloques a enviar a cada proceso no son todos del mismo tamaño, tenemos la función MPI_Scatterv(), con un interfaz más complejo pero más flexible.

int MPI_Scatterv(void* sendbuf, int *sendcounts,

int *displs, MPI_Datatype sendtype, void* recvbuf,

int recvcount, MPI_Datatype recvtype, int root,

MPI_Comm comm);

Page 125: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. Scatter.c

#include "mpi.h"#include <stdio.h>#define SIZE 4int main(int argc,char *argv[]) {

nt numtasks, rank, sendcount, recvcount, source;float sendbuf[SIZE][SIZE] = {{1.0, 2.0, 3.0, 4.0}, {5.0, 6.0,7.0,8.0}, {9.0, 10.0, 11.0, 12.0}, {13.0, 14.0, 15.0, 16.0}};float recvbuf[SIZE];MPI_Init(&argc,&argv);MPI_Comm_rank(MPI_COMM_WORLD, &rank);MPI_Comm_size(MPI_COMM_WORLD, &numtasks);if (numtasks == SIZE) {

source = 1; sendcount = SIZE; recvcount = SIZE;MPI_Scatter(sendbuf,sendcount,MPI_FLOAT,recvbuf,recvcount,MPI_FLOAT,source,MPI_COMM_WORLD);printf("rank= %d Results: %f %f %f %f\n",rank,recvbuf[0],recvbuf[1],recvbuf[2],recvbuf[3]);

} else printf("Must specify %d processors.Terminating.\n",SIZE);MPI_Finalize();

}

Page 126: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos

Scatter en las filas de una matriz. Salida del programa

rank= 0 Results: 1.000000 2.000000 3.000000 4.000000

rank= 1 Results: 5.000000 6.000000 7.000000 8.000000

rank= 2 Results: 9.000000 10.000000 11.000000 12.000000

rank= 3 Results: 13.000000 14.000000 15.000000 16.000000

Page 127: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Distribución all-to-all

La comunicación de todos con todos supone que, inicialmente, cada proceso tiene un vector con tantos elementos como procesos hay en el comunicador.

Para i, j y k entre 0 y N-1 (donde N es el número de procesos del comunicador), cada proceso i envía una copia de sendbuf[j] al proceso j, y recibe del proceso k un elemento, que almacena en recvbuf[k].

MPI_Alltoall() equivale, por tanto, a una sucesión de N operaciones de distribución, en cada una de las cuales el proceso i toma el rol de raíz.

int MPI_Alltoall(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype,

MPI_Comm comm);

int MPI_Alltoallv(void* sendbuf, int *sendcounts, int *sdispls, MPI_Datatype sendtype, void* recvbuf, int *recvcounts, int *rdispls, MPI_Datatype recvtype, MPI_Comm comm);

Page 128: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Distribución all-to-all

Page 129: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Reducción

Una reducción es una operación realizada de forma cooperativa entre todos los procesos de un comunicador, de tal forma que se obtiene un resultado final que se almacena en el proceso raíz.

int MPI_Reduce(void* sendbuf, void* recvbuf, int count,

MPI_Datatype datatype, MPI_Op op, int root,

MPI_Comm comm);

Page 130: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplo. Integración numérica

#include <mpi.h>

#include <math.h>

#include <stdio.h>

/*reduce.c*/

float fct(float x) { return cos(x); }

float integral(float ai, float h, int n);

int main(int argc, char* argv[])

{

int n, p, myid, tag, proc, ierr;

float h, integral_sum, a, b, ai, pi, my_int;

char line[10];

int master = 0;

MPI_Comm comm;

comm = MPI_COMM_WORLD;

Page 131: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplo. Integración numérica

ierr = MPI_Init(&argc,&argv); MPI_Comm_rank(comm, &myid);MPI_Comm_size(comm, &p);

pi = acos(-1.0); /* = 3.14159... */ a = 0.; /* lower limit of integration */ b = pi*1./2.; /* upper limit of integration */

if(myid == master) {

printf("The requested number of processors is %d\n",p); printf("Enter number of increments within each process\n");(void) fgets(line, sizeof(line), stdin); (void) sscanf(line, "%d", &n);

}

Page 132: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplo. Integración numérica

/* Broadcast "n" to all processes */ MPI_Bcast( &n, 1, MPI_INT, master, comm);

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 result of %f\n", myid,my_int);

MPI_Reduce( &my_int, &integral_sum, 1, MPI_FLOAT, MPI_SUM, master, comm);

if(myid == 0) {

printf("The result =%f\n",integral_sum); } MPI_Finalize();

}

Page 133: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplo. Integración numérica

float integral(float ai, float h, int n) {

int j; float aij, integ; integ = 0.0; /* initialize */ for (j=0;j<n;j++) { /* sum integrals */

aij = ai + (j+0.5)*h; /* mid-point */ integ += cos(aij)*h;

}return integ;

}

Page 134: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Reducción

MPI define una colección de operaciones del tipo MPI_Op que se pueden utilizar en una reducción:

– MPI_MAX (máximo)– MPI_MIN (mínimo)– MPI_SUM (suma)– MPI_PROD (producto)– MPI_LAND (and lógico)– MPI_BAND (and bit a bit)– MPI_LOR (or lógico)– MPI_BOR (or bit a bit)– MPI_LXOR (xor lógico)– MPI_BXOR (xor bit a bit)– ...

Page 135: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Reducción

En ocasiones el programador puede necesitar otra operación de reducción distinta, no predefinida.

Para ello MPI ofrece la función MPI_Op_create(), que toma como argumento de entrada una función de usuario y devuelve un objeto de tipo MPI_Op que se puede emplear con MPI_Reduce().

int MPI_Op_create(MPI_User_function *function,

int commute, MPI_Op *op );

Ese objeto se puede destruir más adelante con MPI_Op_free().

int MPI_Op_free(MPI_Op *op);

Page 136: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Reducción

La operación a realizar puede ser cualquiera. En general se emplean operaciones conmutativas y asociativas, es decir, cuyo resultado no depende del orden con el que se procesan los operandos. Eso se indica con el valor 1 en el parámetro commute. Si la operación no es conmutativa (commute = 0) entonces se exige que la reducción se realice en orden de dirección (se empieza con el proceso 0, luego con el 1, con el 2, etc.).

En ocasiones resulta útil que el resultado de una reducción esté disponible para todos los procesos. Aunque se puede realizar un broadcast tras la reducción, podemos combinar la reducción con la difusión usando MPI_Allreduce().

int MPI_Allreduce(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);

Page 137: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIComunicaciones colectivas.

Reducción

Si el resultado de la reducción es un vector que hay que distribuir entre los procesadores, podemos combinar la reducción y la distribución usando MPI_Reduce_scatter().

int MPI_Reduce_scatter(void* sendbuf, void* recvbuf, int *recvcounts,MPI_Datatype datatype,MPI_Op op,MPI_Comm comm);

Una variante más de la reducción nos la da MPI_Scan(). Es similar a MPI_Allreduce(), excepto que cada proceso recibe un resultado parcial de la reducción, en vez del final: cada proceso i recibe, en vez del resultado de OP(0..N-1), siendo N el número total de procesos, el resultado de OP(0..i).

int MPI_Scan(void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm );

Page 138: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos Topologías vituales Introducción a MPI-2

Page 139: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITipos de datos derivados

MPI maneja en todas sus funciones de envío/recepción vectores de tipos simples.

En general, se asume que los elementos de esos vectores están almacenados consecutivamente en memoria.

En ocasiones, sin embargo, es necesario el intercambio de tipos estructurados (structs), o de vectores no almacenados consecutivamente en memoria (p.ej: envío de una columna de un array, en vez de envío de una fila).

MPI incluye la posibilidad de definir tipos más complejos (objetos del tipo MPI_Datatype), empleando constructores. Antes de usar un tipo de usuario, hay que ejecutar MPI_Type_commit(). Cuando ya no se necesite un tipo, se puede liberar con MPI_Type_free().

int MPI_Type_commit(MPI_Datatype *datatype);int MPI_Type_free(MPI_Datatype *datatype);

Page 140: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITipos de datos derivados.

Definición de tipos homogéneos

Son tipos homogéneos aquellos tipos construidos en los que todos los elementos constituyentes son del mismo tipo.

Se pueden definir tipos homogéneos con dos funciones distintas:

– MPI_Type_contiguous(): es la más sencilla, y permite definir un tipo formado por una colección de elementos de un tipo básico, todos ellos del mismo tamaño y almacenados consecutivamente en memoria.

int MPI_Type_contiguous (int count, MPI_Datatype oldtype, MPI_Datatype *newtype);

Newtype es un nuevo tipo que consiste en count copias de oldtype.

Page 141: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITipos de datos derivados.

Definición de tipos homogéneos

– MPI_Type_vector(). Los elementos constituyentes del nuevo tipo no están almacenados consecutivamente en memoria, sino que están espaciados a intervalos regulares.

int MPI_Type_vector (int count, int blocklength, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype);

Newtype es un nuevo tipo que consiste en count bloques de datos.

Cada bloque consta de blocklength elementos del tipo oldtype. La distancia entre bloques, medida en múltiplos del tamaño del elemento básico, la da stride.

Una llamada a MPI_Type_contiguous(c, o, n) equivale a una llamada a MPI_Type_vector (c, 1, 1, o, n), o a una llamada a MPI_Type_vector (1, c, x,o, n), siendo x un valor arbitrario.

Page 142: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITipos de datos derivados.

Definición de tipos heterogéneos

Si nos interesa trabajar con tipos no homogéneos, podemos usar una función más genérica: MPI_Type_struct().

MPI_Type_struct (int count, int *array_of_blocklenghts,

MPI_Aint *array_of_displacements,

MPI_Datatype *array_of_types, MPI_Datatype *newtype);

Count determina el número de bloques, así como el tamaño de los arrays array_of_blocklenghts, array_of_displacements y array_of_types.

Cada bloque i tiene array_of_blocklenghts[i] elementos, está desplazado array_of_displacements[i] bytes del anterior, y es de tipo array_of_types[i].

Page 143: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITipos de datos derivados.

Definición de tipos heterogéneos

Veamos un ejemplo.– Si B = {2, 1, 3}

D = {0, 16, 26} y T = {MPI_FLOAT, MPI_INT, MPI_CHAR}

entonces MPI_Type_struct(3, B, D, T, newtype) devuelve un tipo que en memoria tiene este aspecto.

La primera columna hace referencia a la posición de memoria que ocupa cada campo de una instancia de este tipo de datos, relativa al origen del dato.

Page 144: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. contiguous.c

#include <stdio.h>#include<mpi.h>

/* Run with four processes */

void main(int argc, char *argv[]) {int rank;MPI_Status status;struct { int x; int y; int z; } point;MPI_Datatype ptype;

MPI_Init(&argc,&argv);MPI_Comm_rank(MPI_COMM_WORLD,&rank);MPI_Type_contiguous(3,MPI_INT,&ptype);MPI_Type_commit(&ptype);if(rank==3){

point.x=15; point.y=23; point.z=6;MPI_Send(&point,1,ptype,1,52,MPI_COMM_WORLD);

} else if(rank==1) {MPI_Recv(&point,1,ptype,3,52,MPI_COMM_WORLD,&status);printf("P:%dreceived coordsare (%d,%d,%d) \n",rank,point.x,point.y,point.z);

}MPI_Finalize();

}

Page 145: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. vector.c

#include <mpi.h>#include <math.h>#include <stdio.h>

void main(int argc, char *argv[]) {int rank,i,j;MPI_Status status;double x[4][8];MPI_Datatype coltype;

MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD,&rank);MPI_Type_vector(4,1,8,MPI_DOUBLE,&coltype);MPI_Type_commit(&coltype);

if(rank==3){for(i=0;i<4;++i)

for(j=0;j<8;++j) x[i][j]=pow(10.0,i+1)+j; MPI_Send(&x[0][7],1,coltype,1,52,MPI_COMM_WORLD);} else if(rank==1) {

MPI_Recv(&x[0][2],1,coltype,3,52,MPI_COMM_WORLD,&status);for(i=0;i<4;++i) printf("P:%d my x[%d][2]=%1f\n",rank,i,x[i][2]);

}MPI_Finalize();

}

Page 146: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. extent.c

#include <stdio.h>#include<mpi.h>

void main(intargc, char *argv[]) {int rank,i;MPI_Status status;struct{ int num; float x; double data[4]; } a;

int blocklengths[3]={1,1,4};MPI_Datatype types[3]={MPI_INT,MPI_FLOAT,MPI_DOUBLE};MPI_Aint displacements[3];MPI_Datatype restype;MPI_Aint intex,floatex;

MPI_Init(&argc,&argv);MPI_Comm_rank(MPI_COMM_WORLD,&rank);MPI_Type_extent(MPI_INT,&intex);MPI_Type_extent(MPI_FLOAT,&floatex);

Page 147: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos

displacements[0]= (MPI_Aint)0; displacements[1]=intex;displacements[2]=intex+floatex;MPI_Type_struct(3,blocklengths,displacements,types,&restype);MPI_Type_commit(&restype);

if (rank==3){a.num=6; a.x=3.14; for(i=0;i<4;++i)

a.data[i]=(double) i;MPI_Send(&a,1,restype,1,52,MPI_COMM_WORLD);

} else if(rank==1) {

MPI_Recv(&a,1,restype,3,52,MPI_COMM_WORLD,&status); printf("P:%dmy a is %d %f %lf %lf %lf %lf\n",

rank,a.num,a.x,a.data[0],a.data[1],a.data[2],a.data[3]);}

MPI_Finalize(); }

Page 148: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. bcast.c

#include<mpi.h>

#include <stdio.h>

void main (int argc, char *argv[]) {

int rank;

double param;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD,&rank);

if(rank==5)

param=23.0;

MPI_Bcast(&param,1,MPI_DOUBLE,5,MPI_COMM_WORLD);

printf("P:%d after broadcast parameter is %f\n",rank,param);

MPI_Finalize();

}

Page 149: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. scatterdos.c

#include <mpi.h>#include <stdio.h>void main (int argc, char *argv[]) {

int rank,size,i,j;double param[4],mine;int sndcnt,revcnt;

MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD,&rank);MPI_Comm_size(MPI_COMM_WORLD,&size);

revcnt=1;if(rank==3){

for(i=0;i<4;i++) param[i]=23.0+i;

sndcnt=1;}MPI_Scatter(param,sndcnt,MPI_DOUBLE,&mine,revcnt,MPI_DOUBLE,3,MPI_COMM_WORLD);printf("P:%dmine is %f\n",rank,mine);MPI_Finalize();

}

Page 150: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. reducedos.c

#include <mpi.h>#include <stdio.h>

void main (int argc, char *argv[]) {int rank;struct{ double value; int rank;} in, out;int root;

MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD,&rank);in.value=rank+1;in.rank=rank;root=7;MPI_Reduce(&in,&out,1,MPI_DOUBLE_INT,MPI_MAXLOC,root,MPI_COMM_WORLD);if(rank==root)

printf("PE:%dmax=%lf at rank %d\n",rank,out.value,out.rank);MPI_Reduce(&in,&out,1,MPI_DOUBLE_INT,MPI_MINLOC,root,MPI_COMM_WORLD);if(rank==root)

printf("PE:%dmin=%lf at rank %d\n",rank,out.value,out.rank);MPI_Finalize();

}

Page 151: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. create.c

#include <mpi.h>#include <stdio.h>/*Con 4 procesadores*/

#define TRUE 1typedef struct{

double real,imag;} complex;void cprod(complex *in, complex *inout, int *len, MPI_Datatype *dptr) {

int i;complex c;for (i=0; i<*len; ++i) {

c.real=(*in).real * (*inout).real-(*in).imag* (*inout).imag;c.imag=(*in).real * (*inout).imag+ (*in).imag* (*inout).real;*inout=c;in++;inout++;

}}

Page 152: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos. create.c

void main (int argc, char *argv[]) {int rank;int root;complex source,result;MPI_Op myop;MPI_Datatypectype;

MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD,&rank);MPI_Type_contiguous(2,MPI_DOUBLE,&ctype);MPI_Type_commit(&ctype);MPI_Op_create(cprod,TRUE,&myop);

root=2;source.real=rank+1;source.imag=rank+2;MPI_Reduce(&source,&result,1,ctype,myop,root,MPI_COMM_WORLD);if(rank==root)

printf("PE:%d result is %lf + %lfi\n",rank, result.real, result.imag);MPI_Finalize();

}--------------------------------------------

P:2 result is -185.000000 + -180.000000i

Page 153: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos (Modularidad) Topologías vituales Introducción a MPI-2

Page 154: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad

MPI permite definir grupos de procesos. Un grupo es una colección de procesos, y define un espacio de direcciones (desde 0 hasta el tamaño del grupo menos 1).

Los miembros del grupo tienen asignada una dirección dentro de él. Un proceso puede pertenecer simultáneamente a varios grupos, y tener una dirección distinta en cada uno de ellos.

Un comunicador es un universo de comunicación. Básicamente consiste en un grupo de procesos, y un contexto de comunicación. Las comunicaciones producidas en dos comunicadores diferentes nunca interfieren entre sí.

Page 155: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad

El concepto de comunicador se introdujo para facilitar la elaboración de bibliotecas de programas: el programa de un usuario se ejecuta en un comunicador, y las funciones de la biblioteca en otro diferente (posiblemente, con el mismo grupo de procesos, pero con un contexto diferente).

Así no hay riesgo de que se mezclen mensajes del usuario con mensajes privados de las funciones de la biblioteca.

Además, así tampoco hay problemas a la hora de usar etiquetas.

Dos de las funciones sobre comunicadores ya han sido presentadas:

– MPI_Comm_size() para averiguar el tamaño (número de procesos) de un comunicador

int MPI_Comm_size(MPI_Comm comm, int *size);

Page 156: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad

– MPI_Comm_rank() para que un proceso obtenga su identificación dentro del comunicador.

int MPI_Comm_rank(MPI_Comm comm, int *rank);

– La función MPI_Comm_dup() permite crear un nuevo comunicador, con el mismo grupo de procesos, pero diferente contexto. Se puede usar antes de llamar a una función de una biblioteca.

int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm);

Page 157: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad

La Figura muestra cómo puede ocurrir que un mensaje del usuario (flecha fina) interfiera con los mensajes propios de una función de biblioteca (flechas gruesas). Si la biblioteca trabaja en un comunicador diferente (derecha) entonces no hay problemas de interferencia.

Page 158: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad

– La operación MPI_Comm_dup(), así como todas las demás que crean comunicadores, son operaciones colectivas: tienen que ser invocadas por todos los procesos implicados, con argumentos compatibles.

– MPI_Comm_free() destruye un comunicador que ya no se va a emplear.

MPI_Comm_dup (MPI_COMM_WORLD, &newcomm);

/* llamada a función, que se ejecutará dentro de newcomm */

MPI_Comm_free (&newcomm);

Page 159: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad

– Por su parte, MPI_Comm_split() crea, a partir de un comunicador inicial, varios comunicadores diferentes, cada uno con un conjunto disjunto de procesos. La variable color determina en qué comunicador queda cada uno de los procesos.

int MPI_Comm_split(MPI_Comm comm, int color, int key,

MPI_Comm *newcomm);

Page 160: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad. Ejemplo

Veamos un ejemplo de creación de comunicadores con MPI_Comm_split().

– Partiendo del comunicador universal, definimos dos comunicadores: uno con aquellos procesos que tienen dirección par en el comunicador MPI_COMM_WORLD, y otro con los procesos impares. Cada proceso pertenecerá a dos comunicadores: al universal y al recién creado, y tendrá por lo tanto dos direcciones, una por comunicador.

int myglobalid, myotherid, color; MPI_Comm newcom;MPI_Comm_rank (MPI_COMM_WORLD, &myglobalid);if (myglobalid%2 == 0) color = 0;else color = 1;MPI_Comm_split (comm, color, myglobalid, &newcom);MPI_Comm_rank (newcom, &myotherid);

/* operaciones entre pares e impares, por separado */

MPI_Comm_free (&newcom);

Page 161: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad. Ejemplo

La Figura muestra una colección de seis procesos que forman inicialmente parte del comunicador universal y que, tras MPI_Comm_split() pasan a formar dos nuevos comunicadores

disjuntos.

Page 162: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad.

– La función MPI_Intercomm_create() nos permite crear un intercomunicador.

int MPI_Intercomm_create(MPI_Comm local_comm, int local_leader, MPI_Comm peer_comm, int remote_leader, int tag, MPI_Comm

*newintercomm);

Los procesos que se encuentran en dos grupos diferentes no pueden comunicarse entre sí, a no ser que se cree un intercomunicador (los comunicadores vistos hasta ahora se denominan intracomunicadores).

Page 163: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad.

– Todos los procesos de los dos comunicadores que quieren interconectarse deben hacer una llamada a MPI_Intercomm_create() con argumentos compatibles.

– Interpretar los argumentos de esta función no es trivial. En primer lugar, cada proceso tiene que facilitar el comunicador ( local_comm), y nombrar a un proceso local como lider del intercomunicador (local_leader). Luego hay que facilitar un comunicador que englobe a los dos comunicadores que queremos intercomunicar (peer_comm; MPI_COMM_WORLD siempre resulta válido), y la dirección de un proceso del otro comunicador que va a actuar como líder (remote_leader), teniendo en cuenta que esa dirección corresponde al comunicador global.

– Con esto ya se tiene tendido un “puente” entre los dos comunicadores. También hay que facilitar un número de etiqueta (tag) que esté libre y que el programador no debe emplear para ningún otro propósito.

– El intercomunicador lo obtenemos en newintercomm. Una vez que se tiene un intercomunicador, se puede usar para acceder al comunicador que está “al otro lado”. Las direcciones de los procesos receptores que hay que facilitar en las funciones de envío, o las de los procesos emisores que se obtienen tras una función de recepción, hacen referencia a ese “otro lado”.

Page 164: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad.

Page 165: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad. Ejemplo

– El siguiente ejemplo toma como punto de partida los dos comunicadores creados en el ejemplo anterior: uno con los procesos que en MPI_COMM_WORLD tienen dirección par, y otro con los que tienen en ese comunicador dirección impar. Cada proceso tiene almacenado en newcom el comunicador al que pertenece, y en myotherid su dirección en ese comunicador. Tras crear, de forma colectiva, el intercomunicador, cada proceso del comunicador “par” envía un mensaje a su semejante en el comunicador “impar”.

Page 166: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIModularidad. Ejemplo

if (myglobalid%2 == 0) {

MPI_Intercomm_create (newcom, 0, MPI_COMM_WORLD,

1, 99, &intercomm);

MPI_Send(msg, 1, type, myotherid, 0, intercomm);

}

else {

MPI_Intercomm_create (newcom, 0, MPI_COMM_WORLD,

0, 99, &intercomm);

MPI_Recv(msg, 1, type, myotherid, 0, intercomm, &status);

}

Page 167: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos (Modularidad) Topologías vituales Introducción a MPI-2

Page 168: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

Particionar: debemos definir como asignar partes (el rango [s,e))a cada proceso.

La forma en que el hardware está conectado entre sí se llama “topología de la red” (anillo, estrella, toroidal ...)

La forma óptima de particionar y asignar a los diferentes procesos puede depender del hardware subyacente. Si la topología del hardware es tipo anillo, entonces conviene asignar franjas consecutivas en el orden en que avanza el anillo.

En muchos programas cada proceso comunica con un número reducido de procesos vecinos. Esta es la “topología de la aplicación”.

Page 169: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

Para que la implementación paralela sea eficiente debemos hacer que la topología de la aplicación se adapte a la topología del hardware.

MPI permite al vendedor de hardware desarrollar rutinas de topología especializadas a través de la implementacióon de las funciones de MPI de topología.

Al elegir una “topología de la aplicación” o “topología virtual”, el usuario está diciendo como va a ser preponderantemente la comunicación. Sin embargo, como siempre, todos los procesos podrán comunicarse entre sí.

Page 170: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

La topología virtual más simple (y usada corrientemente en aplicaciones numéricas) es la “cartesiana”.

En la forma en que lo describimos hasta ahora, usaríamos una topología cartesiana 1D, pero en realidad el problema llama a una topología 2D. También hay topologías cartesianas 3D, y de dimensión arbitraria

Page 171: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

En la topología cartesiana 2D a cada proceso se le asigna una tupla de dos números (I; J). MPI provee una serie de funciones para definir, examinar y manipular estas topologías.

La rutina MPI_Cart_create(...) permite definir una topología cartesiana 2D.

MPI-Cart-create(MPI-Comm comm-old, int ndims,2 int *dims, int *periods, int reorder, MPI-Comm *new-comm);

dims: vector que contiene el número de filas/columnas en cada dirección.periods: un vector de flags que indica si una dirección dada es periódica o no.reorder: El argumento bool reorder activado quiere decir que MPI puede reordenar los procesos de tal forma que optimice la relación entre la topología virtual y la de hardware.

Page 172: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

Ejemplo:

…int dims[2]={4,4}, periods[2]={0,0};MPI-Comm comm2d;MPI-Cart-create(MPI-COMM-WORLD,2,dims, periods, 1, comm2d); …

Page 173: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

Ejemplos de topologías virtuales:

Page 174: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

MPI_Cart_get() permite recuperar las dimensiones, periodicidad y coordenadas (dentro de la topología) del proceso.

int MPI-Cart-get(MPI-Comm comm, int maxdims, int *dims, int *periods, int *coords );

Con MPI_Cart_coords() se pueden conseguir directamente sólo la tupla de coordenadas del proceso en la topología.

int MPI_Cart_coords(MPI-Comm comm,int rank, int maxdims, int *coords);

Page 175: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

Antes de hacer una operación de actualización uk uk+1 , tenemos que actualizar los ghost values.

Por ejemplo, con una topología 1D:

Enviar e-1 a P+1Recivir e de P+1Enviar s a P-1Recivir s-1 de P-1

Page 176: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

En general se puede ver como que estamos haciendo un “shift” de los datos hacia arriba y hacia abajo.

Esta es una operación muy común y MPI provee una rutina (MPI_Cart_shift()) que calcula los rangos de los procesos para una dada operación de shift:

int MPI-Cart-shift(MPI-Comm comm,int direction,int displ,int *source,int *dest);

Por ejemplo, en una topolog´ıa 2D, para hacer un shift en la dirección horizontal

int source-rank, dest-rank;MPI-Cart-shift(comm2d,0,1,

&source-rank,&dest-rank);

Page 177: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

Que ocurre en los bordes? Si la topología es de 5x5, entonces un shift en la direccion 0 (eje x) con desplazamiento displ = 1 para el proceso (4; 2) da

Page 178: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

MPI_PROC_NULL es un “proceso nulo”. La idea es que enviar a MPI_PROC_NULL equivale a no hacer nada (como el /dev/null de Unix).

Una operación como

MPI-Send(. . .,dest,. . .)

equivaldría a

if (dest != MPI-PROC-NULL) MPI-Send(. . .,dest,. . .);

Page 179: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

Si el número de filas a procesar n-1 es múltiplo de size, entonces podemos calcular el rango [s,e) de las filas que se calculan en este proceso haciendo

s = 1 + myrank*(n-1)/size;e = s + (n-1)/size;

Si no es múltiplo podemos hacer:

// All receive ‘nrp’ or ’nrp+1’// First ‘rest’ processors are assigned ’nrp+1’nrp = (n-1)/size;rest = (n-1) % size;s = 1 + myrank*nrp+(myrank<rest? myrank : rest);e = s + nrp + (myrank<rest);

Page 180: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales

MPI provee una rutina MPE_Decomp1d() que hace esta operación.

int MPE-Decomp1d(int n,int size,int rank,int *s,int *e);

Si el peso de los procesos no es uniforme, entonces podemos aplicar el siguiente algoritmo.

– Queremos distribuir n objetos entre size procesos proporcionalmente a weights[j] (normalizados).

– A cada procesador le corresponden en principio weights[j]*n objetos, pero como esta cuenta puede dar no entera reparamos en

weights[j]*n = floor(weights[j]*n) + carry;

– Recorremos los procesadores y vamos acumulando carry, cuando llega a uno, a ese procesador le asignamos un objeto más.

Page 181: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales. Ejemplo

Por ejemplo, queremos distribuir 1000 objetos en 10 procesadores con pesos:

in [0] weight 0.143364, wants 143.364373, assigned 143in [1] weight 0.067295, wants 67.295034, assigned 67in [2] weight 0.133623, wants 133.623150, assigned 134in [3] weight 0.136241, wants 136.240810, assigned 136in [4] weight 0.155558, wants 155.557799, assigned 156in [5] weight 0.033709, wants 33.708929, assigned 33in [6] weight 0.057200, wants 57.200313, assigned 57in [7] weight 0.131086, wants 131.085889, assigned 132in [8] weight 0.047398, wants 47.397738, assigned 47in [9] weight 0.094526, wants 94.525966, assigned 95total rows 1000

Page 182: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales. Ejemplo

La siguiente función reparte n objetos entre size procesadores con pesos weights[].

void decomp(int n,vector<double> &weights,vector<int> &nrows) {int size = weights.size();nrows.resize(size);double sum-w = 0., carry=0., a;for (int p=0; p<size; p++) sum-w += weights[p];int j = 0;double tol = 1e-8;for (int p=0; p<size; p++) {

double w = weights[p]/sum-w;a = w*n + carry + tol;nrows[p] = int(floor(a));carry = a - nrows[p] - tol;j += nrows[p];

}assert(j==n);assert(fabs(carry) < tol);

}

Page 183: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPITopologías virtuales. Ejemplo

La siguiente función reparte n objetos entre size procesadores con pesos weights[].

void decomp(int n,vector<double> &weights,vector<int> &nrows) {int size = weights.size();nrows.resize(size);double sum-w = 0., carry=0., a;for (int p=0; p<size; p++) sum-w += weights[p];int j = 0;double tol = 1e-8;for (int p=0; p<size; p++) {

double w = weights[p]/sum-w;a = w*n + carry + tol;nrows[p] = int(floor(a));carry = a - nrows[p] - tol;j += nrows[p];

}assert(j==n);assert(fabs(carry) < tol);

}

Esto es hacer “balanceo estático” de carga

Page 184: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos

#include<mpi.h>

/* Run with 12 processes */

void main(intargc, char *argv[]) {int rank;MPI_Comm vu;int dim[2],period[2],reorder;int coord[2],id;

MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD,&rank);

dim[0]=4; dim[1]=3;period[0]=TRUE; period[1]=FALSE;reorder=TRUE;

Page 185: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos

MPI_Cart_create(MPI_COMM_WORLD,2,dim,period,reorder,&vu);if(rank==5){

MPI_Cart_coords(vu,rank,2,coord);printf("P:%dMy coordinates are %d %d\n",rank,coord[0],coord[1]);

}if(rank==0) {

coord[0]=3; coord[1]=1;MPI_Cart_rank(vu,coord,&id);printf("Theprocessor at position (%d, %d) has rank %d\n",coord[0],coord[1],id);

}MPI_Finalize();}

Page 186: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos

#include<mpi.h>

#define TRUE 1#define FALSE 0

void main(intargc, char *argv[]) {int rank;MPI_Comm vu;int dim[2],period[2],reorder;int up,down,right,left;

MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD,&rank);

dim[0]=4; dim[1]=3;period[0]=TRUE; period[1]=FALSE;reorder=TRUE;

Page 187: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIEjemplos

MPI_Cart_create(MPI_COMM_WORLD,2,dim,period,reorder,&vu);

if(rank==9){

MPI_Cart_shift(vu,0,1,&left,&right);

MPI_Cart_shift(vu,1,1,&up,&down);

printf("P:%dMy neighbors are r: %d d:%d 1:%d u:%d\n",rank,right,down,left,up);

}

MPI_Finalize();

}

Page 188: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

II. PROGRAMACIÓN CON PASO DE MENSAJES (MPI) Introducción Getting started Comunicaciones punto a punto Comunicaciones colectivas Tipos de datos derivados Comunicadores y grupos (Modularidad) Topologías vituales Introducción a MPI-2

Page 189: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Introducción

MPI-1 se creó para agrupar las diferentes liberías de paso de mensajes bajo una misma sintaxis

MPI-2 añade nuevas funcionalidades requeridas por los programadores:

– Mejoras y extensiones a MPI-1– Gestión dinámica de procesos– Acceso remoto a memoria– Entrada/Salida paralela– Interacción con threads– Interoperabilidad con lenguajes– …

Page 190: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

E/S Paralela

Se puede ver como una versión avanzada de la E/S de Unix:

– Acceso no contiguo a memoria y ficheros– Operaciones colectivas de E/S– Uso de offsets explícitos para evitar seeks separados– Punteros individuales y compartidos a ficheros– E/S no bloqueante– Representaciones de datos portables y personalizados

Page 191: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

E/S Paralela

Page 192: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

E/S Paralela

Page 193: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

E/S Paralela

Page 194: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

E/S Paralela

Page 195: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

E/S Paralela

Page 196: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

E/S Paralela

Page 197: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Acceso remoto a memoria

MPI-1 provee una completa interfaz para el paso de mensajes.

MPI-2, además, permite acceder directamente a la memoria de otros procesos.

Va a usar operaciones del tipo get, put y update para acceder a datos remotos.

Es eficiente y portable para diferentes arquitecturas

Page 198: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Acceso remoto a memoria

Tres pasos principales:

– Definir en el proceso qué memoria va a usarse para operaciones RMA. Se crea un objeto MPI_Win.

– Especificar qué datos se van a mover y a dónde. Se usan las operaciones MPI_Put, MPI_Get y MPI_Accumulate.

– Verificar que los datos se han recibido por completo. Se usa la función MPI_Win_fence. Otro método es usar MPI_Win_lock y MPI_Win_unlock.

Page 199: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Acceso remoto a memoria

Memory Windows (ventanas de memoria)

– Son los espacios de memoria reservados para ser usados en las operaciones de acceso remoto a memoria..

– Crea una ventana.

int MPI_Win_create(void *base, MPI_Aint size, int disp_unit, MPI_Info info, MPI_Comm comm, MPI_Win *win);

– Liberar una ventana. Sólo debe llamarse cuando han terminado todas las operaciones RMA.

int MPI_Win_free(MPI_Win *win);

– Ambas son operaciones colectivas, deben ser llamadas por todos los procesos involucrados.

Page 200: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Acceso remoto a memoria

Moviendo datos

– Pone datos en una ventana de memoria (no bloqueante)

int MPI_Put(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_blank, MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win);

– Obtiene datos de una ventana de memoria (no bloqueante)

int MPI_Get(void *origin_addr, int origin_count, MPI_Datatype origin_datatype,int target_rank, MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win);

Page 201: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Acceso remoto a memoria

Moviendo datos

– Actualiza los datos de una ventana de memoria

int MPI_Accumulate(void *origin_addr, int origin_count,

MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count,

MPI_Datatype target_datatype, MPI_Op op,

MPI_Win win);

– Completa una transferencia de datos

int MPI_Win_fence(int assert, MPI_Win win);

Page 202: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Acceso remoto a memoria

Page 203: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Acceso remoto a memoria

Page 204: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Gestión dinámica de procesos

En MPI-1 el número de procesos de COMM_WORLD es fijo durante toda la ejecución.

En MPI-2 podemos crear procesos usando la operación colectiva MPI_Comm_spawn

– Esta función devuelve un intercomunicador que desde el punto de vista de los ”padres”, agrupa a los padres, mientras que para los ”hijos” sería su propio COMM_WORLD.

Page 205: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Gestión dinámica de procesos

Intracomunicador: conjunto de procesos (MPI-1)

Intercomunicador: engloba 2 conjuntos de procesos (local y remoto). La idea existe en MPI-1, pero la especificación de operaciones colectivas en intercomunicadores aparece en MPI-2.

Page 206: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Gestión dinámica de procesos

Creación de procesos hijos

int MPI_Comm_spawn(char *command, char *argv[], int maxprocs, MPI_Info info, int root, MPI_Comm comm, MPI_Comm *intercomm, int array_of_errcodes[]);

Debe ser ejecutada por todos los procesos de comm

Obtiene el comunicador de los padres

int MPI_Comm_get_parent(MPI_Comm *parent);

Sólo ejecutado por los hijos

Page 207: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Gestión dinámica de procesos

Creación de múltiples procesos hijos

int MPI_Comm_spawn_multiple(int count,

char *array_of_commands[], char **array_of_argv[],

int array_of_maxprocs[], MPI_Info array_of_info[], int root,

MPI_Comm comm, MPI_Comm *intercomm,

int array_of_errcodes[]);

Page 208: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Gestión dinámica de procesos

Filosofía cliente/servidor

Page 209: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Gestión dinámica de procesos

Filosofía cliente/servidor

Page 210: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

II. MPIIntroducción a MPI-2

Entorno de ejecución

Lam

Mvapich

Openmpi

Mpich2 pero no mpich (mpich2 no esta en EULER)

Page 211: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

i. PROGRAMACIÓN EN ENTORNO CLUSTER

ii. PROGRAMACIÓN CON PASO DE MENSAJES (MPI)

iii. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OpenMP)

Page 212: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

III. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OMP)

Introducción Conceptos básicos Paralelismo de datos Directivas OMP Regiones paralelas Run-Time library

Page 213: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

III. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OMP)

Introducción Conceptos básicos Paralelismo de datos Directivas OMP Regiones paralelas Run-Time library

Page 214: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPIntroducción

El OpenMP Application Program Interface (API) es:

Conjunto de directivas de compilacion, librerías y variables de entorno que permiten expresar el paralelismo de tareas en programas escritos en C, C++ y Fortran

Toda la información está disponible en la página web: www.openmp.org

Page 215: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPIntroducción

El estándar es definido y revisado por el comité OpenMP Architecture Review Board compuesto actualmente por:

– U.S. DoD: Aeronautical Systems Center– cOMPunity (Comunidad de usuarios de OpenMP)– Edinburgh Parallel Computing Centre (EPCC)– Laboratorio NASA Ames– ST Microelectronics: The Portland Group– Fujitsu– Hewlett Packard– International Business Machines (IBM)– Intel Corporation– KAI Software Lab (KSL)– NEC Corporation– Silicon Graphics Inc. (SGI)– Sun Microsystems– Universidad RWTH Aachen

Page 216: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPIntroducción

Antes de la introducción de OpenMP cada fabricante tenía su propio “estándar”

– Los programas tenían portabilidad nula

– El estándar ANSI X3H5 fracasó por falta de apoyo

– Se perdió interés en las máquinas SMP

El estándar OpenMP se introdujo para resolver esto:– En 1997 se publicó la versión 1.0– En 1999 se publicó la versión 1.1– En 2000 se publicó la versión 2.0– En 2005 se publicó la versión 2.5

Page 217: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPIntroducción

OpenMP se fundamenta en directivas y cláusulas:– Las directivas especifican qué hacer– Las cláusulas indican cómo hacerlo– Se añaden como comentarios al código

Tipos de directivas en OpenMP:– Directivas de distribución de trabajo– Directivas de sincronización de tareas

Tipos de cláusulas en OpenMP:– Cláusulas de datos– Cláusulas de comportamiento– Cláusulas de sincronía

Page 218: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPIntroducción

Ventajas de OpenMP:

– Sencillo: no requiere el envío explícito de mensajes como en MPI– La descomposición de los datos es automática– Admite la paralelización incremental del código– Mismo código fuente para las versiones serial y paralela– Permite implementar granularidad gruesa y fina– Elevada portabilidad

Page 219: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPIntroducción

Inconvenientes de OpenMP:

– Requiere un compilador que entienda OpenMP– El estándar sólo contempla C y Fortran– Sólo es eficiente en máquinas de memoria compartida– En general la eficiencia paralela es baja– La escalabilidad está limitada por el acceso a memoria– Aumentar la eficiencia requiere reestructurar el código

Page 220: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPIntroducción

Compiladores que soportan OpenMP– SGI MIPSpro– IBM XL– Sun Studio– Portland Group Compilers and Tools– Absoft Pro FortranMP– Lahey/Fujitsu Fortran 95– Fujitsu-Siemens Fortran 95 (Solaris)– Intel Software Development Products– PathScale– GNU GCC (a partir de la versión 4.2)– HP

Page 221: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPIntroducción

El soporte para OpenMP ha de ser activado

– Versión serial de un programa:

ifort ejemplo.f90– Versión paralela de un programa:

ifort -openmp ejemplo.f90

En casi todos los compiladores la opción es -openmp

Page 222: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

III. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OMP)

Introducción Conceptos básicos Paralelismo de datos Directivas OMP Regiones paralelas Run-Time library

Page 223: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Un programa secuencial es un caso especial de un programa de memoria compartida

Paralelización incremental es el proceso de convertir un programa secuencial a un programa paralelo poco a poco

Las iteraciones de un bucle for se pueden ejecutar en paralelo si ninguna iteración depende de otra anterior.

Ejemplos: for (i=first;i<size;i += prime) marked[i]=1

for (i=1;i<=n;i++) suma += suma + v[i]

III. OpenMP Conceptos básicos

Page 224: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPConceptos básicos

DO / for – iteraciones compartidas de un bucle por el equipo.

Representa un tipo de “paralelismo de datos".

SECTIONS – particiona el trabajo ensecciones separadas.

Cada sección es ejecutada por un hilo.Se puede utilizar para implementar un

tipo de “paralelismo funcional”

SINGLE – serializa unasección de código

Page 225: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Una pragma, en C o C++, es una directiva al compilador.

La sintaxis es

#pragma omp <el resto de la pragma>

Ejemplo:

#pragma omp parallel for

le dice al compilador que trate a paralelizar el bucle for que sigue, por tanto, el compilador tiene que verificar que cuando se ejecuta, habrá disponible la información necesaria para llevar a cabo las iteraciones

III. OpenMP Conceptos básicos

Page 226: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Ejemplo #include <omp.h>

#include <stdio.h>

int main (int argc, char *argv[]) {

int p,th_id;

p=omp_get_num_procs();

omp_set_num_threads(p);

#pragma omp parallel private(th_id);

{

th_id = omp_get_thread_num();

printf("Hello World from thread %d\n", th_id);

}

return 0;

}

III. OpenMP Conceptos básicos

Page 227: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

El contexto de ejecución– Todo hilo tiene un contexto de ejecutación, que consiste en

el espacio de direcciones que el hilo puede acceder– El contexto de ejecutación incluye variables estáticas,

estructuras dinámicamente asignadas, etc

III. OpenMP Conceptos básicos

Page 228: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

III. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OMP)

Introducción Conceptos básicos Paralelismo de datos Directivas OMP Regiones paralelas Run-Time library

Page 229: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

Características generales de cláusulas de datos:– Especifican propiedades “paralelas” de las variables– Pueden aparecer tantas veces como sea necesario– Pueden usarse con cualquier directiva OpenMP

Restricciones generales de cláusulas de datos:– Una variable no puede aparecer en más de una cláusula– Sólo admiten variables que sean visibles desde la subrutina o

función que incluya la cláusula

Page 230: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Variables compartidas y Variables privadas– Una variable compartida tiene la misma dirección en el

contexto de ejecutación de cada hilo.– Una variable privada tiene una dirección distinta en el

contexto de ejecutación de cada hilo.– Un hilo no puede acceder a las variables privadas de otro

hilo.

III. OpenMP Paralelismo de datos

Page 231: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

La cláusula SHARED– Especifica que una variable es compartida por las tareas:

#pragma omp parallel for SHARED( c,d)

o

! $OMP PARALLEL SHARED (c,d)

...

! $OMP END PARALLEL

Page 232: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

La cláusula SHARED– Características de las variables compartidas:

o Todas las tareas ven su contenidoo Todas las tareas pueden cambiar su contenidoo Todas las tareas ven los cambios realizados

– Peculiaridades de las variables compartidas:o Los cambios no son inmediatos (cache coherency)o Pueden requerir de sincronía entre tareaso Existen algunas limitaciones en Fortran

Page 233: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

La cláusula PRIVATE– Especifica que una variable es privada a cada tarea:

#pragma omp parallel for PRIVATE(a,b )

o

! $OMP PARALLEL PRIVATE (a,b)

...

! $OMP END PARALLEL

Page 234: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

La cláusula PRIVATE– Características de las variables privadas:

o Cada tarea tiene su propia versión de la variableo Eso se consigue replicando la variable en memoriao Las otras tareas no pueden ver su contenido

– Peculiaridades de las variables privadas:o Su valor inicial no está definidoo Tras la región paralela su valor tampoco está definidoo Existen algunas limitaciones

Page 235: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Variables privadas

for (i = 0; i < BLOCK_SIZE(id,p,n); i++)

for (j = 0; j < n; j++)

a[i][j] = MIN(a[i][j],a[i][k]+tmp[j]);

– Cualquier de los bucles se podria ejecutar en paralelo– Es mejor paralelizar el bucle exterior para reducir el número de forks/joins– Todas las variables excepto el indice son compartidas.

– Deberiamos dar cada hilo su copia privada de j

III. OpenMP Conceptos básicos

Page 236: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Variables privadas

#pragma omp parallel for private(j)#pragma omp parallel for private(j)

for (i = 0; i < BLOCK_SIZE(id,p,n); i++)

for (j = 0; j < n; j++)

a[i][j] = MIN(a[i][j],a[i][k]+tmp[j]);

– Cualquier de los bucles se podria ejecutar en paralelo– Es mejor paralelizar el bucle exterior para reducir el número de forks/joins– Todas las variables excepto el indice son compartidas.

– Deberiamos dar cada hilo su copia privada de j

III. OpenMP Conceptos básicos

Page 237: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

La cláusula DEFAULT– Especifica el comportamiento por defecto:

#pragma omp parallel for DEFAULT( PRIVATE ) SHARED (a)

o

! $OMP PARALLEL DEFAULT ( PRIVATE ) SHARED (a)...! $OMP END PARALLEL

Page 238: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

La cláusula DEFAULT– Características de la cláusula:

o Sólo puede aparecer una única vez en cada directivao Admite tres opciones: PRIVATE, SHARED y NONEo Con NONE todas las variables deben ser definidaso Sólo afecta a las variables directamente visibles:o Las variables definidas dentro de la subrutina ejemplo no se ven

afectadas por la cláusula DEFAULT

Page 239: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

firstprivate()– Es una extensiónd e la cláusula PRIVATE– Se usa para crear una variable privada que tiene su valor inicial

igual al valor de la variable controlada por el hilo maestro cuando se entra el bucle.

– Si un hilo cambia el valor de una variable en alguna iteración, entonces este valor será el valor de la variable en iteraciones subsecuentes

III. OpenMP Conceptos básicos

Page 240: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

firstprivate()x[0] = complex_function();

for (i-0;j<n;i++)

{

for (j=1;j<4;j++)

x[j]=g(I,x[j-1]);

answer[i] = x[i] – x[j];

}

Se puede hacer el bucle exterior paralelo si hacemos j y x privadas. Sin

embargo, x[0] se necesita en la primera iteración del bucle interior.

III. OpenMP Conceptos básicos

Page 241: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

firstprivate()– Se podría mover la inicialización de x[0] dentro del bucle anterior, pero es caro.– Mejor:

x[0] = complex_function();

#pragma op parallel for private[j] firstprivate(x)

for (i-0;j<n;i++)

{

for (j=1;j<4;j++)

x[j]=g(I,x[j-1]);

answer[i] = x[i] – x[j];

}

III. OpenMP Conceptos básicos

Page 242: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

La cláusula FIRSTPRIVATE– Características de las variables FIRSTPRIVATE:

o Cada tarea tiene su propia versión de la variableo Eso se consigue replicando la variable en memoriao Las otras tareas no pueden ver su contenidoo Su valor es inicializado con la variable original

– Peculiaridades de las variables FIRSTPRIVATE:o Tras la región paralela su valor no está definido

Page 243: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

La cláusula LASTPRIVATE– La cláusula se usa para copiar el valor privado del hilo que ejecutó la

última iteración a la copia del hilo maestro

III. OpenMP Conceptos básicos

Page 244: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPParalelismo de datos

Resumen de cláusulas de datos– Cláusulas de datos vistas:

o SHARED, PRIVATE, DEFAULT, FIRSTPRIVATE

– Cláusulas de datos adicionales:o LASTPRIVATE, REDUCTION, COPYIN, COPYPRIVATE

– Condiciones generales a tener en cuenta:o Una variable sólo puede aparecer en una cláusula, salvo en

FIRSTPRIVATE y LASTPRIVATE, a la vezo El contador de un bucle siempre es privadoo Cada cláusula tiene sus limitaciones

Page 245: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

III. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OMP)

Introducción Conceptos básicos Paralelismo de datos Directivas OMP Regiones paralelas Run-Time library

Page 246: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPDirectivas distribución de trabajo

Características de estas directivas:– Distribuyen una carga de trabajo sobre varias tareas– No crean nuevas tareas, usan las ya existentes– Funcionan en regiones seriales y en regiones paralelas– Incluyen al final una sincronización implicita

Restricciones de estas directivas:– Deben ser encontradas por todas las tareas– Sólo pueden contener bloques estructurados de código

Page 247: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPDirectivas distribución de trabajo

La directiva PRAGMA OMP PARALLEL FOR– Características de la directiva:

o Distribuye la carga de un bucle entre las tareaso La descomposición se hace en el espacio de iteracioneso El contador es implícitamente declarado PRIVATE

– Restricciones :o En C, el bucle debe ser de un tipo determinadoo En Fortran, el bucle no puede ser del tipo do whileo El contador debe ser el mismo para todas las tareaso Sólo admite bloques estructurados de códigoo Las variables SHARED sólo se actualizan al final

Page 248: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

La directiva PRAGMA OMP PARALLEL SECTION– Hasta ahora hemos considerado paralelismo de data nada

más– OpenMP nos permite asignar hilos distintos a partes

distintas del código (paralelismo funcional)– Permite implementar el paralelismo tipo MIMD– Precede a un bloque de k bloques de código que se puede

ejecutar en paralelo por k hilos– La sintaxis:

#pragma omp parallel sections

III. OpenMPDirectivas distribución de trabajo

Page 249: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

v = alpha(); w = beta(); x = gamma(v, w); y = delta(); printf ("%6.2f\n", epsilon(x,y));

a lp h a b e ta

g am m a d elta

ep s ilo n

Se puede ejecutaralpha, beta, and deltaen paralelo.

III. OpenMPDirectivas distribución de trabajo

Page 250: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

La directiva PRAGMA OMP SECTION– Precede cada bloque de código dentro del bloque grande – Se puede omitir para el primer bloque después de la

pragma parallel sections – La sintaxis:

#pragma omp section

III. OpenMPDirectivas distribución de trabajo

Page 251: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

•Ejemplo de parallel section

#pragma omp parallel sections{

#pragma omp section /* Optional */ v = alpha();

#pragma omp section w = beta();

#pragma omp section y = delta();}x = gamma(v, w);printf ("%6.2f\n", epsilon(x,y));

III. OpenMPDirectivas distribución de trabajo

Page 252: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Otra Posibilidad

a lp h a b e ta

g am m a d elta

ep s ilo n

Ejecutar alpha ybeta en paralelo.Ejecutar gama ydelta en paralelo.

III. OpenMPDirectivas distribución de trabajo

Page 253: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

La directiva PRAGMA OMP SECTIONS– Aparece a dentro de un bloque paralelo de código– Tiene el mismo significado como la pragma parallel

sections – Varias pragmas sections dentro de un bloque paralelo

podría reducir los gastos de fork/join

– Restricciones de la directiva:o La manera de asignar secciones a tareas no está

definidao Cada sección debe ser un bloque estructurado de

códigoo No se crean nuevas tareas, se usan las existenteso Las variables SHARED sólo se actualizan al final

III. OpenMPDirectivas distribución de trabajo

Page 254: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

#pragma omp parallel { #pragma omp sections { v = alpha(); #pragma omp section w = beta(); } #pragma omp sections { x = gamma(v, w); #pragma omp section y = delta(); } } printf ("%6.2f\n", epsilon(x,y));

III. OpenMPDirectivas distribución de trabajo

Page 255: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

III. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OMP)

Introducción Conceptos básicos Paralelismo de datos Directivas OMP Regiones paralelas Run-Time library

Page 256: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPRegiones paralelas

Para crear regiones paralelas se utilizan las directivas #PRAGMA OMP PARALLEL :

– Definen una región paralela– crea un conjunto de tareas– Las cláusulas especifican condiciones a cumplir– Todas las tareas ejecutan las instrucciones

Page 257: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPRegiones paralelas

Hay tres formas de especificar el número de tareas– La variable de entorno OMP_NUM_THREADS:

export OMP_NUM_THREADS=4

– La subrutina omp_set_num_threadsvoid omp_set_num_threads(int t);

La cláusula NUM_THREADS:#PRAGMA OMP PARALLEL NUM_THREADS (4)

Cada una de ellas sobreescribe la especificación anterior

Page 258: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPRegiones paralelas

Características de la cláusula IF:

– Crear una región paralela es algo costoso– La opción condition permite sopesarlo:

o Si condition = TRUE entonces ejecuta en paraleloo Si condition = FALSE entonces ejecuta en serie

– Sólo se puede imponer una condición#PGRAMA OMP PARALLEL IF( condition )

... instructions ...

Page 259: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

ÍNDICE

III. PROGRAMACIÓN CON PARALELISMO IMPLÍCITO (OMP)

Introducción Conceptos básicos Paralelismo de datos Directivas OMP Regiones paralelas Run-Time library

Page 260: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

RUTINAS DE CONTROL

– Función omp_get_num_procso Devuelve el número de procesadores fisicos que están

dispondible para el uso del programa paralelo

int omp_get_num_procs(void)

– Función omp_set_num_threadso Se usa para asignar el número de hilos a ser activos en

secciones paralelas del códigoo Se puede llamar en varios puntos del programa

void omp_set_num_threads(int t)

III. OpenMPRun-Time Library

Page 261: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

– Función omp_get_num_procso Devuelve el número de procesadores fisicos que están dispondible

para el uso del programa paralelo

int omp_get_num_procs(void)– Función omp_set_num_threads

o Se usa para asignar el número de hilos a ser activos en secciones paralelas del código

o Se puede llamar en varios puntos del programa

void omp_set_num_threads(int t)– Función omp_get_thread_num

o Todo hilo tiene una identificación que es el número del hilo

omp_get_thread_num()devuelve el número del hilo

III. OpenMPRun-Time Library

Page 262: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPRun-Time Library

Rutinas cerrojo– Herramienta adicional para la sincronización de tareas:

o Permite introducir cerrojos (“locks”) en el códigoo Un cerrojo puede estar echado o no echadoo Un cerrojo no echado puede ser echado por una tareao La tarea pasa entonces a poseer el cerrojoo Las tareas no pueden alterar cerrojos que no poseen

– Existen dos tipos de cerrojos:o cerrojos simples: sólo pueden echarse una vezo cerrojos anidables: pueden echarse más de una vez

Page 263: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPRun-Time Library

Rutinas de cronometraje– Permiten medir tiempos de ejecución de manera portable:

o Proporcionan el wall clock time de cada tareao El origen de tiempos no es el comienzo del programao El tiempo proporcionado no es consistente entre tareaso Para determinar el tiempo de ejecución:

Time_Seconds = omp_get_wtime ()o Para determinar la precisión del cronómetro:

Seconds_per_Tick = omp_get_wtick ()

Page 264: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPRecomendaciones

Recomendaciones – Revisar el estándar a la hora de programar con OpenMP– Buscar sencillez y no optar por soluciones rebuscadas– Especificar el número de tareas con OMP NUM THREADS– Usar las cláusulas de datos sólo con PARALLEL– Declarar todas las variables como SHARED y sólo las mínimas

necesarias como PRIVATE– No usar directivas combinadas de distribución de trabajo– No escribir a disco desde una región paralela

Page 265: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPEjemplos

Calcular el valor de la integral usando una suma de rectángulos:

Page 266: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

III. OpenMPEjemplos

Page 267: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Agradecimientos

Oscar FloresUniversidad Politécnica de Madrid

Miguel Hermanns Universidad Politécnica de Madrid Mario Storti

Centro Internacional de Métodos Numéricos en Ingeniería – CIMEC Argentina

Manuel Martín Salvadorhttp://draxus.org

José Miguel AlonsoFacultad de Informática UPV/EHU

Page 268: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Agradecimientos

Guillermo Marshall

Laboratorio de Sistemas Complejos, Departamento de Computacion, FCEyN, UBA.

Luis Miguel de la Cruz

Unidad de Investigación en Cómputo Aplicado, DGSCA-UNAM.

Page 269: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

Bibliografía

http://www.intel.com/software/products http://www.openmp.org/drupal/ http://www-unix.mcs.anl.gov/mpi/ http://www.gnu.org/ http://www.gnu.org/manual/ddd/ http://www.fing.edu.uy

Page 270: PROGRAMACIÓN CON  MPI  Y  OPENMP EN EL CLUSTER  EULER

PROGRAMACIÓN CON MPI Y OPENMP

EN EL CLUSTER EULER

____________________________________________Angelines Alberto MorillasTelf. +34 91 346 6025Divisón de Supercomputación y Desarrollo GridCIEMATAvenida Complutense, 2228040 Madrid____________________________________________