Paralelismo en la ordenación por mezcla

Documentos relacionados
Algoritmos en Árbol y Grafo Computación Pipeline

Paralelización de problemas de recorrido de árboles Trabajadores replicados y esquema maestro esclavo

Divide y Vencerás Programación Dinámica

Relación de Ejercicios. Programación Paralela 4º de Grado en Ingeniería Informática.

Algoritmos y Estructuras de Datos Curso 06/07. Ejercicios

UNIDAD II Metodología de programación paralela. Lic. Jesús Germán Andrés PAUTSCH - FCEQyN - UNaM

Programa de teoría. Algoritmos y Estructuras de Datos II. 2. Divide y vencerás. 1. Análisis de algoritmos

Tema 2. Divide y vencerás.

3. DISEÑO DE ALGORITMOS PARALELOS Y DISTRIBUIDOS

Diseño de algoritmos paralelos

Tema 9. Recursividad

Esquema de Dividir y Vencer

Parte de Algoritmos de la asignatura de Programación Master de Bioinformática. Divide y vencerás

Análisis de algoritmos

PARTE II: ALGORÍTMICA

Paralelismo Relajado Paralelismo Síncrono

Análisis y Diseño de Algoritmos

Esquemas algorítmicos paralelos - Particionado y Paralelismo de Datos

Diseño de Algoritmos Paralelos Prof. Gilberto Díaz

Programa de teoría. Algoritmos y Estructuras de Datos II. 3. Algoritmos voraces. 1. Análisis de algoritmos 2. Divide y vencerás

Modelado y autooptimización en esquemas paralelos de backtracking

TEMA 1. INTRODUCCIÓN A LA PROGR. DISTRIBUIDA Y PARALELA

1. Planteamiento general

Problema de las N Reinas. Resolución paralela

Análisis y Complejidad de Algoritmos. Arboles Binarios. Arturo Díaz Pérez

Análisis y Diseño de Algoritmos (AyDA) Isabel Besembel Carrera

Algoritmos sobre Listas

PROGRAMACIÓN PARALELA. Modelos de programación paralela Paradigmas de programación paralela

5. ESTRUCTURAS DE REPETICIÓN

Conceptos. Generales ALGORITMOS

Granularidad y latencia

Lenguaje de Diseño. Primera Parte. Resolución de Problemas y Algoritmos. Primer Cuatrimestre Ing. En Informática e Ing.

ORGANIZACIÓN DE COMPUTADORAS DRA. LETICIA FLORES PULIDO

168 Capítulo 4. Representación de conjuntos mediante árboles

Universidad de Valladolid. Departamento de informática. Campus de Segovia. Estructura de datos Tema 4: Ordenación. Prof. Montserrat Serrano Montero

Divide-y-vencerás, backtracking y programación dinámica

Métodos de Ordenamiento. Unidad VI: Estructura de datos

Esquemas algorítmicos paralelos - Particionado y Paralelismo de Datos

Archivos Indice. Indexación y. Asociación. Conceptos Básicos Indices Ordenados Arboles. Asociación. Docente: Albert A.

PARADIGMA y LENGUAJES DE PROGRAMACIÓN

Definición recursiva de los árboles

Recursión como herramienta en resolución de problemas computacionales

Tema 2 Fundamentos de Complejidad Algorítmica

Un árbol binario T se define como un conjunto finito de elementos, llamados nodos, de forma que:

José Matías Cutillas Lozano PROGRAMACIÓN PARALELA Y COMPUTACIÓN DE ALTAS PRESTACIONES

Tema 9. Algoritmos sobre listas. Programación Programación - Tema 9: Algoritmos sobre listas

Lenguaje de Diseño. Primera Parte. Segundo Cuatrimestre 2017

Unidad I: Introducción a las estructuras de datos

Algorítmica y Lenguajes de Programación. Eficiencia y notación asintótica (i)

EVALUACIÓN DE MÉTODOS DE ORDENACIÓN: QuickSort vs. QuickSort con pseudomediana

Tema 2 Conceptos básicos de programación. Fundamentos de Informática

Lógica de programación

Análisis de algoritmos

Capítulo 6: EVALUACIÓN Y COMPARACIÓN DE MÉTODOS

