Transcript LP-mpi

.3.
PROGRAMACIÓN DE SISTEMAS DE
MEMORIA DISTRIBUIDA:
MPI
Laboratorio de Paralelismo
IF - EHU
Índice
1. Introducción.
2.
3.
4.
5.
6.
7.
8.
Funciones MPI básicas.
Otros modos de envío y recepción.
Comunicación en grupo.
Tipos de datos derivados.
Comunicadores y topologías.
Entrada/salida paralela (introd.).
Performance, debugging, profiling...
Laboratorio de Paralelismo
IF - EHU
Introducción
MPI
3
 Paralelizar una aplicación para que se ejecute en un
sistema de memoria compartida SMP “no es muy
complejo”.
El uso de variables compartidas facilita la
comunicación entre procesos, aunque implica:
– analizar detalladamente el tipo de variables.
– sincronizar correctamente el acceso a las
variables compartidas.
 Sin embargo, el número de procesadores de un
sistema SMP no suele ser muy grande, por lo que no
es fácil conseguir altos niveles de paralelismo.
Laboratorio de Paralelismo
IF - EHU
3
Introducción
MPI
 Es relativamente sencillo conseguir una máquina
paralela tipo cluster con muchos procesadores,
uniendo P máquinas independientes mediante una
red de conexión estándar.
 Por ejemplo, nosotros vamos a utilizar una máquina
de 32 + 3 nodos (32 + 3x4 = 44 pr.), unidos
mediante una red gigabit ethernet.
No es una máquina de alto rendimiento, pero es
“barata” y sencilla de ampliar (en nodos de cálculo y
en comunicación).
Laboratorio de Paralelismo
IF - EHU
3
4
Introducción
MPI
 Sin embargo, programar aplicaciones para sistemas
de memoria distribuida es más complejo.
 Recuerda:
• la memoria de cada procesador es de uso
privado, por lo que todas las variables son, por
definición, privadas.
• la comunicación entre procesos debe hacerse a
través de paso explícito de mensajes.
• la red de comunicación juega un papel
importante en el rendimiento del sistema.
Laboratorio de Paralelismo
IF - EHU
3
5
Introducción
MPI
 Diferentes alternativas para programar aplicaciones:
• utilizar lenguajes diseñados específicamente para
sistemas paralelos (OCCAM).
• ampliar la sintaxis de un lenguaje estándar para
gestionar el paso de mensajes (Fortran M).
• utilizar un lenguaje estándar y una librería de
funciones de comunicación.
Laboratorio de Paralelismo
IF - EHU
3
6
Introducción
MPI
3
 Necesitamos:
- un método para crear procesos: estático / dinámico.
- un método para enviar y recibir mensajes,
punto a punto y de manera global.
 El estándar actual de programación de los sistemas
de memoria distribuida, mediante paso de
mensajes, es MPI (message-passing interface).
PVM → MPI 1.0 (94) → MPI 2.0 (97)
Laboratorio de Paralelismo
IF - EHU
7
Introducción
MPI
3
 MPI es, básicamente, una librería (grande) de
funciones de comunicación para el envío y
recepción de mensajes entre procesos.
Para Fortran y C.
Se busca: portabilidad, eficiencia...
 El objetivo de MPI es explicitar la comunicación entre
procesos, es decir:
> el movimiento de datos entre procesadores
> la sincronización de procesos
Laboratorio de Paralelismo
IF - EHU
8
Introducción
MPI
3
 El modelo de paralelismo que implementa MPI es
SPMD (Single Program Multiple Data).
if (pid==1)
ENVIAR_a_pid2
else if (pid==2) RECIBIR_de_pid1
Recuerda que cada proceso dispone de su propio espacio
de direcciones.
 También se puede trabajar con un modelo MPMD
(Multiple Program Multiple Data): se ejecutan
programas diferentes en los nodos.
Laboratorio de Paralelismo
IF - EHU
9
Introducción
MPI
3
 MPI gestiona los procesos (número y asignación) de
manera estática (MPI2 permite gestión dinámica de
procesos).
 La comunicación entre procesos puede hacerse de
formas muy diferentes.
Elegiremos una determinada estrategia en función de
la longitud de los mensajes, de la estructura del
programa...
Laboratorio de Paralelismo
IF - EHU
10
Introducción
MPI
3
 En todo caso, ten en cuenta que la eficiencia en la
comunicación va a ser determinante en el
rendimiento del sistema paralelo, sobre todo en
aquellas aplicaciones en las que la comunicación
juega un papel importante (paralelismo de grano
medio / fino).
 Además de implementaciones específicas, dos implementaciones libres de uso muy extendido: LAM y
MPICH.
Nosotros vamos a usar MPICH.
Laboratorio de Paralelismo
IF - EHU
11
Introducción: el cluster
MPI
g000002.gi.ehu.es
3
nodo00
nodoxx
gigabit ethernet

Recuerda: ethernet
- switch / conmutación de paquetes
- formato de paquetes
check
4 bytes
datos
< 1,5 Kbytes
tipo
2 bytes
- direcciones IP: 32 bits (4 × 8)
- direcciones del NIC (MAC, 48 bits)
Laboratorio de Paralelismo
IF - EHU
@orig
6 bytes
@dest
cabecera
6 bytes
8 bytes
12
Introducción: el cluster
MPI
 Para poder ejecutar MPI en el cluster:
1. Generar fichero de claves para ssh
> ssh-keygen –t rsa
(pasar al directorio .ssh)
> cp id_rsa.pub authorized_keys
> chmod go-rw authorized_keys
(salir del directorio .ssh)
Entrar la primera vez en cada máquina:
> ssh nodo01 ..... yes .... exit
2. Crear en el directorio principal el fichero .mpd.conf
con una línea que ponga: secretword=xxxxx
> chmod 600 .mpd.conf
Laboratorio de Paralelismo
IF - EHU
3
13
Introducción: el cluster
MPI
3
 El proceso de compilación/ejecución de programas
MPI depende de la implementación concreta. En el
caso de MPICH2:
1. Lanzar daemons en cada procesador:
> mpdboot –v –n zz –f fichero_maquinas
2. Tras compilar (mpicc …), ejecutar el programa (spmd):
> mpiexec –n xx programa
2’. En su caso (mpmd), indicar qué ejecutar en cada nodo:
> mpiexec –n 1 –host nodo00 p1 : -n 1 –host nodo01 p2
(o en un fichero)
Laboratorio de Paralelismo
IF - EHU
14
Introducción: el cluster
MPI
3
 Algunas herramientas para gestionar el cluster
como si fuera una máquina única. Una muy sencilla
es C3 (Cluster Command and Control suite).
http://www.csm.ornl.gov/torc/C3
Fichero de configuración
cluster cluster32
{
g000002:nodo00 #head node
dead 0
nodo0[1-9]
nodo[10-31]
acpt48
acpt49
acpt51
}
Laboratorio de Paralelismo
IF - EHU
Algunos comandos
cshutdown
clist, cname, cnum
cget, cpush, cpushimage
crm
ckill, cexec
15
Índice
1. Introducción.
2. Funciones MPI básicas
inicio y control de procesos
envío y recepción de mensajes
3.
4.
5.
6.
7.
8.
Otros modos de envío y recepción.
Comunicación en grupo.
Tipos de datos derivados.
Comunicadores y topologías.
Entrada/salida paralela (introd.).
Performance, debugging, profiling...
Laboratorio de Paralelismo
IF - EHU
Funciones básicas
MPI
 Aunque MPI consta de más de 320 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(…)
#include <mpi.h>
Laboratorio de Paralelismo
IF - EHU
3
17
Funciones básicas
MPI
 Los parámetros de las funciones MPI son de tres
tipos:
IN:
OUT:
IN/OUT:

la función lee el argumento
la función modifica el argumento
la función lee y modifica el argumento
Las funciones MPI (casi todas) devuelven un entero como
código de error.
error = MPI_Funcion(...)
Si no ha habido problemas, MPI_SUCCESS (0 en esta
implementación); en caso de errores, el valor que indica el tipo
de error depende de la implementación.
Laboratorio de Paralelismo
IF - EHU
3
18
F. básicas: Init / Finalize
MPI
1.
3
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.
No se pueden utilizar funciones MPI antes de _Init, y si
un proceso no ejecuta _Finalize el programa queda
como “colgado”.
Laboratorio de Paralelismo
IF - EHU
19
Funciones básicas
MPI
 Los procesos que se van a ejecutar se agrupan en
conjuntos denominados comunicadores.
Cada proceso tiene un identificador o pid en cada
comunicador.
El comunicador MPI_COMM_WORLD (un objeto de
tipo MPI_COMM) se crea por defecto y engloba a
todos los procesos.
Laboratorio de Paralelismo
IF - EHU
3
20
F. básicas: Comm_rank / _size
MPI
2.
Identificación de procesos
> MPI_Comm_rank(comm, &pid);
Devuelve en pid (int) el identificador del proceso
dentro del grupo de procesos, comunicador comm,
especificado.
Recuerda que un proceso se identifica mediante dos
parámetros: identificador (pid) y grupo (comm).
> MPI_Comm_size(comm, &npr);
Devuelve en npr (int) el número de procesos del
comunicador especificado.
Laboratorio de Paralelismo
IF - EHU
3
21
MPI
Funciones básicas
3
 Un ejemplo simple
#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(“Proceso %d de %d activado. A = %d \n”, pid, npr, A);
MPI_Finalize();
}
Laboratorio de Paralelismo
IF - EHU
22
MPI
Funciones básicas
 Otro ejemplo: planificación de un bucle
