Transcript tema 9.1

Arquitecturas Paralelas
9.
Herramientas para la
programación de aplicaciones
paralelas: OpenMP y MPI
(introducción).
Computadores de alta velocidad (la
lista top500).
Arquitecturas Paralelas
IF - EHU
Programación aplicaciones paralelas
9
 Como sabemos, los sistemas paralelos MIMD
presentan dos arquitecturas diferenciadas: memoria
compartida y memoria distribuida.
 El modelo de memoria utilizado hace que la
programación de aplicaciones paralelas para cada
caso sea esencialmente diferente.
Arquitecturas Paralelas
IF - EHU
2
Programación aplicaciones paralelas
 Para los sistemas de memoria compartida tipo SMP,
la herramienta más utilizada es OpenMP.
 Para los sistemas de memoria distribuida (MPP), el
“estándar” de programación, mediante paso de
mensajes, es MPI.
 Otras opciones:
UPC (Unified Parallel C)
shrmem (Cray)
Tarjetas gráficas: CUDA / OpenCL
Arquitecturas Paralelas
IF - EHU
9
3
Programación aplicaciones paralelas
Earth Simulator
Arquitecturas Paralelas
IF - EHU
9
4
9
OpenMP
una pequeña introducción
Arquitecturas Paralelas
IF - EHU
5
OpenMP
Introducción
 OpenMP es el estándar actual para programar
aplicaciones paralelas en sistemas de memoria
compartida.
 No se trata de un nuevo lenguaje de programación,
sino de un API (application programming interface)
formado por:
 directivas para el compilador
(C)
#pragma omp <directiva>
 unas pocas funciones de biblioteca
 algunas variables de entorno
Arquitecturas Paralelas
IF - EHU
9
6
OpenMP
9
Introducción
 El modelo de programación
paralela que aplica OpenMP
es Fork - Join.
En un determinado
momento, el thread master
genera P threads que se
ejecutan en paralelo.
thread master
FORK
región paralela
thread master
Arquitecturas Paralelas
IF - EHU
JOIN
7
OpenMP
Introducción
 Todos los threads ejecutan la misma copia del
código (SPMD). A cada thread se le asigna un
identificador (tid).
 Para diferenciar las tareas ejecutadas por cada
thread:
 if (tid == 0) then ... else ...
 constructores específicos de reparto de tareas
(work sharing).
Arquitecturas Paralelas
IF - EHU
9
8
OpenMP
Introducción
9
 En resumen, partiendo de un programa serie, para
obtener un programa paralelo OpenMP hay que
añadir:
 directivas que especifican una región paralela
(código replicado), reparto de tareas
(específicas para cada thread), o sincronización
entre threads.
 funciones de biblioteca (include <omp.h>):
para gestionar o sincronizar los threads..
Arquitecturas Paralelas
IF - EHU
9
OpenMP
Ejemplo
main () {
#pragma omp parallel private(tid)
{
tid = omp_get_thread_num();
printf (“ thread %d en marcha \n”, tid);
#pragma omp for schedule(static) reduction(+:B)
}
for (i=0; i<1000; i++)
{ A[i] = A[i] + 1;
B = B + A[i];
}
if (tid==0) printf(“ B = %d \n”, B);
}
Arquitecturas Paralelas
IF - EHU
9
10
OpenMP
Conceptos básicos
0 Procesos paralelos (threads).
1 REGIONES PARALELAS. Ámbito de las variables.
2 REPARTO DE TAREAS.
Datos: bucles for. Reparto de iteraciones.
Funciones: sections / single / ...
3 SINCRONIZACIÓN.
Secciones críticas, cerrojos, barreras.
Arquitecturas Paralelas
IF - EHU
9
11
OpenMP
0
Conceptos básicos
Número de threads
 estático, una variable de entorno::
> export OMP_NUM_THREADS = 10
 dinámico, mediante una función:
