Está en la página 1de 79

Programa de Doctorado Dpto.

Informtica
Curso: Extraccin de Conocimiento en Grandes Bases de Datos Parte 3: Limitaciones Arquitectnicas y sus soluciones

Ideas principales

Muchos datos Muchas operaciones sobre ellos

Imposible computar secuencialmente con la tecnologa actual

Solucin:

Computar en paralelo o distribuidamente

Limitiaciones en la minera de datos

La necesidad de aumentar las prestaciones limitadas de los procesadores para ejecutar programas que requieren mucha capacidad de computo conduce a la bsqueda de alternativas que permitan acelerar los programas sin aumentar las prestaciones de los procesadores.

Ejemplo: Seleccin de variables 2^# de variables

Suponemos que evaluar una solucin cuesta 0,0001 seg. Necesitaremos 4019693684133147518,698 aos para evaluar todas las soluciones si tenemos 100 variables. Para solucionar estos problemas se recurre al uso de varios procesadores o computadores trabajando en paralelo para resolver el mismo problema.

Computacin paralela

Dentro de la computacin paralela se engloban los siguientes aspectos:


Diseo de computadores paralelos

Escalables y con velocidad en las comunicaciones


Minimicen las comunicaciones y sean portables

Diseo de algoritmos paralelos eficientes

Mtodos de evaluacin de estos algoritmos Lenguajes de programacin

Flexibilidad y abstraccin frente a las distintas arquitecturas Depuracin, simulacin y visualizacin

Herramientas de programacin paralela

Programacin automtica de computadores paralelos

Compiladores que paralelicen

Clasificacin de las Arquitecturas paralelas

Segn taxonoma de Flynn se puede distinguir entre:

SISD

Limitado por la velocidad de ejecucin de las instrucciones y por la velocidad de acceso a memoria

SIMD MISD MIMD S:simple I:secuencia de instruccines M: multiple D:secuencias de datos

Programacin paralela usando MPI


Sistemas SIMD En los SIMD, una nica unidad de control proporciona una nica secuencia de instrucciones que se ejecutan sncronamente operando sobre distintos flujos de datos. Los SIMD requieren menos memoria puesto que ejecutan el mismo cdigo. Son ms apropiados para los problemas que presenten un mayor paralelismo de datos. Al ejecutar todos los procesadores el mismo cdigo de forma sncrona, habr procesadores trabajando y otros desocupados, dependiendo de los datos que estn procesando. El diseo de los programas es ms sencillo.

Programacin paralela usando MPI


Sistemas MIMD En los MIMD cada unidad de procesamiento funciona independientemente. Cada procesador puede ejecutar sus propios programas de forma asncrona. Los MIMD presentan una mayor escalabilidad puesto que se pueden agregar distintas unidades de procesamiento. Hay dos tipos: memoria compartida (multiprocesadores) y memoria distribuida (multicomputadores).

Estructuras de programas paralelos o paradigmas de programacin paralela Paralelismo de datos: los procesos operan de igual forma sobre distintos grupos de datos

Paralelismo de datos puro. Iteracin sncrona

Paralelismo funcional: cada proceso se encarga de realizar una tarea concreta

Dueo-Esclavo (master-slave) o granja de tareas (task-farming). Descomposicin recursiva. Segmentacin de cauce.

Existe la posibilidad de combinar ambos tipos de paralelismo.

Paralelismo de datos puro Se utiliza cuando el volumen de datos a procesar es de grandes dimensiones. Todos los procesos operan sobre distintas particiones de los datos.

Ej. Multiplicacin paralela de matrices

Iteracin sncrona Un mtodo iterativo secuencial se reorganiza de modo que se puedan ejecutar varias instancias en paralelo.

Ej. Resolucin de sistemas de ecuaciones lineales por iteracin

Dueo-Esclavo Existe un proceso dueo y varios esclavos. El dueo se encarga de distribuir las tareas entre los distintos esclavos para luego recoger los resultados. No suele existir comunicacin entre los esclavos. Pueden existir varios dueos con sus respectivos esclavos para aumentar la escalabilidad.

Ej. Evaluacin de individuos en algoritmos genticos

Segmentacin El problema se divide en etapas y cada etapa es asignada a un proceso. Cada proceso ejecuta una tarea tomando como entrada la salida de otro/s proceso. Divide y vencers Estrategia utilizada cuando el problema puede dividirse en subproblemas cuyas soluciones, al combinarse, proporcionan la solucin al primer problema. Puede darse el caso de recursividad cuando el subproblema es el mismo que el problema original.