...
main (int argc, char *argv[])
{
...
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &pid);
MPI_Comm_size(MPI_COMM_WORLD, &npr);
for (i=pid; i<N; i=i+npr) func(i);
MPI_Finalize();
}
Laboratorio de Paralelismo
IF - EHU
3
23
MPI
3.
F. básicas: comunicación
3
Envío y recepción de mensajes
MPI ofrece dos (tres) tipos de comunicación:
 punto a punto, del proceso i al j (participan ambos).
 en grupo (colectiva): entre un grupo de procesos, de
uno a todos, de todos a uno, o de todos a todos.
 one-sided: del proceso i al j (participa uno solo).
Además, básicamente en el caso de comunicación entre
dos procesos, hay múltiples variantes en función de cómo
se implementa el proceso de envío y de espera.
Laboratorio de Paralelismo
IF - EHU
24
MPI
3.
F. básicas: comunicación
3
Envío y recepción de mensajes entre dos procesos
La comunicación entre procesos requiere (al menos) de
dos participantes: emisor y receptor.
El emisor ejecuta una función de envío y el receptor otra
de recepción.
A
enviar
recibir
B
La comunicación es un proceso cooperativo: si una de
las dos funciones no se ejecuta, no se produce la
comunicación (y podría generarse un deadlock).
Laboratorio de Paralelismo
IF - EHU
25
F. básicas: comunicación
MPI

3
MPI ofrece diferentes modo de comunicación. Veamos un
resumen.
 Modos de comunicación (1)
• síncrona: la comunicación no se EMI
produce hasta que emisor y receptor
se ponen de acuerdo (sin búfer
intermedio).
- petición de transmisión (espera)
- aceptación de transmisión
- envío de datos (de usuario a usuario)
Laboratorio de Paralelismo
IF - EHU
REC
RTS
D
RTR
26
F. básicas: comunicación
MPI
3
 Modos de comunicación (1)
• con búfer (buffered): 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.
REC
EMI
usuario
s.o.
¡Ojo con el tamaño del búfer!
Laboratorio de Paralelismo
IF - EHU
s.o.
usuario
27
F. básicas: comunicación
MPI
3
28
 Modos de comunicación (2)
• bloqueante
Se espera a que la “comunicación” se produzca, antes de
continuar con la ejecución del programa.
La comunicación síncrona es bloqueante. La comunicación con búfer también, si el mensaje no cabe en el búfer.
• no bloqueante
Se retorna “inmediatamente” de la función de comunicación, y se continúa con la ejecución.
Se comprueba más tarde si la comunicación se ha
efectuado.
Laboratorio de Paralelismo
IF - EHU
F. básicas: comunicación
MPI
3
 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 búfer.
Además del intercambio de datos, sirve para sincronizar
los procesos.
Ojo: al ser bloqueante es posible un deadlock!
> con búfer: el emisor no se bloquea si el receptor no
está disponible, pero hay que hacer copia(s) del
mensaje (más lento).
Laboratorio de Paralelismo
IF - EHU
29
F. básicas: comunicación
MPI
3
 Para enviar o recibir un mensaje es necesario
especificar:
•
•
•
•
a quién se envía (o de quién se recibe)
los datos a enviar (dirección de comienzo y cantidad)
el tipo de los datos
la clase de mensaje (tag)
Todo lo que no son los datos forma el “sobre” del mensaje
(que se puede “procesar”).
 Las dos funciones estándar para enviar y recibir
mensajes son:
Laboratorio de Paralelismo
IF - EHU
30
F. básicas: Send y Recv
MPI
3
 Función estándar para enviar un mensaje:
> MPI_Send(&mess, count, type, dest,
tag, comm);
- mensaje a enviar: [mess
(@comienzo),
(@destino),
count
(tamaño),
type]
- receptor:
[dest
- tag:
0..32767 (clase de mensajes, orden...)
comm
(comunicador)]
Tipos : MPI_CHAR, INT, LONG, FLOAT, DOUBLE, BYTE...
Send utiliza la capacidad de buffering del sistema; es
decir, retorna una vez copiado en el búfer el mensaje a
enviar… ¡siempre que quepa!
Laboratorio de Paralelismo
IF - EHU
31
F. básicas: Send y Recv
MPI
 Función básica para recibir un mensaje:
> MPI_Recv(&mess, count, type, source,
tag, comm, &status);
- mensaje a recibir:
[mess, count, type]
- emisor:
[source, comm]
- tag:
clase de mensaje
- status: devuelve información sobre el mensaje recibido
Recv se bloquea hasta que se efectúa la recepción.
Laboratorio de Paralelismo
IF - EHU
3
32
F. básicas: Send y Recv
MPI
3
 Algunas precisiones:
• source, dest, count y tag son enteros (int); comm
y status son de tipo MPI_Comm y MPI_Status.
• para que la comunicación se efectúe tienen que
coincidir las direcciones de emisor y receptor, y el
tag del mensaje.
• el tamaño del mensaje (count) definido en la función
Recv debe ser igual o mayor al definido en Send.
• el origen de un mensaje en la función Recv puede ser
MPI_ANY_SOURCE, y el tipo de mensaje puede ser
MPI_ANY_TAG.
Laboratorio de Paralelismo
IF - EHU
33
F. básicas: Send y Recv
MPI
3
 Algunas precisiones:
• status es un struct con tres campos, en el que se
devuelve información sobre el mensaje recibido:
status.MPI_SOURCE: indica el emisor del mensaje
status.MPI_TAG: devuelve el tag del mensaje recibido
status.MPI_ERROR: devuelve un código de error
(aunque lo más habitual es abortar en caso de error)
• también puede obtenerse el tamaño del mensaje
recibido ejecutando:
> MPI_Get_count(&status, type, &count);
Laboratorio de Paralelismo
IF - EHU
34
F. básicas: Send y Recv
MPI
 Algunas precisiones:
• si un proceso tiene varios mensajes pendientes de
recibir, no se reciben en el orden en que se enviaron
sino en el que se indica en la recepción mediante los
parámetros de origen y tag del mensaje.
• si el tag del mensaje que se recibe puede ser
cualquiera, los mensajes que provienen del mismo
origen se reciben en el orden en que se enviaron.
Laboratorio de Paralelismo
IF - EHU
3
35
MPI
3
Ejemplo
...
#define
N 10
int main (int argc, char **argv)
{
int pid, npr, orig, dest, ndat, tag;
int i, VA[N];
MPI_Status info;
else if (pid == 1)
{
for (i=0;i<N;i++) printf(“%4d”,VA[i]);
orig = 0; tag = 0;
MPI_Recv(&VA[0], N, MPI_INT, orig,
tag, MPI_COMM_WORLD, &info);
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD,&pid);
MPI_Get_count(&info, MPI_INT, &ndat);
printf(“Datos desde pr %d; tag = %d,
ndat = %d \n”, info.MPI_SOURCE,
info.MPI_TAG, ndat);
for (i=0;i<N;i++) VA[i] = 0;
if (pid == 0)
{
for (i=0;i<N;i++) VA[i] = i;
dest = 1; tag = 0;
MPI_Send(&VA[0], N, MPI_INT, dest,
tag, MPI_COMM_WORLD);
}
for (i=0;i<ndat;i++)
printf(“%4d”,VA[i]);
}
MPI_Finalize();
}
Laboratorio de Paralelismo
IF - EHU
36
F. básicas: Probe
MPI
 ¿Y si se desconoce el tamaño del mensaje que hay
que recibir (p.e., se calcula dinámicamente)?
• Lo más sencillo, mandar primero un mensaje con la
longitud del segundo mensaje.
Tras ello, puede asignarse la memoria correspondiente para el
mensaje que se va a recibir.
• MPI_Probe(source, tag, comm, &status)
permite obtener información (fuente, tamaño y tag) de
un mensaje que esté a la espera de ser recibido.
Podemos así reservar espacio en memoria, decidir cómo recibir el
mensaje en función de quién lo envía, o incluso no recibirlo si nos
basta con el tag (p.e., es un mensaje vacío, un aviso).
Laboratorio de Paralelismo
IF - EHU
3
37
F. básicas: temporización
MPI
 Un par de funciones MPI para obtener tiempos de
ejecución:
double
MPI_Wtime();
tiempo (s) transcurrido desde algún instante anterior
double
MPI_Wtick();
devuelve la precisión de la medida de tiempo
t1 = MPI_Wtime();
...
t2 = MPI_Wtime();
printf(“T = %f\n”, t2-t1);
Laboratorio de Paralelismo
IF - EHU
3
38
F. básicas: entrada/salida
MPI
3
 Una cuestión previa sobre las operaciones de
entrada/salida.
Lo habitual es que sólo un proceso tenga acceso a
teclado y pantalla; ese proceso se encargará de leer los
datos y distribuirlos, así como de recoger resultados e
imprimirlos.
Un procedimiento simple para hacerlo podría ser:
if (pid==0)
{ leer_datos();
distribuir_datos();
}
else
recibir_datos();
Laboratorio de Paralelismo
IF - EHU
39
Índice
1. Introducción.
2. Funciones MPI básicas.
3. Otros modos de envío/recepción
comunicación síncrona, inmediata...
4.
5.
6.
7.
8.
Comunicación en grupo.
Tipos de datos derivados.
Comunicadores y topologías.
Entrada/salida paralela (introd.).
Performance, debugging, profiling...
Laboratorio de Paralelismo
IF - EHU
Otros modos de comunicación
MPI
 Aparte de las funciones estándar de envío y
recepción, MPI ofrece varias alternativas con el
objetivo de lograr el máximo rendimiento.
Aunque bastaría con un solo modo, cada alternativa
está pensada para determinado tipo de situación.
 Las principales alternativas al modo estándar son:
- comunicación síncrona
- comunicación inmediata
Laboratorio de Paralelismo
IF - EHU
3
41
Comunicación síncrona
MPI
3
1. Comunicación síncrona
En modo síncrono, la función de envío no retorna hasta
que se produce la comunicación.
En principio, no se necesita un búfer intermedio.
> MPI_Ssend (mismos parámetros que Send);
 La función síncrona es bloqueante; si no se produce el