omp_set_num_threads (10);
0
¿Quién soy / cuántos somos?
tid = omp_get_thread_num();
nth = omp_get_num_threads();
Arquitecturas Paralelas
IF - EHU
9
12
OpenMP
Regiones paralelas
9
1 REGIÓN PARALELA (parallel regions)
# pragma omp parallel [VAR,...]
{ código
}
Una región paralela es un trozo de código que se va
a repetir y ejecutar en paralelo en todos los threads.
Las variables de una región paralela pueden ser
compartidas (shared) o privadas (private).
Arquitecturas Paralelas
IF - EHU
13
9
Regiones paralelas
OpenMP
> Un ejemplo sencillo:
...
#define N
int
12
i, tid, nth, A[N];
main ( ) {
for (i=0; i<N; i++) A[i]=0;
#pragma omp parallel private(tid,nth) shared(A)
{ nth = omp_get_num_threads ();
tid = omp_get_thread_num ();
printf ("Thread %d de %d en marcha
\n", tid, nth);
A[tid] = 10 + tid;
barrera
printf (" El thread %d ha terminado \n", tid);
}
for (i=0; i<N; i++) printf (“A(%d) = %d \n”, i, A[i]);
}
Arquitecturas Paralelas
IF - EHU
14
OpenMP
Reparto de tareas: bucles
2 REPARTO DE TAREAS: bucles
Los bucles son uno de los puntos de los que extraer
paralelismo de manera “sencilla” (paralelismo de
datos (domain decomposition) de grano fino).
Obviamente, la simple replicación de código no es
suficiente. Por ejemplo,
#pragma omp parallel shared(A) private(i)
{
for (i=0; i<100; i++)
A[i] = A[i] + 1;
}
?
Arquitecturas Paralelas
IF - EHU
9
15
OpenMP
9
Reparto de tareas: bucles
Tendríamos que hacer algo así:
#pragma omp parallel shared(A)
private(tid,nth, ini,fin,i)
{ tid = omp_get_thread_num();
nth = omp_get_num_threads();
ini = tid * 100 / nth;
fin = (tid+1) * 100 / nth;
!
for (i=ini; i<fin; i++) A[i] = A[i] + 1;
}
El reparto de bucles se realiza automáticamente con la
directiva pragma omp for.
Arquitecturas Paralelas
IF - EHU
16
OpenMP
9
Reparto de tareas: bucles
ámbito variables
#pragma omp parallel [...]
reparto iteraciones
{ …
sincronización
#pragma omp for [clausulas]
for (i=0; i<100; i++) A[i] = A[i] + 1;
…
}
barrera
0..24
25..49
50..74
75..99
Arquitecturas Paralelas
IF - EHU
17
OpenMP
Reparto de tareas: bucles
for (i=0; i<N; i++)
for (j=0; j<M; j++)
{
X = B[i][j] * B[i][j];
A[i][j] = A[i][j] + X;
C[i][j] = X * 2 + 1;
}
#pragma omp parallel for
private (i,j,X)
for (i=0; i<N; i++)
for (j=0; j<M; j++)
{
X = B[i][j] * B[i][j];
A[i][j] = A[i][j] + X;
C[i][j] = X * 2 + 1;
}
Se ejecutará en paralelo el bucle externo, y los threads
ejecutarán el bucle interno. Paralelismo de grano “medio”.
Las variables i, j y X se declaran como privadas.
Arquitecturas Paralelas
IF - EHU
9
18
OpenMP
Reparto de tareas: bucles
for (i=0; i<N; i++)
for (j=0; j<M; j++)
{
X = B[i][j] * B[i][j];
A[i][j] = A[i][j] + X;
C[i][j] = X * 2 + 1;
}
for (i=0; i<N; i++)
#pragma omp parallel for
private (j,X)
for (j=0; j<M; j++)
{
X = B[i][j] * B[i][j];
A[i][j] = A[i][j] + X;
C[i][j] = X * 2 + 1;
}
Los threads ejecutarán en paralelo el bucle interno (el
externo se ejecuta en serie). Paralelismo de grano fino.
Las variables j y X se declaran como privadas.
Arquitecturas Paralelas
IF - EHU
9
19
OpenMP
Reparto de las iteraciones
9
 ¿Cómo se reparten las iteraciones de un bucle entre
los threads?
Puesto que el pragma for termina con una barrera,
si la carga de los threads está mal equilibrada
tendremos una pérdida (notable) de eficiencia.
 La cláusula schedule permite definir diferentes
estrategias de reparto, tanto estáticas como
dinámicas.
Arquitecturas Paralelas
IF - EHU
20
OpenMP
Reparto de las iteraciones
9
> Ejemplo
#pragma omp parallel for
shared(A) private(i)
schedule(static,2)
for (i=0; i<32; i++)
A[i] = A[i] + 1;
Recuerda:
estático
dinámico
Arquitecturas Paralelas
IF - EHU
pid
0:
1:
2:
3:
iteraciones
0,1,8,9,16,17,24,25
2,3,10,11,18,19,26,27
4,5,12,13,20,21,28,29
6,7,14,15,22,23,30,31
menos coste / mejor localidad datos
más coste / carga más equilibrada
21
OpenMP
Rep.de tareas: funciones
9
22
2 REPARTO DE TAREAS: funciones
También puede usarse paralelismo de función (function
decomposition), mediante la directiva sections.
#pragma omp parallel [clausulas]
{
#pragma omp sections [clausulas]
{
}
}
#pragma omp section
fun1();
#pragma omp section
fun2();
#pragma omp section
fun3();
Arquitecturas Paralelas
IF - EHU
fun1
fun2
fun3
pragma omp sections
OpenMP
Rep.de tareas: funciones
2 REPARTO DE TAREAS: funciones
Dentro de una región paralela, la directiva single
asigna una tarea a un único thread.
Sólo la ejecutará un thread, pero no sabemos cúal.
Arquitecturas Paralelas
IF - EHU
9
23
OpenMP
Sincronización de threads
3 SINCRONIZACIÓN
Cuando no pueden eliminarse las dependencias de
datos entre los threads, entonces es necesario
sincronizar su ejecución.
OpenMP proporciona los mecanismos de
sincronización más habituales: exclusión mutua y
sincronización por eventos.
Arquitecturas Paralelas
IF - EHU
9
24
OpenMP
Sincronización de threads
9
a. Secciones críticas: pragma omp critical
Por ejemplo, calcular el
máximo y el mínimo de
los elementos de un
vector.
#pragma omp parallel for
for (i=0; i<N; i++)
{
A[i] = fun(i);
if (A[i]>MAX)
#pragma omp critical(SMAX)
{ if (A[i]>MAX) MAX = A[i]; }
if (A[i]<MIN)
#pragma omp critical(SMIN)
{ if (A[i]<MIN) MIN = A[i]; }
}
Arquitecturas Paralelas
IF - EHU
25
OpenMP
Sincronización de threads
a. Secciones críticas: pragma omp atomic
Una sección crítica para una operación simple de
tipo RMW. Por ejemplo,
#pragma omp parallel ...
{
...
#pragma omp atomic
X = X + 1;
...
}
Arquitecturas Paralelas
IF - EHU
9
26
OpenMP
Sincronización de threads
b. Cerrojos
- omp_set_lock (&C)
espera a que el cerrojo C esté abierto; en ese
momento, cierra el cerrojo en modo atómico.
- omp_unset_lock (&C)
abre el cerrojo C.
- omp_test_lock (&C)
testea el valor del cerrojo C; devuelve T/F.
Arquitecturas Paralelas
IF - EHU
9
27
OpenMP
Sincronización de threads
> Ejemplo
#pragma omp parallel private(nire_it)
{
omp_set_lock(&C1);
mi_it = i;
i = i + 1;
omp_unset_lock(&C1);
while (mi_it<N)
{
A[mi_it] = A[mi_it] + 1;
omp_set_lock(&C1);
mi_it = i;
i = i + 1;
omp_unset_lock(&C1);
}
}
Arquitecturas Paralelas
IF - EHU
9
28
Sincronización de threads
OpenMP
c. Barreras: pragma omp barrier
#pragma omp parallel private(tid)
{
tid = omp_get_thread_num();
A[tid] = fun(tid);
#pragma omp barrier
#pragma omp for
for (i=0; i<N; i++) B[i] = fun(A,i);
#pragma omp for nowait
for (i=0; i<N; i++) C[i] = fun(A,B,i);
D[tid] = fun(tid);
}
Arquitecturas Paralelas
IF - EHU
9
29
OpenMP
Resumen
9
 Variables de entorno y funciones (núm. de hilos,
identificadores...)
 Directiva para definir regiones paralelas
#pragma omp parallel [var…]
 Directivas de reparto de tareas
#pragma omp for [var,sched…]
#pragma omp sections [var]
 Directivas y funciones de sincronización
#pragma omp critical [c] / atomic
#pragma omp barrier
cerrojos (set_lock, unset_lock, test_lock)
Arquitecturas Paralelas
IF - EHU
30
OpenMP
Más información
TEXTOS
• R. Chandra et al.: Parallel Programming in OpenMP
Morgan Kaufmann, 2001.
WEB
• www.openmp.org (especificación 3.0, software…)
COMPILADORES
• de pago
• libres: p. e., el compilador de C/C++ de Intel
Arquitecturas Paralelas
IF - EHU
9
31
9
MPI
una pequeña introducción
Arkitektura Paraleloak
IF - EHU
32
MPI
Introducción
9
 Si para los sistemas SMP la opción es OpenMP, el
“estándar” actual de programación de los sistemas
de memoria distribuida, mediante paso de
mensajes, es MPI (message-passing interface).
 MPI es, básicamente, una librería (grande) de
funciones de comunicación para el envío y
recepción de mensajes entre procesos.
 MPI indica explicitamente la comunicación entre
procesos, es decir:
-- los movimientos de datos
-- la sincronización
Arquitecturas Paralelas
IF - EHU
33
MPI
Tipos de comunicación
 Dos tipos de comunicación:
• punto a punto
• global
 El modelo de paralelismo que implementa MPI es
SPMD.
if (pid == 1)
ENVIAR_a_pid2
else if (pid == 2) RECIBIR_de_pid1
Recuerda: cada proceso dispone de su propio
espacio independiente de direcciones.
Arquitecturas Paralelas
IF - EHU
9
34
MPI
Tipos de comunicación
 Modos de comunicación (1)
• síncrona
La comunicación no se produce hasta que emisor y
receptor se ponen de acuerdo.
• mediante un búfer
El emisor deja el mensaje en un búfer y retorna.
La comunicación se produce cuando el receptor está
dispuesto a ello. El búfer no se puede reutilizar hasta
que se vacíe.
Arquitecturas Paralelas
IF - EHU
9
35
MPI
Tipos de comunicación
9
 Modos de comunicación (2)
• bloqueante
Se espera a que la comunicación se produzca.
La comunicación síncrona es siempre bloqueante. En el
caso buffered, existen ambas alternativas.
• no bloqueante
Se retorna y se continúa con la ejecución.
Más adelante, se comprueba si la comunicación ya se
ha efectuado.
Arquitecturas Paralelas
IF - EHU
36
MPI
Tipos de comunicación
9
 Cada estrategia tiene sus ventajas e inconvenientes:
> síncrona: es más rápida si el receptor está dispuesto
a recibir; nos ahorramos la copia en el buffer.
Además del intercambio de datos, sirve para
sincronizar los procesos.
Ojo: al ser bloqueante es posible un deadlock!
> buffered: el emisor no se bloquea si el receptor no
está disponible, pero hay que hacer copia(s) del
mensaje (más lento).
Arquitecturas Paralelas
IF - EHU
37
Introducción
MPI
9
 MPI gestiona los procesos estáticamente (número y
asignación) (MPI2 también dinámicamente).
Cada proceso tiene un identificador o pid.
 MPI agrupa los procesos implicados en una
ejecución paralela en “comunicadores”.
Un comunicador agrupa a procesos que pueden
intercambiarse mensajes.
El comunicador MPI_COMM_WORLD está creado por
defecto y engloba a todos los procesos.
Arquitecturas Paralelas
IF - EHU
38
Funciones básicas
MPI
 Aunque MPI consta de más de 300 funciones, el
núcleo básico lo forman sólo 6:
2 de inicio y finalización del programa.
2 de control del número de procesos.
2 de comunicación.
Sintaxis: MPI_Funcion(…)
Arquitecturas Paralelas
IF - EHU
9
39
F. básicas: Init / Finalize
MPI
1.
Comienzo y final del programa:
> MPI_Init(&argc, &argv);
> MPI_Finalize();
Estas dos funciones son la primera y última función
MPI que deben ejecutarse en un programa.
Arquitecturas Paralelas
IF - EHU
9
40
F. básicas: Comm_rank / _size
MPI
2.
9
Identificación de procesos
> MPI_Comm_rank(comm, &pid);
Devuelve en pid el identificador del proceso dentro
del comunicador comm especificado.
Los procesos se identifican mediante dos parámetros:
el pid y el grupo (comm, p.e., MPI_COMM_WORLD).
> MPI_Comm_size(comm, &npr);
Devuelve en npr el número de procesos del
comunicador comm.
Arquitecturas Paralelas
IF - EHU
41
MPI
Funciones básicas
9
 Un ejemplo sencillo
#include <stdio.h>
#include <mpi.h>
main (int argc, char *argv[])
{
int pid, npr, A = 2;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &pid);
MPI_Comm_size(MPI_COMM_WORLD, &npr);
A = A + 1;
printf(“Proc. %d de %d activado, A = %d\n”, pid,npr,A);
MPI_Finalize();
}
Arquitecturas Paralelas
IF - EHU
42
MPI
3.
9
F. básicas: Send / Receive
Envío y recepción de mensajes
La comunicación entre procesos necesita (al menos) de
dos participantes: el emisor y el receptor.
El emisor ejecuta la función de envío de mensajes, y el
receptor la de recepción.
A
enviar
recibir
B
La comunicación es un proceso cooperativo. Si una de
las dos funciones no se ejecuta, la comunicación no tiene
lugar (y podría producirse un deadlock!).
Arquitecturas Paralelas
IF - EHU
43
9
F. básicas: Send / Receive
MPI
 Función básica para enviar un mensaje:
> MPI_Send(&mess, count, type, dest,
tag, comm);
- mensaje:
[mess
(@com),
- receptor:
[dest, comm
- tag:
dato de control, de 0 a 32767
count
(tamaño),
(grupo)]
(tipo de mensaje, orden...)
Arquitecturas Paralelas
IF - EHU
type]
44
F. básicas: Send / Receive
MPI
9
 Función básica para recibir un mensaje:
> MPI_Recv(&mess, count, type, source,
tag, comm, &status);
- mensaje (espacio): [mess, count, type]
- emisor:
[source, comm]
- tag:
clase de mensaje...
- status: información de control sobre el mensaje recibido
Recv se bloquea hasta que se recibe el mensaje.
Arquitecturas Paralelas
IF - EHU
45
MPI
9
Ejemplo
...
#define
N 10
int main (int argc, char **argv)
{
int pid, npr, orig, dest, ndat, tag;
int i, VA[N];
MPI_Status info;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD,&pid);
for (i=0;i<N;i++) VA[i] = 0;
if (pid == 0)
{
for (i=0;i<N;i++) VA[i] = i;
else if (pid == 1)
{
for (i=0;i<N;i++) printf(“%4d”,VA[i]);
orig = 0; tag = 0;
MPI_Recv(VA, N, MPI_INT, orig, tag,
MPI_COMM_WORLD, &info);
MPI_Get_count(&info, MPI_INT, &ndat);
printf(“Datos de pr%d; tag = %d,
ndat = %d \n”, info.MPI_SOURCE,
info.MPI_TAG, ndat);
for (i=0;i<ndat;i++)
printf(“%4d”,VA[i]);
dest = 1; tag = 0;
}
MPI_Send(VA, N, MPI_INT, dest, tag,
MPI_Finalize();
MPI_COMM_WORLD);
}
}
Arquitecturas Paralelas
IF - EHU
46
Más tipos de Send / Receive
MPI
9
47
 Síncrono:
MPI_Ssend (&mes,count,datatype,dest,tag,comm);
Ssend no devuelve control hasta que el receptor comienza la
lectura.
 Inmediato:
MPI_Isend (...);
Retorna nada más ejecutarse; luego, para saber si se ha
producido o no la comunicación:
MPI_Test (...)
MPI_Wait (...)
Arquitecturas Paralelas
IF - EHU
devuelve 0 o 1
espera a que finalice
Comunicaciones colectivas
MPI
 Muchas aplicaciones requieren de operaciones de
comunicación en las que participan muchos
procesos.
La comunicación es colectiva si participan en ella
todos los procesos del comunicador.
 Ejemplo: un broadcast, envío de datos desde un
proceso a todos los demás.
¿Uno a uno en un bucle?
Arquitecturas Paralelas
IF - EHU
9
48
Comunicaciones colectivas
MPI
9
 Las funciones de comunicación colectiva son
bloqueantes.
Todos los procesos que forman parte del comunicador
deben ejecutar la función.
 Tres tipos
1
2
3
Movimiento de datos
Operaciones en grupo
Sincronización
Arquitecturas Paralelas
IF - EHU
49
9
CC: movimento de datos
MPI
1a Broadcast: envío de datos desde un proceso
(root) a todos los demás.
P0
A
P2
P1
P0
A
A
P1
P3
P2
A
A
P3
> MPI_Bcast(&mess, count, type, root, comm);
(implementación logarítmica en árbol)
Arquitecturas Paralelas
IF - EHU
50
9
CC: movimento de datos
MPI
1b Scatter: reparto de datos desde un proceso al resto
P0
ABCD
P2
P1
P0
P3
P2
ABCD A
C
B
P1
D
P3
1c Gather: recolección de datos de todos los procesos
P0
A
B
P1
P0
A ABCD
B
P1
P2
C
D
P3
P2
C
D
P3
Arquitecturas Paralelas
IF - EHU
51
9
KK: operaciones en grupo
MPI
2. Reduce (en árbol)
P0
A
B
P1
P0 A A+B+C+D
B
P1
P2
C
D
P3
P2
C
D
P3
Allreduce: todos obtienen el resultado (Reduce + BC)
Arquitecturas Paralelas
IF - EHU
52
MPI
CC: sincronización
3. Barreras de sincronización
Sincronización global entre todos los procesos del
comunicador.
MPI_Barrier (comm);
La función se bloquea hasta que todos los procesos
del comunicador la ejecutan.
Arquitecturas Paralelas
IF - EHU
9
53
Comunicaciones colectivas
MPI
9
> Ejemplo: V(i) = V(i) *  V(j)
sum = 0;
for (j=0; j<N; i++) sum = sum + V[j];
for (i=0; i<N; i++) V[i] = V[i] * sum;
1.
2.
3.
4.
5.
6.
7.
8.
Leer N (el pid = 0)
Broadcast de N/npr (tamaño del vector local)
Scatter del vector V (trozo correspondiente)
Cálculo local de la suma parcial
Allreduce de sumas parciales (todos obtienen suma total)
Cálculo local de V(i) * sum
Gather de resultados
Imprimir resultados (el pid = 0)
Arquitecturas Paralelas
IF - EHU
54
MPI
Ej.: cálculo del número pi
#include <stdio.h>
#include <mat.h>
#include “mpi.h”
int main (int argc, char **argv)
{
int pid, npr, i, n;
double
PI = 3.1415926536;
double h, ×, pi_loc, pi_glob, sum;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD,&pid);
MPI_Comm_size(MPI_COMM_WORLD,&npr);
if (pid == 0)
{ printf(“ Núm de intervalos”;
scanf("%d",&n);
}
MPI_Bcast(&n, 1, MPI_INT, 0,
MPI_COMM_WORLD);
Arquitecturas Paralelas
IF - EHU
9
h = 1.0 / (double) n;
sum = 0.0;
for (i=pid; i<n; i+=npr)
{
x = (i + 0.5) * h;
sum += 4.0 / (1.0 + x*x);
}
pi_loc = h * sum;
MPI_Reduce(&pi_loc, &pi_glob, 1,
MPI_DOUBLE, MPI_SUM, 0,
MPI_COMM_WORLD);
if (pid == 0)
printf("pi(+/-) = %.16f, error
= %.16f\n", pi_glob,
fabs(pi_glob - PI));
MPI_Finalize();
}
55
Implementaciones de MPI
MPI
9
 De libre distribución: MPICH / LAM
 En general, previo a la ejecución en paralelo en un
máquina tipo cluster, se necesita:
- un fichero con la lista de máquinas que conforman
el sistema (identificadores en la red).
- unos daemons que se ejecuten en cada máquina.
- indicar, al ejecutar, el número concreto de procesos
que se desea generar:
mpiexec -n 8 pi
Arquitecturas Paralelas
IF - EHU
56
9
Más información
MPI
TEXTOS
• P. S. Pacheco: Parallel Programming with MPI.
Morgan Kaufmann, 1997.
• W. Groop et al.: Using MPI. Portable Parallel
Programming with the Message Passing Interface (2. ed.).
MIT Press, 1999.
• M. Snir et al.: MPI - The complete reference (vol. 1 y 2).
The MIT Press, 1998.
WEB
• www-unix.mcs.anl.gov/mpi/
Arquitecturas Paralelas
IF - EHU
(todo)
57