05 Programacion con MPI

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 34

Programación con MPI

Cluster Beowulf

• Un cluster Beowulf es una colección de computadoras personales


(PC's) interconectadas por medio de una red privada de alta
velocidad, corriendo como sistema operativo alguna distribución
Linux.

• Los nodos en el cluster son dedicados exclusivamente a ejecutar


tareas asignadas al cluster.

• Por lo general el cluster se encuentra comunicado al mundo exterior


a través de un solo nodo, llamado nodo “Principal", el cual también
esta reservado para accesar, compilar y manejar las aplicaciones a
ejecutar.
Arquitectura del Cluster

nodo-01

Servidor de Archivos
nfs.pci.uas.edu.mx

alfa.miservidor.mx
nodo-02

Internet
Nodo Principal
colhuacan.pci.uas.edu.mx
maestro.miservidor.mx
Nodo-03
beta.miservidor.mx

nodo-04
¿Qué es MPI?

MPI (iniciales de Message Passing Interface) es:

– una especificación para programación de paso de


mensajes.

– Proporciona una biblioteca de funciones para C, C++ o


Fortran que son empleadas en los programas para
comunicar datos entre procesos.
¿Quién define MPI?

– MPI es la biblioteca de paso de mensajes estándar y


portable, especificada por consenso por el MPI Forum,
con unas 40 organizaciones participantes, como
modelo que permita desarrollar programas que puedan
ser migrados a diferentes computadoras paralelos.

– http://www.mpi-forum.org

– El primer estándar MPI 1.0 fue acabado y publicado en


mayo 1994. El estándar ha sido actualizado desde
entonces, estando actualmente en desarrollo el MPI 2.
Características de MPI

• Estándar actual de programación de los sistemas de


memoria distribuida

• Portabilidad: multiprocesadores y multicomputadoras.

• Se basa en el envío y recepción de mensajes entre


procesos.

• Las implementaciones de MPI esta orientadas a Fortran


y C.
Implementaciones

• MPICH (MPI/Chameleon). Producida por la


Universidad del Estado de Mississippi.

• LAM (Local Area Multicomputer) es un ambiente de


programación y un sistema de desarrollo sobre redes
de computadores heterogéneas. Esta implementación
es del Centro de Supercomputación de Ohio.

• OpenMPI es el sucesor de la herramienta LAM


Funciones básicas de MPI

• Cualquier programa paralelo con MPI puede


implementarse con tan sólo 6 funciones, aunque hay
más de 120 para aspectos avanzados.

• Todas las funciones empiezan por MPI_ y obligan a


que los programas MPI tengan #include <mpi.h>

• Los programas MPI deben ser obligatoriamente


inicializados y finalizados en MPI (MPI_Init,
MPI_Finalize).
Funciones de Inicio y Terminación

• MPI_Init()
• int MPI_Init(int *argc, char ***argv)

• MPI_Finalize()
• int MPI_Finalize(void)
Ingreso

Conexión remota con ssh


$ ssh [email protected]
//12AB34cd*

Crear una carpeta personal


$ mkdir nombre

• Ingresar a la carpeta
$ cd nombre
Primer Programa

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

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

MPI_Init(&argc, &argv);
printf("Hola Mundo!!!\n");
MPI_Finalize();
}
Compilación y Ejecución con OpenMPI

Compilación
• $ mpicc prog01.c -o prog01

• Ejecutar programa
• $ mpirun -np 4 prog01

• Crear un archivo de nodos (ejem. nodos.lst) con


• alfa
• beta

• Ejecutar programa
• $ mpirun -hostfile nodos.lst -np 4 prog01
Funciones de Información de Ambiente

• Algunas de las preguntas que nos podemos hacer


son:

– ¿Cuántos procesos hay?

– ¿Qué proceso soy?

– ¿En dónde estoy corriendo?


Comunicadores

• Un comunicador corresponde a un grupo de procesos