Procesamiento Paralelo

Sistemas Operativos Distribuidos

RECORDAR TIPOS DE DATOS

5 Métodos de Ordenamiento. 5.1 Métodos de Ordenamiento Internos Burbuja Quicksort Heapsort Inserción Simple 5.1.

Programación Concurrente y Paralela. Unidad 1 Introducción

Tema 07: Backtraking. M. en C. Edgardo Adrián Franco Martínez edgardoadrianfrancom

Tema 2. Fundamentos Teóricos de la. programación dinámica Teorema de Optimalidad de Mitten

1. Introducción al análisis de algoritmos

1. 1. Introducción al concepto de algoritmia

TEMA 1: Algoritmos y programas

CIENCIA DE LA COMPUTACION

Taller de Programación Paralela

COMPARACIÓN DE MODELOS DE SINCRONIZACIÓN EN PROGRAMACIÓN PARALELA SOBRE CLUSTER DE MULTICORES

COMPUTACIÓN DE ALTA PERFORMANCE 2013

Resolución de problemas en paralelo

Estructuras de Datos y Algoritmos

Paradigma de paso de mensajes

Lógica de programación 1

Análisis y Diseño de Algoritmos

INSTITUTO NACIONAL SUPERIOR DEL PROFESORADO TÉCNICO - TÉCNICO SUPERIOR EN INFORMÁTICA APLICADA - PROGRAMACIÓN I

Paralelismo. MPI Paso de mensajes. Francisco García Sánchez Departamento de Informática y Sistemas

El Pseudo-código de PsInt

Divide & Conquer. Herman Schinca. Clase de Junio de 2011

Métodos de ordenamiento y búsqueda en vectores

FICHEROS Y BASES DE DATOS (E44) 3º INGENIERÍA EN INFORMÁTICA. Tema 3. Estructuras de Almacenamiento. Básicas. Definición y Manejo.

Universidad Autónoma del Estado de México Facultad de Medicina

Programación II Recursividad Dr. Mario Rossainz López

Estructura de datos y de la información Boletín de problemas - Tema 10

Capítulo 3. Clasificación en Memoria Secundaria

