You are on page 1of 270

PROGRAMACIN CON

MPI Y OPENMP
EN EL CLUSTER EULER
____________________________________________
Angelines Alberto Morillas
Telf. +34 91 346 6025
Divisn de Supercomputacin y Desarrollo Grid
CEMAT
Avenida Complutense, 22
28040 Madrid
____________________________________________
NDICE
i. PROGRAMACN EN ENTORNO CLUSTER EULER
ii. PROGRAMACN CON PASO DE MENSAJES (MP)
iii. PROGRAMACN CON PARALELSMO MPLCTO
(OpenMP)
NDICE
i. PROGRAMACN EN ENTORNO CLUSTER EULER
ii. PROGRAMACN CON PASO DE MENSAJES (MP)
iii. PROGRAMACN CON PARALELSMO MPLCTO
(OpenMP)
NDICE
I. PROGRAMACIN EN ENTORNO CLUSTER EULER

Caractersticas

Conexin a EULER

So!t"are en EULER

Co#$i%a&ores

O$ti#i'acin

De$(racin &e Errores

Pro)ra#acin $ara%e%a

E*ec(cin $ara%e%a
I. CLUSTER EULER
Caractersticas.

En su configuracin actual dispone de 146 nodos ntel(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.

Adems dispone de dos nodos para acceso interactivo y dos


nodos de gestin

Todos los nodos se han interconectado a una red de alta


velocidad nfiniband que se utilizar para la comunicacin entre
los procesos que colaboran en los trabajos paralelos MP.
I. CLUSTER EULER
Caractersticas.

El cluster est basado en el sistema operativo linux (Red Hat


Enterprise).

Dispone las herramientas habituales de software libre.

Existen dos nodos que actan como frontend para que los
usuarios puedan conectarse en forma interactiva.

El resto de los nodos actan como servidores de clculo


accesibles slo a travs del entorno batch.
I. CLUSTER EULER
Conexin a EULER.

Para conectarse desde un desktop basado en MS +in&o"s,CENIT


se dispone de un cliente ssh llamado PUTTY
(Z:\P32\PUTTY\PUTTY.EXE)

Tambin se puede utilizar el emulador de ventanas X llamado


Exceed. (http
://intranet.ciemat.es/CEMATportal/portal.do?TR=A&DR=1&identifi
cador=1679
)

En desktop basado en Lin(x basta utilizar el cliente habitual ssh.


Ejemplos:
ss- e(%er
ss- .! ./ e(%er )no#e.ter#ina%
I. CLUSTER EULER
So!t"are en EULER.

Siste#a O$erati0o

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


herramientas grficas de administracin, planificador de
procesamiento paralelo, distribucin dinmica de procesos, etc.

Co#$i%a&ores

Se han instalado los dos grupos de compiladores ms usuales


en estas plataformas:
o
GNU: Compiladores de Fortran 90, C y C++ .
Se han instalado dos versiones de los compiladores:

la versin 3.4 (comandos gcc, g++ y g77)

la versin 4.1 (comandos gcc4, g++4 y gfortran).


o
Inte%: Compiladores de Fortran, C y C++ versin 10.1.
I. CLUSTER EULER
So!t"are en EULER.

Herramientas para desarrollo de aplicaciones paralelas:

MPI: (Message Passing nterface), el estndar de facto para


programacin con paso de mensajes explcitos.

O$enMP: Es una AP (Application Program nterface) basada en


directivas, rutinas y variables de entorno que facilita la
paralelizacin en arquitecturas de memoria compartida.
Est integrada en los co#$i%a&ores &e Inte%, y se accede con un
simple flag.

Uti%i&a&es &e so!t"are $12%ico:

La mayor parte de la coleccin de software de GNU. Se instalar


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

Siste#a &e )estin &e 2ac- y planificacin basado en Torque/Moab.


I. CLUSTER EULER
Co#$i%a&ores.

La mquina dispone de compiladores de Fortran, C y C++, tanto de


Inte% como de GNU, que se pueden invocar con los siguientes
comandos:
i!ort .o $ro) $ro).!34 56ortran 347 co#$i%a&or &e Inte%8
)99 .o $ro) $ro).! 56ortran 997 co#$i%a&or &e GNU8
)!ortran .o $ro) $ro).!34 56ortran 347 co#$i%a&or &e GNU8
icc .o $ro) $ro).c 5C7 co#$i%a&or &e Inte%8
)cc,)cc: .o $ro) $ro).c 5C7 co#$i%a&or &e GNU8
ic$c .o $ro) $ro).cc 5C;;7 co#$i%a&or &e Inte%8
);;,);;: .o $ro) $ro).cc 5C;;7 co#$i%a&or &e GNU8
I. CLUSTER EULER
Co#$i%a&ores.

En caso de utilizar los compiladores de ntel es necesario aadir los


directorios correspondientes al "PATH y al "LD_LB 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
I. CLUSTER EULER
O$ti#i'acin &e Inte%

Los flags (opciones) ms comunmente utilizados al invocar el compilador de


Fortran de ntel, en general para optimizar cdigo y conseguir que se ejecute
ms rpidamente, son los siguientes

6%a)s $ara o$ti#i'acin<


o
.O4: Sin optimizacin.
o
.O=: Optimizacin local.
o
.O>,-O: Optimizacin extensiva. Es el defecto.
o
.O?: Ejecuta ms SWP, prefetching, reogarnizacin de loop, etc.
o
.i$: intra-file/inter-file interprocedural optimization.
o
.$ro!@)en,.$ro!@(se: optimizacin con feedback; til si se tienen un buen
conjunto de pruebas.
o
.!no.a%ias7 .!no.!na%ias: Mejor optimizacin al indicar el uso de punteros sin
utilizar aliasing.
o
.o$t@re$ort: Genera un reporte de la optimizacin.
o
.!t': fija underflows a cero, evitando traps del kernel (habilitado por defecto
en -03).
I. CLUSTER EULER
O$ti#i'acin &e Inte%

Una regla prctica a seguir es Intentar al menos "-O2" en todas las


rutinas. Tratar de compilar las rutinas que ms 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. Adems aumentar el tiempo de compilacin, por lo que
no conviene utilizar estos flags cuando se est desarrollando.
I. CLUSTER EULER
O$ti#i'acin &e Inte%

6%a)s &e $ara%e%i'acin:


o
$ara%%e%: AutoParalelizacin. Convierte de forma a utomtica cdigo
secuencial en paralelo por medio de directivas.
o
o$en#$: Hace que el compilador reconozca las directivas OpenMP.

6%a)s $ara !aci%itar e% $ortin) A &e2() &e c&i)os:


o
-$osix%i2: Funciones de EEE* POSX FORTRAN-77 Language
bindings, como especficado en EEE Standard 1003.9-1992.
o
-iB: Representacin interna de enteros en 64 bits (8 bytes).
o
-rB: Representacin interna de reales y complejos en 64 bits.
o
-'ero: nicializa variables a 0.
o
-): Genera cdigo apto para depurar (debug).
o
-save: Colocacin de variables en memoria esttica.
I. CLUSTER EULER
De$(racin &e errores

Para el "debugging" de cdigo disponemos de diferentes


herramientas que nos ayudan a encontrar fallos en el cdigo fuente:

De2())er &e Inte% 5i&28<

Soporta Fortran, C y C++. Tiene una interface basada en lnea de


comandos. Se invocacon el comando "idb seguido del nombre del
ejecutable. Adems, idb cuenta con una interfaz grfica, para ello,
se invoca con el flag "-gui. Ejemplos:
i&2 a.o(t 5#o&o %nea8
i&2 .)(i a.o(t 5#o&o )rC!ico en / "in&o"8

De2())er &e GNU 5)&28<

GNU debugger. Soporta C y C++ y Fortran. Tambin es un


depurador en modo lnea, y por lo tanto se utiliza poco.
I. CLUSTER EULER
De$(racin &e errores

Data Dis$%aA De2())er 5&&&8<


o
Es uninterfaz grfico para gdb y otros debuggers (incluido el de
intel).
o
Funciona bajo X Window ya que se trata de una herramienta grfica.
o
Para iniciar un ciclo de depuracin (debug) se debe compilar el
cdigo con el flag "-g", que inhibe parcialmente la optimizacin y
genera informacin simblica en el cdigo ejecutable para el
debugger, esencialmente los nmeros de lneas correspondientes
entre fuente y ejecutable:
ifort -g -o prog.exe prog.f (Fortran)
icc -g -o prog.exe prog.c (C)
o
A continuacin se invoca al debugger:
ddd prog.exe
o
Aparecer una ventana X en la q ue podemos realizar las
operaciones necesarias para la depuracin de nuestro cdigo. Una
forma sencilla de empezar consiste en pisar el botn "Run" que
inicia la ejecucin y esperar a ver en qu lnea se muere nuestro
programa.
I. CLUSTER EULER
Pro)ra#acin $ara%e%a

O$enMP

Se pueden compilar y ejecutar programas que utilicen directivas


OpenMP, utilizando los compiladores de ntel.

Se dene compilar el cdigo con el flag " -openmp".

Antes de ejecutar se debe declarar la variable de entorno


"OMP_NUM_THREADS" con el nmero de procesadores que
deseemos:
ifort -openmp prog.f -o prog.exe
setenv OMP_NUM_THREADS 4 (csh)
export OMP_NUM_THREADS=4 (sh)
prog.exe
I. CLUSTER EULER
Pro)ra#acin $ara%e%a

MPI

La mquina dispone de varias implementaciones de la librera


MP que pueden utilizarse segn conveniencia.

La motivacin de tener varias implementaciones es ayudar a los


usuarios en los problemas relacionados con la portabilidad de
cdigos.

Existen cdigos de clculo basados en MP fciles de portar a la


plataforma con una determinada implementacin y no con otras.
El usuario debe elegir cual de ellas es mejor para su cdigo.

Las implementaciones de la librera MP disponibles en nuestro


cluster son MPCH, MPCH2, LAM, OPENMP y MVAPCH.
I. CLUSTER EULER
Pro)ra#acin $ara%e%a

MPI

OPENMP parece ser la implementacin dominante ltimamente.

Otras implementaciones como MPCH2 y LAM/MP ofrecen la


ventaja de menores tiempos de latencia.

Las tres implementaciones de la librera que soportan


comunicaciones a travs de la red infiniband son MVAPCH,
MVAPCH2 y OPENMP.

La mayora de las aplicaciones paralelas pueden potencialmente


obtener mejores resultados en cuanto a velocidad y escalado
utilizando infiniband.

Las otras implementaciones darn menor rendimiento en la


mayor parte de los casos, pero estn instaladas por motivos de
portabilidad de software.
I. CLUSTER EULER
Pro)ra#acin $ara%e%a

MPI

Para ver la lista de implementaciones de MP disponibles


ejecutar el comando:
switcher mpi --list

En el momento de escribir este manual las opciones son las


siguientes:
lam-X.X.X
lam-intel-X.X.X
mpich-ch_p4-gcc-X.X.X
mpich-ch_p4-intel-X.X.X
openmpi-X.X.X
openmpi-intel-X.X.X
ib-mvapich-X.X.X-gcc
ib-mvapich-X.X.X-intel
ib-mvapich2-X.X.X-gcc
ib-mvapich2-X.X.X-intel
ib-openmpi-X.X.X-gcc
ib-openmpi-X.X.X-intel
I. CLUSTER EULER
Pro)ra#acin $ara%e%a

MPI

Se puede averiguar el mdulo cargado en en el perfil del usuario


con el siguiente comando:
switcher mpi

Para compilar y ejecutar programas con MP, tendremos que


tener en el "path los comandos adecuados y en el "library path
las libreras correspondientes.

El programador puede hacerlo del modo usual en UNX,


modificando las variables de entorno "PATH y
"LD_LBRARY_PATH, o con la utilidad "switcher.
I. CLUSTER EULER
Pro)ra#acin $ara%e%a

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 configuracin y el


segundo lo carga para actualizar las variables de entorno.

Una vez elegida la implementacin de MP que se va a utilizar,


ya se dispone en el PATH de las utilidades necesarias para
compilar y ejecutar aplicaciones.

Actualmente es necesario ejecutar tambin el comando:


mpi-selector-menu (elegir la opcin adecuada)
I. CLUSTER EULER
Pro)ra#acin $ara%e%a

MPI

La compilacin se realiza utilizando los comandos "mpif90,


"mpcc y "mpicxx que se encargan de invocar a los
compiladores y aadir los flags para las libreras propias de MP.

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

La ejecucin de una aplicacin MP depende de la


implementacin que se haya utilizado para compilarla. Lo usual
es utilizar los comandos "mpirun o "mpiexec.

Ejemplos:
mpirun -np 8 prog.exe
mpiexec -n 8 prog.exe

En la prctica estos comandos se utilizan en el entorno batch.