correspondiente matching, habrá un deadlock.
Laboratorio de Paralelismo
IF - EHU
42
MPI
Comunicación síncrona
 Deadlock
P1
Ssend_to_2;
Recv_from_2;
P2
Ssend_to_1;
Recv_from_1;
Obviamente, hay que cambiar el orden.
 ¿Y con el Send estándar?
P1
Send_to_2;
Recv_from_2;
Laboratorio de Paralelismo
IF - EHU
P2
Send_to_1;
Recv_from_1;
3
43
Comunicación síncrona
MPI
2. Comunicación inmediata
La función de comunicación retorna sin esperar a que
se produzca una determinada acción (es una especie de
post/signal).
Es, por definición, no bloqueante y se busca solapar las
latencias de cálculo y comunicación.

La comunicación se divide en dos fases: un aviso de
envío/recepción, y una verificación de que se ha
producido.
Se utiliza un handle para obtener información sobre el
estado de la comunicación.
Laboratorio de Paralelismo
IF - EHU
3
44
Comunicación inmediata
MPI
3
45
 Funciones de envío y recepción
> MPI_Isend(..., &request);
> MPI_Irecv(..., &request);
request debe ser una variable de tipo MPI_Request, y se utiliza
para preguntar sobre el estado de la función.
El búfer no se puede acceder hasta que la comunicación se produce.
 Funciones de test (status debe ser de tipo MPI_Status)
> MPI_Test(&request, &flag, &status);
devuelve en flag un 0 si la operación no se ha completado
> MPI_Wait(&request, &status);
espera hasta que la comunicación se haya efectuado
Laboratorio de Paralelismo
IF - EHU
MPI
Comunicación inmediata
 Ejemplo
int
MPI_Status
int
MPI_Request
flag = 0; // sólo parte del código
status;
bufer[grande];
info;
...
MPI_Isend(bufer, grande, MPI_INT, dest, tag,
MPI_COMM_WORLD, &info);
while(!flag && hay_tareas)
{
...
/* realizar una tarea */
MPI_Test(&info, &flag, &status);
}
if (!flag) MPI_Wait(&info, &status);
...
Laboratorio de Paralelismo
IF - EHU
3
46
Otros modos de comunicación
MPI
 Hay más opciones (muchas):
- MPI_Sendrecv(…);
Por ejemplo, en una comunicación en anillo, recibe del
anterior y envía al siguiente, asegurando que no se
produce deadlock.
- Comunicación con buffering
Obligamos a que la comunicación se haga mediante un
búfer definido por el usuario.
Hay un conjunto de funciones con esas características
(Bsend, …), más otras funciones para gestionar los
búferes.
Laboratorio de Paralelismo
IF - EHU
3
47
Otros modos de comunicación
MPI
3
 Hay más opciones (muchas):
- Comunicación persistente
Si se van a enviar repetidamente mensajes con los mismos
argumentos (por ejemplo, dentro de un bucle), dividimos la
comunicación en dos partes: (1) crear el contexto, una
sola vez, y (2) enviar el mensaje (las veces que haga
falta).
> MPI_Send_init(…, &request);
> MPI_Recv_init(…, &request);
> MPI_Start(&request);
(Isend = Send_init + Start)
- Mezclas de todas ellas
Laboratorio de Paralelismo
IF - EHU
48
MPI
3
Resumen
 La comunicación es uno de los puntos clave en el
rendimiento de un sistema paralelo de memoria
distribuida. Por ello, MPI ofrece una gran variedad de
estrategias de comunicación.
 Resumen de modos de envío / recepción
Modo
Fun. bloq.
estándar
síncrono
MPI_Send
MPI_Ssend
MPI_Bsend
MPI_Rsend
buffered
(ready
En todos los casos: Recv / Probe
Laboratorio de Paralelismo
IF - EHU
Func. no bloq.
MPI_Isend
MPI_Issend
MPI_Ibsend
MPI_Irsend)
Irecv / Iprobe
49
MPI
Resumen
3
 El uso recomendado sería el siguiente:
 MPI_Ssend: cuando es posible, ofrece los mejores
resultados, puesto que no se utilizan búferes intermedios
(ojo con los deadlocks).
 MPI_Send: la alternativa más habitual.
 MPI_Isend: si, por cuestiones de rendimiento, se
necesitan rutinas no bloqueantes.
(p.e., en clusters en los que la comunicación sea “cara”, para
solapar cálculo y comunicación).
 El resto de opciones, para casos especiales.
Laboratorio de Paralelismo
IF - EHU
50
Índice
1. Introducción.
2. Funciones MPI básicas.
3. Otros modos de envío/recepción.
4. Comunicación en grupo: broadcast,
gather, scatter / reduce / barrier
5.
6.
7.
8.
Tipos de datos derivados.
Comunicadores y topologías.
Entrada/salida paralela (introd.).
Performance, debugging, profiling...
Laboratorio de Paralelismo
IF - EHU
Comunicación en grupo
MPI
3
 Muchas aplicaciones requieren de operaciones de
comunicación en las que participan muchos procesos.
La comunicación es en grupo o 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.
En general, podría ejecutarse mediante un bucle de
funciones tipo send/receive, pero no sería muy
eficiente.
Laboratorio de Paralelismo
IF - EHU
52
Comunicación en grupo
MPI
3
 Todos los procesos del comunicador deben ejecutar
la función. Las funciones de comunicación en grupo
son bloqueantes en el mismo sentido que la función
Send.
 Tres tipos:
1 Movimiento de datos
2 Cálculo en grupo
3 Sincronización
 Las principales funciones de comunicación en grupo
que ofrece MPI son las siguientes:
Laboratorio de Paralelismo
IF - EHU
53
MPI
3
Mov. de datos: broadcast
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);
(La implementación suele ser en árbol)
Laboratorio de Paralelismo
IF - EHU
54
MPI
3
CG: mov. de datos, scatter
1b SCATTER: reparto de datos desde un proceso al
resto de procesos del comunicador.
P0
ABCD
P2
Laboratorio de Paralelismo
IF - EHU
P1
P0
P3
P2
ABCD A
C
B
P1
D
P3
55
MPI
3
CG: mov. de datos, scatter
56
> MPI_Scatter(&send_data, send_count, send_type,
&recv_data, recv_count, recv_type,
root, comm);
- el proceso root distribuye send_data en P trozos,
uno por procesador, de tamaño send_count.
- los datos se reciben en recv_data (también en root).
- lo lógico es que el tamaño y tipo de los datos que se
envían y se reciben sean iguales.
Ejemplo: A = (0, 1, 2, 3, 4, 5, 6, 7) en P0
MPI_Scatter(A, 2, MPI_INT, B, 2, MPI_INT, 0, comm);
(P0) B = 0, 1
Laboratorio de Paralelismo
IF - EHU
(P1) B = 2, 3
(P2) B = 4, 5
(P3) B = 6, 7
MPI
3
CG: mov. de datos, gather
1c GATHER: recolección de datos de todos los procesos
en uno de ellos (orden estricto de pid).
P0
A
B
P1
P0
A ABCD
B
P1
P2
C
D
P3
P2
C
D
P3
Laboratorio de Paralelismo
IF - EHU
57
MPI
3
CG: mov. de datos, gather
58
> MPI_Gather(&send_data, send_count, send_type,
&recv_data, recv_count, recv_type,
root, comm);
- el proceso root recolecta en recv_data los datos
enviados en send_data por cada proceso del comunicador.
- los datos se guardan en el orden marcado por el pid.
- recv_count indica el tamaño de los datos recibidos de
cada proceso, no el total; lo lógico es que tamaño y tipo de
los datos que se envían y se reciben sean iguales.
Ejemplo: (P0) B = 0, 1
(P1) B = 2, 3
(P2) B = 4, 5
(P3) B = 6, 7
MPI_Gather(B, 2, MPI_INT, C, 2, MPI_INT, 0, comm);
→ en P0: C = 0, 1, 2, 3, 4, 5, 6, 7
Laboratorio de Paralelismo
IF - EHU
MPI
CG: movimiento de datos
3
 Otras versiones de estas funciones
al final, todos los procesos disponen
de todos los datos.
> MPI_Gatherv(…);
la información que se recolecta es de
tamaño variable.
> MPI_Allgatherv(…); “suma” de las dos anteriores.
> MPI_Allgather(…);
> MPI_Alltoall(…);
> MPI_Scatterv(…);
> MPI_Alltoallv(…);
Laboratorio de Paralelismo
IF - EHU
todos los procesos distribuyen datos a
todos los procesos.
la información que se distribuye es de
tamaño variable.
“suma” de las dos anteriores.
59
MPI
CG: movimiento de datos
 Ejemplo: reparto de trozos de un vector A, de
tamaños diferentes y no consecutivos:
> MPI_Scatterv(A, tam, desp, tipo,
buf, tamrec, tipo, root, comm);
- Tam: vector (int) que contiene un elemento por proceso, e
indica el número de datos del trozo a enviar a cada uno.
- Desp: vector (int) que contiene un elemento por proceso, e
indica la distancia desde el comienzo de A al comienzo de
cada trozo que hay que repartir.
- Tamrec: entero que indica el número de elementos a recibir
en buf en el procesador local.
No se admite solapamiento “fisico” de los trozos a enviar.
Laboratorio de Paralelismo
IF - EHU
3
60
CG: cálculo en grupo, reduce
MPI
3
61
2 REDUCE: una operación de reducción con los
datos de cada procesador, dejando el resultado en
uno de ellos (root).
P0
A
B
P1
P0 A A+B+C+D
B
P1
P2
C
D
P3
P2
C
D
P3
> MPI_Reduce(&operand, &result, count, datatype,
operator, root, comm);
Laboratorio de Paralelismo
IF - EHU
CG: cálculo en grupo, reduce
MPI
3
 Algunos comentarios