Prestaciones en computadores paralelos Normalmente se utilizan las siguientes medidas:

Tiempo de ejecucin (respuesta) de una aplicacin en el sistema. Se utiliza ms en computacin de altas prestaciones. Productividad dada por el nmero de aplicaciones que se pueden procesar por unidad de tiempo. Se utiliza ms en el mbito de servidores.

Otras posibles medidas son:


Funcionalidad que se desee. Alta disponibilidad, hace referencia a la existencia de elementos redundantes para reducir la degradacin de prestaciones ante fallos. Fiabilidad, tiempo que puede funcionar sin fallos (1=100%). Tolerancia a fallos, requiere una alta disponibilidad Expansibilidad, permite expandir el sistema modularmente. Escalabilidad, es decir, que al aumentar los recursos, aumenten las prestaciones. Consumo de potencia.

Rendimiento y escalabilidad de sistemas paralelos El redimiendo no solo se refiere a la reduccin en el tiempo de ejecucin sino a los recursos (memoria, red,) que se requieren durante la ejecucin del programa. Se definen varias mtricas que, dependiendo del problema, sern ms importantes que otras.

Ganancia en velocidad (speedup) Es una forma de ver como se incrementan las prestaciones en un sistema con varios procesadores y se calcula mediante:

T Sp s ( ) T(p ) p
donde p es el nmero de procesadores, Ts el tiempo de ejecucin secuencial y Tp(p) el tiempo de ejecucin en paralelo usando p procesadores.

El tiempo de ejecucin paralelo viene dado por el tiempo de ejecucin del programa ms el tiempo que est parado y el tiempo de sobrecarga, To (overhead), que tiene como origen:

Tiempo para comunicacin/sincronizacin Tiempo para crear/terminar procesos Tiempo de ejecucin de las instrucciones aadidas en la versin paralela

Idealmente, si tenemos p procesadores, el tiempo secuencial debera ser reducido a Ts/p, obteniendo una ganancia lineal. Esto normalmente est limitado al aprovechamiento del grado de paralelismo (nmero de tareas que se pueden ejecutar) y a la reduccin debido a la sobrecarga. Es posible obtener ganancias superlineales:

Se introducen ms recursos. Dependiendo del problema, se explora ms el espacio solucin.

Eficiencia A la hora de comparar implementaciones paralelas, el tiempo de computacin puede no ser suficiente. La eficiencia es la fraccin de tiempo en la que los procesadores realizan trabajo til:

S T E) s ( p p pT () pp

En un sistema ideal S=PE=1 aunque generalmente 0<E<1. Tiende a aumentar con el tamao del problema y a disminuir cuando el nmero de procesadores aumenta.

Escalabilidad Un sistema es escalable cuando es posible mantener E constante incrementando simultneamente el tamao del problema y el nmero de procesadores.

En un sistema paralelo es la capacidad para incrementar la ganancia en proporcin al nmero de procesadores.

Diseo metdico de algoritmos paralelos

El tener una metodologa de diseo nos permitir evaluar distintas alternativas y deshacer errores de diseo. La metodologa a estudiar est denominada mediante el acrnimo PCAM:

Particionamiento Comunicacin Aglomeracin Mapeo

Concurrencia y escalabilidad Localidad y mejora de prestaciones

Particionamiento Se dividen la computacin y los datos asociados al problema en elementos lo ms pequeos posibles (descomposicin de grano fino). Lo ideal es que estos elementos eviten la replicacin de cdigo o datos, aunque no siempre es posible. Dos enfoques para el particionamiento:

Descomposicin del dominio Descomposicin funcional

Descomposicin del dominio Primero se descomponen los datos en partes aproximadamente iguales, posteriormente se divide la computacin a realizar con los datos. Cuanto menor sean las partes, ms flexibilidad tendremos en el diseo.

Descomposicin funcional

Se concentra en las operaciones sobre los datos en vez de en los datos. Gracias a esta descomposicin, el cdigo del programa puede simplificarse y clarificarse. Una vez divididas las tareas, se analizan los requerimientos de datos que tendr cada una.

Si los datos de cada tarea se solapan, ser necesario comunicar estas tareas para evitar la replicacin de datos.

Comunicacin En momento u otro de la ejecucin, las tareas debern comunicarse para transmitir datos (si se hizo una descomposicin del dominio) de entrada o datos procesados (si se hizo una descomposicin funcional). Es deseable que las operaciones de comunicacin se hagan de forma distribuida y, por tanto, puedan ser simultaneas. Dentro de la metodologa de diseo, se pueden distinguir las siguientes clases de comunicaciones:

Local Global Estructurada No estructurada Esttica Dinmica Sncrona Asncrona

Local Cuando una tarea necesita los datos de un subconjunto de tareas, bien por solapamiento de datos a procesar o por la necesidad de utilizar los datos producidos por las tareas vecinas. Global Este tipo de comunicacin ocurre cuando muchas tareas participan de modo que es difcil agruparlas en zonas localizadas. Cuando se emplea este tipo de comunicacin los problemas de centralizacin y secuencialidad pueden presentarse.

Aglomeracin Una vez descompuesto el problema, se puede optimizar su ejecucin para un computador que posea menos procesadores que tareas definidas en los pasos anteriores. En esta fase se analiza si es recomendable replicar datos y/o operaciones o si es apropiado unir tareas (aglomerarlas). Los objetivos a cumplir son:

Reducir los costes de comunicacin (incrementando la granularidad) Mantener flexibilidad para escalar y mapear posteriormente

Mapeo Tiene como objetivo minimizar el tiempo de ejecucin especificando donde se ejecutar cada tarea. Para ello:

Se mapean las tareas que ejecutan operaciones concurrentemente en procesadores distintos. Se mapean tareas que se comunican frecuentemente (p.ej. Productor/consumidor) en el mismo procesador.

Cuando tambin se planifica el orden de ejecucin de las tareas dentro de un procesador tambin se denomina planificacin.

Programacin paralela usando MPI

La tecnologa actual est desarrollando multiprocesadores con memoria compartida, aunque todava es ms fcil y barato crear un multicomputador de memoria distribuida. La forma ms comn de programar multicomputadores es usando el paradigma de paso de mensajes entre procesos. Para programar multiprocesadores, OpenMP se muestra como la gran favorita. Se pueden combinar ambas metodologas para programar multicomputadores donde cada computador sea multiprocesador.

Paso de mensajes Es el paradigma ms usado para la programacin de multicomputadores de memoria distribuida. Consiste en que los procesos se comuniquen mediante en envo y la recepcin explcita de mensajes. Dentro de este paradigma se han desarrollado varias tecnologas:

MPI (Message Passage Interface) PVM (Parallel Virtual Machine)

Principales ventajas de MPI sobre PVM MPI tiene ms de una implementacin de calidad de distribucin gratuita. Las implementaciones LAM y MPICH son las ms populares. La eleccin de las herramientas de desarrollo no est sujeta a la implementacin escogida. MPI tiene comunicaciones completamente asncronas. Los envios y las recepciones de los mensajes pueden solaparse completamente con la computacin. MPI posee grupos que son slidos, eficientes y deterministas. La pertenencia a un grupo es esttica, esto implica que no hay condiciones de carrera causadas por un proceso que independientemente acceda a un grupo o que salga, la formacin de los grupos es colectiva.

MPI hace una sincronizacin que protege otro software en ejecucin. Las comunicaciones que se realizan entre grupos son marcadas de modo que no interfieran con los parametros de otras comunicaciones que utilicen la librera. MPI es completamente portable. MPI est formalmente especificada. Todas las implementaciones tienen que cumplir las especificaciones. MPI es un estandar. Fue diseada segn un consenso abierto.

#include <stdio.h> #include <string.h> #include mpi.h main(int argc, char * argv[]){ int mi_rank; int p; int source; int dest; int tag=0; char message[100]; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &mi_rank); MPI_Comm_size(MPI_COMM_WORLD, &p); if(mi_rank!=0){ sprintf(message, Hola desde el procesador %d, mi_rank); dest=0; MPI_Send(message, strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD); } else{ for (source=1; source < p; source++){ MPI_Recv(message,100,MPI_CHAR, source, tag, MPI_COMM_WORLD, &status); printf(%s \n, message); } } MPI_Finalize();

MPI_Init Inicializa el entorno de ejecucin MPI MPI_Init(&argc,&argv); int MPI_Init(int *pargc, char ***pargv)

Parametros de entrada:
pargc - Puntero al nmero de argumentos pargv - Puntero al vector de argumentos Observaciones: En la especificacin de MPI no se utilizan los argumentos de la lnea de comandos aunque tambin se da la oportunidad de usarlos. La implementacin de LAM/MPI utiliza el comando de ejecucin mpirun para obtener los parmetros de la lnea de comandos.

MPI_Finalize Termina la ejecucin del entorno MPI MPI_Finalize(); int MPI_Finalize(void) Observaciones: Todos los procesos deben invocar esta funcin antes de terminar su ejecucin y, es recomendable que sea la ltima lnea en el cdigo (antes de un return).

MPI_Comm_rank del proceso

Determina el indentificador (rank)

MPI_Comm_rank(MPI_COMM_WORLD, &mi_rank); int MPI_Comm_rank(MPI_Comm comm, int *rank) Entrada: comm Salida: rank - rank del proceso que ha invocado la funcin dentro del comunicador comm ERRORS Cuando ocurre un error se aborta la ejecucin de este proceso.

- comunicador

MPI_Comm_size Determina el tamao del grupo asociado al comunicador MPI_Comm_size(MPI_COMM_WORLD, &p);

int MPI_Comm_size(MPI_Comm comm, int *psize)


Entrada: comm - comunicador Salida: psize - nmero de procesos dentro del grupo del comunicador. Observaciones: MPI_COMM_NULL is not considered a valid argument to this function.

if(mi_rank!=0){ sprintf(message, Hola desde el procesador %d, mi_rank); dest=0; MPI_Send(message, strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD); } else{ for (source=1; source < p; source++){ MPI_Recv(message,100,MPI_CHAR, source, tag, MPI_COMM_WORLD, &status); printf(%s \n, message); }

Si el identificador del proceso es distinto de 0, envo mi mensaje al proceso 0, si s soy el proceso 0, recibo todos los mensajes enviados por el resto de los procesos y los imprimo en pantalla
Un elemento importante a considerar es que proceso puede hacer las operaciones de entrada salida sobre la entrada y salida estndar. Depende de la configuracin del sistema.

MPI_Send -

Realiza un envo bsico

MPI_Send(message, strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD);

int MPI_Send(void *buf, int count, MPI_Datatype dtype, int dest, int tag, MPI_Comm comm) Entrada: buf count dtyp dest tag comm Observaciones: Esta funcin realiza un envio bloqueante hasta que el mensaje sea totalmente recibido por el destinatario.

direccin de inicio nmero de elementos tipo de dato de MPI rank del proceso de etiqueta comunicador

del buffer a enviar a enviar que se va a enviar destino

MPI_Recv -

Recepcin bsica

MPI_Recv(message,100,MPI_CHAR, source, tag, MPI_COMM_WORLD, &status); int MPI_Recv(void *buf, int count, MPI_Datatype dtype, int src, int tag, MPI_Comm comm, MPI_Status *stat) Entrada: count dtype src tag comm Salida: buf - direccin de memoria de comienzo del buffer stat - objeto Status, que puede ser sustituido por la constante de MPI: MPI_STATUS_IGNORE si los datos de estado no interesan.

mximo nmero de elementos a recibir tipo de dato a recibir rank del origen del mensaje etiqueta comunicador

Observaciones:
para saber exactamente el nmero de elementos recibidos hay que mirar el estado de la recepcin mediante MPI_Get_count. Dentro de las constantes definidas en MPI, tenemos: MPI_ANY_SOURCE Indica que el mensaje a recibir puede venir de cualquier destinatario MPI_ANY_TAG Indica que la etiqueta no tiene que ser igual a la del envo

MPI_Get_count -

calcula el nmero de elementos recibidos

int MPI_Get_count(MPI_Status *stat, MPI_Datatype dtype, int *count) Entrada: stat dtype Salida: count - nmero de elementos recibidos - el Status de la recepcin - el tipo de dato recibido en el buffer

Observaciones: No es posible pasarle MPI_STATUS_IGNORE.

MPI_Status
Este tipo de dato es una estructura que contiene los siguientes elementos que pueden ser utilizados por el programador: MPI_SOURCE envi el mensaje MPI_TAG MPI_ERROR Indica el rank del proceso que Indica la etiqueta del mensaje Indica el posible error

Programa para la integracin mediante la regla trapezoidal Se trata de calcular la integral definida entre dos puntos a y b para la funcin f(x). La aproximacin para calcular el area se hace mediante la divisin en trapezoides del rea, calculando sus reas respectivas y sumandolas finalmente. Suponemos que n trapecios tienen la misma base h = (b-a)/n, que estar en el intervalo [a+(i1)h,a+ih] con i=1,,n.

Definimos f(xi-1) = a + ih con i=1,,n. El rea de un trapecio es: 1/2h[f(xi-1)+ f(xi)] y el rea total es la suma de todos. Programa secuencial:
h=(b-a)/n Integral=(f(a)+f(b))/2.0 x=a For i=1,i<n,i++ x=x+h integral=integral+f(x) Integral=integral*h

Versin paralela Hacemos una descomposicin del dominio donde cada proceso calcule el rea de una zona determinada. Para que un proceso pueda saber que zona debe calcular debe saber:

Nmero de procesos p Su identificador Los lmites de integracin a,b El nmero de subintervalos n

Una vez que cada proceso ha calculado la suma de sus reas, las enva al proceso 0 que computa la suma final.

Es importante recordar que no sabemos exactamente como se implementara la E/S. Comnmente es el proceso 0 el que puede interactuar con la E/S estandar de modo que hace falta un paso previo de comunicacin que reparta la informacin. Otras posibilidades de acceso a ficheros dependen del sistema aunque MPI tambin posee un conjunto de funciones especifico para E/S.

Algoritmo paralelo:

El proceso 0 se encarga de leer los datos y repartirlos entre los procesos Cada proceso calcula el intervalo en el que debe integrar y calcula la integral de la funcin Cada proceso distinto del 0 enva el resultado al proceso 0 Proceso 0 calcula la suma de todos los resultados y muestra los resultados

/*Algoritmo paralelo para el clculo de la integral de una funcin mediante * la regla trapezoidal. * * Entradas: a, b, n * Salida: Estamacin de la integral enrte a y b de la funcin f(x) * mediante n trapezoides * * Nota: Utilizaremos f(x) como una funcin fija. */

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


void Get_data(int p, int my_rank, double* a_p, double* b_p, int* n_p); /* Funcion para calcular la integral*/ double Trap(double local_a, double local_b, int local_n, double h); /* Funcion que sera integrada */ double f(double x);

int main(int argc, char** argv) { int my_rank; /* Mi numero de proceso */ int p; /* El numero total de procesos */ double a; /* Primer elemento del intervalo */ double b; /* Ultimo elemento del intervalo */ int n; /* Numero de trapezoides */ double h; /* Longitud de la base del trapezoide */ double local_a; /* Primer elemento de mi subintervalo */ double local_b; /* Ultimo elemento de mi subintervalo */ int local_n; /* Numero de trapezoides para mi intervalo*/ double integral; /* Valor de la integral en mi intervalo */ double total; /* Integral total */ int source; int dest = 0; /* Inicializamos dest a 0 */ int tag = 0; MPI_Status status;

MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); MPI_Comm_size(MPI_COMM_WORLD, &p); /* Todos los procesos obtienen los datos */ Get_data(p, my_rank, &a, &b, &n); /* calculamos h y el numero local de trapezoides */ h = (b-a)/n; local_n = n/p; /* Calculamos el intervalo local de integracion en funcion de nuestro rango */ local_a = a + my_rank*local_n*h; local_b = local_a + local_n*h; /* Calculamos el valor de la integral en nuestro intervalo local */ integral = Trap(local_a, local_b, local_n, h);

/* Si soy 0, recibo y sumo las integrales, si no, envio mi integral local */ if (my_rank == 0) { total = integral; for (source = 1; source < p; source++) { MPI_Recv(&integral, 1, MPI_DOUBLE, source, tag, MPI_COMM_WORLD, &status); total = total + integral; } } else { MPI_Send(&integral, 1, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD); } /* Si soy 0, imprimo los resultados */ if (my_rank == 0) { printf(Utilizando n = %d trapezoides, the integral from %f to %f = %23.16e\n", n,a, b, total); } MPI_Finalize(); return 0; } /* main */

/* * Get_data 1 * Lee los datos de entrada y los envia a los otros procesos * Entradas: p, my_rank * Salidas: a_p, b_p, n_p (parametros de la integral) */ void Get_data(int p, int my_rank, double* a_p, double* b_p, int* n_p) { int i; MPI_Status status;

if (my_rank == 0) { printf(Introduzca a, b, and n\n"); scanf("%lf %lf %d", a_p, b_p, n_p);
for (i = 1; i < p; i++) { MPI_Send(a_p, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD); MPI_Send(b_p, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD); MPI_Send(n_p, 1, MPI_INT, i, 0, MPI_COMM_WORLD); } } else { MPI_Recv(a_p, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status); MPI_Recv(b_p, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status); MPI_Recv(n_p, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status); }

/* * Trap * Calcula la integral * Entradas:local_a, local_b, local_n * h * Salida: La integral entre local_a y local_b de f(x) usando local_n trapezoides de base h */ double Trap(double local_a, double local_b, int local_n, double h) { double integral; double x; int i; integral = (f(local_a) + f(local_b))/2.0; x = local_a; for (i = 1; i < local_n; i++) { x = local_a + i*h; integral = integral + f(x); } integral = integral*h; return integral; } /* Trap */

/* f * Funcion a ser integrada * Entrada: x */ double f(double x) { double return_val; return_val = x*x; return return_val; } /* f */

Comunicaciones Colectivas

Se realizan de forma sncrona, todos los procesos la realizan al mismo tiempo. Estn implementadas para simplificar y optimizar las comunicaciones entre varios procesos. Para sincronizar a los procesos sin tener que realizar ninguna operacin disponemos de la funcin MPI_Barrier(comm).

MPI_Bcast - Enva un mensaje desde el proceso con rank root a todos los dems procesos en el comunicador int MPI_Bcast(void *buff, int count, MPI_Datatype datatype, int root, MPI_Comm comm) Entradas/salida: buff - direccin de inicio del buffer count - nmero de elementos en el buffer datatype tipo de dato de los elementos del buffer root - rank del proceso que enva comm - comunicador donde se enva el mensaje Observaciones: Si hay menos de 4 procesos se itera sobre un bucle, en caso contrario, se utiliza un algoritmo basado en una estructura de rbol.

A la hora de realizar el envo de los datos ledos por el proceso 0, la funcin Get_data1 es ineficiente puesto que el proceso de ms rank es el ltimo en recibir los datos. Gracias a la funcin MPI_Bcast, esto puede ser mejorado mediante la comunicacin basada en estructura en rbol.

/* * Get_data 2 */ void Get_data2(int my_rank, double* a_p, double* b_p, int* n_p) { if (my_rank == 0) { printf(Introduzca a, b, and n\n"); scanf("%lf %lf %d", a_p, b_p, n_p); } MPI_Bcast(a_p, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(b_p, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Bcast(n_p, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); } } /* Get_data */

MPI_Reduce - Reduce una serie de valores a un nico valor en el procesador root int MPI_Reduce(void *sbuf, void* rbuf, int count, MPI_Datatype dtype, MPI_Op op, int root, MPI_Comm comm) Entradas: sbuf - direccin del buffer donde estn los datos a reducir rbuf - direccin del buffer donde se almacena el resultado count - nmero de elementos en el buffer dtype - tipo de dato op - operacin de reduccin root - rank del proceso root comm - comunicador Salidas rbuf - direccin de memoria de comienzo del buffer (root) Observaciones: Si hay menos de 4 procesos, se itera sobre un bucle normal recibiendo de los procesos, si no, se emplea una estructura en rbol donde se aplica la reduccin en cada nodo padre, distribuyendo de este modo el clculo de la operacin.

Tipos de operaciones de reduccin:


MPI_MAX maximum MPI_MIN minimum MPI_SUM sum MPI_PROD product MPI_LAND logical and MPI_BAND bit-wise and MPI_LOR logical or MPI_BOR bit-wise or MPI_LXOR logical xor MPI_BXOR bit-wise xor MPI_MAXLOC max value and location MPI_MINLOC minimum value and location

Se pueden definir operaciones especficas de reduccin

MPI_Allreduce - Reduce una serie de valores a un nico valor en todos los procesadores int MPI_AllReduce(void *sbuf, void* rbuf, int count, MPI_Datatype dtype, MPI_Op op, int root, MPI_Comm comm) Entradas: sbuf - direccin del buffer donde estn los datos a reducir count - nmero de elementos en el buffer dtype - tipo de dato op - operacin de reduccin root - rank del proceso root comm - comunicador Salidas rbuf - direccin de memoria de comienzo del buffer (root) Observaciones: Es equivalente a realizar un MPI_Reduce y luego un MPI_Bcast. Se hace una comunicacin estructurada en rbol para cada proceso.

if (my_rank == 0) { total = integral; for (source = 1; source < p; source++) { MPI_Recv(&integral, 1, MPI_DOUBLE, source, tag, MPI_COMM_WORLD, &status); total = total + integral; } } else { MPI_Send(&integral, 1, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD); }

int MPI_Reduce(void *sbuf, void* rbuf, int count, MPI_Datatype dtype, MPI_Op op, int root, MPI_Comm comm)

MPI_Reduce(&integral, &total, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

MPI_Gather - Reune valores de un grupo de procesos en un proceso MPI_Allgather - Reune valores de un grupo de procesos en todos los procesos int MPI_Gather(void *sbuf, int scount, MPI_Datatype sdtype, void *rbuf, int rcount, MPI_Datatype rdtype, int root, MPI_Comm comm) int MPI_Allgather(void *sbuf, int scount, MPI_Datatype sdtype, void *rbuf, int rcount, MPI_Datatype rdtype, int root, MPI_Comm comm) Entradas: sbuf - direccin del buffer con los datos a enviar scount numero de elementos a enviar sdtype tipo de datos rcount numero de elementos a recibir por proceso(no el total recibido) rdtype - tipo de datos root - rank del root comm - comunicador Salidas: rbuf - direccin del buffer con los datos recibidos

MPI_Scatter - Dispersa datos desde un proceso a todos los dems en el grupo int MPI_Scatter(void *sbuf, int scount, MPI_Datatype sdtype, void *rbuf, int rcount, MPI_Datatype rdtype, int root, MPI_Comm comm) Entradas: sbuf - direccin del buffer con los elementos a enviar scount nmero de elementos a enviar sdtype tipo de datos rcount nmero de elementos a recibir rdtype tipo root - del que enva comm - comunicador Salidas: rbuf - direccin del buffer de almacenamiento

MPI_Reduce_scatter Primero realiza una reduccin en un vector distribuido en los procesos y luego reparte el vector entre los procesos.

MPI_Reduce_scatter (&sendbuf,&recvbuf,recvcount,datatype, ...... op,comm) MPI_Alltoall Cada proceso en el grupo realiza una dispersin (Allscatter) de sus datos sobre el resto de procesos. MPI_Alltoall (&sendbuf,sendcount,sendtype,&recvbuf, ...... recvcnt,recvtype,comm)

Tipos de datos derivados y empaquetamiento de datos En Get_data hemos tenido que realizar 3 operaciones para enviar 3 datos, esto se puede optimizar enviando en el mismo mensaje los datos. Problema: los datos a enviar no estn en posiciones de memoria continuas desde la direccin de comienzo del buffer. Solucin: Definir tipos de datos derivados o empaquetar datos.

MPI permite la definicin de estructuras de datos complejas (tipos de datos derivados) a partir de los tipos de datos simples que proporciona. De este modo se pueden enviar mensajes que contengan varios tipos de datos. Gracias a los tipos derivados podremos enviar mensajes cuyo contenido no es contiguo en memoria. Un tipo de dato derivado consiste en pares (tipo de dato, desplazamiento) donde tipo de dato es un dato del tipo MPI_xxx y desplazamiento es el nmero de bytes que hay entre la posicin de memoria del inicio del buffer y el comienzo del dato. MPI proporciona varios modos para la creacin de tipos de datos derivados: contiguos, vectores, indexados y estructurados.

Creacin del tipo estruturado (MPI_Type_struct):

MPI_Type_struct(n_elem,block_lengths,displacements, typelist, tipo_nuevo); n_elem: nmero de bloques en la estructura (int) block_lengths: nmero de elementos en cada bloque (int []) displacements: desplazamiento de cada bloque desde el primer elemento (MPI_Aint []) typelist: tipos de dato MPI de los bloques (MPI_Datatype []) tipo_nuevo: nuevo tipo de dato (MPI_Datatype *) (por ref.) MPI_Type_commit(MPI_Datatype * tipo_nuevo) confirma su uso para la comunicacin (podra usarse nicamente para formar otros tipos de datos ms complejos). MPI_Address(void * elemento, MPI_Aint * direc) almacena en direc la direccin de memoria del elemento

El resto de tipos derivados hacen referencia a conjuntos de elementos del mismo tipo pero distribuidos de una forma no continua en memoria. Es especialmente til a la hora de realizar operaciones con secciones de matrices. A la hora de hacer comunicaciones entre pares de procesos, se pueden enviar tipos de datos derivados sin necesidad de haber creado el tipo en el proceso receptor, bastara con indicar el nmero de elementos del tipo a recibir (type matching)

Una vez usado un tipo de dato derivado puede ser necesario liberar memoria, para ello utilizaremos: MPI_Type_free(MPI_Datatype * datatype)

Podemos crear explcitamente un buffer con los datos que queremos enviar tal que estn almacenados en zonas de memoria contiguas. Mediante la funcin MPI_Pack iremos concatenando los elementos de distintos tipos:

MPI_Pack(void * elem,int n_elem, MPI_Datatype tipo, void * buffer,int buffer_size,int * posicion, MPI_Comm comunicador)

Una vez enviado el buffer, los datos se recuperan en el mismo orden en el que se introdujeron mediante:

MPI_Unpack(void * buffer,int size, int * posicion, void * elem, int n_elem,MPI_Datatype tipo, MPI_Comm comunicador)

Grupos y Comunicadores: Un grupo es un conjunto de procesos. Cada proceso dentro de un grupo tiene asociado un nico identificador dentro de ese grupo. Los identificadores empiezan con el nmero 0 hasta N-1 donde N es el nmero de procesos que hay en el grupo. Los grupos se representan como objetos ocultos al programador que accede a ellos mediante manejadores (handles). Un grupo est siempre asociado con un comunicador.

Cada mensaje debe especificar un comunicador. La idea bsica es que un comunicador es como una etiqueta extra que es asignada a un mensaje, hacindolo nico. Al igual que con los grupos, los comunicadores estn ocultos al programador. Desde la perspectiva del programador, no hay diferencia entre un grupo y un comunicador, si bien cabe la posibilidad de que se hayan creado dos comunicadores distintos utilizando el mismo grupo.

Los motivos para usar comunicadores y grupos son:


Permitir la organizacin de los procesos. Permitir las comunicaciones colectivas en subconjuntos de procesos. Proporcionan la base para la definicin de topologas virtuales. Proporcionan comunicaciones seguras.

Los grupos y los comunicadores pueden ser creados y destruidos dinmicamente durante la ejecucin del programa. Cada proceso puede pertenecer a varios grupos y comunicadores teniendo distintos identificadores asignados. El procedimiento ms comn a la hora de usar grupos y comunicadores es:

Obtener el grupo asociado al comunicador global MPI_COMM_WORLD utilizando la funcin MPI_Comm_group. Crear un nuevo grupo utilizando los identificadores del grupo original usando MPI_Group_incl Crear un nuevo comunicador asociado al grupo nuevo usando MPI_Comm_create Obtener el nuevo rank usando MPI_Comm_rank Realizar las comunicaciones Liberar recursos usando MPI_Comm_free y MPI_Group_free

Cuando se crea un comunicador se realiza una sincronizacin al igual que con las comunicaciones colectivas. Podemos crear varios comunicadores simultneamente mediante MPI_Comm_split, utilizando un identificador de grupo y otro de rango.

/* Obtenemos el manejador del grupo global */ MPI_Comm_group(MPI_COMM_WORLD, &orig_group); /* Dividimos las tareas en dos conjuntos */ if (rank < NPROCS/2) { MPI_Group_incl(orig_group, NPROCS/2, ranks1, &new_group); } else { MPI_Group_incl(orig_group, NPROCS/2, ranks2, &new_group); } /* Creamos los comunicadores y realizamos las comunicaciones */ MPI_Comm_create(MPI_COMM_WORLD, new_group, &new_comm); MPI_Allreduce(&sendbuf, &recvbuf, 1, MPI_INT, MPI_SUM, new_comm); MPI_Group_rank (new_group, &new_rank); printf("rank= %d newrank= %d recvbuf= %d\n",rank,new_rank,recvbuf);

Topologas virtuales Son mecanismos para asociar diferentes modos de direccionamiento a la hora de realizar comunicaciones dentro de un grupo. Hay dos grupos: cartesianas (grid) y grafos. Las topologas son virtuales, es decir, la ordenacin de los procesos no tiene nada que ver con la arquitectura real sobre la que se ejecuta el programa. Son tiles por:

Su utilidad en aplicaciones que siguen ciertos patrones de comunicacin. Pueden mejorar las prestaciones si es posible combinar la topologa virtual con la topologa real de la plataforma paralela.

MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, reorder, &cartcomm); MPI_Comm_rank(cartcomm, &rank);

MPI_Cart_coords(cartcomm, rank, 2, coords);


MPI_Cart_shift(cartcomm, 0, 1, &nbrs[UP], &nbrs[DOWN]);

Comunicaciones entre pares de procesos:

Bloqueantes

MPI_Send, MPI_Recv, MPI_Sendrecv, MPI_Wait, MPI_Waitall MPI_Isend, MPI_Irecv, MPI_Test, MPI_Testall, MPI_Iprobe

No bloqueantes

También podría gustarte