Message Passing Interface (MPI)

Anuncio
Message Passing Interface (MPI)
INTRODUCCIÓN
MPI (Message Passing Interface) como es un interfaz estandarizada para la realización de
aplicaciones paralelas basadas en pasaje de mensajes. El modelo de programación que
subyace tras MPI es MIMD (Multiple Instruction streams, Multiple Data streams) aunque
se dan especiales facilidades para la utilización del modelo SPMD (Single Program
Multiple Data), un caso particular de MIMD en el que todos los procesos ejecutan el
mismo programa, aunque no necesariamente la misma instrucción al mismo tiempo. El
pasaje de mensajes es un paradigma ampliamente usado en determinadas clases de
máquinas paralelas, especialmente aquellas con memoria distribuida. Aún habiendo
bastantes variaciones, los conceptos básicos de las comunicaciones entre procesos por
medio de mensajes están bien estudiados, en los últimos 15 años se han hecho
progresos sustanciales en lo que hace a las aplicaciones de este paradigma y cada
distribuidor ha implementado su propia variante, así es como recientemente muchos
sistemas han demostrado ser eficientes y portables. De esta manera y con el tiempo es
como se ha definido la sintaxis y la semántica de un núcleo de librerías de rutinas que
hace del pasaje de mensajes una herramienta absolutamente útil para un amplio rango de
usuarios e implementable sobre variedad de computadoras.
De esta manera, el estándar incluye:
• Comunicaciones punto a punto.
• Operaciones colectivas
• Grupos de procesos
• Contextos de comunicación
• Topologías de procesos
• Interfaces para para Fortran 77 y C
• Manejo y análisis del ambiente de desarrollo
• Perfiles de interfaz
Pero no se especifica:
• Operaciones explícitas de memoria compartida
• Operaciones que requieren de un soporte del sistema mayor que el estándar
corriente, por ejemplo, manejo de interrupciones, ejecución remota o mensajes
activos.
• Herramientas de construcción de programas
• Facilidades de depuración
• Soporte explícito para cadenas (threads)
• Soporte para administración de tareas
• Funciones de Entrada/Salida (I/O)
1
DEFINICIONES
Proceso (Process)
Es una subparte paralelizable o ejecutable de un problema o algoritmo, si bien puede
estar asociada a un procesador por cuestiones de eficiencia, puede presentarse también
de manera que haya más de un proceso por procesador o CPU. Todos los procesos se
comunican con otros a través de mensajes, aún corriendo sobre el mismo procesador.
Comunicador (Communicator)
Un comunicador es un dominio de comunicación que define un grupo de procesos que les
permite comunicarse entre ellos, de manera que puedan separarse los contextos en los
que se producen las comunicaciones, es decir un mecanismo que permite al programador
definir módulos que encapsulen estructuras de comunicación. Cada proceso tiene una
identidad (rank) dentro del comunicador, que va de 0 a N-1, donde hay N procesos.
Actualmente se puede disponer de dos tipos de comunicadores , un intracomunicador
para comunicaciones dentro de un grupo o un intercomunicador para comunicaciones
entre grupos. Para programas simples solo se usan intracomunicadores pues no suele ser
necesario más que un grupo y generalmente se usa el comunicador por defecto
MPI_COMM_WORLD que engloba a todos los procesos dentro de una aplicación.
Rango o identidad (Rank)
Cada proceso tiene su propia y única identidad, identificada por un número entero que le
es asignado por el sistema cuando el proceso se inicializa. Algunas veces el rank es
llamado “process ID”. Los ranks son contiguos y empiezan desde cero. Es usado por el
programador para identificar la fuente y destino de los mensajes y con frecuencia se
utiliza con un condicional.
Ejemplo:
If (rank == 0)
/* …. */
else
/* ..... */
Grupo (Group)
Un grupo es un conjunto ordenado de N procesos. Cada proceso en un grupo sigue
asociado con un único rank entero.
Buffer de aplicación
Es el espacio de direcciones de memoria que mantiene los datos para mandar o recibir.
Buffer del sistema
Espacio de memoria del sistema para el almacenamiento de mensajes. Datos del buffer
de aplicación pueden ser copiados a/de el espacio de sistema para operaciones de
enviar/recibir pudiendo mantener una comunicación asíncrona.
COMPLETADO DE UNA TAREA
Son varias las versiones de funciones para enviar y recibir, y para describir estas
variaciones suelen verse términos como “localmente completo” o “globalmente completo”.
Entonces una rutina es localmente completa cuando ha completado su parte en la
operación. Una rutina es globalmente completa cuando todas las partes involucradas en
2
una operación han concluido, esto es que todas las rutinas deben ser localmente
completas para que la operación sea globalmente completa.
Rutinas bloqueantes
En MPI, una rutina bloqueante (enviar o recibir) retorna cuando es localmente completa.
La condición de localmente completa para una rutina de envío bloqueante es que la
locación usada para mantener el mensaje pueda ser usada otra vez o alterada sin afectar
el mensaje que ha sido enviado. Esencialmente, el proceso fuente es bloqueado, el
mínimo tiempo que es requerido para acceder al mensaje.
Rutinas no-bloqueantes
Una rutina no-bloqueante retorna inmediatamente, esto es que permite ejecutar la
próxima sentencia, tanto si está localmente completa como si no lo está, es decir que
retornará aún antes de que la locación fuente sea segura para ser modificada.
FUNCIONES BÁSICAS
MPI es un sistema complejo, por lo tanto es mucho lo que se puede decir, en su totalidad
comprende más de 130 funciones, muchas de las cuales tienen numerosos parámetros o
variantes. Nuestro objetivo es presentar conceptos esenciales de la programación con
pasaje de mensajes, con lo que la utilización de 24 funciones básicas es más que
suficiente para un amplio rango de aplicaciones y aún con sólo 6 se pueden elaborar
muchas de ellas.
Estas 6 funciones básicas son:
MPI_INIT que inicializa el ambiente MPI, necesaria en todos los programas.
int MPI_INIT(int *argc, char argv[ ]);
MPI_FINALIZE, termina la ejecución del ambiente MPI, al igual que la función anterior
debe estar presente en todos los programas MPI.
int MPI_Finalize(void)
3
MPI_COMM_RANK, determina el rango o identificación del proceso en el
comunicador.
int MPI_Comm_rank(MPI_Comm comm.,int *rank)
MPI_COMM_SIZE, determina el número de procesos corriendo asociados con
comunicador.
int MPI_Comm_size(MPI_Comm comm, int *size)
MPI_SEND , envía un mensaje a otro proceso.
int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
MPI_RECV, recibe un mensaje de otro proceso.
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag,MPI_Comm comm,
MPI_Status *status)
INTRODUCCIÓN A LOS COMUNICADORES
• Comunicador = variable de tipo MPI_Comm = Grupo_procs + Contexto
– Grupo de procesos: Subconjunto de procesos
– Contexto de comunicación: Ámbito de paso de mensajes en el que se comunican
dichos procesos.
• Argumento en funciones de transferencia.
• MPI_COMM_WORLD : Comunicador MPI por defecto que incluye todos los procesos en
ejecución
• Identificación unívoca de procesos participantes en comunicador
– Un proceso puede pertenecer a diferentes comunicadores
– Cada proceso tiene un identificador: desde 0 a size_comm-1
– Mensajes destinados a diferentes contextos de comunicación no interfieren entre sí.
4
OBTENIENDO INFORMACIÓN
Ejemplo de obtención del rango (rank) y tamaño (size)
#include <stdio.h>
#include "mpi.h"
int main(int argc, char *argv[ ] )
{ int rank, size;
MPI_Init( &argc, &argv );
MPI_Comm_size( MPI_COMM_WORLD, &size );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
printf( "Hello world from process %d of %d\n", rank, size );
MPI_Finalize( );
return 0;
}
Envío y recepción de mensajes
int MPI_Send ( void *buf, int count, MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm )
– Envía datos almacenados en buffer apuntado por buf al proc. dest con la etiqueta
tag (entero >0) dentro del comunicador comm.
– Existen implementaciones bloqueantes y no bloqueantes
int MPI_Recv ( void *buf, int count, MPI_Datatype datatype, int source, int tag,
MPI_Comm comm, MPI_Status *status )
– Recibe mensaje de proceso source dentro del comunicador comm.
– Sólo se recibe un mensaje enviado desde source con etiqueta tag pero existen
agumentos comodín: MPI_ANY_SOURCE, MPI_ANY_TAG.
– Mensaje es almacenado en posiciones continuas desde buf.
– Argumentos count y datatype: especifican la longitud del buffer.
– Objeto status : Estructura con campos MPI_SOURCE y MPI_TAG.
– Permite obtener información sobre el mensaje recibido
– Obtener tamaño del mensaje recibido: Función MPI_Get_count
5
– int MPI_Get_count( MPI_Status *status, MPI_Datatype dtype, int *count )
Ejemplo: Programa para dos procesos
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
if (rank == 0) { value=100;
MPI_Send (&value, 1, MPI_INT, 1, 0, MPI_COMM_WORLD );
else
MPI_Recv ( &value, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status );
MPI_Finalize( );
Envío y recepción de mensajes. Ejemplo
#include <stdio.h>
#include "mpi.h"
int main(int argc, char *argv[ ]);
{
int rank, value, size; MPI_Status status;
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &size );
do {
if (rank == 0)
{
scanf( "%d", &value );
MPI_Send(&value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD );}
else
{
MPI_Recv( &value, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD, &status );
if (rank < size - 1)
MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD );
}
printf( "Process %d got %d\n", rank, value );
}
while (value >= 0);
MPI_Finalize( );
return 0;
}
6
Descargar