sobre el que se realiza la comunicación.

• Dentro de un comunicador cada proceso tiene un


rango que lo identifica.

• Existe un comunicador básico MPI_COMM_WORLD


que contiene a todos los procesos.

• Existen funciones que nos permiten saber el rango y


el número de procesos dentro de un comunicador.
Numero de procesos

El valor para el número de procesos se obtiene con

int MPI_Comm_size(MPI_Comm comm, int *nproc)

Retorna el número de procesos involucrados en una ejecución

Entrada comm comunicador


Salida nproc número de procesos en el grupo de comm
Identificador de Proceso

Para obtener el identificador o rango del proceso se utiliza

int MPI_Comm_rank(MPI_Comm comm, int *idproc)

Retorna el identificador o rango de un proceso

Entrada comm comunicador


Salida idproc rango del proceso en el grupo de comm

El identificador o rango es un número entre cero (0) y el total de


procesos menos uno (procesos -1).
En múltiples
En un solo nodo nodo (CLUSTER)
Nombre del procesador

Para saber donde se esta corriendo el proceso

int MPI_Get_processor_name(char *name, int *resultlen)

Retorna el nombre del procesador sobre el cual se esta


corriendo al momento de hacer la llamada

Salida name - nombre del procesador


Salida resultlen - longitud en número de caracteres de name
Segundo Ejemplo

#include <stdio.h>
#include <mpi.h>
int idproc, nproc, resultlen;
char nombre[30];
int main (int argc, char** argv)
{
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &idproc);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Get_processor_name(nombre, &resultlen);

printf("Hola Mundo! Yo soy %d de %d corriendo en %s\n",idproc, nproc,


nombre);
MPI_Finalize();
}
Ejercicio

• Desarrolle un programa que lea en paralelo 4 archivos que contienen


una serie de números de tipo flotante, es necesario saber cual es el
valor menor y mayor de cada archivo así como su promedio, se
deben generar archivos para cada salida de información.

• Procese los archivos en paralelo con 4 nodos con MPI.


Tarea

• Modifique el ejercicio anterior para que pueda realizar los cálculos


para N archivos en N nodos.
Funciones Básicas de Comunicación

• La forma de comunicación en MPI es a través de


mensajes que contienen datos.

• La forma más simple es la comunicación punto a


punto, donde se envía un mensaje de un proceso a
otro.

• Esto se realiza usando las funciones MPI_Send y


MPI_ Recv.
Funciones Básicas de Comunicación

Envío de Datos

int MPI Send(void *Datos, int cont, MPI_Datatype dtype, int


destino, int tag, MPI_Comm comunicador)

Recepción de datos

int MPI Recv(void *Datos, int cont, MPI_Datatype dtype,


int fuente, int tag, MPI_Comm comunicador,
MPI_ Status *estado)
Funciones Básicas de Comunicación

void *Datos Datos de envío o recepción

int cont Número de datos

MPI_Datatype dtype Tipo de datos

int destino/fuente rango del nodo al que se


envía/recibe

int tag Etiqueta que diferencia al


mensaje, para ignorarla en
puede pasar MPI_ANY_TAG
en MPI_Recv
Funciones Básicas de Comunicación

MPI Comm comm Comunicador

MPI_Status *estado Estado de la recepción (solo


MPI_Recv) para ignorarlo
pasar
MPI_STATUS_IGNORE
Tipos de Datos

• Al enviar un dato es necesario especificar su tipo.

• Cada tipo tiene una equivalencia con un instancia del


tipo MPI_Datatype.

• Esto permite el uso de MPI en ambientes


heterogéneos.

• Es posible generar tipos de datos más complejos,


Tipos de Datos
Tipo de dato MPI Tipo de dato C
MPI_CHAR signed char
MPI_SHORT signed short int
MPI_INT signed int
MPI_LONG signed long int
MPI_UNSIGNED_CHAR unsigned char
MPI_UNSIGNED unsigned int
MPI_UNSIGNED_LONG unsigned long int
MPI_FLOAT float
MPI_DOUBLE double
MPI_LONG_DOUBLE long double
MPI_BYTE
Comunicación con bloqueo