• Operación: result = result operator operand
• result es una variable del proceso destino, de nombre
diferente a operand (no aliasing).
• Funciones típicas de reducción: MPI_MAX, _MIN,
_SUM, _PROD, _BAND, _BOR, _BXOR, _LAND, _LOR,
_LXOR, _MAXLOC, _MINLOC
• Pueden definirse otras operaciones de reducción:
MPI_Op_create(…);
Laboratorio de Paralelismo
IF - EHU
MPI_Op_free(…);
62
CG: cálculo en grupo, reduce
MPI
 Otras funciones del mismo tipo:
> MPI_Allreduce(…);
> MPI_Reduce_scatter(…);
> MPI_Scan(…);
ALLREDUCE
3 pasos (log P)
Laboratorio de Paralelismo
IF - EHU
3
63
MPI
CG: sincronización
3 BARRIER: sincronización global entre los procesos
del comunicador.
> MPI_Barrier(comm);
La función se bloquea hasta que todos los procesos del
comunicador la ejecutan.
Laboratorio de Paralelismo
IF - EHU
3
64
Comunicación en grupo
MPI
 Ejemplo: V(i) = V(i) * V(j)
(Leer N; sum = 0);
for (j=0; j<N; j++) 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 el resultado (el pid = 0)
Laboratorio de Paralelismo
IF - EHU
3
65
Índice
1.
2.
3.
4.
Introducción.
Funciones MPI básicas.
Otros modos de envío/recepción.
Comunicación en grupo.
5. Tipos de datos derivados
vector, indexed, struct / packed
6. Comunicadores y topologías.
7. Entrada/salida paralela (introd.).
8. Performance, debugging, profiling...
Laboratorio de Paralelismo
IF - EHU
MPI

Tipos de datos derivados
La comunicación entre procesos es costosa (en
función de la red). Por ello, es mejor enviar un
paquete con 3 datos que 3 paquetes con un dato
cada uno.
 Las funciones Send y Recv indican explícitamente la
dirección de comienzo del mensaje y el número de
elementos que lo componen, pero hay una
restricción: deben ser elementos consecutivos y
del mismo tipo.
Laboratorio de Paralelismo
IF - EHU
3
67
MPI
Tipos de datos derivados
3
68
 Ejemplo: enviar la fila 2 de la matriz A, de P0 a P1
int A[N][M];
...
orig = 0; dest = 1;
if (pid == orig)
MPI_Send(&A[2][0], M, MPI_INT, dest, 0,
MPI_COMM_WORLD);
else if (pid == dest)
MPI_Recv(&A[2][0], M, MPI_INT, orig, 0,
MPI_COMM_WORLD, &info);
Pero, ¿cómo se envía una columna en un solo mensaje?
¿cómo se envían en un mensaje datos de tipos diferentes?
Laboratorio de Paralelismo
IF - EHU
MPI
Tipos de datos derivados
3
 Tenemos dos soluciones:
1. Definir nuevos tipos de datos, en los que se
permita agrupar datos de diferente tipo, tamaño...
para formar un mensaje con cierta “estructura”.
2. “Empaquetar” los datos que hay enviar (que en
general serán de diferente tipo, tamaño y
estructura) en un único paquete, que el receptor
deberá desempaquetar de manera adecuada.
Laboratorio de Paralelismo
IF - EHU
69
MPI
Tipos de datos derivados
3
1. Definición de tipos derivados
 La generación de tipos de datos derivados se
efectúa mediante dos funciones:
1. definición del tipo de datos derivado
2. creación del tipo (commit)
 Los nuevos tipos de datos que se crean se declaran
como MPI_Datatype.
Veamos la opciones que disponemos.
Laboratorio de Paralelismo
IF - EHU
70
MPI
TDD: vector
3
1a. Tipo “vector”
Se define un vector de n elementos, del mismo tipo y
tamaño, a distancia (stride) constante.
(normalmente un subconjunto de un array mayor).
> MPI_Type_vector(num_elem, tam, stride, tipo,
&nuevo_tipo);
El nuevo tipo contiene num_elem elementos de tamaño tam, a
distancia stride uno de otro.
[ - MPI_Type_contiguous(num_elem, tipo, &nuevo_tipo); ]
Laboratorio de Paralelismo
IF - EHU
71
MPI
TDD: vector
3
72
 Ejemplo: enviar la columna 2 de la matriz A, de P0 a P1.
int A[N][M];
MPI_Datatype Columna;
...
MPI_Type_vector(N, 1, M, MPI_INT, &Columna);
MPI_Type_commit(&Columna);
orig = 0; dest = 1;
if (pid == orig)
MPI_Send(&A[0][2], 1, Columna, dest, 0, MPI_COMM_WORLD);
else if (pid == dest)
MPI_Recv(&A[0][2], 1, Columna, orig, 0, MPI_COMM_WORLD, &info);
Laboratorio de Paralelismo
IF - EHU
OJO: 1 columna
MPI
TDD: indexed
3
1b. Tipo “indexed”
Se define un vector de n elementos, del mismo tipo,
con tamaño y stride variable.
> MPI_Type_indexed(num_elem, tam, desp, tipo,
&nuevo_tipo);
tam[]: array que contiene el número de componentes de cada
elemento que forma el nuevo tipo.
desp[]: array que contiene el desplazamiento necesario para
acceder desde el comienzo del nuevo tipo a cada
elemento (de tipo MPI_Aint).
Laboratorio de Paralelismo
IF - EHU
73
MPI
3
TDD: indexed
74
 Ejemplo: enviar de P0 a P1 el triángulo superior de
la matriz A.
int A[N][M], T[N][M];
MPI_Datatype Mtri;
...
M
N
for(i=0; i<N; i++) {
long_bl[i] = M - i;
desp[i] = (M+1) * i;
}
MPI_Type_indexed (N, long_bl, desp, MPI_INT, &Mtri);
MPI_Type_commit (&Mtri);
MPI_Send(A, 1, Mtri, 1, 0, MPI_COMM_WORLD);
else if (pid == 1) MPI_Recv(T, 1, Mtri, 0, 0, MPI_COMM_WORLD, &info);
if (pid == 0)
Laboratorio de Paralelismo
IF - EHU
MPI
3
TDD: struct
1c. Tipo “struct”
Es un caso más general, en el que se agrupan n
elementos de tamaño y tipo diferente.
Por ejemplo, P0 tiene que enviar a todos los procesadores
tres parámetros: A y B, flotantes, y C, entero. Podemos
formar un “paquete” con los tres parámetros y efectuar un
único envío (BC).
Para ello construimos un struct con:
- número de elementos
- tipo de cada elemento
- desplazamiento de cada elemento
desde el origen
Laboratorio de Paralelismo
IF - EHU
f
f
i
A
B
C
2
6
75
MPI
TDD: struct
3
1c. Tipo “struct”
La función para definir el tipo es:
> MPI_Type_create_struct(num_elem, tam, desp,
tipo, &nuevo_tipo);
tam[]: número de componentes de cada elemento que
forma el nuevo tipo.
desp[]: desplazamiento necesario para acceder desde el
comienzo del nuevo tipo a cada elemento (MPI_Aint).
tipo[]: tipo de cada elemento (MPI_Datatype).
> MPI_Get_address (&A, &dirA)
Devuelve la dirección de A en dirA (de tipo MPI_Aint)
Laboratorio de Paralelismo
IF - EHU
76
MPI
3
TDD: struct
void
Crear_Tipo
77
(float* A, B; int* C; MPI_Datatype* Mensaje) {
int
tam[3];
MPI_Aint
desp[3], dir1, dir2;
MPI_Dataype tipo[3];
// address int
tam[0] = tam[1] = tam[2] = 1;
tipo[0] = tipo[1] = MPI_FLOAT;
tipo[2] = MPI_INT;
despl[0] = 0;
MPI_Get_address
MPI_Get_address
despl[1] = dir2
MPI_Get_address
despl[2] = dir2
... (A, B, C, punteros a las variables)
Crear_Tipo(A, B, C, &Mensaje);
(A, &dir1);
MPI_Bcast(A, 1, Mensaje, 0, MPI_COMM_WORLD);
(B, &dir2);
...
- dir1;
(C, &dir2);
- dir1;
MPI_Type_create_struct(3, tam, desp, tipo, Mensaje);
MPI_Type_commit(Mensaje);
}
Laboratorio de Paralelismo
IF - EHU
MPI
TDD: subarrays
3
1d. Subarrays
Una submatriz de N dimensiones a partir de una de N
dimensiones. Por ejemplo, un bloque 2D de una
matriz 2D:
> MPI_Type_create_subarray(...);
> MPI_Type_create_darray(...);
Laboratorio de Paralelismo
IF - EHU
78
MPI
TDD: subarrays
3
1d. Subarrays
Una submatriz de N dimensiones a partir de una de N
dimensiones. Por ejemplo, un bloque 2D de una
matriz 2D;
> MPI_Type_create_subarray(ndims, tam_a, tam_sa,
dir_sa, orden, tipo, &nuevo_tipo);
ndims:
dimensiones del array original
tam_a[], tam_sa[]: elementos en cada dimensión
dir_sa[]: comienzo del subarray
orden:
MPI_ORDER_C, _FORTRAN
Laboratorio de Paralelismo
IF - EHU
79
MPI
TDD: subarrays
3
 Tamaño y extensión del tipo:
1. Tamaño: número de bytes que se transmiten (sin
incluir huecos).
2. Extensión: Distancia entre el primer y el último
byte (incluyendo huecos).
Un par de funciones MPI devuelven estos
parámetros del tipo de datos.
Laboratorio de Paralelismo
IF - EHU
80
MPI
TDD: packed
3
2. Empaquetamiento
Alternativa a la definición de tipos: “empaquetar” los
datos que hay que enviar en posiciones consecutivas
de memoria.
La comunicación se efectúa en tres fases:
• Antes de enviar el mensaje, se van añadiendo los datos a un
búfer (vector) mediante la función MPI de empaquetamiento.
• Se envía el vector, que es de tipo MPI_PACKED.
• El receptor desempaqueta los datos recibidos mediante
la función MPI de desempaquetamiento.
Laboratorio de Paralelismo
IF - EHU
81
MPI
TDD: packed
3
2. Empaquetamiento
La función para empaquetar datos es:
> MPI_Pack(&dat, tam, tipo, bufer, tambuf,
&pos, comm);
Añade a bufer (char, de tamaño tambuf) la variable dat,
a partir de la posición marcada por el puntero pos.
El puntero queda apuntando a la primera posición libre de
bufer. Al final de las operaciones de empaquetamiento,
indica el tamaño del paquete.
La función MPI_Pack_size (ver manual) devuelve el tamaño mínimo
necesario para empaquetar un objeto. Se puede usar para calcular el
tamaño final del paquete y reservar memoria para el mismo.
Laboratorio de Paralelismo
IF - EHU
82
MPI
TDD: packed
2. Empaquetamiento
La función para desempaquetar datos es:
> MPI_Unpack(bufer, tambuf, &pos, &dat, tam,
tipo, comm);
Recupera de bufer (apuntado por pos) la variable dat
del tamaño y tipo indicado (pos queda apuntando a la
siguiente variable).
Tambuf debe ser suficiente para que quepa el mensaje
recibido.
Laboratorio de Paralelismo
IF - EHU
3
83
MPI
3
TDD: packed
void Leer_Datos (float* A, B; int* C; int pid) {
char bufer[100]; int pos;
if (pid == 0) {
printf(“-> A, B y C\n”);
scanf(“%f %f %d”, A, B, C);
pos = 0;
// A, B, C, punteros a las vbles.
MPI_Pack(A, 1, MPI_FLOAT, bufer, 100, &pos, MPI_COMM_WORLD);
MPI_Pack(B, 1, MPI_FLOAT, bufer, 100, &pos, MPI_COMM_WORLD);
MPI_Pack(C, 1, MPI_INT, bufer, 100, &pos, MPI_COMM_WORLD);
MPI_Bcast(bufer, pos, MPI_PACKED, 0, MPI_COMM_WORLD);
} else {
MPI_Bcast(bufer, 100, MPI_PACKED, 0, MPI_COMM_WORLD);
pos = 0;
MPI_Unpack(bufer, 100, &pos, A, 1, MPI_FLOAT, MPI_COMM_WORLD);
MPI_Unpack(bufer, 100, &pos, B, 1, MPI_FLOAT, MPI_COMM_WORLD);
MPI_Unpack(bufer, 100, &pos, C, 1, MPI_INT, MPI_COMM_WORLD);
}
}
Laboratorio de Paralelismo
IF - EHU
84
MPI
TDD: resumen

Para reducir el overhead de la comunicación se pueden
definir “tipos de datos” que agrupen los datos a enviar en
posiciones consecutivas de memoria.
Especialmente útil cuando se repite el mismo tipo de
comunicación una y otra vez.

Un tipo derivado es básicamente un struct que se crea en
ejecución y que puede pasarse como argumento a una
función de comunicación.
3
Tipos: MPI_Type_vector, _indexed, _struct

Otra alternativa es empaquetar datos y desempaque-tarlos
tras recibirlos (MPI_PACKED).
Laboratorio de Paralelismo
IF - EHU
85
MPI
TDD: resumen
3

Lo más habitual es utilizar el mecanismo estándar de
transmisión: datos consecutivos de un array.

Si los datos a enviar son muchos y no consecutivos, y se
envían repetidamente, lo mejor sería definir un tipo
específico:
- datos homogéneos: contiguous, vector, indexed
- datos heterogéneos: struct

Si se envían datos heterogéneos una sola vez (o pocas), lo
más adecuado sería empaquetar.
Laboratorio de Paralelismo
IF - EHU
86
MPI
TDD: resumen
3
 Matching de tipos
Send y Recv especifican el tipo de los datos que se envían
y reciben. Se llama firma (signature) de tipos a la
secuencia {t0, t1..., tn-1}, donde ti es el tipo del elemento i.
El tipo no tiene por qué ser el mismo en ambas funciones,
pero la firma de tipos del tipo de datos especificado en
Recv tiene que tener al menos tantos elementos como la
de Send, y los tipos han de ser iguales: es decir, se
deben recibir al menos tantos datos como se envían
y del mismo tipo.
Ojo: en las funciones colectivas el tipo debe ser el mismo!
Laboratorio de Paralelismo
IF - EHU
87
MPI
TDD: resumen
3
 Matching de tipos
El paquete de datos lleva los datos sin “estructura”. La
estructura se “recompone”, si se desea, al recibirlos.
Por ejemplo, enviamos N elementos de una columna de
una matriz utilizando el tipo columna.
Si recibimos los datos con el tipo columna, se cargarán en
la columna de la matriz que indiquemos.
Si los recibimos como N enteros, se cargarán uno tras otro
a partir de la dirección que indiquemos; si los recibimos
con tipo “diagonal”, se cargarán en la diagonal; etc.
Laboratorio de Paralelismo
IF - EHU
88
Índice
1.
2.
3.
4.
5.
Introducción.
Funciones MPI básicas.
Otros modos de envío/recepción.
Comunicación en grupo.
Tipos de datos derivados.
6. Comunicadores y topologías.
7. Entrada/salida paralela (introd.).
8. Performance, debugging, profiling...
Laboratorio de Paralelismo
IF - EHU
MPI
Comunicadores
3
 Un comunicador MPI define un grupo de procesos
entre los cuales es posible el intercambio de mensajes.
Cada proceso se identifica en el comunicador mediante
su pid.
El comunicador predefinido MPI_COMM_WORLD
engloba a todos los procesos de la aplicación paralela.
 En muchos casos es útil definir otros grupos de
procesos o comunicadores para hacer más simple la
comunicación.
Así, un proceso puede tener más de un pid: uno por
cada grupo del que forme parte.
Laboratorio de Paralelismo
IF - EHU
90
MPI
Comunicadores
 Un comunicador está formado, al menos, por un
3
grupo de procesos y un contexto.
El contexto define un espacio propio e identificado de
comunicación.
 Un comunicador puede incluir más datos asociados,
tales como una topología, características específicas
de los procesadores que lo componen,
entrada/salida, etc.
 Para ver la utilidad de definir grupos de procesos,
analicemos un ejemplo sencillo: producto de dos
matrices.
Laboratorio de Paralelismo
IF - EHU
91
Motivación
MPI
3
92
 Ejemplo: C = A × B
C
B
A
x
Cij = Ai,0 B0,j + Ai,1 B1,j +
=
...
+ Ai,i Bi,j +
...
+ Ai,n-1 Bn-1,j
En el caso de una matriz “densa”, hay que efectuar O(N3)
operaciones. ¿Cómo paralelizar el cálculo de manera
eficiente entre P procesadores? ¿Cuál es la mejor manera
de distribuir los datos entre los procesos?
Objetivo: minimizar el tiempo asociado a la comunicación.
Laboratorio de Paralelismo
IF - EHU
Motivación (A × B)
MPI
3
1. Descomposición unidimensional (filas)
(P procesadores, N/P filas por procesador)
P0
x
=
•
Computación por procesador
•
Pero hay que añadir comunicación: N2/P datos desde
cada uno de los P-1 procesadores restantes → O(N2).
Podría ser un allgather de N2/P datos, que se ejecuta
en log P pasos.
Laboratorio de Paralelismo
IF - EHU
C
B
A
(* y +)
: O(N3/P)
93
Motivación (A × B)
MPI
•
Si Tcom = ti + tw N
ti tiempo de inicio
tw tiempo por palabra
2
2

N
N
log P
  ti log P  t w
Tcom  log P  ti  t w

P 
P

•
Tejec = Tcalc + Tcom
2N 3
N 2 log P

top  ti log P  t w
P
P
Eficiente sólo si:
Laboratorio de Paralelismo
IF - EHU
top >> tw
o
P es pequeño (<<N)
3
94
MPI
Motivación
N = 100
3
ti = 100 tw
tw = 100 top
speed-up = Ts / Tp
100
eficiencia = Ts / (Tp*P)
1
0.8
80
0.6
60
0.4
40
0.2
20
0
20
40
60
P
Laboratorio de Paralelismo
IF - EHU
80
0
100
95
Motivación (A × B)
MPI
3
2. Descomposición bidimensional:
P0
C
B
A
x
=
• Computación por procesador: O(N3/P)
• Pero ahora la necesidad de comunicación es menor.
Cada procesador necesita los datos de “los bloques de su
fila y su columna”.
Se necesita recibir 2(P1/2-1)(N2/P) datos.
¿Cuál es la manera más eficiente de procesar/enviar esos datos?
Laboratorio de Paralelismo
IF - EHU
96
MPI
Motivación (A × B)
3
97
 Algoritmo de multiplicación (Fox):
A00B00+ A01B10+ A02B20
bc
A00B01+ A01B11+ A02B21
bc
A10B00+ A11B10+ A12B20
A10B01+ A11B11+ A12B21
bc
A20B00+ A21B10+ A22B20
bc
Laboratorio de Paralelismo
IF - EHU
A00B02+ A01B12+ A02B22
A20B01+ A21B11+ A22B21
A10B02+ A11B12+ A12B22
bc
A20B02+ A21B12+ A22B22
bc
Motivación (A × B)
MPI
3
 Algoritmo de multiplicación (Fox):
