Title: Sin ttulo de diapositiva
1REDES DE ALTAS PRESTACIONES Y SUS APLICACIONES
Lección 7. Aprovechamiento del Paralelismo.
MPI/PVM
Departamento de Arquitectura y Tecnología de
Computadores
E.T.S. Ingeniería Informática
Julio Ortega Lopera. Curso 2004/2005
2Índice
- Introducción al procesamiento paralelo
- PVM
- MPI
Curso de Doctorado RAPyA (2004/05)
3EJEMPLO DE ALGORITMO PARALELO
4PASOS EN EL PROCESO DE PARALELIZACIÓN
Computación Secuencial
Procesos
Programa Paralelo
Tareas
Procesadores
Descomposición
Agrupamiento
Orquestación
Mapeo
Particionado
5Granularidad, Particionado, y Prestaciones
Grano Fino
Secuencial
Grano Grueso
6OBJETIVOS DEL PARTICIONADO
Equilibrado de carga entre los procesadores y
reducción de tiempos de espera en los puntos de
sincronización. Reducir la Comunicación Reducir
el trabajo extra asociado al agrupamiento de
tareas en procesos
Identificar concurrencia suficiente en la
descomposición usando paralelismo de datos, o
paralelismo funcional (Amdahl) Decidir si
agrupamiento estático o dinámico Determinar la
granularidad a la que se va a explotar la
concurrencia Reducir los costos de serialización
y sincronización
7Medidas de Ganancia de Velocidad (Speedup)
Speedup Velocidad (P) / Velocidad (1)
(Trabajo (P) / Tiempo (P)) / (Trabajo (1) /
Tiempo (1))
Speedup(TC) Trabajo (P) / Trabajo (1)
Tiempo Fijo (Tiempo-real)
Speedup(WC) Tiempo (1) / Tiempo (P)
Trabajo Fijo
Memoria por Procesador Fija
Speedup(MC) (Trabajo (P) / Trabajo (1)) /
(Tiempo(P) / Tiempo (1))
8LEY DE AMDAHL
En todo problema hay una parte secuencial, donde
no se puede aprovechar el trabajo cooperativo de
los procesadores, limitando de forma importante
la ganancia de velocidad alcanzable
S (P,f) lt P / ( 1 f(P-1))
S(P,f)
1/f1
Fracción Secuencial f
1/f2
Procesadores
9Ganancia de Velocidad Efecto de los costos
asociados al Procesamiento Paralelo
10Ganancia de Velocidad Efecto de los costos
asociados al Procesamiento Paralelo (2)
1/f
S
Overhead
S P
Número óptimo de procesadores para un tamaño de
problema dado
P
11Índice
- Introducción al procesamiento paralelo
- PVM
- MPI
Curso de Doctorado RAPyA (2004/05)
12PARALLEL VIRTUAL MACHINE (PVM)
PVM es una biblioteca de funciones de paso de
mensajes, creación de tareas, etc. que permite
que una red de computadores puedan ser utilizados
como un computador paralelo de memoria
distribuida (Máquina Virtual) Desarrollado en el
Oak Ridge National Lboratory, Tennessee Página
Web http//www.epm.ornl.gov/pvm/intro.html Modos
de Uso - Modo Transparente las tareas se
ejecutan en los diversos computadores de la
manera más adecuada (PVM se encarga de distribuir
las tareas automáticamente). - Modo Dependiente
de Arquitectura el usuario especifica el tipo de
computador donde se debe ejecutar cada tarea. -
Modo de Bajo Nivel el usuario especifica el
computador donde ha de ejecutarse cada tarea.
13PROGRAMACIÓN EN PVM (I)
Cada programa PVM debe incluir una cabecera de
fichero PVM con la información acerca de la
interfaz de programación en PVM. Así, al
principio hay que incluir include pvm3.h La
primera función llamada por un programa PVM
declara al proceso como proceso PVM asociándole
un número de identificación (tid es un entero que
devuelve la función indicando el número de
identificación del proceso o que ha habido error,
si es negativo) int tid pvm_mytid() Cuando un
programa termina debe llamara a una función que
le indica al deamond de pvm que el proceso
abandona PVM (esta rutina no mata al
proceso) pvm_exit()
14PROGRAMACIÓN EN PVM (II)
Creación de Procesos Con la función pvm_spawn()
se pueden iniciar ntask copias del fichero
ejecutable task en la máquina virtual. int numt
pvm_spawn(char task, char argv, int flag, char
where, int ntask, int tids) El puntero
argv señala a un array de argumentos para task
(el final del array indicado por NULL) y flag
permite especificar ciertas opciones mediante la
suma de los códigos 0 PvmTaskDefault PVM escoge
donde generar los procesos 1 PvmTaskHost El
argumento where indica la máquina donde generar
los procesos 2 PvmTaskArch El argumento where
indica la arquitectura donde se van a generar los
procesos utilizando ARCH 4 PvmTaskDebug Comienza
los procesos bajo el debugger 8 PvmTaskTrace Las
llamadas a PVM en los procesos generados
producirá datos de traza La función devuelve el
número de tareas generadas con éxito o un error
si no se generó ninguna. Si se genera alguna, se
devuelve el vector de los tids de las tareas
generadas y si alguna no se generó, en la
posición ntask-numt del vector aparece el código
de error.
15PROGRAMACIÓN EN PVM (III)
Primitivas de Comunicación mediante Mensajes Para
enviar un mensaje hay que realizar tres
pasos (1) Definir un buffer de salida (zona de
memoria donde se van a almacenar los
datos) pvm_initsend() pvm_mkbuf() (2)
Empaquetar los datos del mensaje en el
buffer pvm_pack() (3) Enviar el mensaje
completo pvm_send() pvm_mcast() Para recibir un
mensaje (1) Llamar a una rutina de recepción de
un mensaje (con o sin bloqueo) pvm_recv()
pvm_nrecv() (2) Desempaquetar los datos recibidos
en el buffer de entrada pvm_unpack() Con
pvm_bufinfo() se obtiene información del mensaje
en el buffer bufid
16PROGRAMACIÓN EN PVM (IV)
Ejemplo de Emisión info pvm_send(tid,msgtag) En
vía el dato en el buffer de salida al proceso
identificado con tid (tid-1 indica que se envía
a todos), y se marca el mensaje con el entero
msgtag. Mediante la marca del mensaje se
identifica el mensaje para que el receptor
identifique qué tipo de mensaje se está
recibiendo. En PVM 3.3 existe pvm_psend() que
empaqueta y envía el mensaje Ejemplo de
Recepción bufid pvm_recv (tid,msgtag) Espera
un mensaje desde la tarea tid con la marca
msgtag. Si se especifica -1 en tid se espera un
mensaje desde cualquier tarea y si msgtag es -1
se espera un mensaje con cualquier marca.
17PROGRAMACIÓN EN PVM (V)
- Grupo Dinámico de Procesos
- Es posible dar un nombre a un conjunto de
procesos PVM cada proceso tiene un número que le
identifica dentro del grupo al que pertenece,
además del tid. - Incluir tarea en un grupo inum
pvm_joingroup(nombre_de_grupo) - inum es 0 para el primer proceso que hace la
llamada y a los que se van incluyendo se le van
dando números correlativos. Un proceso puede
estar en más de un grupo a la vez - Dejar un grupo pvm_lvgroup()
- Información de grupos pvm_getint(),
pvm_gettid(), pvm_gsize() - Devuelven, respectivamente, el número de grupo,
tid, y el tamaño del grupo. - Envío a los miembros de un grupo pvm_bcast()
- En un pvm_mcast() se envía el mensaje a todos
los procesos con índices en un array de tids. - Sincronización en un grupo pvm_barrier()
- El proceso espera hasta que todos los procesos
del grupo llamen a pvm_barrier()
18PROGRAMACIÓN EN PVM (VI)
Formatos de algunas funciones más utilizadas int
tid pvm_parent() Devuelve el tid del proceso
que generó (spawned) la tarea que lo llama o
devuelve PvmNoParent si no se ha creado con
pvm_spawned() (es el padre) int bufid
pvm_initsend(int encoding) Borra el buffer por
defecto para enviar un mensaje y especifica el
tipo de codificación PvmDataDefault (0) indica
codificaciób XDR si el sistema es heterogéneo
PvmDataRaw (1) indica que no se utiliza
codificación de datos PvmDataInPlace (2) indica
que el buffer sólo tiene los tamaños y los
punteros a los datos, que se copian de la memoria
de usuario al hacer el pvm_send() bufid es el
identificador del buffer (valores menores que 0
indican error) int bufid pvm_mkbuf(int
encoding) Crea un nuevo buffer para enviar
mensajes y especifica el tipo de codificación
19PROGRAMACIÓN EN PVM (VII)
Formato de las funciones más utilizadas int info
pvm_multicast(int tids, int ntask, int
msgtag) Envía los datos contenidos en el buffer
activo para mensajes a un conjunto de
tareas ntask número de tareas a las que se
envía el mensaje tids array de enteros, de
longitud igual al menos a ntask que contiene los
identificadores de las tareas a las que se envía
el mensaje msgtag entero mayor o igual a 0 que
marca el mensaje para que se pueda distinguir en
el destino. info si es menor que cero, indica
error
20PROGRAMACIÓN EN PVM (VIII)
Formato de las funciones más utilizadas int info
pvm_pkXX (tipo YY, int nitem, int
stride) Empaqueta los datos, según el tipo YY
en el buffer para mensajes nitem número de
items a empaquetar (no es el número de
bytes) stride Salto utilizado para seleccionar
los elementos del array a partir del primero (al
que apunta YY). YY xp (puntero al comienzo de
un bloque de bytes char xp, XXbyte) cp
(puntero a un array complejo con nitemstride
elementos, float cp, XXcplx) zp (array
complejo de doble precisión con nitemstride
elementos, double zp, XXdclpx) dp (array de
reales con al menos nitestride elementos,
double dp, XXdouble) fp (array de reales con
nitemstride elementos, float fp, XXfloat)
ip (array de enteros con nitemstride elementos,
int ip, XXint) jp (array de enteros largos
con nitemstride elementos, long jp, XXlong)
sp (puntero a una cadena de caracteres
terminada en NULL, char sp, XXstr). int info
pvm_upkXX (tipo YY, int nitem, int stride)
21CONSOLA DE PVM
La consola de PVM permite lanzar el daemon de
pvm, añadir máquinas para configurar la máquina
virtual, consultar su estado, y modificarla. Al
ejecutar PVM se activa el daemon de PVM si no
estuviera activado, y aparece el prompt PVMgt add
(seguido del nombre de una máquina) permite
añadir máquinas a la MV delete (seguido del
nombre de una máquina) permite quitar máquinas de
la MV conf permite listar las máquinas que
constituyen la MV ps -a permite conocer todos los
procesos en la máquina virtual, su TID, etc. quit
permite salir de la consola (el daemon de PVM
sigue activo) halt permite matar todos los
procesos PVM (entre ellos el daemon) setenv
muestra o cambia las variables de entorno help da
información acerca de los comandos interactivos
de PVM
22Ejemplo de Código
Programa PVM ejemplo spmd.c que permite crear
NPROC4 procesos, que organiza como un anillo, y
entre los que se pasa un token.
23EJEMPLO DE ALGORITMO PARALELO
24Índice
- Introducción al procesamiento paralelo
- PVM
- MPI
Curso de Doctorado RAPyA (2004/05)
25Message-Passing Interface (MPI)
Es una biblioteca de funciones que se pueden
llamar desde programas en C o en Fortran 77 para
construir programas paralelos con paso de
mensajes. Se puede considerar un estándar dada su
gran difusión que ha sido desarrollado por un
Foro Internacional en el que han participado
tanto la Industria como la Universidad y Centros
de Investigación Objetivos uso eficiente de la
plataforma y portabilidad de código Pacheco,
P.S.Parallel Programming with MPI. Morgan
Kaufmann, 1997 http//www.mkp.com
Curso de Doctorado RAPyA (2004/05)
26MPI (II)
/ Send a message from all processes with rank !
0 to proc 0. Process 0 prints the messages
received. / include ltstdio.hgt include
ltstring.hgt include "mpi.h" main(int argc, char
argv) int my_rank / rank
of process / int p
/ number of processes / int
source / rank of sender / int
dest / rank of receiver
/ int tag 0 / tag for
messages / char message100 /
storage for message / MPI_Status status
/ return status for /
/ receive
/ / Start up MPI / MPI_Init(argc,
argv) / Find out process rank /
MPI_Comm_rank(MPI_COMM_WORLD, my_rank) /
Find out number of processes /
MPI_Comm_size(MPI_COMM_WORLD, p)
if (my_rank ! 0) / Create message /
sprintf(message, "Greetings from process
d !",my_rank) dest 0 / Use
strlen1 so that '\0' gets transmitted /
MPI_Send(message, strlen(message)1, MPI_CHAR,
dest, tag, MPI_COMM_WORLD) else
/ my_rank 0 / for (source 1
source lt p source)
MPI_Recv(message, 100, MPI_CHAR, source, tag,
MPI_COMM_WORLD, status)
printf("s\n", message) /
Shut down MPI / MPI_Finalize() / main /
cc o saludos saludos.c lmpi Salida Greetings
form process 1 ! Greetings form process
Curso de Doctorado RAPyA (2004/05)
27MPI (III)
Todo programa MPI debe tener la directiva
include mpi.h El fichero mpi.h contiene las
definiciones y declaraciones necesarias para
compilar un programa MPI Antes de hacer cualquier
llamada a funciones de MPI hay que utilizar
MPI_Init(argc, argv) (sus parámetros son
punteros a los parámetros de la función main Una
vez se termina de utilizar la biblioteca MPI hay
que llamar a MPI_Finalize() que libera la memoria
asignada a MPI, etc.
Para saber cuantos procesos están implicados en
la ejecución de un programa se utiliza la
función int MPI_Comm_size( MPI_Comm com /
in /, int numero_de_procesos / out
/) Comunicador (MPI_Comm) es un conjunto de
procesos que pueden enviarse mensajes entre
si MPI_COMM_WORLD es un comunicador predefinido
(todos los procesos que se están ejecutando
cuando comienza la ejecución del programa)
Curso de Doctorado RAPyA (2004/05)
28MPI (IV)
Para que un proceso pueda conocer su
identificador (rango, rank) se utiliza int
MPI_Comm_rank( MPI_Comm com / in
/, int mi_rango / out /)
Para enviar un mensaje se utiliza int
MPI_Send( void mensaje / in
/, int cuenta / in /, MPI_Datatype tipo_
de_datos / in /, int dest / in
/, int tag / in /, MPI_Comm com / in
/) mensaje se refiere a los datos a transmitir,
cuenta es el número de datos del tipo
MPI_Datatype (un tipo de datos predefinido para
MPI) y por lo tanto determina el tamaño del
mensaje, dest es el destino del mensaje, tag es
una marca del mensaje que, junto con el
comunicador com permite que no se mezclen mensajes
Curso de Doctorado RAPyA (2004/05)
29MPI (V)
Para recibir un mensaje se utiliza int
MPI_Recv( void mensaje / out
/, int cuenta / in /, MPI_Datatype tipo_
de_datos / in /, int source / in
/, int tag / in /, MPI_Comm com / in
/, MPI_Status status / out /) source es
el origen del mensaje, status es un puntero que
devuelve el origen y la marca del mensaje que se
ha recibido Por tanto Cada mensaje contiene
tanto los datos que se envían como una serie de
datos adicionales (que reciben el nombre de
envelope, sobre) rango del emisor y el receptor,
marca, y comunicador)
Curso de Doctorado RAPyA (2004/05)
30MPI (VI)
Curso de Doctorado RAPyA (2004/05)
31MPI (VII)
/ Parallel Trapezoidal Rule, first
version/ include ltstdio.hgt / We'll be using
MPI routines, definitions, etc. / include
"mpi.h main(int argc, char argv) int
my_rank / My process rank /
int p / The number of
processes / float a 0.0 / Left
endpoint / float b 1.0
/ Right endpoint / int
n 1024 / Number of trapezoids /
float h / Trapezoid base length
/ float local_a / Left endpoint
my process / float local_b /
Right endpoint my process / int
local_n / Number of trapezoids for /
/ my calculation
/ float integral / Integral over my
interval / float total / Total
integral / int source
/ Process sending integral / int
dest 0 / All messages go to 0 /
int tag 0 MPI_Status status
float Trap(float local_a, float local_b, int
local_n, float h) / Calculate
local integral / / Let the system do what
it needs to start up MPI / MPI_Init(argc,
argv)
/ Get my process rank / MPI_Comm_rank(MPI_CO
MM_WORLD, my_rank) / Find out how many
processes are being used /
MPI_Comm_size(MPI_COMM_WORLD, p) h
(b-a)/n / h is the same for all processes
/ local_n n/p / So is the number of
trapezoids / / Length of each process'
interval of integration local_nh. So
my interval starts at / local_a a
my_ranklocal_nh local_b local_a
local_nh integral Trap(local_a, local_b,
local_n, h) / Add up the integrals
calculated by each process / if (my_rank
0) total integral for
(source 1 source lt p source)
MPI_Recv(integral, 1, MPI_FLOAT, source, tag,
MPI_COMM_WORLD, status)
total total integral else
MPI_Send(integral, 1, MPI_FLOAT,
dest, tag, MPI_COMM_WORLD)
Curso de Doctorado RAPyA (2004/05)
32MPI (VIII)
/ Print the result / if (my_rank 0)
printf("With n d trapezoids, our
estimate\n", n) printf("of
the integral from f to f f\n",
a, b, total) / Shut down MPI /
MPI_Finalize() / main /
En este programa paralelo, los datos se
distribuyen entre los distintos procesos SPMD Se
supone que el proceso 0 es el que puede escribir
en la salida estándar El resultado se obtiene
combinando las sumas parciales obtenidas por cada
proceso
Curso de Doctorado RAPyA (2004/05)
33MPI (IX)
Comunicaciones colectivas
int MPI_Bcast( void mensaje / in/out
/, int contador / in
/, MPI_Datatype datatype / in
/, int root / in /, MPI_Comm com /
in /) El proceso con rango 0 es la raíz
(root) y envía el mensaje a todos los demás
procesos en el comunicador, que lo reciben (por
eso mensaje es de entrada/salida)
int MPI_Reduce( void operando / in
/, void resultado / out
/, int contador / in
/, MPI_Datatype datatype / in
/, MPI_Op operador / in
/, int root / in /, MPI_Comm com /
in /) El proceso con rango 0 es la raíz
(root) recibe el resultado que se obtiene
aplicando el operador a los distintos operandos
(MPI_MAX, MPI_MIN, MPI_PROD, MPI_LAND MPI_BAND,)
Curso de Doctorado RAPyA (2004/05)
34MPI (X)
int MPI_Gather( void send_data / in
/, int send_contador / in
/, MPI_Datatype send_type / in
/, void recv_data / out
/, int recv_contador / in
/, MPI_Datatype recv_type / in
/, int root / in /, MPI_Comm com /
in /) Envía los datos en send_data en
cada proceso en comm, a la posición de memoria
recv_data en el proceso raíz
a b c d
Curso de Doctorado RAPyA (2004/05)
35MPI (XI)
int MPI_Scatter( void send_data / in
/, int send_contador / in
/, MPI_Datatype send_type / in
/, void recv_data / out
/, int recv_contador / in
/, MPI_Datatype recv_type / in
/, int root / in /, MPI_Comm com /
in /) Distribuye los datos en
send_data en el proceso raíz, a la posición de
memoria recv_data en los distintos procesos en
comm
a b c d
Curso de Doctorado RAPyA (2004/05)
36MPI (XII)
int MPI_Allreduce( void operando / in
/, void resultado / out
/, int contador / in
/, MPI_Datatype datatype / in
/, MPI_Op operador / in
/, MPI_Comm com / in /) Todos los
procesos reciben el resultado que se obtiene
aplicando el operador a los distintos operandos
(MPI_MAX, MPI_MIN, MPI_PROD, MPI_LAND MPI_BAND,)
int MPI_Allgather( void send_data / in
/, int send_contador / in
/, MPI_Datatype send_type / in
/, void recv_data / out
/, int recv_contador / in
/, MPI_Datatype recv_type / in
/, MPI_Comm com / in /) Envía los
datos en send_data en cada proceso en comm, a la
posición de memoria recv_data en los demás
procesos
Curso de Doctorado RAPyA (2004/05)
37MPI (XIII)
Agrupación de datos para la comunicación
int MPI_Pack( void pack_data / in
/, int in_contador / in
/, MPI_Datatype datatype / in
/, void buffer / out
/, int buffer_size / in
/, int posicion / in/out
/, MPI_Comm com / in /) El
parámetro pack_data se refiere al dato a
introducir en el buffer (debe ser igual a
in_contador elementos del tipo datatype). posicion
como entrada indica que los datos se copiarán a
partir de buffer posicion y como salida da la
dirección de la primera posición después de
copiar el dato en el buffer
Curso de Doctorado RAPyA (2004/05)
38MPI (XIV)
int MPI_Unpack( void buffer / out
/, int size / in /, int posicion
/ in/out /, void unpack_data / in
/, int contador / in
/, MPI_Datatype datatype / in
/, MPI_Comm com / in /) El
parámetro buffer se refiere al dato a
desempaquetar (contiene size bytes). El parámetro
posicion como entrada indica que los datos a
partir de buffer posicion se copia en
unpack_data y como salida da la dirección de la
primera posición en buffer después de copiar el
dato Se copiarán contador elementos con el tipo
datatype en unpack_data
Hay más funciones de agrupación de datos
MPI_Type_contiguous, MPI_Type_vector,
MPI_Type_vector, MPI_Type_indexed,
MPI_Type_struct, MPI_Type_commit,
Curso de Doctorado RAPyA (2004/05)
39MPI (XV)
Inicio de LAM ( Booting) El usuario debe crear
un fichero con las máquinas que participan en el
cluster (y que configuran la plataforma de varios
procesadores) shell cat lamhosts a 2-node
LAM node1.cluster.example.com node2.cluster.exam
ple.com Cada máquina tiene un identificador de
nodo (nodeid) que empieza por cero en la primera
máquina, uno en la segunda, etc.
Curso de Doctorado RAPyA (2004/05)
40MPI (XVI)
Mediante la herramienta recon se puede verificar
que el cluster se puede arrancar shell recon v
lamhosts recon - - testing n0 (node1.cluster.exam
ple.com) recon - - testing n1 (node2.cluster.exam
ple.com) Para iniciar LAM en el cluster
definido se utiliza shell lamboot v
lamhosts Para comprobar que, efectivamente, LAM
está activo se puede utilizar el comando
tping shell tping c1 N
Curso de Doctorado RAPyA (2004/05)
41MPI (XVII)
Para compilar un programa (ejemplo.c) MPI en C se
utiliza shell mpicc o ejemplo ejemplo.c
Para ejecutar un programa compilado con mpicc
se utiliza el comando mpirun shell mpirun v
np 2 ejemplo Una aplicación con varios
programas debe describirse en un esquema de
aplicación que es un fichero que contiene cada
uno de los programas y el nodo en el que se
ejecutan shell cat appfile (Aplicación con
un maestro y 2 esclavos) n0 master n0-1
slave Para ejecutarlo shell mpirun v appfile
Curso de Doctorado RAPyA (2004/05)
42MPI (XVIII)
Para eliminar los procesos de usuario y los
mensajes sin tener que reiniciar (por ejemplo, se
termina un programa y se quiere ejecutar otro,
sin tener que hacer lamboot) shell lamclean
v killing processes, done, sweeping messages,
done.. Para terminar LAM (no se va a
necesitar más) se usa shell lamhalt En el
caso de un fallo catastrófico se debe utilizar
wipe, ya que la utilidad lamhalt se puede quedar
bloqueada shell wipe v lamhosts Executing
tkill on n0 (node1.cluster.example.com) Executing
tkill on n1 (node2.cluster.example.com)
Curso de Doctorado RAPyA (2004/05)
43MPI (XIX)
MPI Forum www.mpi-forum.org Newsgroup
comp.parallel.mpi MPICH ftp//info.mcs.anl.gov/p
ub/mpi LAM-MPI www.mpi.nd.edu/lam/download
Tutoriales http//www.lam-mpi.org/tutorials/
www-unix.mcs.anl.gov/mpi www.erc.msstate.edu/mp
i
Curso de Doctorado RAPyA (2004/05)