I. CLUSTER EULER
E*ec(cin $ara%e%a

La ejecucin de los programas de clculo se debe realizarse


utilizando el sistema de 2atc-.

Para ello, lo usual es crear un "script o fichero de comandos de


shell que contenga en las primeras lneas los "flags para el sistema
batch.

A continuacin se ofrece un ejemplo sencillo:


#PBS -l nodes=8
cd ${PBS_O_WORKDR}
NUMPROC=`wc -l ${PBS_NODEFLE} | awk ' {print $1} ' `
mpirun -np $NUMPROC -machinefile ${PBS_NODEFLE} prog.exe
I. CLUSTER EULER
E*ec(cin $ara%e%a

La sintaxis de la ltima lnea es vlida en el caso de utilizar las


implementaciones MPICD y OPENMPI.

En caso de utilizar MEAPICD> debe cambiarse por estas dos:


mpdboot -n $NUMPROC -f $PBS_NODEFLE
mpiexec -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 implementacin LAM entonces debe


cambiarse por estas lneas:
lamboot -d -f $PBS_NODEFLE
mpiexec -n $NUMPROC prog.exe
lamcleanup
NDICE
i. PROGRAMACN EN ENTORNO CLUSTER
ii. PROGRAMACN CON PASO DE MENSAJES (MP)
iii. PROGRAMACN CON PARALELSMO MPLCTO
(OpenMP)
NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones 2%oG(eantes A no 2%oG(eantes

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones 2%oG(eantes A no 2%oG(eantes

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
II. MPI
Intro&(ccin. Para%e%is#o

Paralelismo:

Significa realizar mltiples cosas al mismo tiempo, de tal manera que


se hace ms trabajo en el mismo lapso de tiempo.

Uso de mltiples unidades de procesamiento para resolver un


problema. Las unidades de procesamiento son:

Procesos lgicos.

Procesadores fsicos (cores).

Uso de mltiples 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.


II. MPI
Intro&(ccin. Ti$os &e $ara%e%is#o

Tipos de paralelismo

Memoria compartida (Shared).

Memoria distribuida (Distributed).

Hbrido (Shared/Distributed).

Hilos, Procesos, Multi-hilos, Multi-procesos

Di%os (Threads): secuencias de ejecucin que comparten un


rea de memoria (address space).

$rocesos (Processes): secuencias de ejecucin son su propia


memoria independiente.

M(%ti.-i%os (Multi-threading): paralelismo va multiples hilos.

M(%ti.$rocesa#iento (Multi-processing): paralelismo va


multiples procesos.
II. MPI
Intro&(ccin. Re)%as )enera%es

Reglas generales

Paralelismo de memoria compartida => hilos.

Paralelismo distribuido => procesos.

Cuantas ms unidades de procesamiento se tengan se puede


reducir el tiempo de ejecucin.

Cuantas ms unidades de procesamiento se tengan se


pueden resolver problemas ms grandes.

En la prctica algunos trminos se usan indistintamente:


o
Paralelismo
o
Concurrencia
o
Multihilos
o
Multiprocesamiento
II. MPI
Intro&(ccin. Me#oria co#$arti&a

Un computadora de memoria compartida provee de hardware


que soporta acceso (lectura/escritura) a un espacio de memoria
para varios procesadores (Multiprocessors).

Los procesadores interactan 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.

Adems, en cada lectura/escritura, cada procesador debe pasar


por mltiples etapas.

Una solucin es aadir una memoria local a cada procesador.

UMA (Uniform Memory Access), NUMA, Cache-coherence.


II. MPI
Intro&(ccin. Me#oria co#$arti&a

Memoria compartida. Arquitectura bsica


II. MPI
Intro&(ccin. Me#oria co#$arti&a

Memoria compartida. Arquitectura bsica


II. MPI
Intro&(ccin. Me#oria &istri2(i&a

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 lmite para el nmero de procesadores, esto depende de la red


de interconexin.

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
comunicacin con otros procesadores.
o
Tiempo para construir y enviar un mensaje.
o
Tiempo para recibir y desempaquetar el mensaje.
II. MPI
Intro&(ccin. Me#oria &istri2(i&a

Memoria distribuida. Arquitectura bsica


II. MPI
Intro&(ccin. Me#oria &istri2(i&a

Memoria distribuida. Ring


II. MPI
Intro&(ccin. Taxono#as

Una taxonoma es un modelo basado en un conjunto de


caractersticas que provee una informacin condensada que es til
cuando se comparan cosas.

La taxonma ms famosa en cmputo paralelo es la de Flynn que


se basa en el flujo de informacin (instrucciones y datos) en una
computadora.

Esta informacin solo tiene dos valores: uno(single) o


varios(multiple).

Instr(ction strea#: se refiere a la progresin de instrucciones


que se ejecutan en la computadora.

Data strea#: se refiere a la progresin de los valores de los


datos que son llevados a la memoria del CPU.
II. MPI
Intro&(ccin. Taxono#a &e 6%Ann

Taxonoma de Flynn

SISD (Single nstruction, Single Data) : Computadora de von


Neumann.

SIMD (Single nstruction, Multiple Data) : En estas computadoras se


aplica una instruccin a un grupo de datos simultneamente.

MISD (Multiple nstruction, Single Data) : Ningn tipo de arquitectura


cae dentro de este tipo.

MIMD (Multiple nstruction, Multiple Data) : Los procesadores


obedecen automticamente sus propias secuencias de instrucciones y
las aplican a sus propios datos.
II. MPI
Intro&(ccin. Taxono#a &e 6%Ann

6%(*o &e in!or#acin


II. MPI
Intro&(ccin. Taxono#a &e 6%Ann

Me#oria
II. MPI
Intro&(ccin. Taxono#a &e 6%Ann

Me#oria A $rocesa&ores
II. MPI
Intro&(ccin. HI(J es MPIK

Biblioteca estndar para programacin paralela bajo el paradigma de


comunicacin de procesos mediante pasaje de mensajes.

Li2%ioteca, no lenguaje. Proporciona funciones.

Propuesta por un comit conformado de especialistas, vendedores y


usuarios de HPC:

BM, ntel, 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, BM, Oregon Grad
nst, ntel, NOAA, University of New Mexico, KA, 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 estndar portable y eficiente, para programacin


paralela.
II. MPI
Intro&(ccin. HI(J es MPIK

Fue diseado para HPC sobre computadoras masivamente


paralelas y clusters.( Memoria distribuida).

Paralelismo explcito ( definido y controlado en su totalidad por el


programador)

Modelo de programa: SPMD

nico mecanismo de comunicacin: MP.

Existen implementaciones libres y algunas particulares para ciertas


plataformas.

MPCH, LAM, OpenMP, winmpich.

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

Java(?), ms informacin : mpiJava, Java grande.


II. MPI
Intro&(ccin. HI(J es MPIK

Actualmente es muy maduro, fcil de entender, eficiente y existe


mucho software alrededor de MP.

Caractersticas de MP-1.1 (1995)

Modular, portable, heterogeneo, comunicaciones seguras, subgrupos,


topologas, herramientas para medicin de desempeo, comunicacin
punto a punto, comunicacin colectiva.

Caractersticas de MP-1.2 y MP-2 (1997)

Extensiones, aclaraciones y correcciones de MP-1.1.

MP-2: manejo y creacin de procesos, operaciones colectivas


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

MPCH2 (http://www.mcs.anl.gov/research/projects/mpich2)
II. MPI
Intro&(ccin. HI(J es MPIK

Cuando usar MP?

Si se requiere un programa paralelo, portable y de buen


desempeo.

Cuando NO usar MP?

No se requiere paralelismo.

Cuando se puede usar HPF, OpenMP, Threads (POSX, Java,


etc.).
NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones 2%oG(eantes A no 2%oG(eantes

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
II. MPI
Gettin) starte&

C : Los nombres de todas las funciones de MP comienzan con el


prefijo MP_. Los tipos y funciones definidas en MP tienen una
letra mayscula despus del prefijo; las letras siguientes son
minsculas.

C;; : Todas las funciones y clases estan en el espacio de nombres


MP, de tal manera que para referirnos a una funcin de MP se
usa MP::Xxxxx.

6ortran : Los nombres de todas las funciones de MP comienzan


con el prefijo MP_ y todas las dems letras son maysculas.
II. MPI
Gettin) starte&

mpi.h y mpif.h proveen de las definiciones bsicas de MP


(funciones y tipos).

Para iniciar MP se usa:

int MP_nit(int *argc, char **argv); (C)

void MP::nit(int& argc, char**& argv); (C++)

NTEGER ERR y MP_NT(ERR) (Fortran)

Para finalizar MP se usa:

int MP_Finalize(void); (C)

void MP::Finalize(); (C++)

NTEGER ERR y MP_FNALZE(ERR) (Fortran)


II. MPI
Gettin) starte&. De%%o "or%& con C
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[])
{
int rank, size,tam;
char Name[MP_MAX_PROCESSOR_NAME];
MP_nit(&argc, &argv);
MP_Comm_rank(MP_COMM_WORLD, &rank);
MP_Comm_size(MP_COMM_WORLD, &size);
MP_Get_processor_name(Name,&tam);
printf("Hello world from %s! am %d of %d\n", Name, rank, size);
MP_Finalize();
return 0;
}
II. MPI
Gettin) starte&. De%%o "or%& con C;;
#include <iostream>
#include <mpi.h>
using namespace std;
int main(int argc, char *argv[])
{
int rank, size;
MP::nit(argc, argv);
rank = MP::COMM_WORLD.Get_rank();
size = MP::COMM_WORLD.Get_size();
cout << "Hello world! am " << rank << " of "<< size << endl;
MP::Finalize();
return 0;
}
II. MPI
Gettin) starte&. De%%o "or%& con 6
program main
include 'mpif.h'
integer rank, size, ierr
call MP_NT(ierr)
call MP_COMM_RANK(MP_COMM_WORLD, rank, ierr)
call MP_COMM_SZE(MP_COMM_WORLD, size, ierr)
print *, 'Hello world! am ', rank , ' of ', size
call MP_FNALZE(ierr)
stop
end
II. MPI
Gettin) starte&.

MP_NT : La versin de C/C++ acepta los argumentos argc y argv


que proveen de argumentos main().

Casi todas las rutinas de Fortran tienen un cdigo entero de error


como su ltimo argumento.

En el caso de C/C++ dichas funciones regresan un entero como


cdigo de error.

No se garantiza interoperabilidad entre lenguajes.

Programas que mezclan lenguajes funcionarn siempre y cuando


solo uno de ellos use MP.

Todas las funciones que no son de MP corren de manera local:

Por ejemplo: printf() se ejecuta sobre cada procesador


II. MPI
Gettin) starte&.

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 nmero de rank individual, entre 0 y


size-1.

En general podra haber ms de un "proceso en cada


"procesador.
II. MPI
Gettin) starte&.

Cuantos procesadores hay?

MP_COMM_SZE

Quin soy yo?

MP_COMM_RANK

El rango est en [0,SZE - 1]

MP_COMM_WORLD

La comunicacin en MP toma lugar con respecto a grupos de


procesos (comunicadores).

El grupo MP_COMM_WORLD se crea cuando se inicia MP y


contiene todos los procesos de MP.

MP_COMM_WORLD es el grupo de procesos por omisin.

Puede haber subgrupos de procesos.


II. MPI
Gettin) starte&.
,M Iniciar MPI M,
MPI@Init5Nar)c7 Nar)08O

,M Sa2er e% n1#ero G(e ten)o &e $rocesoM,
MPI@Co##@ranP5MPI@COMM@+ORLD7 N#A@ranP8O

,M Sa2er e% n1#ero &e $rocesos tota%es M,
MPI@Co##@si'e5MPI@COMM@+ORLD7 N$8O

NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones 2%oG(eantes A no 2%oG(eantes

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
II. MPI
Co#(nicacin $(nto a $(nto.

Un buen nmero de funciones de MP estn dedicadas


a la comunicacin entre pares de procesos
(comunicacin punto a punto).

Existen mltiples formas distintas de intercambiar un


mensaje entre dos procesos, en funcin del modelo y
el modo de comunicacin elegido
II. MPI
Co#(nicacin $(nto a $(nto.

MP define &os #o&e%os &e co#(nicacin:


bloqueante (blocking) y no bloqueante (nonblocking).

El #o&e%o &e co#(nicacin tiene que ver con el


tiempo que un proceso pasa bloqueado tras llamar a
una funcin de comunicacin, sea sta de envo o de
recepcin.

Una !(ncin 2%oG(eante mantiene a un proceso bloqueado


hasta que la operacin solicitada finalice.

Una !(ncin no 2%oG(eante supone simplemente "encargar al


sistema la realizacin de una operacin, recuperando el control
inmediatamente. El proceso tiene que preocuparse, ms
adelante, de averiguar si la operacin ha finalizado o no.
II. MPI
Co#(nicacin $(nto a $(nto.

MP define un envo como finalizado cuando el emisor


puede reutilizar, sin problemas de causar interferencias,
el buffer de emisin que tena el mensaje.

Se puede entender que tras hacer un send (envo)


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 informacin que se est enviando.
II. MPI
Co#(nicacin $(nto a $(nto.

Al margen de si la funcin invocada es bloqueante o no, el


programador puede tener un cierto control sobre la forma en la que
se realiza y completa un envo. MP define, en relacin a este
aspecto, 4 modos de envo:

bsico(basic)

con buffer (buffered)

sncrono (synchronous)

listo (ready).
II. MPI
Co#(nicacin $(nto a $(nto.

Cuando se hace un envo con 2(!!er se guarda inmediatamente, en un


buffer al efecto en el emisor, una copia del mensaje. La operacin se da
por completa en cuanto se ha efectuado esta copia. Si no hay espacio en
el buffer, el envo fracasa.

Si se hace un envo sncrono, la operacin se da por terminada slo


cuando el mensaje ha sido recibido en destino.

El modo de envo 2Csico no especifica la forma en la que se completa la


operacin: es algo dependiente de la implementacin. Normalmente
equivale a un envo con buffer para mensajes cortos y a un envo sncrono
para mensajes largos. Se intenta as agilizar el envo de mensajes cortos a
la vez que se procura no perder demasiado tiempo realizando copias de la
informacin.

En cuanto al envo en modo %isto, slo se puede hacer si antes el otro


extremo est preparado para una recepcin 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.
II. MPI
Co#(nicacin $(nto a $(nto. LCsica

El resultado de la combinacin de dos modelos y cuatro modos


de comunicacin nos da 8 diferentes funciones de envo.

Funciones de recepcin slo hay dos, una por modelo.

MPI@Sen&58 y MPI@Rec058 que son, respectivamente, las


funciones de envo y recepcin bsicas bloqueantes.
int MP_Send(void* buf, int count, MP_Datatype datatype,
int dest, int tag, MP_Comm comm);
int MP_Recv(void* buf, int count, MP_Datatype datatype,
int source, int tag, MP_Comm comm, MP_Status *status);
II. MPI
Co#(nicacin $(nto a $(nto. LCsica

Enviando y recibiendo mensajes

Preguntas:

Donde est la info?

Que tipo de info se enva?

Que cantidad de info se enva?

A quin se enva la info?

Como identifica el receptor el mensaje?


II. MPI
Co#(nicacin $(nto a $(nto. LCsica

En MP se especifica con address, datatype y count: co(nt copias de un


dato del tipo &atatA$e que se encuentran (o se van a dejar) en memoria a
partir de la direccin indicada por 2(!.

Dest es el identificador del proceso destinatario del mensaje.

So(rce es el identificador del emisor del cual esperamos un mensaje. Si


no nos importa el origen del mensaje, podemos poner
MP_ANY_SOURCE.

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

Co## es un comunicador (comunicador universal MP_COMM_WORLD).

Stat(s es un resultado que se obtiene cada vez que se completa una


recepcin, y nos informa de aspectos tales como el tamao del mensaje
recibido, la etiqueta del mensaje y el emisor del mismo.
II. MPI
Co#(nicacin $(nto a $(nto. LCsica

Si queremos saber el tamao de un mensaje, lo haremos con la


funcin MPI@Get@co(nt58<
int MP_Get_count(MP_Status *status, MP_Datatype datatype,
int *count);

MPI@Isen&58 y MPI@Irec058 son las funciones de emisin/recepcin


bsicas no bloqueantes.
int MP_send(void* buf, int count, MP_Datatype datatype, int dest,
int tag, MP_Comm comm, MP_Request *request);
int MP_recv(void* buf, int count, MP_Datatype datatype,
int source, int tag, MP_Comm comm, MP_Request
*request);
II. MPI
Co#(nicacin $(nto a $(nto. LCsica

Asociadas a MPI@Isen&58 y MPI@Irec058 existen otras tres


funciones:
int MP_Wait(MP_Request *request, MP_Status *status);
int MP_Test(MP_Request *request, int *flag, MP_Status *status);
int MP_Cancel(MP_Request *request);

MPI@+ait58 toma como entrada un recibo (request), y bloquea al


proceso hasta que la operacin correspondiente termina.

Hacer un MPI@Isen&58 seguido de un MPI@+ait58 equivale a hacer


un envo bloqueante.

Sin embargo, entre la llamada a la funcin de envo y la llamada a


la funcin de espera el proceso puede haber estado haciendo
cosas tiles, es decir, consigue solapar parte de clculo de la
aplicacin con la comunicacin.
II. MPI
Co#(nicacin $(nto a $(nto. LCsica

Asociadas a MPI@Isen&58 y MPI@Irec058 existen otras tres


funciones:
int MP_Wait(MP_Request *request, MP_Status *status);
int MP_Test(MP_Request *request, int *flag, MP_Status *status);
int MP_Cancel(MP_Request *request);

Cuando no interesa bloquearse, sino simplemente saber si la


operacin ha terminado o no, podemos usar MPI@Test58. Esta
funcin actualiza un !%a) que se le pasa como segundo parmetro.
Si la funcin ha terminado, este flag toma el valor 1, y si no ha
terminado pasa a valer 0.

Por ltimo, MPI@Cance%58 nos sirve para cancelar una operacin


de comunicacin pendiente, siempre que sta an no se haya
completado.
II. MPI
E*e#$%os

Calcular el valor de la integral usando una suma de


rectngulos:
II. MPI
E*e#$%os.
program main
include 'mpif.h'
double precision P25DT
parameter (P25DT = 3.141592653589793238462643d0)
double precision mypi,pi,h,suma,x,f,a
double precision startime,endtime
integer n,myid,numprocs,i,ierr
! FUNCON PARA NTEGRAR
f(a)=4.d0/(1.d0+a*a)
call MP_NT(ierr)
call MP_COMM_RANK(MP_COMM_WORLD,myid,ierr)
call MP_COMM_SZE(MP_COMM_WORLD,numprocs,ierr)
II. MPI
E*e#$%os.
10 if(myid .eq. 0) then
print *, 'ntroduzca el numero de intervalos (0 salir)'
read(*,*) n
print *, 'lo he leido y es ', n
endif
! BROADCAST N
startime=MP_WTME()
call MP_BCAST(n,1,MP_NTEGER,0,MP_COMM_WORLD,ierr)
! CHEQUEAR POR POSBLE SALDA
if (n .le. 0) goto 30
II. MPI
E*e#$%os.
! CALCULAR EL TAMANO DEL NTERVALO
h=1.0d0/n
suma=0.0d0
do 20 i=myid+1,n,numprocs
x=h*(dble(i)-0.5d0)
suma=suma+f(x)
20 continue
mypi=h*suma
! RECOLECTAR TODAS LAS SUMAS PARCALES
call MP_REDUCE(mypi,pi,1,MP_DOUBLE_PRECSON,MP_SUM,0,
MP_COMM_WORLD,ierr)
II. MPI
E*e#$%os.
! EL NODO 0 MPRMRA LA RESPUESTA
entime=MP_WTME()
if(myid .eq. 0) then
print *, 'pi es', pi, 'Error es ', abs(pi-P25DT)
print *, 'tiempo es ', (endtime-starttime), 'segundos'
endif
! goto 10
30 call MP_FNALZE(ierr)
stop
end
II. MPI
E*e#$%os.
#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


II. MPI
E*e#$%os.
#include <iostream>
#include "mpi.h
using namespace std;
int main(int argc, char ** argv)
{
int mynode, totalnodes;
int sum = 0,startval,endval,accum;
MP_Status status;
MP_nit(&argc,&argv);
MP_Comm_size(MP_COMM_WORLD, &totalnodes);
MP_Comm_rank(MP_COMM_WORLD, &mynode);
startval = 1000*mynode/totalnodes+1;
endval = 1000*(mynode+1)/totalnodes;

SUMA. Algoritmo paralelo


II. MPI
E*e#$%os.
for(int i=startval;i<=endval;i=i+1)
sum = sum + i;
if(mynode!=0)
MP_Send(&sum, 1, MP_NT, 0, 1, MP_COMM_WORLD);
else
for(int j=1;j<totalnodes;j=j+1)
{
MP_Recv(&accum, 1, MP_NT, j,
1,MP_COMM_WORLD, &status);
sum = sum + accum;
}
if(mynode == 0)
cout << "The sum from 1 to 1000 is: "<< sum << endl;
MP_Finalize();
}

SUMA. Algoritmo paralelo


II. MPI
E*e#$%os.

SUMA. Algoritmo paralelo

Compilacin: mpicxx o sumaparalelo sumaParalelo.cpp

Ejecucin: mpiexec -n 4 ./suma_para

Resultado: The sum from 1 to 1000 is: 500500


II. MPI
E*e#$%os.

Programa greetings
/* Envo 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];
MP_Status status;
MP_nit(&argc,&argv);
MP_Comm_size(MP_COMM_WORLD, &p);
MP_Comm_rank(MP_COMM_WORLD, &my_rank);
II. MPI
E*e#$%os.
if (my_rank != 0) {
/* Creamos el mensaje */
sprintf(message, "Greetings from process %d!", my_rank);
dest = 0;
/* Longitud strlen+1 porque en C se aade al final de una cadena '\0' */
MP_Send(message, strlen(message)+1, MP_CHAR, dest, tag, MP_COMM_WORLD);
}
else { /* my_rank == 0 */
for (source = 1; source < p; source++) {
MP_Recv(message, 100, MP_CHAR, source, tag, MP_COMM_WORLD, &status);
printf("%s\n", message);
}
}
MP_Finalize();
}

II. MPI
E*e#$%os.

Co#$i%ar
#$icc Qo )reetin)s )reetin)s.c

E*ec(tar
#$ir(n .n$ > )reetin)s

El programa corrido con 2 procesos, genera el output


Greetin)s !ro# $rocess =R

El programa corrido con 4 procesos, genera el output


Greetin)s !ro# $rocess =R
Greetin)s !ro# $rocess >R
Greetin)s !ro# $rocess ?R
II. MPI
E*e#$%os. Inte)racin n(#Jrica

Problema de integracin numrica


The example application is to integrate cosine(! 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, co(!, 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.
II. MPI
E*e#$%os. Inte)racin n(#Jrica
II. MPI
E*e#$%os. Inte)racin n(#Jrica

SECUENCAL
#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 */
II. MPI
E*e#$%os. Inte)racin n(#Jrica

SECUENCAL
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);
}
II. MPI
E*e#$%os. Inte)racin n(#Jrica

SECUENCAL
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;
}
II. MPI
E*e#$%os. Inte)racin n(#Jrica

PARALELO. Comunicacin 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 */
MP_Comm comm;
MP_Status status;
comm = MPI@COMM@+ORLD;
ierr = MPI@Init(&argc,&argv);
MPI@Co##@ranP(comm, &myid);
MPI@Co##@si'e(comm, &p);
II. MPI
E*e#$%os. Inte)racin n(#Jrica

PARALELO. Comunicacin 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 */
II. MPI
E*e#$%os. Inte)racin n(#Jrica

PARALELO. Comunicacin bloqueante


printf("Process %d has the partial integral of %f\n", myid,my_int);
MPI@Sen&(&my_int, 1, MP_FLOAT, master, tag, comm);
if(myid == master)
{ /* Receives serialized */
integral_sum = 0.0;
for (proc=0;proc<p;proc++)
{
MPI@Rec0( &my_int, 1, MP_FLOAT, proc, tag, comm,&status);
integral_sum += my_int;
}
printf("The ntegral =%f\n",integral_sum);
}
MPI@6ina%i'e();
}
II. MPI
E*e#$%os. Inte)racin n(#Jrica

PARALELO. Comunicacin 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;
}
II. MPI
E*e#$%os. Inte)racin n(#Jrica

PARALELO. Comunicacin 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;
MP_Comm comm;
MP_Request request;
MP_Status status;
comm = MPI@COMM@+ORLD;
ierr = MPI@Init(&argc,&argv);
MPI@Co##@ranP(comm, &myid);
MPI@Co##@si'e(comm, &p);
II. MPI
E*e#$%os. Inte)racin n(#Jrica

PARALELO. Comunicacin 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);
II. MPI
E*e#$%os. Inte)racin n(#Jrica

PARALELO. Comunicacin con Send (no bloqueante) y Recev


if(myid == master)
{
integral_sum = my_int;
for (proc=1;proc<p;proc++)
{
MPI@Rec0( &my_int, 1, MP_FLOAT, MP_ANY_SOURCE,
MP_ANY_TAG, comm, &status);
integral_sum += my_int;
}
printf("The ntegral =%f\n",integral_sum);
}
else
{
MPI@Isen&(&my_int, 1, MP_FLOAT, master, tag, comm, &request);
other_work(myid);
MPI@+ait(&request, &status); * block until send is done */
}
MPI@6ina%i'e();
}
II. MPI
E*e#$%os. Inte)racin n(#Jrica

PARALELO. Comunicacin 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;
}
II. MPI
E*e#$%os. )etco(nt.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];
MP_Status status;
MP_nit(&argc,&argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
II. MPI
E*e#$%os. )etco(nt.c
if(rank==1) {
for(i=0;i<100;++i) data[i]=i;
MP_Send(data,100,MP_FLOAT,0,55,MP_COMM_WORLD);
}
else
{
MP_Recv(value,200,MP_FLOAT,MP_ANY_SOURCE,55,
MP_COMM_WORLD,&status);
printf("P:%dGot data from processor %d \n",rank, status.MP_SOURCE);
MP_Get_count(&status,MP_FLOAT,&count);
printf("P:%dGot %d elements \n",rank,count);
printf("P:%dvalue[5]=%f \n",rank,value[5]);
}
MP_Finalize();
}
II. MPI
E*e#$%os. L(!!er.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;
MP_Status status;
int x[TAM];
int buff[BUFTAM];
int tambuff=BUFTAM;
MP_nit(&argc,&argv);
MP_Comm_size(MP_COMM_WORLD,&p);
MP_Comm_rank(MP_COMM_WORLD,&my_rank);
II. MPI
E*e#$%os. L(!!er.c
MP_Buffer_attach(buff, tambuff);
if(my_rank ==0){
printf("Proceso 0: mando al proceso 1\n);
MP_Bsend(&x,TAM,MP_NT,1,tag,MP_COMM_WORLD);
printf("Proceso 0: vuelta de la operacin de envio\n);
}
else{
printf("Proceso 1: recibiendo del proceso 0\n);
MP_Recv(&c,TAM,MP_NT,0,tag,MP_COMM_WORLD,&status);
printf("Proceso 1: recibidos %d elementos\n,TAM);
}
MP_Buffer_detach(&buff,&tambuff);
MP_Finalize();
}
II. MPI
Co#(nicacin $(nto a $(nto. L(!!er

Problema del envo bsico: el programador NO tiene control sobre


cunto tiempo va a tardar en completarse la operacin:

Puede que apenas tarde, si es que el sistema se limita a hacer una


copia del mensaje en un buffer, que saldr ms tarde hacia su destino;

Puede que mantenga al proceso bloqueado un largo tiempo,


esperando a que el receptor acepte el mensaje.

MPI@Lsen&58 solicita explcitamente que la comunicacin se


complete copiando el mensaje en un buffer, que tendr que
asignar al efecto el propio proceso.
int MP_Bsend(void* buf, int count, MP_Datatype datatype,
int dest, int tag, MP_Comm comm);
II. MPI
Co#(nicacin $(nto a $(nto. L(!!er

Para que se pueda usar el envo con buffer es necesario que el


programador asigne un buffer de salida. Para ello hay reservar
previamente una zona de memoria (de forma esttica o con
malloc()) y luego indicarle al sistema que la emplee como buffer.

Esta ltima operacin la hace MPI@L(!!er@attac-58.

Ese buffer se puede recuperar usando MPI@L(!!er@&etac-58.


int MP_Buffer_attach(void* buffer, int size);
int MP_Buffer_detach(void* buffer, int* size);

Problema de los envos 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.
II. MPI
Co#(nicacin $(nto a $(nto.
Rece$cin $or enc(esta

Las funciones de recepcin de mensajes engloban en una


operacin la sincronizacin con el emisor (esperar a que haya un
mensaje disponible) con la de comunicacin (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 gustara saber el valor de la etiqueta antes de leer


el mensaje.

Tambin puede ocurrir que nos llegue un mensaje de longitud


desconocida, y resulte necesario averiguar primero el tamao para
as asignar dinmicamente el espacio de memoria requerido por el
mensaje.
II. MPI
Co#(nicacin $(nto a $(nto.
Rece$cin $or enc(esta

Las funciones MPI@Pro2e58 y MPI@I$ro2e58 nos permiten saber si


tenemos un mensaje recibido y listo para leer, pero sin leerlo.

A partir de la informacin 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@Rec058 o
MPI@Irec058.
int MP_probe(int source, int tag, MP_Comm comm, int *flag,
MP_Status *status);
int MP_Probe(int source, int tag, MP_Comm comm, MP_Status
*status);
II. MPI
Co#(nicacin $(nto a $(nto.
Rece$cin $or enc(esta

MPI@Pro2e58 es bloqueante: slo devuelve el control al proceso


cuando hay un mensaje listo.

MPI@I$ro2e58 es no bloqueante: nos indica en el argumento !%a) si


hay un mensaje listo o no, es decir, realiza una encuesta.
II. MPI
Co#(nicacin $(nto a $(nto.
Mo&os &e co#(nicacin
En0io L%oG(eante No 2%oG(eante

Estndar.
MP_Send MP_send

Con Buffer: Usa un buffer para copiar los datos a enviar. No se


requiere recepcin para iniciar ni finalizar.
MP_Bsend MP_bsend

Sncrono: Debe sincronizarse con alguna recepcin para poder


finalizar. No la requiere para arrancar.
MP_Ssend MP_ssend

Listo: Requiere una recepcin para arrancar.


MP_Rsend MP_rsend
II. MPI
Co#(nicacin $(nto a $(nto.
Mo&os &e co#(nicacin
Rece$cin L%oG(eante No
2%oG(eante

Estndar.
MP_Recv MP_recv
II. MPI
Ti$o &e &atos e%e#enta%es

Los mensajes gestionados por MP son secuencias de co(nt


elementos del tipo &atatA$e.

MP define una coleccin de tipos de datos primitivos,


correspondientes a los tipos de datos existentes en C. Hay otra
coleccin, distinta, para FORTRAN.
II. MPI
Ti$o &e &atos e%e#enta%es

Aunque una aplicacin desarrollada en C trabaja con los tipos de


datos habituales, cuando se realice un paso de mensajes habr que
facilitar a MP un descriptor del tipo equivalente, tal como lo define
MP.

La idea de fondo es la siguiente: los procesadores que participan en


una aplicacin MP no tienen por qu ser todos iguales. Es posible
que existan diferencias en la representacin de los datos en las
distintas mquinas. Para eliminar los problemas que puedan surgir,
MP realiza, si son necesarias, transformaciones de sintaxis que
posibilitan la comunicacin en entornos heterogneos. La excepcin
la constituyen los datos de tipo MP_BYTE, que se copian sin ms
de una mquina a otra.

Aparte de los tipos simples definidos de forma primitiva por MP, se


permite la definicin de tipos de usuario, ms complejos.
NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
II. MPI
Co#(nicaciones co%ecti0as

Muchas aplicaciones requieren de la comunicacin entre ms de


dos procesos.

Esto se puede hacer combinando operaciones punto a punto, pero


para que le resulte ms cmodo al programador, y para posibilitar
implementaciones optimizadas, MP incluye una serie de
operaciones colectivas:

Barreras de sincronizacin

Broadcast (difusin)

Gather (recoleccin)

Scatter (distribucin)

Operaciones de reduccin (suma, multiplicacin, mnimo, etc.)

Combinaciones de todas ellas


II. MPI
Co#(nicaciones co%ecti0as

Una operacin 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


designacin de un proceso como root, o raz de la
operacin.
II. MPI
Co#(nicaciones co%ecti0as.
Larreras A 2roa&cast

Dos de las operaciones colectivas ms comunes son las barreras de


sincronizacin (MPI@Larrier58) y el envo de informacin en modo
difusin (MPI@Lroa&cast58).

En MPI@Larrier no exige ninguna clase de intercambio de


informacin. Es una operacin puramente de sincronizacin, 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, asegurndose de que todos han terminado
antes de dar comienzo a la siguiente.
int MP_Barrier(MP_Comm comm);
II. MPI
Co#(nicaciones co%ecti0as.
Larreras A 2roa&cast

MPI@Lroa&cast58 sirve para que un proceso, el raz, enve un


mensaje a todos los miembros del comunicador.

Esta funcin ya muestra una caracterstica peculiar de las


operaciones colectivas de MP: todos los participantes invocan la
misma funcin, designando al mismo proceso como raz de la
misma.

Una implementacin alternativa sera tener una funcin de envo


especial, en modo broadcast, y usar las funciones de recepcin
normales para leer los mensajes.
int MP_Bcast(void* buffer, int count, MP_Datatype datatype,
int root, MP_Comm comm);
II. MPI
Co#(nicaciones co%ecti0as.
Larreras A 2roa&cast

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 raz (suponemos que es el 0)


tiene el dato A. Tras realizar el broadcast, todos los procesos
(incluyendo el raz) tienen una copia de A0.
II. MPI
Co#(nicaciones co%ecti0as.
Reco%eccin 5)at-er8

MPI@Gat-er realiza una recoleccin de datos en el proceso raz.

Este proceso recopila un vector de datos, al que contribuyen todos


los procesos del comunicador con la misma cantidad de datos.

El proceso raz almacena las contribuciones de forma consecutiva.


int MP_Gather(void* sendbuf, int sendcount,
MP_Datatype sendtype, void* recvbuf, int recvcount,
MP_Datatype recvtype, int root, MP_Comm comm);
II. MPI
Co#(nicaciones co%ecti0as.
Reco%eccin 5)at-er8

Slo el proceso raz tiene que preocuparse de los parmetros


rec2(!, rec0co(nt y rec0tA$e.

Sin embargo, todos los procesos (raz incluido) tienen que facilitar
valores vlidos para sen&2(!, sen&co(nt y sen&tA$e.
II. MPI
Co#(nicaciones co%ecti0as.
Reco%eccin 5)at-er8

Existe una versin de la funcin de recoleccin, llamada


MPI@Gat-er058, que permite almacenar los datos recogidos en
forma no consecutiva, y que cada proceso contribuya con bloques
de datos de diferente tamao .
int MP_Gatherv(void* sendbuf, int sendcount,
MP_Datatype sendtype, void* recvbuf, int *recvcounts,
int *displs, MP_Datatype recvtype, int root, MP_Comm comm);

La tabla rec0co(nts establece el tamao del bloque de datos


aportado por cada proceso, y &is$%s indica cul es el
desplazamiento entre bloque y bloque
II. MPI
Co#(nicaciones co%ecti0as.
Reco%eccin 5)at-er8

Muchas veces interesa distribuir a todos los procesos el resultado de


una recoleccin previa. (Esto se puede hacer concatenando una
recoleccin con un broadcast).

Existen funciones que se encargan de hacer todo esto en un nico


paso: MPI@A%%)at-er58 (si los bloques de datos son de tamao fijo y
se almacenan consecutivamete) y MPI@A%%)at-er058 (si los tamaos
de los datos son variables y/o se almacenan de forma no
consecutiva).
int MP_Allgather(void* sendbuf, int sendcount,
MP_Datatype sendtype, void* recvbuf, int recvcount,
MP_Datatype recvtype, MP_Comm comm);
int MP_Allgatherv(void* sendbuf, int sendcount,
MP_Datatype sendtype,void* recvbuf, int *recvcounts,
int *displs, MP_Datatype recvtype, MP_Comm comm);
II. MPI
Co#(nicaciones co%ecti0as.
Reco%eccin 5)at-er8
II. MPI
E*e#$%o. Inte)racin n(#Jrica
#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 */
MP_Comm comm;
comm = MPI@COMM@+ORLD;
ierr = MPI@Init(&argc, &argv);
MPI@Co##@ranP(comm, &myid);
MPI@Co##@si'e(comm, &p);
II. MPI
E*e#$%o. Inte)racin n(#Jrica
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@Gat-er( &#A@int7 =7 MPI@6LOAT, 2(!7 =7 MPI@6LOAT, #aster, comm);
II. MPI
E*e#$%o. Inte)racin n(#Jrica
if(myid == master)
{
integral_sum = 0.0;
for (i=0; i<p; i++)
{
integral_sum += buf[i];
}
printf("The ntegral =%f\n",integral_sum);
}
MPI@6ina%i'e();
}
II. MPI
E*e#$%o. Inte)racin n(#Jrica
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;
}
II. MPI
Co#(nicaciones co%ecti0as.
Distri2(cin 5scatter8

MPI@Scatter58 realiza la operacin simtrica a MPI@Gat-er58.

El proceso raz posee un vector de elementos, uno por cada


proceso del comunicador. Tras realizar la distribucin, cada
proceso tiene una copia del vector inicial.

Recordemos que MP permite enviar bloques de datos, no slo


datos individuales.
int MP_Scatter(void* sendbuf, int sendcount,
MP_Datatype sendtype, void* recvbuf, int recvcount,
MP_Datatype recvtype, int root, MP_Comm comm);
II. MPI
Co#(nicaciones co%ecti0as.
Distri2(cin 5scatter8
II. MPI
Co#(nicaciones co%ecti0as.
Distri2(cin 5scatter08

Si los datos a enviar no estn almacenados de forma


consecutiva en memoria, o los bloques a enviar a cada
proceso no son todos del mismo tamao, tenemos la funcin
MPI@Scatter0587 con un interfaz ms complejo pero ms
flexible.
int MP_Scatterv(void* sendbuf, int *sendcounts,
int *displs, MP_Datatype sendtype, void* recvbuf,
int recvcount, MP_Datatype recvtype, int root,
MP_Comm comm);
II. MPI
E*e#$%os. Scatter.c
#include "mpi.h"
#include <stdio.h>
#define SZE 4
int main(int argc,char *argv[]) {
nt numtasks, rank, sendcount, recvcount, source;
float sendbuf[SZE][SZE] = {{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[SZE];
MP_nit(&argc,&argv);
MP_Comm_rank(MP_COMM_WORLD, &rank);
MP_Comm_size(MP_COMM_WORLD, &numtasks);
if (numtasks == SZE) {
source = 1; sendcount = SZE; recvcount = SZE;
MP_Scatter(sendbuf,sendcount,MP_FLOAT,recvbuf,recvcount,
MP_FLOAT,source,MP_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",SZE);
MP_Finalize();
}
II. MPI
E*e#$%os

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
II. MPI
Co#(nicaciones co%ecti0as.
Distri2(cin a%%.to.a%%

La comunicacin 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 nmero de procesos del


comunicador), cada proceso i enva una copia de sendbuf[j] al proceso j, y
recibe del proceso k un elemento, que almacena en recvbuf[k].

MPI@A%%toa%%58 equivale, por tanto, a una sucesin de N operaciones de


distribucin, en cada una de las cuales el proceso i toma el rol de raz.
int MP_Alltoall(void* sendbuf, int sendcount, MP_Datatype sendtype,
void* recvbuf, int recvcount, MP_Datatype recvtype,
MP_Comm comm);
int MP_Alltoallv(void* sendbuf, int *sendcounts, int *sdispls,
MP_Datatype sendtype, void* recvbuf, int *recvcounts,
int *rdispls, MP_Datatype recvtype, MP_Comm comm);
II. MPI
Co#(nicaciones co%ecti0as.
Distri2(cin a%%.to.a%%
II. MPI
Co#(nicaciones co%ecti0as.
Re&(ccin

Una reduccin es una operacin 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 raz.
int MP_Reduce(void* sendbuf, void* recvbuf, int count,
MP_Datatype datatype, MP_Op op, int root,
MP_Comm comm);
II. MPI
E*e#$%o. Inte)racin n(#Jrica
#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;
MP_Comm comm;
comm = MPI@COMM@+ORLD;
II. MPI
E*e#$%o. Inte)racin n(#Jrica
ierr = MPI@Init(&argc,&argv);
MPI@Co##@ranP(comm, &myid);
MPI@Co##@si'e(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);
}

II. MPI
E*e#$%o. Inte)racin n(#Jrica
/* Broadcast "n" to all processes */
MPI@Lcast( &n7 =7 MPI@INT, #aster, 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@Re&(ce( &my_int, &inte)ra%@s(#, 1, MP_FLOAT, MPI@SUM, #aster, comm);
if(myid == 0)
{
printf("The result =%f\n",integral_sum);
}
MPI@6ina%i'e();
}
II. MPI
E*e#$%o. Inte)racin n(#Jrica
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;
}
II. MPI
Co#(nicaciones co%ecti0as.
Re&(ccin

MP define una coleccin de operaciones del tipo MP_Op que se


pueden utilizar en una reduccin:

MP_MAX (mximo)

MP_MN (mnimo)

MP_SUM (suma)

MP_PROD (producto)

MP_LAND (and lgico)

MP_BAND (and bit a bit)

MP_LOR (or lgico)

MP_BOR (or bit a bit)

MP_LXOR (xor lgico)

MP_BXOR (xor bit a bit)

...
II. MPI
Co#(nicaciones co%ecti0as.
Re&(ccin

En ocasiones el programador puede necesitar otra operacin de


reduccin distinta, no predefinida.

Para ello MP ofrece la funcin MPI@O$@create587 que toma como


argumento de entrada una funcin de usuario y devuelve un objeto
de tipo MP_Op que se puede emplear con MPI@Re&(ce58.
int MP_Op_create(MP_User_function *function,
int commute, MP_Op *op );

Ese objeto se puede destruir ms adelante con MPI@O$@!ree58.


int MP_Op_free(MP_Op *op);
II. MPI
Co#(nicaciones co%ecti0as.
Re&(ccin

La operacin 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 parmetro co##(te.
Si la operacin no es conmutativa (co##(te = 0) entonces se exige
que la reduccin se realice en orden de direccin (se empieza con el
proceso 0, luego con el 1, con el 2, etc.).

En ocasiones resulta til que el resultado de una reduccin est


disponible para todos los procesos. Aunque se puede realizar un
broadcast tras la reduccin, podemos combinar la reduccin con la
difusin usando MPI@A%%re&(ce58.
int MP_Allreduce(void* sendbuf, void* recvbuf, int count,
MP_Datatype datatype, MP_Op op, MP_Comm comm);
II. MPI
Co#(nicaciones co%ecti0as.
Re&(ccin

Si el resultado de la reduccin es un vector que hay que distribuir


entre los procesadores, podemos combinar la reduccin y la
distribucin usando MPI@Re&(ce@scatter58.
int MP_Reduce_scatter(void* sendbuf, void* recvbuf,
int *recvcounts,MP_Datatype datatype,MP_Op op,
MP_Comm comm);

Una variante ms de la reduccin nos la da MPI@Scan58. Es similar a


MPI@A%%re&(ce587 excepto que cada proceso recibe un resultado
parcial de la reduccin, en vez del final: cada proceso i recibe, en vez
del resultado de OP(0..N-1), siendo N el nmero total de procesos, el
resultado de OP(0..i).
int MP_Scan(void* sendbuf, void* recvbuf, int count,
MP_Datatype datatype, MP_Op op, MP_Comm comm );
NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
II. MPI
Ti$os &e &atos &eri0a&os

MP maneja en todas sus funciones de envo/recepcin vectores de


tipos simples.

En general, se asume que los elementos de esos vectores estn


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: envo de una columna de un
array, en vez de envo de una fila).

MP incluye la posibilidad de definir tipos ms complejos (objetos del


tipo MPI@DatatA$e), empleando constructores. Antes de usar un tipo
de usuario, hay que ejecutar MPI@TA$e@co##it58. Cuando ya no se
necesite un tipo, se puede liberar con MPI@TA$e@!ree58.
int MP_Type_commit(MP_Datatype *datatype);
int MP_Type_free(MP_Datatype *datatype);
II. MPI
Ti$os &e &atos &eri0a&os.
De!inicin &e ti$os -o#o)Jneos

Son tipos homogneos aquellos tipos construidos en los que todos


los elementos constituyentes son del mismo tipo.

Se pueden definir tipos homogneos con dos funciones distintas:

MPI@TA$e@conti)(o(s58: es la ms sencilla, y permite definir un


tipo formado por una coleccin de elementos de un tipo bsico,
todos ellos del mismo tamao y almacenados consecutivamente
en memoria.
int MP_Type_contiguous (int count, MP_Datatype oldtype,
MP_Datatype *newtype);
Ne"tA$e es un nuevo tipo que consiste en co(nt copias de
o%&tA$e.
II. MPI
Ti$os &e &atos &eri0a&os.
De!inicin &e ti$os -o#o)Jneos

MPI@TA$e@0ector58. Los elementos constituyentes del nuevo tipo no


estn almacenados consecutivamente en memoria, sino que estn
espaciados a intervalos regulares.
int MP_Type_vector (int count, int blocklength, int stride,
MP_Datatype oldtype, MP_Datatype *newtype);
Ne"tA$e es un nuevo tipo que consiste en co(nt bloques de datos.
Cada bloque consta de 2%ocP%en)t- elementos del tipo o%&tA$e. La
distancia entre bloques, medida en mltiplos del tamao del elemento
bsico, la da stri&e.

Una llamada a MP_Type_contiguous(c, o, n) equivale a una llamada


a MP_Type_vector (c, 1, 1, o, n), o a una llamada a
MP_Type_vector (1, c, x,o, n), siendo x un valor arbitrario.
II. MPI
Ti$os &e &atos &eri0a&os.
De!inicin &e ti$os -etero)Jneos

Si nos interesa trabajar con tipos no homogneos, podemos usar


una funcin ms genrica: MPI@TA$e@str(ct58.
MP_Type_struct (int count, int *array_of_blocklenghts,
MP_Aint *array_of_displacements,
MP_Datatype *array_of_types, MP_Datatype *newtype);

Co(nt determina el nmero de bloques, as como el tamao de los


arrays arraA@o!@2%ocP%en)-ts, arraA@o!@&is$%ace#ents y
arraA@o!@tA$es.

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].
II. MPI
Ti$os &e &atos &eri0a&os.
De!inicin &e ti$os -etero)Jneos

Veamos un ejemplo.

Si B = {2, 1, 3}
D = {0, 16, 26} y
T = {MP_FLOAT, MP_NT, MP_CHAR}
entonces MP_Type_struct(3, B, D, T, newtype) devuelve un tipo que en
memoria tiene este aspecto.

La primera columna hace referencia a la posicin de memoria que ocupa
cada campo de una instancia de este tipo de datos, relativa al origen del
dato.
II. MPI
E*e#$%os. conti)(o(s.c
#include <stdio.h>
#include<mpi.h>
/* Run with four processes */
void main(int argc, char *argv[]) {
int rank;
MP_Status status;
struct { int x; int y; int z; } point;
MP_Datatype ptype;
MP_nit(&argc,&argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
MP_Type_contiguous(3,MP_NT,&ptype);
MP_Type_commit(&ptype);
if(rank==3){
point.x=15; point.y=23; point.z=6;
MP_Send(&point,1,ptype,1,52,MP_COMM_WORLD);
} else if(rank==1) {
MP_Recv(&point,1,ptype,3,52,MP_COMM_WORLD,&status);
printf("P:%dreceived coordsare (%d,%d,%d) \n",rank,point.x,point.y,point.z);
}
MP_Finalize();
}
II. MPI
E*e#$%os. 0ector.c
#include <mpi.h>
#include <math.h>
#include <stdio.h>
void main(int argc, char *argv[]) {
int rank,i,j;
MP_Status status;
double x[4][8];
MP_Datatype coltype;
MP_nit(&argc, &argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
MP_Type_vector(4,1,8,MP_DOUBLE,&coltype);
MP_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; MP_Send(&x[0]
[7],1,coltype,1,52,MP_COMM_WORLD);
} else if(rank==1) {
MP_Recv(&x[0][2],1,coltype,3,52,MP_COMM_WORLD,&status);
for(i=0;i<4;++i) printf("P:%d my x[%d][2]=%1f\n",rank,i,x[i][2]);
}
MP_Finalize();
}
II. MPI
E*e#$%os. extent.c
#include <stdio.h>
#include<mpi.h>
void main(intargc, char *argv[]) {
int rank,i;
MP_Status status;
struct{ int num; float x; double data[4]; } a;
int blocklengths[3]={1,1,4};
MP_Datatype types[3]={MP_NT,MP_FLOAT,MP_DOUBLE};
MP_Aint displacements[3];
MP_Datatype restype;
MP_Aint intex,floatex;
MP_nit(&argc,&argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
MP_Type_extent(MP_NT,&intex);
MP_Type_extent(MP_FLOAT,&floatex);
II. MPI
E*e#$%os
displacements[0]= (MP_Aint)0;
displacements[1]=intex;
displacements[2]=intex+floatex;
MP_Type_struct(3,blocklengths,displacements,types,&restype);
MP_Type_commit(&restype);
if (rank==3){
a.num=6;
a.x=3.14;
for(i=0;i<4;++i)
a.data[i]=(double) i;
MP_Send(&a,1,restype,1,52,MP_COMM_WORLD);
} else
if(rank==1) {
MP_Recv(&a,1,restype,3,52,MP_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]);
}
MP_Finalize();
}
II. MPI
E*e#$%os. 2cast.c
#include<mpi.h>
#include <stdio.h>
void main (int argc, char *argv[]) {
int rank;
double param;
MP_nit(&argc, &argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
if(rank==5)
param=23.0;
MP_Bcast(&param,1,MP_DOUBLE,5,MP_COMM_WORLD);
printf("P:%d after broadcast parameter is %f\n",rank,param);
MP_Finalize();
}
II. MPI
E*e#$%os. scatter&os.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;
MP_nit(&argc, &argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
MP_Comm_size(MP_COMM_WORLD,&size);
revcnt=1;
if(rank==3){
for(i=0;i<4;i++)
param[i]=23.0+i;
sndcnt=1;
}
MP_Scatter(param,sndcnt,MP_DOUBLE,&mine,revcnt,MP_DOUBLE,3,MP_COMM_WORLD);
printf("P:%dmine is %f\n",rank,mine);
MP_Finalize();
}
II. MPI
E*e#$%os. re&(ce&os.c
#include <mpi.h>
#include <stdio.h>
void main (int argc, char *argv[]) {
int rank;
struct{ double value; int rank;} in, out;
int root;
MP_nit(&argc, &argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
in.value=rank+1;
in.rank=rank;
root=7;
MP_Reduce(&in,&out,1,MP_DOUBLE_NT,MP_MAXLOC,root,MP_COMM_WORLD);
if(rank==root)
printf("PE:%dmax=%lf at rank %d\n",rank,out.value,out.rank);
MP_Reduce(&in,&out,1,MP_DOUBLE_NT,MP_MNLOC,root,MP_COMM_WORLD);
if(rank==root)
printf("PE:%dmin=%lf at rank %d\n",rank,out.value,out.rank);
MP_Finalize();
}
II. MPI
E*e#$%os. create.c
#include <mpi.h>
#include <stdio.h>
/*Con 4 procesadores*/
#define TRUE 1
typedef struct{
double real,imag;
} complex;
void cprod(complex *in, complex *inout, int *len, MP_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++;
}
}
II. MPI
E*e#$%os. create.c
void main (int argc, char *argv[]) {
int rank;
int root;
complex source,result;
MP_Op myop;
MP_Datatypectype;
MP_nit(&argc, &argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
MP_Type_contiguous(2,MP_DOUBLE,&ctype);
MP_Type_commit(&ctype);
MP_Op_create(cprod,TRUE,&myop);
root=2;
source.real=rank+1;
source.imag=rank+2;
MP_Reduce(&source,&result,1,ctype,myop,root,MP_COMM_WORLD);
if(rank==root)
printf("PE:%d result is %lf + %lfi\n",rank, result.real, result.imag);
MP_Finalize();
}
--------------------------------------------
P:2 result is -185.000000 + -180.000000i
NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os 5Mo&(%ari&a&8

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
II. MPI
Mo&(%ari&a&

MP permite definir grupos de procesos. Un grupo es una coleccin


de procesos, y define un espacio de direcciones (desde 0 hasta el
tamao del grupo menos 1).

Los miembros del grupo tienen asignada una direccin dentro de l.


Un proceso puede pertenecer simultneamente a varios grupos, y
tener una direccin distinta en cada uno de ellos.

Un comunicador es un uni"erso de comunicaci#n. Bsicamente


consiste en un grupo de procesos, y un conteto de comunicacin.
Las comunicaciones producidas en dos comunicadores diferentes
nunca interfieren entre s.
II. MPI
Mo&(%ari&a&

El concepto de comunicador se introdujo para facilitar la elaboracin


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.

Adems, as tampoco hay problemas a la hora de usar etiquetas.

Dos de las funciones sobre comunicadores ya han sido


presentadas:

MPI@Co##@si'e58 para averiguar el tamao (nmero de procesos) de


un comunicador
int MP_Comm_size(MP_Comm comm, int *size);
II. MPI
Mo&(%ari&a&

MPI@Co##@ranP58 para que un proceso obtenga su


identificacin dentro del comunicador.
int MP_Comm_rank(MP_Comm comm, int *rank);

La funcin MPI@Co##@&($58 permite crear un nuevo


comunicador, con el mismo grupo de procesos, pero diferente
contexto. Se puede usar antes de llamar a una funcin de una
biblioteca.
int MP_Comm_dup(MP_Comm comm, MP_Comm *newcomm);
II. MPI
Mo&(%ari&a&
La Figura muestra cmo puede ocurrir que un mensaje del
usuario (flecha fina) interfiera con los mensajes propios de una
funcin de biblioteca (flechas gruesas). Si la biblioteca trabaja en
un comunicador diferente (derecha) entonces no hay problemas
de interferencia.
II. MPI
Mo&(%ari&a&

La operacin MPI@Co##@&($587 as como todas las dems que


crean comunicadores, son operaciones colectivas: tienen que
ser invocadas por todos los procesos implicados, con
argumentos compatibles.

MPI@Co##@!ree58 destruye un comunicador que ya no se va a


emplear.
.
MP_Comm_dup (MP_COMM_WORLD, &newcomm);
/* llamada a funcin, que se ejecutar dentro de newcomm */
MP_Comm_free (&newcomm);
.
II. MPI
Mo&(%ari&a&

Por su parte, MPI@Co##@s$%it58 crea, a partir de un


comunicador inicial, varios comunicadores diferentes, cada uno
con un conjunto disjunto de procesos. La variable co%or
determina en qu comunicador queda cada uno de los procesos.
int MP_Comm_split(MP_Comm comm, int color, int key,
MP_Comm *newcomm);
II. MPI
Mo&(%ari&a&. E*e#$%o

Veamos un ejemplo de creacin de comunicadores con MP_Comm_split().

Partiendo del comunicador universal, definimos dos comunicadores: uno con


aquellos procesos que tienen direccin par en el comunicador
MP_COMM_WORLD, y otro con los procesos impares. Cada proceso
pertenecer a dos comunicadores: al universal y al recin creado, y tendr por lo
tanto dos direcciones, una por comunicador.
int myglobalid, myotherid, color;
MP_Comm newcom;
MP_Comm_rank (MP_COMM_WORLD, &myglobalid);
if (myglobalid%2 == 0) color = 0;
else color = 1;
MP_Comm_split (comm, color, myglobalid, &newcom);
MP_Comm_rank (newcom, &myotherid);
/* operaciones entre pares e impares, por separado */
MP_Comm_free (&newcom);
II. MPI
Mo&(%ari&a&. E*e#$%o

La Figura muestra una coleccin de seis procesos que forman


inicialmente parte del comunicador universal y que, tras
MPI@Co##@s$%it58 pasan a formar dos nuevos comunicadores
disjuntos.
II. MPI
Mo&(%ari&a&.

La funcin MPI@Interco##@create58 nos permite crear un


intercomunicador.
int MP_ntercomm_create(MP_Comm local_comm,
int local_leader, MP_Comm peer_comm,
int remote_leader, int tag, MP_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).
II. MPI
Mo&(%ari&a&.

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

nterpretar los argumentos de esta funcin no es trivial. En primer lugar, cada


proceso tiene que facilitar el comunicador ( %oca%@co##), y nombrar a un
proceso local como lider del intercomunicador (%oca%@%ea&er). Luego hay que
facilitar un comunicador que englobe a los dos comunicadores que queremos
intercomunicar ($eer@co##; MP_COMM_WORLD siempre resulta vlido), y la
direccin de un proceso del otro comunicador que va a actuar como lder
(re#ote@%ea&er), teniendo en cuenta que esa direccin corresponde al
comunicador global.

Con esto ya se tiene tendido un "puente entre los dos comunicadores. Tambin
hay que facilitar un nmero de etiqueta (ta)) que est libre y que el programador
no debe emplear para ningn otro propsito.

El intercomunicador lo obtenemos en ne"interco##. 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 envo, o las de los procesos emisores que se obtienen tras una
funcin de recepcin, hacen referencia a ese "otro lado.
II. MPI
Mo&(%ari&a&.
II. MPI
Mo&(%ari&a&. E*e#$%o

El siguiente ejemplo toma como punto de partida los dos


comunicadores creados en el ejemplo anterior: uno con los
procesos que en MP_COMM_WORLD tienen direccin par, y
otro con los que tienen en ese comunicador direccin impar.
Cada proceso tiene almacenado en newcom el comunicador al
que pertenece, y en myotherid su direccin en ese comunicador.
Tras crear, de forma colectiva, el intercomunicador, cada proceso
del comunicador "par enva un mensaje a su semejante en el
comunicador "impar.
II. MPI
Mo&(%ari&a&. E*e#$%o
if (myglobalid%2 == 0) {
MP_ntercomm_create (newcom, 0, MP_COMM_WORLD,
1, 99, &intercomm);
MP_Send(msg, 1, type, myotherid, 0, intercomm);
}
else {
MP_ntercomm_create (newcom, 0, MP_COMM_WORLD,
0, 99, &intercomm);
MP_Recv(msg, 1, type, myotherid, 0, intercomm, &status);
}
NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os 5Mo&(%ari&a&8

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
II. MPI
To$o%o)as 0irt(a%es

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


"topologa de la red (anillo, estrella, toroidal ...)

La forma ptima de particionar y asignar a los diferentes procesos


puede depender del hardware subyacente. Si la topologa 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 nmero


reducido de procesos vecinos. Esta es la "topologa de la
aplicacin.
II. MPI
To$o%o)as 0irt(a%es

Para que la implementacin paralela sea eficiente debemos hacer


que la topologa de la aplicacin se adapte a la topologa del
hardware.

MP permite al vendedor de hardware desarrollar rutinas de


topologa especializadas a travs de la implementacion de las
funciones de MP de topologa.

Al elegir una "topologa de la aplicacin o "topologa virtual, el


usuario est diciendo como va a ser preponderantemente la
comunicacin. Sin embargo, como siempre, todos los procesos
podrn comunicarse entre s.
II. MPI
To$o%o)as 0irt(a%es

La topologa virtual ms simple (y usada corrientemente en


aplicaciones numricas) es la "cartesiana.

En la forma en que lo describimos hasta ahora, usaramos una


topologa cartesiana 1D, pero en realidad el problema llama a una
topologa 2D. Tambin hay topologas cartesianas 3D, y de
dimensin arbitraria
II. MPI
To$o%o)as 0irt(a%es

En la topologa cartesiana 2D a cada proceso se le asigna una tupla de


dos nmeros (; J). MP provee una serie de funciones para definir,
examinar y manipular estas topologas.

La rutina MPI@Cart@create5...8 permite definir una topologa cartesiana


2D.
MP-Cart-create(MP-Comm comm-old, int ndims,2 int *dims,
int *periods, int reorder, MP-Comm *new-comm);
&i#s< vector que contiene el nmero de filas/columnas en cada
direccin.
$erio&s< un vector de flags que indica si una direccin dada es peridica
o no.
reor&er: El argumento bool reorder activado quiere decir que MP puede
reordenar los procesos de tal forma que optimice la relacin entre la
topologa virtual y la de hardware.

II. MPI
To$o%o)as 0irt(a%es

Ejemplo:
.
int dims[2]={4,4}, periods[2]={0,0};
MP-Comm comm2d;
MP-Cart-create(MP-COMM-WORLD,2,dims, periods, 1, comm2d);
.
II. MPI
To$o%o)as 0irt(a%es

Ejemplos de topologas virtuales:


II. MPI
To$o%o)as 0irt(a%es

MPI@Cart@)et58 permite recuperar las dimensiones, periodicidad y


coordenadas (dentro de la topologa) del proceso.
int MP-Cart-get(MP-Comm comm, int maxdims, int *dims,
int *periods, int *coords );

Con MPI@Cart@coor&s58 se pueden conseguir directamente slo la


tupla de coordenadas del proceso en la topologa.
int MP_Cart_coords(MP-Comm comm,int rank, int maxdims,
int *coords);
II. MPI
To$o%o)as 0irt(a%es

Antes de hacer una operacin de


actualizacin u
k
u
k+1
, tenemos que
actualizar los ghost values.

Por ejemplo, con una topologa 1D:


Enviar e-1 a P+1
Recivir e de P+1
Enviar s a P-1
Recivir s-1 de P-1
II. MPI
To$o%o)as 0irt(a%es

En general se puede ver como que estamos haciendo un "shift de


los datos hacia arriba y hacia abajo.

Esta es una operacin muy comn y MP provee una rutina


(MP_Cart_shift()) que calcula los rangos de los procesos para una
dada operacin de shift:
int MP-Cart-shift(MP-Comm comm,int direction,int displ,
int *source,int *dest);

Por ejemplo, en una topologa 2D, para hacer un shift en la


direccin horizontal
int source-rank, dest-rank;
MP-Cart-shift(comm2d,0,1,
&source-rank,&dest-rank);
II. MPI
To$o%o)as 0irt(a%es

Que ocurre en los bordes? Si la topologa es de 5x5, entonces un


shift en la direccion 0 (eje x) con desplazamiento displ = 1 para el
proceso (4; 2) da
II. MPI
To$o%o)as 0irt(a%es

MPI@PROC@NULL es un "proceso nulo. La idea es que enviar a


MP_PROC_NULL equivale a no hacer nada (como el /dev/null de
Unix).

Una operacin como


MP-Send(. . .,dest,. . .)
equivaldra a
if (dest != MP-PROC-NULL)
MP-Send(. . .,dest,. . .);
II. MPI
To$o%o)as 0irt(a%es

Si el nmero de filas a procesar n-1 es mltiplo 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 mltiplo 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);
II. MPI
To$o%o)as 0irt(a%es

MP provee una rutina MPE@Deco#$=&58 que hace esta operacin.


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 ms.
II. MPI
To$o%o)as 0irt(a%es. E*e#$%o

Por ejemplo, queremos distribuir 1000 objetos en 10 procesadores


con pesos:
in [0] weight 0.143364, wants 143.364373, assigned 143
in [1] weight 0.067295, wants 67.295034, assigned 67
in [2] weight 0.133623, wants 133.623150, assigned 134
in [3] weight 0.136241, wants 136.240810, assigned 136
in [4] weight 0.155558, wants 155.557799, assigned 156
in [5] weight 0.033709, wants 33.708929, assigned 33
in [6] weight 0.057200, wants 57.200313, assigned 57
in [7] weight 0.131086, wants 131.085889, assigned 132
in [8] weight 0.047398, wants 47.397738, assigned 47
in [9] weight 0.094526, wants 94.525966, assigned 95
total rows 1000
II. MPI
To$o%o)as 0irt(a%es. E*e#$%o

La siguiente funcin 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);
}
II. MPI
To$o%o)as 0irt(a%es. E*e#$%o

La siguiente funcin 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
esttico de carga
II. MPI
E*e#$%os
#include<mpi.h>
/* Run with 12 processes */
void main(intargc, char *argv[]) {
int rank;
MP_Comm vu;
int dim[2],period[2],reorder;
int coord[2],id;
MP_nit(&argc, &argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
dim[0]=4; dim[1]=3;
period[0]=TRUE; period[1]=FALSE;
reorder=TRUE;
II. MPI
E*e#$%os
MP_Cart_create(MP_COMM_WORLD,2,dim,period,reorder,&vu);
if(rank==5){
MP_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;
MP_Cart_rank(vu,coord,&id);
printf("Theprocessor at position (%d, %d) has rank %d\n",coord[0],coord[1],id);
}
MP_Finalize();
}
II. MPI
E*e#$%os
#include<mpi.h>
#define TRUE 1
#define FALSE 0
void main(intargc, char *argv[]) {
int rank;
MP_Comm vu;
int dim[2],period[2],reorder;
int up,down,right,left;
MP_nit(&argc, &argv);
MP_Comm_rank(MP_COMM_WORLD,&rank);
dim[0]=4; dim[1]=3;
period[0]=TRUE; period[1]=FALSE;
reorder=TRUE;
II. MPI
E*e#$%os
MP_Cart_create(MP_COMM_WORLD,2,dim,period,reorder,&vu);
if(rank==9){
MP_Cart_shift(vu,0,1,&left,&right);
MP_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);
}
MP_Finalize();
}
NDICE
II. PROGRAMACIN CON PASO DE MENSAFES 5MPI8

Intro&(ccin

Gettin) starte&

Co#(nicaciones $(nto a $(nto

Co#(nicaciones co%ecti0as

Ti$os &e &atos &eri0a&os

Co#(nica&ores A )r($os 5Mo&(%ari&a&8

To$o%o)as 0it(a%es

Intro&(ccin a MPI.>
II. MPI
Intro&(ccin a MPI.>
Intro&(ccin

MPI.= se cre para agrupar las diferentes liberas de paso de


mensajes bajo una misma sintaxis

MPI.> aade nuevas funcionalidades requeridas por los


programadores:

Mejoras y extensiones a MP-1

Gestin dinmica de procesos

Acceso remoto a memoria

Entrada/Salida paralela

nteraccin con threads

nteroperabilidad con lenguajes

.
II. MPI
Intro&(ccin a MPI.>
E,S Para%e%a

Se puede ver como una versin avanzada de la E/S de Unix:

Acceso no contiguo a memoria y ficheros

Operaciones colectivas de E/S

Uso de offsets explcitos para evitar seeks separados

Punteros individuales y compartidos a ficheros

E/S no bloqueante

Representaciones de datos portables y personalizados


II. MPI
Intro&(ccin a MPI.>
E,S Para%e%a
II. MPI
Intro&(ccin a MPI.>
E,S Para%e%a
II. MPI
Intro&(ccin a MPI.>
E,S Para%e%a
II. MPI
Intro&(ccin a MPI.>
E,S Para%e%a
II. MPI
Intro&(ccin a MPI.>
E,S Para%e%a
II. MPI
Intro&(ccin a MPI.>
E,S Para%e%a
II. MPI
Intro&(ccin a MPI.>
Acceso re#oto a #e#oria

MPI.= provee una completa interfaz para el paso de mensajes.

MPI.>, adems, permite acceder directamente a la memoria de otros


procesos.

Va a usar operaciones del tipo $et, put y update para acceder a


datos remotos.

Es eficiente y portable para diferentes arquitecturas


II. MPI
Intro&(ccin a MPI.>
Acceso re#oto a #e#oria

Tres pasos principales:

Definir en el proceso qu memoria va a usarse para operaciones


RMA. Se crea un objeto MPI@+in.

Especificar qu datos se van a mover y a dnde. Se usan las


operaciones MPI@P(t, MPI@Get y MPI@Acc(#(%ate.

Verificar que los datos se han recibido por completo. Se usa la


funcin MPI@+in@!ence. Otro mtodo es usar MPI@+in@%ocP y
MPI@+in@(n%ocP.
II. MPI
Intro&(ccin a MPI.>
Acceso re#oto a #e#oria

Memory Windows (ventanas de memoria)

Son los espacios de memoria reservados para ser usados en las


operaciones de acceso remoto a memoria..

%rea una "entana.


int MPI@+in@create(void *base, MP_Aint size, int disp_unit,
MP_nfo info, MP_Comm comm, MP_Win *win);

&iberar una "entana. '#lo debe llamarse cuando (an terminado todas las
operaciones )*+.
int MPI@+in@!ree(MP_Win *win);

Ambas son operaciones colectivas, deben ser llamadas por todos los
procesos involucrados.
II. MPI
Intro&(ccin a MPI.>
Acceso re#oto a #e#oria

Moviendo datos

,one datos en una "entana de memoria (no bloqueante!


int MPI@P(t(void *origin_addr, int origin_count,
MP_Datatype origin_datatype, int target_blank,
MP_Aint target_disp, int target_count,
MP_Datatype target_datatype, MP_Win win);

Obtiene datos de una "entana de memoria (no bloqueante!


int MPI@Get(void *origin_addr, int origin_count,
MP_Datatype origin_datatype,int target_rank,
MP_Aint target_disp, int target_count,
MP_Datatype target_datatype, MP_Win win);
II. MPI
Intro&(ccin a MPI.>
Acceso re#oto a #e#oria

Moviendo datos

+ctuali-a los datos de una "entana de memoria


int MPI@Acc(#(%ate(void *origin_addr, int origin_count,
MP_Datatype origin_datatype, int target_rank,
MP_Aint target_disp, int target_count,
MP_Datatype target_datatype, MP_Op op,
MP_Win win);

%ompleta una trans.erencia de datos


int MPI@+in@!ence(int assert, MP_Win win);
II. MPI
Intro&(ccin a MPI.>
Acceso re#oto a #e#oria
II. MPI
Intro&(ccin a MPI.>
Acceso re#oto a #e#oria
II. MPI
Intro&(ccin a MPI.>
Gestin &inC#ica &e $rocesos

En MPI.= el nmero de procesos de COMM@+ORLD es fijo durante


toda la ejecucin.

En MPI.> podemos crear procesos usando la operacin colectiva


MPI@Co##@s$a"n

Esta funcin devuelve un intercomunicador que desde el punto


de vista de los padres, agrupa a los padres, mientras que para
los hijos sera su propio COMM@+ORLD.
II. MPI
Intro&(ccin a MPI.>
Gestin &inC#ica &e $rocesos

Intraco#(nica&or: conjunto de procesos (MP-1)

Interco#(nica&or: engloba 2 conjuntos de procesos (local y


remoto). La idea existe en MP-1, pero la especificacin de
operaciones colectivas en intercomunicadores aparece en MP-2.
II. MPI
Intro&(ccin a MPI.>
Gestin &inC#ica &e $rocesos

Creacin de procesos hijos


int MPI@Co##@s$a"n(char *command, char *argv[], int maxprocs,
MP_nfo info, int root, MP_Comm comm,
MP_Comm *intercomm, int array_of_errcodes[]);
Debe ser ejecutada por todos los procesos de comm

Obtiene el comunicador de los padres


int MPI@Co##@)et@$arent(MP_Comm *parent);
Slo ejecutado por los hijos
II. MPI
Intro&(ccin a MPI.>
Gestin &inC#ica &e $rocesos

Creacin de mltiples procesos hijos


int MPI@Co##@s$a"n@#(%ti$%e(int count,
char *array_of_commands[], char **array_of_argv[],
int array_of_maxprocs[], MP_nfo array_of_info[], int root,
MP_Comm comm, MP_Comm *intercomm,
int array_of_errcodes[]);
II. MPI
Intro&(ccin a MPI.>
Gestin &inC#ica &e $rocesos

Filosofa cliente/servidor
II. MPI
Intro&(ccin a MPI.>
Gestin &inC#ica &e $rocesos

Filosofa cliente/servidor
II. MPI
Intro&(ccin a MPI.>
Entorno &e e*ec(cin

Lam

Mvapich

Openmpi

Mpich2 pero no mpich (mpich2 no esta en EULER)


NDICE
i. PROGRAMACN EN ENTORNO CLUSTER
ii. PROGRAMACN CON PASO DE MENSAJES (MP)
iii. PROGRAMACN CON PARALELSMO MPLCTO
(OpenMP)
NDICE
III. PROGRAMACIN CON PARALELISMO IMPLCITO
5OMP8

Intro&(ccin

Conce$tos 2Csicos

Para%e%is#o &e &atos

Directi0as OMP

Re)iones $ara%e%as

R(n.Ti#e %i2rarA
NDICE
III. PROGRAMACIN CON PARALELISMO IMPLCITO
5OMP8

Intro&(ccin

Conce$tos 2Csicos

Para%e%is#o &e &atos

Directi0as OMP

Re)iones $ara%e%as

R(n.Ti#e %i2rarA
III. O$enMP
Intro&(ccin

El OpenMP Application Program nterface (AP) es:


%on/unto de directi"as de compilacion0 librer1as 2 "ariables de
entorno que permiten epresar el paralelismo de tareas en
pro$ramas escritos en %0 %33 2 4ortran

Toda la informacin est disponible en la pgina web:


www.openmp.or$
III. O$enMP
Intro&(ccin

El estndar 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

nternational Business Machines (BM)

ntel Corporation

KA Software Lab (KSL)

NEC Corporation

Silicon Graphics nc. (SG)

Sun Microsystems

Universidad RWTH Aachen


III. O$enMP
Intro&(ccin

Antes de la introduccin de OpenMP cada fabricante tena su propio


"estndar

Los programas tenan portabilidad nula

El estndar ANS X3H5 fracas por falta de apoyo

Se perdi inters en las mquinas SMP

El estndar OpenMP se introdujo para resolver esto:

En 1997 se public la versin 1.0

En 1999 se public la versin 1.1

En 2000 se public la versin 2.0

En 2005 se public la versin 2.5


III. O$enMP
Intro&(ccin

OpenMP se fundamenta en directivas y clusulas:

Las directivas especifican qu hacer

Las clusulas indican cmo hacerlo

Se aaden como comentarios al cdigo

Tipos de directivas en OpenMP:

Directivas de distribucin de trabajo

Directivas de sincronizacin de tareas

Tipos de clusulas en OpenMP:

Clusulas de datos

Clusulas de comportamiento

Clusulas de sincrona
III. O$enMP
Intro&(ccin

Ventajas de OpenMP:

Sencillo: no requiere el envo explcito de mensajes como en MP

La descomposicin de los datos es automtica

Admite la paralelizacin incremental del cdigo

Mismo cdigo fuente para las versiones serial y paralela

Permite implementar granularidad gruesa y fina

Elevada portabilidad
III. O$enMP
Intro&(ccin

nconvenientes de OpenMP:

Requiere un compilador que entienda OpenMP

El estndar slo contempla C y Fortran

Slo es eficiente en mquinas 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 cdigo


III. O$enMP
Intro&(ccin

Compiladores que soportan OpenMP

SG MPSpro

BM XL

Sun Studio

Portland Group Compilers and Tools

Absoft Pro FortranMP

Lahey/Fujitsu Fortran 95

Fujitsu-Siemens Fortran 95 (Solaris)

ntel Software Development Products

PathScale

GNU GCC (a partir de la versin 4.2)

HP
III. O$enMP
Intro&(ccin

El soporte para OpenMP ha de ser activado

Versin serial de un programa:


ifort ejemplo.f90

Versin paralela de un programa:


ifort -openmp ejemplo.f90

En casi todos los compiladores la opcin es -openmp


NDICE
III. PROGRAMACIN CON PARALELISMO IMPLCITO
5OMP8

Intro&(ccin

Conce$tos 2Csicos

Para%e%is#o &e &atos

Directi0as OMP

Re)iones $ara%e%as

R(n.Ti#e %i2rarA

Un programa secuencial es un caso especial de un programa de


memoria compartida

Paralelizacin 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 iteracin 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. O$enMP
Conce$tos 2Csicos
III. O$enMP
Conce$tos 2Csicos
DO , !or iteraciones compartidas
de un bucle por el equipo.
Representa un tipo de
"paralelismo de datos".
SECTIONS particiona el trabajo en
secciones separadas.
Cada seccin es ejecutada por un hilo.
Se puede utilizar para implementar un
tipo de "paralelismo funcional
SINGLE serializa una
seccin de cdigo

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 informacin necesaria para
llevar a cabo las iteraciones
III. O$enMP
Conce$tos 2Csicos

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. O$enMP
Conce$tos 2Csicos

E% contexto &e e*ec(cin

Todo hilo tiene un contexto de ejecutacin, que consiste en


el espacio de direcciones que el hilo puede acceder

El contexto de ejecutacin incluye variables estticas,


estructuras dinmicamente asignadas, etc
III. O$enMP
Conce$tos 2Csicos
NDICE
III. PROGRAMACIN CON PARALELISMO IMPLCITO
5OMP8

Intro&(ccin

Conce$tos 2Csicos

Para%e%is#o &e &atos

Directi0as OMP

Re)iones $ara%e%as

R(n.Ti#e %i2rarA
III. O$enMP
Para%e%is#o &e &atos

Caractersticas generales de clusulas de datos:

Especifican propiedades "paralelas de las variables

Pueden aparecer tantas veces como sea necesario

Pueden usarse con cualquier directiva OpenMP

Restricciones generales de clusulas de datos:

Una variable no puede aparecer en ms de una clusula

Slo admiten variables que sean visibles desde la subrutina o


funcin que incluya la clusula

Earia2%es co#$arti&as A Earia2%es $ri0a&as

Una variable compartida tiene la misma direccin en el


contexto de ejecutacin de cada hilo.

Una variable privada tiene una direccin distinta en el


contexto de ejecutacin de cada hilo.

Un hilo no puede acceder a las variables privadas de otro


hilo.
III. O$enMP
Para%e%is#o &e &atos
III. O$enMP
Para%e%is#o &e &atos

La clusula SDARED

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
III. O$enMP
Para%e%is#o &e &atos

La clusula SDARED

Caractersticas de las variables compartidas:


o
Todas las tareas ven su contenido
o
Todas las tareas pueden cambiar su contenido
o
Todas las tareas ven los cambios realizados

Peculiaridades de las variables compartidas:


o
Los cambios no son inmediatos (cache coherency)
o
Pueden requerir de sincrona entre tareas
o
Existen algunas limitaciones en Fortran
III. O$enMP
Para%e%is#o &e &atos

La clusula PRIEATE

Especifica que una variable es privada a cada tarea:


#pragma omp parallel for PRVATE(a,b )
o
! $OMP PARALLEL PRVATE (a,b)
...
! $OMP END PARALLEL
III. O$enMP
Para%e%is#o &e &atos

La clusula PRIEATE

Caractersticas de las variables privadas:


o
Cada tarea tiene su propia versin de la variable
o
Eso se consigue replicando la variable en memoria
o
Las otras tareas no pueden ver su contenido

Peculiaridades de las variables privadas:


o
Su valor inicial no est definido
o
Tras la regin paralela su valor tampoco est definido
o
Existen algunas limitaciones

Variables privadas
for (i = 0; i < BLOCK_SIZE(id,p,n); i++)
for (j = 0; j < n; j++)
a[i][j] = MI(a[i][j],a[i][!]+"#p[j]);

Cualquier de los bucles se podria ejecutar en paralelo

Es mejor paralelizar el bucle exterior para reducir el nmero de forks/joins

Todas las variables excepto el indice son compartidas.

Deberiamos dar cada hilo su copia privada de j


III. O$enMP
Conce$tos 2Csicos

Variables privadas
S$ra)#a o#$ $ara%%e% !or $ri0ate5*8 S$ra)#a o#$ $ara%%e% !or $ri0ate5*8
for (i = 0; i < BLOCK_SIZE(id,p,n); i++)
for (j = 0; j < n; j++)
a[i][j] = MI(a[i][j],a[i][!]+"#p[j]);

Cualquier de los bucles se podria ejecutar en paralelo

Es mejor paralelizar el bucle exterior para reducir el nmero de forks/joins

Todas las variables excepto el indice son compartidas.

Deberiamos dar cada hilo su copia privada de j


III. O$enMP
Conce$tos 2Csicos
III. O$enMP
Para%e%is#o &e &atos

La clusula DE6AULT

Especifica el comportamiento por defecto:


#pragma omp parallel for DEFAULT( PRVATE ) SHARED (a)
o
! $OMP PARALLEL DEFAULT ( PRVATE ) SHARED (a)
...
! $OMP END PARALLEL
III. O$enMP
Para%e%is#o &e &atos

La clusula DE6AULT

Caractersticas de la clusula:
o
Slo puede aparecer una nica vez en cada directiva
o
Admite tres opciones: PRVATE, SHARED y NONE
o
Con NONE todas las variables deben ser definidas
o
Slo afecta a las variables directamente visibles:
o
Las variables definidas dentro de la subrutina ejemplo no se ven
afectadas por la clusula DEFAULT

!irst$ri0ate58

Es una extensind e la clusula PRVATE

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 iteracin,


entonces este valor ser el valor de la variable en iteraciones
subsecuentes
III. O$enMP
Conce$tos 2Csicos

!irst$ri0ate58
x[0] = complex_function();
for (i-0;j<n;i++)
{
for (j=1;j<4;j++)
x[j]=g(,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 iteracin del bucle interior.
III. O$enMP
Conce$tos 2Csicos

!irst$ri0ate58

Se podra mover la inicializacin 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(,x[j-1]);
answer[i] = x[i] x[j];
}
III. O$enMP
Conce$tos 2Csicos
III. O$enMP
Para%e%is#o &e &atos

La clusula 6IRSTPRIEATE

Caractersticas de las variables FRSTPRVATE:


o
Cada tarea tiene su propia versin de la variable
o
Eso se consigue replicando la variable en memoria
o
Las otras tareas no pueden ver su contenido
o
Su valor es inicializado con la variable original

Peculiaridades de las variables FRSTPRVATE:


o
Tras la regin paralela su valor no est definido

La clusula LASTPRIEATE

La clusula se usa para copiar el valor privado del hilo que ejecut la
ltima iteracin a la copia del hilo maestro
III. O$enMP
Conce$tos 2Csicos
III. O$enMP
Para%e%is#o &e &atos

Resumen de clusulas de datos

Clusulas de datos vistas:


o
SHARED, PRVATE, DEFAULT, FRSTPRVATE

Clusulas de datos adicionales:


o
LASTPRVATE, REDUCTON, COPYN, COPYPRVATE

Condiciones generales a tener en cuenta:


o
Una variable slo puede aparecer en una clusula, salvo en
FRSTPRVATE y LASTPRVATE, a la vez
o
El contador de un bucle siempre es privado
o
Cada clusula tiene sus limitaciones
NDICE
III. PROGRAMACIN CON PARALELISMO IMPLCITO
5OMP8

Intro&(ccin

Conce$tos 2Csicos

Para%e%is#o &e &atos

Directi0as OMP

Re)iones $ara%e%as

R(n.Ti#e %i2rarA
III. O$enMP
Directi0as &istri2(cin &e tra2a*o

Caractersticas 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

ncluyen al final una sincronizacin implicita

Restricciones de estas directivas:

Deben ser encontradas por todas las tareas

Slo pueden contener bloques estructurados de cdigo


III. O$enMP
Directi0as &istri2(cin &e tra2a*o

La directiva PRAGMA OMP PARALLEL 6OR

Caractersticas de la directiva:
o
Distribuye la carga de un bucle entre las tareas
o
La descomposicin se hace en el espacio de iteraciones
o
El contador es implcitamente declarado PRVATE

Restricciones :
o
En C, el bucle debe ser de un tipo determinado
o
En Fortran, el bucle no puede ser del tipo do while
o
El contador debe ser el mismo para todas las tareas
o
Slo admite bloques estructurados de cdigo
o
Las variables SHARED slo se actualizan al final

La directiva PRAGMA OMP PARALLEL SECTION

Hasta ahora hemos considerado paralelismo de data nada


ms

OpenMP nos permite asignar hilos distintos a partes


distintas del cdigo (paralelismo funcional)

Permite implementar el paralelismo tipo MMD

Precede a un bloque de 5 bloques de cdigo que se puede


ejecutar en paralelo por 5 hilos

La sintaxis:
S$ra)#a o#$ $ara%%e% sections
III. O$enMP
Directi0as &istri2(cin &e tra2a*o
v = alpha();
w = beta();
x = gamma(v, w);
y = delta();
printf ("%6.2f\n", epsilon(x,y));
a l p h a b e t a
g a m m a d e l t a
e p s i l o n
Se puede ejecutar
alpha, beta, and delta
en paralelo.
III. O$enMP
Directi0as &istri2(cin &e tra2a*o

La directiva PRAGMA OMP SECTION

Precede cada bloque de cdigo dentro del bloque grande

Se puede omitir para el primer bloque despus de la


pragma parallel sections

La sintaxis:
$pra%#a o#p &'("ion
III. O$enMP
Directi0as &istri2(cin &e tra2a*o

E*e#$%o &e $ara%%e% section


$pra%#a o#p para))') &'("ion&
*
$pra%#a o#p &'("ion +, Op"iona) ,+
- = a)p.a();
$pra%#a o#p &'("ion
/ = 0'"a();
$pra%#a o#p &'("ion
1 = d')"a();
2
3 = %a##a(-, /);
prin"f (45678f9n4, 'p&i)on(3,1));
III. O$enMP
Directi0as &istri2(cin &e tra2a*o
Otra Posi2i%i&a&
a l p h a b e t a
g a m m a d e l t a
e p s i l o n
Ejecutar alpha y
beta en paralelo.
Ejecutar gama y
delta en paralelo.
III. O$enMP
Directi0as &istri2(cin &e tra2a*o

La directiva PRAGMA OMP SECTIONS

Aparece a dentro de un bloque paralelo de cdigo

Tiene el mismo significado como la pragma $ara%%e%


sections

Varias pragmas sections dentro de un bloque paralelo


podra reducir los gastos de fork/join

Restricciones de la directiva:
o
La manera de asignar secciones a tareas no est
definida
o
Cada seccin debe ser un bloque estructurado de
cdigo
o
No se crean nuevas tareas, se usan las existentes
o
Las variables SHARED slo se actualizan al final
III. O$enMP
Directi0as &istri2(cin &e tra2a*o
$pra%#a o#p para))')
*
$pra%#a o#p &'("ion&
*
- = a)p.a();
$pra%#a o#p &'("ion
/ = 0'"a();
2
$pra%#a o#p &'("ion&
*
3 = %a##a(-, /);
$pra%#a o#p &'("ion
1 = d')"a();
2
2
prin"f (45678f9n4, 'p&i)on(3,1));
III. O$enMP
Directi0as &istri2(cin &e tra2a*o
NDICE
III. PROGRAMACIN CON PARALELISMO IMPLCITO
5OMP8

Intro&(ccin

Conce$tos 2Csicos

Para%e%is#o &e &atos

Directi0as OMP

Re)iones $ara%e%as

R(n.Ti#e %i2rarA
III. O$enMP
Re)iones $ara%e%as

Para crear regiones paralelas se utilizan las directivas


#PRAGMA OMP PARALLEL :

Definen una regin paralela

crea un conjunto de tareas

Las clusulas especifican condiciones a cumplir

Todas las tareas ejecutan las instrucciones


III. O$enMP
Re)iones $ara%e%as

Hay tres formas de especificar el nmero de tareas

La variable de entorno OMP_NUM_THREADS:


export OMP_NUM_THREADS=4

La subrutina omp_set_num_threads
void omp_set_num_threads(int t);
La clusula NUM_THREADS:
#PRAGMA OMP PARALLEL NUM_THREADS (4)

Cada una de ellas sobreescribe la especificacin anterior


III. O$enMP
Re)iones $ara%e%as

Caractersticas de la clusula F:

Crear una regin paralela es algo costoso

La opcin condition permite sopesarlo:


o
Si condition = TRUE entonces ejecuta en paralelo
o
Si condition = FALSE entonces ejecuta en serie

Slo se puede imponer una condicin


#PGRAMA OMP PARALLEL F( condition )
... instructions ...
NDICE
III. PROGRAMACIN CON PARALELISMO IMPLCITO
5OMP8

Intro&(ccin

Conce$tos 2Csicos

Para%e%is#o &e &atos

Directi0as OMP

Re)iones $ara%e%as

R(n.Ti#e %i2rarA

RUTNAS DE CONTROL

Funcin omp_get_num_procs
o
Devuelve el nmero de procesadores fisicos que estn
dispondible para el uso del programa paralelo
in" o#p_%'"_n:#_pro(&(-oid)

Funcin omp_set_num_threads
o
Se usa para asignar el nmero de hilos a ser activos en
secciones paralelas del cdigo
o
Se puede llamar en varios puntos del programa
-oid o#p_&'"_n:#_".r'ad&(in" ")
III. O$enMP
R(n.Ti#e Li2rarA

Funcin omp_get_num_procs
o
Devuelve el nmero de procesadores fisicos que estn dispondible para
el uso del programa paralelo
in" o#p_%'"_n:#_pro(&(-oid)

Funcin omp_set_num_threads
o
Se usa para asignar el nmero de hilos a ser activos en secciones
paralelas del cdigo
o
Se puede llamar en varios puntos del programa
-oid o#p_&'"_n:#_".r'ad&(in" ")

Funcin omp_get_thread_num
o
Todo hilo tiene una identificacin que es el nmero del hilo
omp_get_thread_num()
devuelve el nmero del hilo
III. O$enMP
R(n.Ti#e Li2rarA
III. O$enMP
R(n.Ti#e Li2rarA

Rutinas cerrojo

Herramienta adicional para la sincronizacin de tareas:


o
Permite introducir cerrojos ("locks) en el cdigo
o
Un cerrojo puede estar echado o no echado
o
Un cerrojo no echado puede ser echado por una tarea
o
La tarea pasa entonces a poseer el cerrojo
o
Las tareas no pueden alterar cerrojos que no poseen

Existen dos tipos de cerrojos:


o
cerrojos simples: slo pueden echarse una vez
o
cerrojos anidables: pueden echarse ms de una vez
III. O$enMP
R(n.Ti#e Li2rarA

Rutinas de cronometraje

Permiten medir tiempos de ejecucin de manera portable:


o
Proporcionan el wall clock time de cada tarea
o
El origen de tiempos no es el comienzo del programa
o
El tiempo proporcionado no es consistente entre tareas
o
Para determinar el tiempo de ejecucin:
Time_Seconds = omp_get_wtime ()
o
Para determinar la precisin del cronmetro:
Seconds_per_Tick = omp_get_wtick ()
III. O$enMP
Reco#en&aciones

Recomendaciones

Revisar el estndar a la hora de programar con OpenMP

Buscar sencillez y no optar por soluciones rebuscadas

Especificar el nmero de tareas con OMP NUM THREADS

Usar las clusulas de datos slo con PARALLEL

Declarar todas las variables como SHARED y slo las mnimas


necesarias como PRVATE

No usar directivas combinadas de distribucin de trabajo

No escribir a disco desde una regin paralela


III. O$enMP
E*e#$%os

Calcular el valor de la integral usando una suma de


rectngulos:
III. O$enMP
E*e#$%os
A)ra&eci#ientos

Oscar Flores
Universidad Politcnica de Madrid

Miguel Hermanns
Universidad Politcnica de Madrid

Mario Storti
Centro nternacional de Mtodos Numricos en
ngeniera CMEC Argentina

Manuel Martn Salvador


http://draxus.org

Jos Miguel Alonso


Facultad de nformtica UPV/EHU
A)ra&eci#ientos

Guillermo Marshall
Laboratorio de Sistemas Complejos, Departamento de
Computacion, FCEyN, UBA.

Luis Miguel de la Cruz


Unidad de nvestigacin en Cmputo Aplicado, DGSCA-
UNAM.
Li2%io)ra!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
PROGRAMACIN CON
MPI Y OPENMP
EN EL CLUSTER EULER
____________________________________________
Angelines Alberto Morillas
Telf. +34 91 346 6025
Divisn de Supercomputacin y Desarrollo Grid
CEMAT
Avenida Complutense, 22
28040 Madrid
____________________________________________

You might also like