for k = 0 to P – 1
• en cada fila i, el proceso (i+k) mod N hace un broadcast
de A (su trozo) al resto de procesos de la fila
• operaciones locales de cálculo: Ci,j += Ai,i+k Bi+k,j
• envío del trozo procesado de B al vecino de arriba
 Comunicación por procesador:
P veces
• broadcast de N2/P datos a P - 1 procesos (se puede
optimizar en log P pasos)
• send de N2/P datos
Laboratorio de Paralelismo
IF - EHU
98
Motivación (A × B)
MPI
3
 Coste global (cálculo + comunicación)
Tejec
2N 3

t op 
P



2 

2N 3
N


t op  P log P  1  ti  t w


P
P


P log P
log P 2
ti 
N tw
2
2 P
[ ¿y el coste de reorganizar las matrices? ]
Laboratorio de Paralelismo
IF - EHU
99
MPI
Motivación
N = 100
3
ti = 100 tw
tw = 100 top
speed-up = Ts / Tp
eficiencia = Ts / (Tp*P)
1
100
0.8
80
0.6
60
0.4
40
0.2
20
0
20
40
60
P
Laboratorio de Paralelismo
IF - EHU
80
0
100
100
Motivación
MPI
3
 Resumen (NxN datos, P procesadores)
N
Com.:
N
N2/P
N2
-
N2/P
=
1
N2(P-1)/P
0.8
COM
0.6
0.4
0.2
P1/2
bloques

Com.:
2 N2/P (P1/2-1) =
N2 2(P1/2-1)/P
0
1
10
100
1000
P
Conclusión: división 2D es más “escalable”, pero requiere
comunicaciones entre subconjuntos de procesos.
Laboratorio de Paralelismo
IF - EHU
101
Creación de comunicadores
MPI
 Para crear grupos de procesos entre los que poder
intercambiar información, hay que seguir los
siguientes pasos:
1. Extraer de un comunicador inicial, com1, el grupo de
procesos asociados, gr1:
> MPI_Comm_group(com1, &gr1);
Si com1 es MPI_COMM_WORLD, gr1 contendrá a
todos los procesos.
Laboratorio de Paralelismo
IF - EHU
3
102
MPI
Creación de comunicadores
3
103
2. Crear un nuevo grupo de procesos, gr2, eligiendo del
grupo gr1 aquellos que queremos que formen parte del
nuevo comunicador:
> MPI_Group_incl(gr1, npr_gr2, pid_gr1, &gr2);
pid_gr1 es un array de npr_gr2 elementos que indica el pid
de los procesos que se eligen para formar el nuevo grupo.
(también se puede hacer por exclusión, con la función MPI_Group_excl)
3. Finalmente, se crea el comunicador com2 con los
procesos del grupo gr2 extraídos del comunicador com1:
> MPI_Comm_create(com1, gr2, &com2);
Laboratorio de Paralelismo
IF - EHU
Creación de comunicadores
MPI

Ejemplo: una matriz está repartida por bloques en n × n
procesos. Así definiríamos el grupo “fila 0” de procesos
y haríamos un broadcast en esa fila:
MPI_Group
MPI_Comm
gr1, grf0;
CF0;
for(i=0; i<n; i++) pids[i] = i;
/* lista de proc. */
MPI_Comm_group (MPI_COMM_WORLD, &gr1);
MPI_Group_incl (gr1, n, pids, &grf0);
MPI_Comm_create(MPI_COMM_WORLD, grf0, &CF0);
...
if (pid < n) {
MPI_Comm_rank(CF0, &pid_f0);
MPI_Broadcast(&A[0][0], tam, MPI_FLOAT, 0, CF0);
}
Laboratorio de Paralelismo
IF - EHU
3
104
Creación de comunicadores
MPI
3
 Algunas precisiones:
• Los grupos de procesos son variables de tipo
MPI_Group y los comunicadores son de tipo MPI_Comm.
• MPI_Comm_create es una operación colectiva, que
debe ser llamada por todos los procesos del comunicador
original (aunque no vayan a formar parte del nuevo
comunicador; se les devuelve el valor MPI_COMM_NULL).
• Al finalizar su uso hay que “deshacer” el comunicador,
ejecutando MPI_Comm_free.
• Otras funciones para trabajar con grupos:
MPI_Group_rank, size, free, union, intersection...
Laboratorio de Paralelismo
IF - EHU
105
Creación de comunicadores
MPI
3
 Si hay que crear comunicadores “similares” a partir de
uno determinado (por ejemplo filas o columnas de
una estructura 2D), podemos generarlos todos a la
vez, mediante la función:
> MPI_Comm_split(com1,split_key,pid_com1,&com2);
Los procesos de com1 se van a agrupar en nuevos
comunicadores en función de la clave con la que llamen a
la función.
Se crean tantos comunicadores como claves diferentes se
utilicen, todos con el mismo nombre com2.
Laboratorio de Paralelismo
IF - EHU
106
Creación de comunicadores
MPI
3
107
 Ejemplo: crear comunicadores para todas las filas
de un grupo de n × n procesos:
// pid = identificador en el comunicador global
mi_fila = pid / n;
MPI_Comm_split(MPI_COMM_WORLD, mi_fila, pid, &CFILA);
Si había 3×3 procesos, ahora tendremos un nuevo comunicador en
el que el grupo de procesos es diferente en función de quién lo use:
{0,1,2} en P0,P1,P2 / {3,4,5} en P3,P4,P5 / {6,7,8} en P6,P7,P8
Se trata de una función colectiva; todos los procesos del comunicador original tienen que ejecutarla. Si un proceso no va a formar
parte de los nuevos comunicadores, llama a la función con la clave
MPI_UNDEFINED (formará parte del comunicador MPI_COMM_NULL).
Laboratorio de Paralelismo
IF - EHU
Topologías
MPI
3
 Un comunicador puede incluir, además del grupo y el
contexto, otro tipo de información o atributos; por
ejemplo, una topología (virtual).
No se refiere a la red de comunicación, sino a una
manera alternativa de identificar a los procesos de un
comunicador.
Se genera un nuevo comunicador.
Dos tipos: cartesian y graph.
Laboratorio de Paralelismo
IF - EHU
108
Topologías
MPI
3
 Por ejemplo, si queremos trabajar con una distribución
2D de datos, podemos definir una “retícula” de
procesos (p.e., de 4x4 si tenemos 16 procesadores).
Para definir un comunicador con una “malla” global
tenemos que indicar:
• número de dimensiones (2)
• elementos por dimensión (4)
• ¿cadenas (0) o anillos (1)?
• optimización (ajuste a la red física)
Laboratorio de Paralelismo
IF - EHU
109
MPI
Topologías
 Ejemplo: definir un comunicador con topología toro
MPI_Comm
CTORO
...
opt = 1; ndim = 2;
kdim[0] = kdim[1] = 4;
c_a[0] = c_a[1] = 1;
MPI_Cart_create (MPI_COMM_WORLD, ndim, kdim, c_a,
opt, &CTORO);
kdim: número de procesos en cada dimensión.
c_a:
0 → malla; 1 → toro;
CTORO es un nuevo comunicador que engloba a los mismos
procesos que MPI_COMM_WORLD, pero que añade coordenadas
cartesianas a los procesos.
Laboratorio de Paralelismo
IF - EHU
3
110
Topologías
MPI
 Ahora podemos trabajar con una identificación doble
de los procesos: el pid en el nuevo comunicador y
las coordenadas cartesianas de la topología
asociada.
Dos funciones permiten pasar de una a otra:
> MPI_Cart_coords(com2, pid2, dim, coord);
com2:
pid2:
dim:
coord:
nuevo comunicador con topología
identificador del proceso en el nuevo comunicador
número de dimensiones
array donde se devuelven las coordenadas
> MPI_Cart_rank(com2, coord, pid);
Laboratorio de Paralelismo
IF - EHU
3
111
Topologías
MPI
3
 Se pueden obtener las direcciones de los “vecinos” en
la topología:
> MPI_Cart_shift(com, direc, desp, &orig, &dest);
dir:
dimensión en la que queremos buscar los vecinos
desp: distancia del vecino
&orig,&dest: vecinos segun el despl (orig, yo, dest)
Laboratorio de Paralelismo
IF - EHU
112
Topologías
MPI
3
113
 Se puede dividir (split) una retícula en otras de menos
dimensiones (p.e., una malla de dos dimensiones en sus
columnas o filas), y crear así nuevos comunicadores:
> MPI_Cart_sub(cart_comm, free_coords, new_comm);
A partir del comunicador que tiene asociada la topología, se crean
comunicadores en función del array booleano free_coords:
0 → se considera esa coordenada
1 → no se tiene en cuenta (free)
Por ejemplo, de una malla de n × n procesos se pueden crear
los comunicadores “fila” haciendo: free_coord[0] = 0;
free_coord[1] = 1; (al revés, las columnas).
Laboratorio de Paralelismo
IF - EHU
Topologías
MPI
3
114
 Un conjunto de funciones similares permite añadir un
“grafo” subyacente a un determinado grupo de
procesos.
 En resumen.
Un comunicador representa a un grupos de procesos
que se reconocen entre sí como posible origen y destino
de sus comunicaciones.
Una topología es un mecanismo alternativo de
identificación “lógica” de procesos dentro de un grupo,
que genera un nuevo comunicador y, en su caso,
subgrupos.
Laboratorio de Paralelismo
IF - EHU
Topologías
MPI
 Resumen de las funciones prinicipales (hay más
funciones, mirar manual) que permiten crear
comunicadores y topologías:
> MPI_Comm_group/create/split/free
> MPI_Group_incl/excl/rank/free
> MPI_Cart_create/rank/coords/shift/sub
Laboratorio de Paralelismo
IF - EHU
3
115
Índice
1.
2.
3.
4.
5.
6.
Introducción.
Funciones MPI básicas.
Otros modos de envío/recepción.
Comunicación en grupo.
Tipos de datos derivados.
Comunicadores y topologías.
7. Entrada/salida paralela (introd.).
8. Performance, debugging, profiling...
Laboratorio de Paralelismo
IF - EHU
MPI
Entrada/salida paralela
3
117
 Algunas aplicaciones utilizan y generan una gran