#include <stdio.h> else // Esclavos


#include <stdlib.h> {
#include <mpi.h> int length;
printf("SLAVE (rank = %i)\n", rank);
#define TAG_LENGTH 1
#define TAG_DATA 2 MPI_Recv(&length, 1, MPI_INT, 0, TAG_LENGTH,
→ MPI_COMM_WORLD, MPI_STATUS_IGNORE);
int main(int argc, char** argv)
{ double* data = (double*)malloc(sizeof(double)*length);
int size;
int rank; MPI_Recv(data, length, MPI_DOUBLE, 0, TAG_DATA,
→ MPI_COMM_WORLD, MPI_STATUS_IGNORE);
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size); free(data);
MPI_Comm_rank(MPI_COMM_WORLD, &rank); }

if (rank == 0) // Maestro MPI_Finalize();


{ return 0;
printf("MASTER (size = %i)\n", size); }
int length = 20;
double* data = (double*)malloc(sizeof(double)*length);
for (int r = 1; r < size; ++r)
{
MPI_Send(&length, 1, MPI_INT, r, TAG_LENGTH,
→ MPI_COMM_WORLD);
MPI_Send(data, length, MPI_DOUBLE, r, TAG_DATA,
→ MPI_COMM_WORLD);
}
free(data);
}

14/10/10
Funciones colectivas

• MPI_Bcast difunde un mensaje del proceso identificado


como root a todos los procesos del grupo

• int MPI_Bcast(void *Datos, int cont, MPI_Datatype tipo,


int root, MPI_Comm comm)

• Difunde datos desde root a todos los procesos


• Entrada/Salida Datos dirección del buffer
• Entrada cont número de elementos en el
buffer de envio
• Entrada tipo tipo de dato de los elementos
Entrada root rango del proceso root
• Entrada comm comunicador
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv)
{
int rank;
int buf;
const int root=0;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(rank == root)
buf = 777;
printf("[%d]: Before Bcast, buf is %d\n", rank, buf);
/* everyone calls bcast, data is taken from root and ends up in everyone's buf
*/
MPI_Bcast(&buf, 1, MPI_INT, root, MPI_COMM_WORLD);
printf("[%d]: After Bcast, buf is %d\n", rank, buf);
MPI_Finalize();
return 0;
}
Funciones colectivas

MPI_Reduce combina los elementos provisto en el


buffer de entrada (inbuf) de cada proceso en el grupo,
usando la operación operador (puede ser una
operación predefinida o definida por el usuario) y
retorna el valor combinado en el buffer de salida
(outbuf) del proceso root

• int MPI_Reduce(void *DatoEnt, void *DatoSal, int


cont, MPI_Datatype tipo, MPI_Op operador, int
root, MPI_Comm comm)
Funciones colectivas

Entrada DatoEnt dirección del buffer de


entrada
Salida DatoSal dirección del buffer de salida
Entrada cont número de elementos en el
buffer de entrada
Entrada tipo tipo de dato de los elementos
del buffer de entrada
Entrada operador operación (ver Tabla).
Entrada root rango del proceso root
Entrada comm comunicador
Funciones colectivas

• Operadores de reducción
Operador Descripción

MPI_SUM Suma

MPI_MAXLOC Máximo y localización

MPI_MINLOC Mínimo y localización


Funciones colectivas
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv)
{
int rank, size, local_value, global_sum;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

local_value = rank;

MPI_Reduce(&local_value, &global_sum, 1, MPI_INT, MPI_SUM, 0,


MPI_COMM_WORLD);
if (rank == 0)
printf("The sum of all ranks is: %d\n", global_sum);

MPI_Finalize();
return 0;
}

También podría gustarte