Introducción Supongamos un subconjunto de n elementos X = {e 1,,e n de un conjunto referencial Y, X Y. Dentro de Y se define una relación de orden tot

Estructura de Datos Árboles Árboles 2-3

Teoría Tema 4 Ampliación - Infinitésimos

Computación de Altas Prestaciones Sistemas computacionales

1. Algoritmo, programa y pseudocódigo. Introducción al estudio de algoritmos. Ejemplos

Estructura de Datos. Temario Unidad VI. Árboles Árboles Binarios

ANÁLISIS Y DISEÑO DE ALGORITMOS

Algoritmo. Programa. Lenguaje algorítmico

Lógica de programación

Transcripción:

Paralelismo en la ordenación por mezcla

Índice MergeSort secuencial. MergeSort paralelo : descomposición en tareas. Descomposición funcional. Descomposición recursiva. Descomposición de dominio. Grafo de dependencias y asignación de tareas. Pseudoalgoritmo. Pensando en la implementación.

MergeSort secuencial Entrada : una secuencia de n números desordenada. Salida : secuencia de n números ordenada. La ordenación por mergesort, se basa en obtener un vector ordenado de n números a partir de uno desordenado; ello lo consigue aplicando el esquema algorítmico divide y vencerás, mediante el cual descompone un vector de tamaño n en dos subvectores de tamaño n/ 2 sucesivamente, hasta que el tamaño del vector obtenido sea lo suficientemente pequeño como para considerar que está ordenado (tamaño 1); una vez obtenido este vector mínimo, recuperaremos el vector original mezclando los resultados, los cuales se volverán a mezclar recursivamente hasta obtener un vector de tamaño n ordenado.

MergeSort paralelo : descomposición en tareas Para poder resolver de forma paralela el problema de la ordenación por mezcla es necesario descomponer de alguna forma el algoritmo en una serie de subtareas. A continuación presento una serie de posibles descomposiciones acompañadas con un pequeño estudio y conclusiones: Descomposición funcional : la cual se realizará mediante la versión pipeline. Descomposición recursiva : utilizando el esquema algorítmico del mergesort secuencial. Descomposición de dominio, centrada en los datos de entrada : aprovecharemos la independencia de los datos de entrada para dividirlos directamente entre los procesos.

Descomposición funcional Leer Ordenar Mezclar La idea de esta descomposición, es descomponer el algoritmo en una serie de módulos, de modo que la ejecución de los mismos se solape de un paso al siguiente. Vamos a ver cuánto tardaría esta descomposición en resolver un problema de tamaño n; para simplificar los cálculos consideraremos el tiempo en el peor caso: T (Leer ) = n, T (Ordenar ) = n/b * log ( n/b ), T(Mezclar ) = k * n/b + n/b Donde b = número de bloques y k = paso del algoritmo. El siguiente paso es inferir el coste del algoritmo a partir de observar el comportamiento en unos pocos pasos. Supongamos que el número de bloques b es igual a 3, el funcionamiento sería el siguiente: T (Mezcla 1 ) = T (leer) + T (Ordenar, b) + T(Mezclar,1,b) = n/b + n/b * log (n/b) + n/b T (Mezcla 2 ) = T (leer) + T (Ordenar, b) + T(Mezclar,2,b) = n/b + n/b * log (n/b) + 2*n/b T (Mezcla 2 ) = T (leer) + T (Ordenar, b) + T(Mezclar,3,b) = n/b + n/b * log (n/b) + 3*n/b Dado que la ejecución de los módulos se solapa de un paso al siguiente, sólo es necesario quedarnos con los pasos más costosos, quedando la siguiente solución: 4n/b + 2 n/b * log (n/b) + (n/b log n/b ó 2 n/b ) -- En función de si log n/b es mayor o no que 2. Supongamos por simplicidad que log n/b es siempre mayor que el número de paso, en ese caso, para un algoritmo de b pasos tardaríamos: (b+1) * n/b + b * n/b log ( n/b) Que si nos quedamos con el mayor término sería t(b) = n * log ( n / b )

Consideraciones sobre la anterior descomposición La versión anterior es bastante mala, como se puede observar en el cálculo del speed-up cuando n tiende a infinito: Lim Speedup = n* log n / ( n * log (n/b) ) = log n / ( log n log b ) = 1 Haciendo aproximaciones podemos observar cómo, en el mejor de los casos, no tenemos ninguna mejora significativa respecto del algoritmo secuencial, y eso que no hemos considerado el coste de las comunicaciones... Esta mala eficiencia del algoritmo se debe a los siguientes factores: No aparece por ningún lado el factor número de procesadores (p), el cual se supone que tiene que ser 3 (un mayor número no mejoraría el tiempo de ejecución). No está balanceado el tiempo de cada operación, claramente el tiempo que el algoritmo tardará en leer va a ser mucho menor que el tiempo que tarda en ordenar e incluso el tiempo que tarda en mezclar. Granularidad muy elevada : los bloques en que hemos descompuesto el algoritmo, siguen siendo muy grandes, con lo que no aprovecharemos las ventajas de la computación paralela, aunque al menos, el coste de las comunicaciones que no hemos considerado, no será muy elevado.

Descomposición recursiva : :... Siguiendo la lógica de la versión secuencial de la ordenación por mezcla, podemos idear una versión palalela donde cada subtarea puede ser ejecutada por un procesador. El nodo raíz leerá los datos y los repartirá equitativamente entre sus dos hijos, los cuales repartirán sus datos entre sus respectivos dos hijos... hasta llegar a un tamaño de los datos a partir del cual no nos interese descomponer más; llegados a este punto, los nodos receptores de la fracción mínima de datos, los ordenarán y los enviarán a uno de sus vecinos (determinado por el paso de la mezcla) para que procedan a mezclar los datos ordenados. El tamaño mínimo de datos determina la granularidad de la descomposición, la cual va a depender directamente del número de procesadores de los que dispongamos; tendremos por tanto, un tamaño mínimo de los datos de n/p antes de empezar a ordenar. Para el estudio de la eficiencia de esta versión sí que vamos a tener en cuenta las comunicaciones, así que distinguimos los siguientes tipos de tiempo: T(Leer) = n T(Dividir) = constante T(Ordenar) = ( n / p ) * log ( n / p ) T(Envío ) = variable y dependiente de n/p T(Mezcla ) = variable y dependiente de n/p

Estudio de la descomposición recursiva Al igual que antes, vamos a partir de un problema, sencillo y a partir del mismo inferiremos el coste para problemas más complejos. Supongamos una lista de tamaño n y un número de procesadores = 4. El límite de datos a descomponer es por tanto n/4, lo que implica que solo descompondremos los datos 2 veces (logaritmo en base 2 de p ). T(Raíz) = T ( Leer ) + T (Dividir) + T (Enviar,n/2) = n + (despreciable) + 2* (ts + tw * n/2 ) (dos envíos de la mitad de la lista de valores) = n + 2 ts + 2 tw * n/2 = n + 2ts + tw * n T(Repartir nivel 1 ) = T(Dividir) + T(Enviar, n/4 ) = 2 * ( ts + tw * n/4) (Los nodos hermanos de un nivel son capaces de ejecutar sus tareas en paralelo, de modo que el tiempo de las mismas en cada uno de ellos se solapa y podemos simplificar el cálculo a las tareas llevadas a cabo por solo uno de ellos). T(Repartir nivel 2) = T(Ordenar) = (n/p) * log (n/p) (Igual que antes, esta tarea también se solapa en los hermanos). T(Mezcla paso 1) = T (Enviar, n/4) + T (Mezclar, n / 4 ) = ts + tw * n/4 + 2 * n/4 T(Mezcla paso 2) = T(Enviar, n/2) + T(Mezclar, n/2 ) = ts + tw * n/2 + 2 * n/2 Y finalmente tendremos nuestro vector ordenado. Podemos generalizar el tiempo de la siguiente forma: T(n,p ) = T Leer T Raíz T hijo nivel i T Mezcla paso i T Ordenar Lo cual, tras eliminar expresiones que no dependen de n y haciendo unos pocos redondeos que no afectarán prácticamente nada para tamaños de n muy grandes, nos queda en : 2 n 1/2 2/log p tw n 1/2 2/log p n/ p log n/ p Donde se puede observar que el término de mayor orden es n/p * log (n/p).

Consideraciones sobre la descomposición recursiva Este método parece bueno, vamos a observar el speed-up cuando n tiene a infinito para confirmarlo. Para este cálculo solo vamos a considerar del tiempo obtenido anteriormente, el factor de mayor orden. n n lim t n /t n/ p =lim n log n / n / p log n / p = p El resultado es p, lo cual significa que con tamaños de n MUY grandes, conseguiremos un speed-up de p (número de procesadores), lo cual es bastante prometedor. A grandes rasgos, la descomposición es bastante buena, sin embargo, presenta algunos problemas que deben ser comentados: Este algoritmo realiza una gran cantidad de comunicaciones y en el estudio hemos asumido que todos los mensajes se envían correctamente a la primera. Qué hace el procesador que envía sus datos ordenados al que realiza la mezcla? En principio, no hace nada, y es trabajo que estamos desperdiciando.

Descomposición de dominio... El esquema es bastante parecido a la descomposición recursiva, únicamente cambiamos el procedimiento de división de los datos, siendo los procedimientos de mezcla y ordenación los mismos que en el anterior esquema. El árbol generado en este caso tiene solamente profundidad 1 y el número de hijos generados, en vez de 2, es n/p; la idea de esta nueva versión es que, si conocemos de antemano el número de datos, el número de procesadores, y, por tanto, el número de divisiones que tenemos que hacer.. por qué no las hacemos directamente? Aunque esta idea puede parecer buena, en realidad, a priori es peor que la descomposición recursiva, debido a que aunque reduzcamos ligeramente el número de comunicaciones necesarias, ahora no se solaparán durante la división de los datos. Así pues, como sabemos que el coste de las comunicaciones va a incrementar, vamos a calcularlo para ver si nos tiene que preocupar: T (Envíar datos ) = p * (ts +tw * n/p) = p * ts + tw * n El término de mayor orden es de orden n,el cual es menor que en la ordenación,que es n/p*log(n/p) Por tanto, para tamaños de n muy grandes, el coste será aproximadamente el mismo. Este tipo de descomposición hereda los problemas de la descomposición recursiva, pero hay 2 puntos positivos: Dado que es el servidor el que centraliza el envío de los datos, podría existir una función que haga mas eficiente el envío de los mismos. El coste de programación de esta solución es menor.

Grafo de dependencias y asignación de tareas La solución que voy a implementar es la basada en al descomposición del dominio, a continuación presento el grafo de flujo de un mergesort para p=4 para mostrar la asignación de tareas que voy a utilizar: Leer Coste = n Procesador 1 Ordenar Coste = n/p * log (n/p) Dividir Coste = cte Coste = ts + tw * (n/p) Procesador 2 Coste = ts + tw* (n/p) Procesador 3 Camino crítico Ordenar Ordenar Ordenar Mezclar Coste=2*n/p Coste = ts + tw * ( 2 n/p) Mezclar Procesador 4 Mezclar Coste = 2 * 2 * n/p L = n + cte + ts + tw *(n/p) + + (n/p)*log(n/p) + ts + tw * (n/p)+2*n/p + + ts + tw * (2*n/p) + 2*2*n/p CosteTotal = n+cte+p*(ts+tw(n/p))+ +p*n/p log(n/p) + + 2*ts+ tw*(n/p)+2*2*2n/p+ +ts + tw*(2*n/p) +2*2*n/p M = (despreciando constantes y coste de las comunicaciones ) = = log (n/4) / ( ¼ * log ( n/4)) = 4 Lo cual significa que para n muy grande y comunicaciones despreciables, tendremos aproximadamente 4 tareas ejecutándose en paralelo.

Pseudoalgoritmo Tras las consideraciones anteriores, presento una versión muy general del algoritmo que resolverá el problema de ordenación por mezcla paralelo con un número de procesadores potencia de 2: Si ( procesador == 1 ) vectorelementos = Leer Datos miparte = trocear(vectorelementos,0,vectorelementos.tamaño/numprocesadores) Para i = 2 hasta numprocesadores Hacer posini = (i 1 ) * vectorelementos.tamaño/numprocesadores; posfin = i * vectorelementos.tamaño/numprocesadores; enviar(trocear(vectorelementos,posini,posfin),i) FinPara Sino recibir (miparte,1); FinSi ordenar(miparte); numpaso = 2 Mientras ( numpaso <= numprocesadores ) Hacer Si ( procesador % numpaso == 0) recibir(partedeotro, ((procesador-numpaso/2)%numprocesadores)) miparte=mezclar(miparte,partedeotro) Sino Si (procesador % numpaso == numpaso/2) enviar(miparte, (procesador+numpaso/2) % numprocesadores) FinSi numpaso = numpaso*2 FinMientras Si ( procesador == numpaso) devolver miparte FinSi

Pensando en la implementación El último paso de la práctica es implementarla, con las limitaciones que ello conlleva. La implementación se realizará haciendo uso del modelo de paso de mensajes (MPI) y el modelo de memoria compartida (OpenMP). Consideraciones con MPI: Las funciones de comunicación MPI_Send y MPI_Receive son bloqueantes, así que en este modelo a priori no tenemos ningún problema de sincronización. Para hacer mas eficiente el reparto de los datos de la raíz a todos los subprocesos, se puede utilizar la función MPI_Scatter. Consideraciones con OpenMP: Una vez leídos los datos,los procesadores pueden trabajar independientemente hasta el procedimiento de mezcla; necesitaremos colocar barreras justo antes del comienzo de esta etapa para asegurarnos de que los vectores que mezclamos están ordenados. Un proceso no utilizará datos de la porción asignada a otro proceso, hasta el proceso de mezcla; afortunadamente, gracias a la barrera anterior, evitaremos además problemas relacionados con lectura/escritura de un mismo bloque de memoria por parte de varios procesos. Por este motivo, y considerando la anterior barrera, ya que por el diseño del algoritmo no presentaremos conflictos de memoria, no será necesario hacer ninguna copia del vector principal de elementos y todos los procesos podrán leer y escribir en él sin problemas.