cantidad de datos, por lo que el tiempo necesario
para las operaciones de I/O puede ser muy
elevado (comparable o mayor que el tiempo estricto de
ejecución).
 Algunos campos en los que se procesan datos de
manera intensiva:
> minería de datos: grano fino / patrones de acceso no predecibles
> multimedia:
grano grueso / predecibles
> cálculo científico: grano fino - grueso / predecibles o no
Laboratorio de Paralelismo
IF - EHU
MPI
Entrada/salida paralela
3
 El número de datos procesados por unidad de tiempo
es mayor en los sistemas paralelos. Si el sistema de
almacenamiento de datos (discos) no responde
adecuadamente, el rendimiento del sistema global
decaerá (Amdahl de nuevo).
 Estructura típica serie:
•
•
•
•
un disco conectado al procesador (servidores, sistema RAID)
datos en diferentes formatos
acceso secuencial / aleatorio
llamadas estándar (fprintf, fscanf...)
•
sistema de ficheros NFS
Laboratorio de Paralelismo
IF - EHU
118
MPI
Entrada/salida paralela
 Resumen RAID (redundant array independent disks)
• objetivos: capacidad (+ disc.), rendimiento (entrelaz.),
fiabilidad (paridad, hamming...)
• estructura:
RAID0: entrelazado de los datos (nivel de subbloque)
entre un conjunto de discos (igual que en la MP)
+ capacidad / + rendimiento / no fiabilidad
RAID1/10 (mirroring): replicación de datos / entrelazado
- capacidad / rendimiento / fiabilidad
RAID5: entrelazado de los datos / paridad
+ capacidad / + rendimiento / tolerancia a fallos
Laboratorio de Paralelismo
IF - EHU
3
119
MPI
Entrada/salida paralela
 La entrada/salida en paralelo hace referencia a dos
cuestiones:
• estructura “física” de los ficheros
> un disco local en cada nodo
I/O local -- almacenamiento temporal
los datos se pueden juntar al final
funciones estándar de I/O en C
> nodos específicos de I/O
mejor rendimiento
funciones paralelas de I/O
Laboratorio de Paralelismo
IF - EHU
3
120
MPI
Entrada/salida paralela
3
 La entrada/salida en paralelo hace referencia a dos
cuestiones:
• estructura “lógica” de los ficheros
> procesadores escribiendo en el mismo fichero
- los datos de cada proceso se intercalan en el fichero
- MPI-2 parallel I/O
> en ficheros diferentes, que se pueden juntar al final
-- en general, un sistema de ficheros tipo PVFS
Laboratorio de Paralelismo
IF - EHU
121
MPI
Entrada/salida paralela
3
 MPI-2 añade un interfaz para el uso compartido de
ficheros en operaciones de entrada/salida.
La lectura y escritura de datos se realiza de forma
similar al envío y recepción de datos.
Los modos de acceso pueden ser bloqueantes (lo más
habitual) y no bloqueantes, así como individuales (lo
más habitual) y colectivos.
Laboratorio de Paralelismo
IF - EHU
122
MPI
Entrada/salida paralela
3
 Cada proceso tiene una “vista” del fichero, compuesta
por tres elementos:
- desplazamiento: punto base de los accesos.
- tipo elemental (e-type): tipo de las unidades que forman
el fichero, y que representa la unidad de acceso y
desplazamiento, normalmente un byte.
- filetype: una plantilla de repeticiones del “e-type” que
indica los datos que pueden ser accedidos por cada proceso
(p.e., los elementos pares/impares de un vector).
 La “vista” por defecto tiene desplazamiento 0, y tipo
elemental y filetype MPI_BYTE.
Laboratorio de Paralelismo
IF - EHU
123
MPI
Entrada/salida paralela
3
124
 Operaciones básicas con ficheros:
1. Apertura y cierre del fichero
> MPI_File_open(comm, &filename, amode, info, &fh);
> MPI_File_close(&fh);
comm:
comunicador
filename: nombre del fichero (char)
amode:
modo de acceso (int)
info:
información sobre el fichero (MPI_Info)
(MPI_INFO_NULL)
fh:
Laboratorio de Paralelismo
IF - EHU
handle para trabajar con el fichero (MPI_File)
MPI
Entrada/salida paralela
3
125
 Operaciones básicas con ficheros:
1. Apertura y cierre del fichero
> MPI_File_open(comm, &filename, amode, info, &fh);
> MPI_File_close(&fh);
Modos de acceso:
MPI_MODE_RDONLY; _RDWR; _WRONLY;
Se pueden añadir (OR, |) otras opciones:
MPI_MODE_CREATE; _EXCL; _DELETE_ON_CLOSE;
UNIQUE_OPEN; _SEQUENTIAL; _APPEND;
Laboratorio de Paralelismo
IF - EHU
MPI
Entrada/salida paralela
3
126
 Operaciones básicas con ficheros:
1. Apertura y cierre del fichero
> MPI_File_open(comm, &filename, amode, info, &fh);
> MPI_File_close(&fh);
Son funciones colectivas; para acceso a ficheros locales (un
solo proceso) se usa el comunicador MPI_COMM_SELF.
> MPI_File_delete(&filename, info);
Permite borrar un fichero que no esté abierto (sólo un proceso).
Laboratorio de Paralelismo
IF - EHU
MPI
Entrada/salida paralela
3
127
 Operaciones básicas con ficheros:
2. Lectura de datos
> MPI_File_read(fh, &buf, count, datatype, &status);
Lee de fh count elementos de tipo datatype y los deja en buf.
Utiliza el puntero privado de acceso al fichero (que se actualiza
automáticamente).
> MPI_File_read_at(fh, offset, &buf, count,
datatype, &status);
Lee comenzando en la dirección marcada por offset, sin utilizar
ni modificar ningún puntero privado.
Laboratorio de Paralelismo
IF - EHU
MPI
Entrada/salida paralela
3
 Operaciones básicas con ficheros:
2. Manejo de punteros
> MPI_File_seek(fh, offset, whence);
Desplaza el puntero offset unidades (bytes) en relación a la
posición actual en el fichero (whence = MPI_SEEK_CUR), al
comienzo del fichero (MPI_SEEK_SET), o al final (MPI_SEEK_END).
> MPI_File_set_view(fh, disp, etype, filetype,
drepr, info);
Crea una “vista” del fichero fh para cada proceso (operación colectiva); posiciona los punteros particulares de cada proceso en disp
(p.e., función del pid). drepr indica el modo de representación de
datos (ver manual).
Laboratorio de Paralelismo
IF - EHU
128
MPI
Entrada/salida paralela
 Operaciones básicas con ficheros:
2. Manejo de punteros
> MPI_File_get_position(fh, offset);
Devuelve en offset la posición actual del puntero privado.
Laboratorio de Paralelismo
IF - EHU
3
129
MPI
Entrada/salida paralela
3
130
 Operaciones básicas con ficheros:
3. Escritura de datos
> MPI_File_write(fh, &buf, count, datatype, &status);
Escribe en fh count elementos de buf de tipo datatype. Utiliza
el puntero privado de acceso al fichero (que se actualiza
automáticamente).
> MPI_File_write_at(fh, offset, &buf, count,
datatype, &status);
Escribe en fh a partir de la dirección marcada por offset, sin
utilizar ni modificar ningún puntero privado.
Laboratorio de Paralelismo
IF - EHU
MPI
Entrada/salida paralela
 Operaciones básicas con ficheros:
4. Flush de datos
> MPI_File_sync(fh);
Obliga a escribir en fh datos que todavía puedan estar sin escribir.
Es una operación colectiva que deben realizar todos los procesos
del comunicador.

Existen muchas más funciones para trabajar con ficheros (ver
manual MPI-2), con el objetivo de conseguir el mayor rendimiento posible en aplicaciones en las que el punto clave sean
las operaciones de entrada/salida.
Laboratorio de Paralelismo
IF - EHU
3
131
Índice
1.
2.
3.
4.
5.
6.
7.
Introducción.
Funciones MPI básicas.
Otros modos de envío/recepción.
Comunicación en grupo.
Tipos de datos derivados.
Comunicadores y topologías.
Entrada/salida paralela (introd.).
8. Performance, debugging, profiling
Laboratorio de Paralelismo
IF - EHU
MPI
Performance
 El objetivo de un programa paralelo es resolver
problemas más grandes y/o en menor tiempo.
 Los parámetros típicos que miden el rendimiento
de una determinada ejecución en paralelo son
(N = tam. probl., P = núm. proc.):
speed-up
eficiencia
S(N,P) = Ts(N) / Tp(N,P)
E(N,P) = S(N,P) / P
La comparación de tiempos hay que hacerla con el
mejor programa serie, y no con el programa paralelo
ejecutado sobre un procesador.
Laboratorio de Paralelismo
IF - EHU
3
133
MPI
Performance
 S debería estar entre 0 y P (E, entre 0 y 1)
S = P es el caso ideal. En todo caso, lo mejor es que S
sea una función lineal de P (escalabilidad).
¡pero puede ser que S < 1! (peor que el caso serie)
S > P?? Influyen otros factores; por ejemplo, el hecho
de que el sistema de P procesadores tenga P veces más
memoria que un solo procesador.
 Factores que limitan el rendimiento
> parte del código se ejecutará en serie (Amdahl)
- a tamaño constante
S  1 / (1-f)
- a tiempo constante
Sf*p
Laboratorio de Paralelismo
IF - EHU
3
134
MPI
3
Performance
 Factores que limitan el rendimiento
Cuando se ejecuta el código en paralelo, hay que hacer más
cosas que simplemente ejecutar cálculo. Lo principal, la
comunicación entre procesos (y las operaciones de
entrada/salida).
Tp(N,P) = T_calc(N,P) + T_com(N,P) + (T_io)
ts + N/B
Laboratorio de Paralelismo
IF - EHU
ts = latencia (start-up)
B = ancho de banda
N = datos a transmitir
135
MPI
3
Performance
 Comunicación
Tc = ts + N/B
ABreal = N / Tc =
= B / (1 + B*ts/N)
5000
Tc
4000
1
3000
(x 1/B)
0.8
2000
0.6
1000
0
ABreal
0
1000 2000 3000
N
0.4
4000 5000
0.2
N
0
Laboratorio de Paralelismo
IF - EHU
1
10
100
1000
104
105
136
MPI
Performance
 Es útil/necesario solapar cálculo y comunicación
en cada proceso:
(a) comunicaciones no bloqueantes.
(b) procesadores específicos de comunicación.
 Factores que limitan el rendimiento
> cálculo extra (replicado)
> tiempos muertos (load balancing)  (+ Tidle)
Tp(N,P) = Tcal(N,P) + Tcom(N,P) + Tidle + (Tio)
Laboratorio de Paralelismo
IF - EHU
3
137
MPI
Performance
3
 Hay que elegir el algoritmo adecuado al problema,
teniendo en cuenta el tiempo de respuesta.
Error: cambiar un buen algoritmo secuencial por un
algoritmo paralelo... ¡desastroso!
 Hay que analizar con cuidado el reparto de datos a
los procesadores (localidad).
Error: suponer que las operaciones de coma flotante son
asociativas (reducciones).
Laboratorio de Paralelismo
IF - EHU
138
MPI
Performance
 Intentar reducir el efecto de la latencia en la
comunicación:
• Agrupar datos en los envíos.
• Aumentar el tamaño de grano de las tareas.
• Utilizar las diferentes estrategias de gestión de los
mensajes para reducir los tiempos muertos en la
comunicación (handshake).
Error: no tomar en consideración las limitaciones de
buffering del sistema (dep. de la máquina!).
Laboratorio de Paralelismo
IF - EHU
3
139
MPI
Debugging
3
 Algunas ideas sobre debugging de programas
paralelos:
• es más difícil; un error puede no corresponder a un
proceso, sino a una secuencia de acciones en diferentes
procesos.
• es imposible predecir el comportamiento de un
programa erróneo, ya que los resultados cambian de
ejecución a ejecución y de sistema a sistema.
• la gran mayoría de los errores no tienen nada
que ver con el paralelismo.
Laboratorio de Paralelismo
IF - EHU
140
MPI
Debugging
3
 Procedimiento a seguir:
1. Hacer una versión serie del programa.
Diseñar previamente el programa antes de escribir
código, seguir un proceso incremental de pruebas,
mejor ser claro que “original”...
Utilizar las herramientas de depuración de programas
serie (por ejemplo, gdb).
2. Tras diseñar el programa paralelo, probarlo en un
solo procesador.
3. Si es correcto, probarlo con más procesadores.
Laboratorio de Paralelismo
IF - EHU
141
MPI
Debugging
 Los problemas específicos están relacionados casi
siempre con la “sincronización” de los procesos:
• Carreras (races)
Los programas paralelos pueden ofrecer resultados no
deterministas, que cambian de ejecución a ejecución.
• Bloqueos (deadlocks)
Los procesos se bloquean en operaciones de
comunicación que no se completan. Por ejemplo:
+ intentar recibir datos con Recv pero no enviarlos.
+ parámetros no correctos en las funciones de
comunicación: direcciones de origen/destino, tags...
Laboratorio de Paralelismo
IF - EHU
3
142
MPI
Debugging
3
 Ante un determinado problema, tres líneas a seguir:
1. Leer el código detenidamente, e intentar deducir
cómo se comporta el programa paralelo (si es sencillo y
sabemos más o menos dónde puede estar el error).
2. Tracear el programa mediante (printf); etiquetar los
mensajes con el nodo y hacer flush(stdout);...
Ojo: la introducción de trazas puede modificar el
comportamiento del programa.
Es útil imprimir los parámetros de comunicación antes de
enviar los mensajes y cuando se reciben.
Laboratorio de Paralelismo
IF - EHU
143
MPI
Debugging
3
 Ante un determinado problema, tres líneas a seguir:
3. Usar un debbuger simbólico: TotalView, gdb...
 Casi todas las funciones MPI devuelven un código que
puede ayudar a identificar problemas.
Manejadores de errores (error handler, EH)
- MPI_ERRORS_ARE_FATAL: el programa aborta.
- MPI_ERRORS_RETURN: devuelve un código de error.
Los EH están asociados a los comunicadores (recuerda que un
comunicador puede llevar parámetros “cacheados”, como, por
ejemplo, una topología). Un ejemplo:
Laboratorio de Paralelismo
IF - EHU
144
MPI
Debugging
int
cod_err;
cod_err = MPI_Errhandler_set (MPI_COMM_WORLD,
MPI_ERRORS_RETURN);
char mens_err[MPI_MAX_ERROR_STRING];
int long_mens;
cod_err = MPI_Broadcast (&x, 1, MPI_INT, 0, comm);
if (cod_err != MPI_SUCCESS) {
MPI_Error_string (cod_err, mens_err, &long_mens);
fprintf (stderr, “Error BC = %s\n”, mens_err);
fprintf (stderr, “Agur Benhur\n”);
MPI_Abort (MPI_COMM_WORLD, -1); // -1: error_code
}
Laboratorio de Paralelismo
IF - EHU
3
145
MPI
Profiling
3
 De cara a mejorar el rendimiento del programa,
tenemos que identificar qué partes del mismo son las
responsables de la mayor parte del tiempo de
ejecución: hay que obtener un “perfil”.
Obviamente, para obtener un buen rendimiento debemos
de partir de un buen algoritmo.
 Hay que medir tiempos:
- gettimeofday, MPI_Wtime…
- barreras (?)
- modificar las funciones MPI, para incluir toma de tiempos
(PMPI)
Laboratorio de Paralelismo
IF - EHU
146
MPI
3
Profiling
 Usar alguna herramienta específica de profiling:
• gprof (serie)
• TotalView, Paragraph, Pablo, Vampir, Paradyne…
(INTEL, KAI, Porland, PALLAS…)
• jumpshot
(xmpi / lam)
Se puede analizar el tiempo de ejecución de cada función MPI,
los patrones de comunicación...
Laboratorio de Paralelismo
IF - EHU
147
MPI
Jumpshot
 Jumpshot es una aplicación que permite analizar
“gráficamente” el comportamiento de programas
paralelos (MPICH / MPE) que se han ejecutado
previamente y de los que se ha obtenido un fichero
tipo “log”.
Para generar el fichero log podemos añadir puntos de
muestreo en lugares concretos (añadiendo funciones de
MPE), o, en casos sencillos, tomar datos de todas las
funciones MPI:
> mpicc –mpe=mpilog –o p1 p1.c
> mpiexec –n num_proc p1
Laboratorio de Paralelismo
IF - EHU
3
148
MPI
Jumpshot
Al ejecutar el programa se genera el fichero p1.clog2,
que, transformado a formato slog2, puede analizarse
mediante jumpshot4
> clog2TOslog2 p1.clog2
> jumpshot
 Veamos unos ejemplos de uso de jumpshot.
Laboratorio de Paralelismo
IF - EHU
3
149
Comunicación one-sided
 Hemos analizado las funciones principales de MPI,
pero hay más.
Por ejemplo, MPI-2 permite generar procesos de
manera dinámica, y no solamente de manera
estática, tal como hemos hecho a lo largo del curso.
También existen operaciones de comunicación onesided (put, get) que permiten a un proceso acceder
a la memoria local de otro (con lo que podríamos
utilizar un modelo de memoria compartida!).
Laboratorio de Paralelismo
IF - EHU
MPI-OpenMP

En la mayoría de los clusters, cada nodo es un pequeño
multiprocesador (4-8 procesadores), o un procesador de
cuatro a ocho núcleos con multithreading.
En esos casos es interesante utilizar simultáneamente los
dos modelos: MPI (paso de mensajes entre nodos de
memoria privada) y OpenMP (hilos de memoria compartida).
Basta con añadir a los procesos MPI las correspondientes
directivas OpenMP, de tal manera que la tarea asignada a
cada nodo se reparta entre los procesadores locales.
Atención al modelo de memoria (variables privadas y
compartidas), que es diferente en cada caso.
Laboratorio de Paralelismo
IF - EHU
Referencias
> MPI
• P. S. Pacheco: Parallel Programming with MPI.
Morgan Kaufmann, 1997.
• W. Gropp et al.: Using MPI. Portable Parallel Programming
with the Message Passing Interface.
Using MPI-2. Advanced Features of the Message Passing
Interface. The MIT Press, 1999.
• M. Snir et al.: MPI - The complete reference (vol. 1 /2).
The MIT Press, 1998.
• mpich:
lam:
Laboratorio de Paralelismo
IF - EHU
www-unix.mcs.anl.gov/mpi/
www.lam-mpi.org
Referencias
> Gestión de un cluster
• T. Sterling: Beowulf Cluster Computing with Linux.
The MIT Press, 2002
• J.D. Sloan: High Performance Linux Clusters with OSCAR,
Rocks, openMosix & MPI.
O’Reilly, 2005
Laboratorio de Paralelismo
IF - EHU