Universidad Politécnica de Madrid
Facultad de Informática
Proyecto fin de carrera
Implementación de un algoritmo
evolutivo basado en MOS
Autor
: Manuel Zaforas
Tutores
: José María Peña Sánchez
Antonio LaTorre de la Fuente
Manuel Zaforas
Madrid, Julio 2008
Tutores:
José María Peña Sánchez (jmpena@fi.upm.es)
Antonio LaTorre de la Fuente (atorre@fi.upm.es)
Cita: "La selección natural, es una fuerza siempre dispuesta a la acción y tan inconmen-surablemente superior a los débiles esfuerzos del hombre como las obras de la Naturaleza lo son a las del Arte."
Charles Darwin.
El origen de las especies, capítulo III.
Agradecimientos
Este proyecto es el colofón a una etapa de mi vida marcada por muchas personas y experiencias
positivas, que me han llevado a donde ahora estoy y a formarme como ingeniero y como persona.
En primer lugar quiero agradecer a mis padres, ya que en gran medida todo lo que soy y lo bueno
que tengo se lo debo a ellos, que me han apoyado siempre incondicionalmente en todo lo que he hecho.
A mi hermana Carlota por toda la paciencia que tiene conmigo y por haber sido siempre mi amiga.
Gracias sobre todo a Nuria, porque desde que te conocí eres el faro que ilumina mi vida y que me
hace feliz al margen de todo lo demás.
Gracias a todos los compañeros con los que he compartido estudios, prácticas y sufrimientos durante
la carrera, especialmente a Javi, Trevi, Jaime, Alvarito, Rafa, Marí Paz, Jose, Marco, Mariajo, Laura,
Jess, Raquel, Luis, Miguel, Soto, Juanito y todos los que me dejo pero que hemos luchado juntos en este
campo de batalla llamado FI, y de vez en cuando hemos hecho una parada para relajarnos y visitar a los
patos tomando una paella. Gracias también a toda la gente de Delegación, Coleópteros, Alfa y Omega,
Histrión y todos los follones en los que he estado metido en la FI.
Gracias a toda la gente del Laboratorio de Sistemas Operativos del DATSI por todo lo que he
apren-dido con ellos y por lo bien que nos lo hemos pasado en esas largas sobremesas de pueblos y caminos.
Gracias a Fernando Pérez por darme la oportunidad de entrar en el laboratorio y por todo lo que he
aprendido de él. Gracias a los doctorandos: Chuso, Juan, Santi y Alberto por todo lo que saben y la
fa-cilidad con que lo transmiten, estando siempre dispuestos a echar una mano. Gracias también a Alberto,
Germán, Luis y el resto de becarios que compartimos el peso del yugo de nuestras becas rodeados de
Gracias especialmente a los AR: Rojo, Santi, Nacho, Zuazo, Diego, Ato, P. Lorenzo, P. José Manuel,
Chunia y Javi Lorenzo, por esas largas, divertidas e improductivas reuniones en el Rufos o en torno a
unas palomitas quemadas. Gracias también a todos los que siempre están ahí para escaparse al ático
cuando es necesario o para desahogarnos dando patadas a un balón, especialmente a Edu, Ian, Líder,
Pablo, Alex, Sonso (que eres como uno más), Merino, Manza, Chuso, Héctor, Paco, Braci, Luquitas y
todos los demás. Gracias sobre todo al P. Carlos por haber sido un segundo padre para mí.
Gracias a toda la gente del equipo de basket, especialmente a Alfre por todas las cosas que hemos
vivido juntos.
Y por último gracias a Chema y Toni, por toda la paciencia que han tenido conmigo y por todo lo
que he aprendido de ellos, porque sin ellos este proyecto no sería una realidad.
Gracias también a tantos que me dejo en el tintero y en general a todos porque sin duda no habría
Índice
Agradecimientos . . . I
Índice . . . III
Índice de figuras . . . IX
Índice de tablas . . . XIII
Acrónimos y abreviaturas . . . XVII
PARTEI INTRODUCCIÓN Y OBJETIVOS
1. Introducción y objetivos . . . 3
1.1. Introducción . . . 3
1.2. Objetivos . . . 4
1.3. Estructura de la memoria . . . 6
PARTEII ESTADO DE LA CUESTIÓN 2. Computación de altas prestaciones con arquitecturas paralelas . . . 9
2.1. Introducción . . . 9
2.2.1. Multiprocesadores . . . 12
2.2.2. Multicomputadores . . . 13
2.2.2.1. Clúster . . . 14
2.2.2.2. Magerit . . . 14
2.3. Topologías y redes de interconexión . . . 15
2.3.1. Tecnologías de interconexión . . . 16
2.4. Rendimiento en computación paralela . . . 17
2.4.1. Factor de aceleración: Speedup . . . 17
2.4.2. Ley de Amdahl . . . 18
2.4.3. Ley de Gustafson . . . 19
2.5. Proceso de paralelización: Principios de diseño . . . 20
2.5.1. Descomposición . . . 21
2.5.2. Asignación . . . 23
2.5.3. Orquestación . . . 23
2.5.3.1. Comunicación unicast vs. broadcast . . . 23
2.5.3.2. Comunicación estructurada vs. no estructurada . . . 24
2.5.3.3. Comunicación estática vs. dinámica . . . 25
2.5.3.4. Comunicación síncrona vs. asíncrona . . . 25
2.5.4. Despliegue . . . 25
2.6. Herramientas de programación paralela . . . 26
2.6.1. HPF . . . 26
2.6.2. MPI . . . 27
2.6.2.1. Funcionamiento de MPI . . . 28
2.6.3. OMP . . . 28
3. Algoritmos evolutivos . . . 31
3.1. Introducción . . . 31
3.2. Algoritmos genéticos . . . 33
Índice
3.2.1.1. Método de la ruleta . . . 36
3.2.1.2. Método de la ruleta extendido con rangos . . . 37
3.2.1.3. Método de selección por torneo . . . 38
3.2.2. Operador de cruce . . . 39
3.2.2.1. Cruce de un punto . . . 39
3.2.2.2. Cruce en dos puntos . . . 39
3.2.2.3. Cruce uniforme . . . 40
3.2.2.4. Cruce aritmético . . . 40
3.2.2.5. Cruce cíclico . . . 40
3.2.2.6. Cruce ordenado . . . 41
3.2.3. Operador de mutación . . . 41
3.2.3.1. Mutación por inversión . . . 41
3.2.3.2. Mutación por intercambio repetido . . . 42
3.2.3.3. Mutación uniforme . . . 42
3.3. Algoritmos EDA . . . 42
3.3.1. Heurísticas para el aprendizaje . . . 44
3.3.1.1. Modelo sin dependencias . . . 45
3.3.1.2. Modelos con dependencias bivariantes . . . 45
3.3.1.3. Modelos con múltiples dependencias . . . 45
3.4. Algoritmos evolutivos paralelos . . . 46
3.4.1. Modelos con población global . . . 46
3.4.1.1. Variante síncrona con maestro-esclavos . . . 46
3.4.1.2. Variante semisíncrona con maestro-esclavos . . . 47
3.4.1.3. Variante asíncrona concurrente . . . 47
3.4.2. Modelos de islas . . . 47
3.4.2.1. Topologías de interconexión . . . 48
PARTEIII DISEÑO Y DESARROLLO DE LA SOLUCIÓN
4. Multiple offspring sampling genetic algorithm en GAEDALib . . . 53
4.1. Introducción . . . 53
4.2. Diseño y arquitectura de MOS . . . 54
4.2.1. Aproximación MOS central . . . 54
4.2.2. Aproximación MOS autonomic . . . 57
4.2.3. Relación de MOS y GAEDALib . . . 58
4.3. Clase GAMOSGA . . . 59
4.4. Técnicas MOS . . . 61
4.4.1. Clase GAMOSTechnique . . . 63
4.4.2. Técnicas MOS GA . . . 65
4.4.3. Técnicas MOS EDA . . . 65
4.4.4. Conjunto de técnicas . . . 65
4.5. Genomas MOS . . . 66
4.5.1. Clase GAMOSGenome . . . 68
4.6. Conversor MOS . . . 69
4.7. Serializador MOS . . . 70
PARTEIV ANÁLISIS DE RESULTADOS 5. Análisis de resultados . . . 75
5.1. Introducción . . . 75
5.2. Resultados con funciones matemáticas . . . 78
5.2.1. Problema MaxBit . . . 78
5.2.1.1. Resultados con Multiple Offspring Sampling (MOS) . . . 79
5.2.2. Problema Royal Road . . . 83
5.2.2.1. Resultados con MOS . . . 83
Índice
5.2.3.1. Resultados con MOS . . . 86
5.2.4. Función Rastrigin . . . 91
5.2.4.1. Resultados con MOS . . . 91
5.3. Resultados con el TSP . . . 97
5.3.1. Introducción al problema TSP . . . 97
5.3.2. Variaciones en el número de nodos y en la población . . . 97
5.3.3. Resultados con hibridación de técnicas basadas en GAs . . . 103
5.3.3.1. Análisis de la participación y la calidad . . . 105
5.3.4. Evolución central versus autonómica . . . 107
5.3.4.1. Análisis de tiempos . . . 111
PARTEV CONCLUSIONES Y LÍNEAS FUTURAS 6. Conclusiones y líneas futuras . . . 115
6.1. Conclusiones . . . 115
6.2. Líneas futuras . . . 116
Índice de figuras
2.1. Taxonomía de Flynn . . . 11
2.2. Arquitecturas UMA y NUMA . . . 12
2.3. Arquitectura de un multicomputador . . . 13
2.4. Magerit. CeSViMa . . . 14
2.5. Topologías de red . . . 16
2.6. Ley de Amdahl . . . 19
2.7. Etapas del proceso de paralelización . . . 21
2.8. Impacto del límite de la concurrencia . . . 22
2.9. Comunicación unicast vs. broadcast . . . 24
2.10. Comunicación estructurada vs. no estructurada . . . 24
2.11. Comunicación síncrona vs. asíncrona . . . 25
2.12. Multithreading con OMP . . . 28
3.1. Ejemplo del método de selección de la ruleta . . . 37
3.2. Método de la ruleta vs. método de la ruleta con rangos . . . 38
3.3. Cruce en un punto . . . 39
3.4. Cruce en dos puntos . . . 39
3.5. Cruce uniforme . . . 40
3.6. Cruce aritmético . . . 40
3.8. Cruce ordenado . . . 41
3.9. Operador de mutación por inversión . . . 41
3.10. Operador de mutación por intercambio . . . 42
3.11. Operador de mutación uniforme . . . 42
3.12. Ejemplo de un modelo gráfico parax= (A,B,C,D) . . . 44
3.13. Topologías de islas implementadas en GAEDALib . . . 49
4.1. Visión general del funcionamiento del algoritmo MOS central . . . 55
4.2. Diagrama de secuencia del algoritmo MOS . . . 56
4.3. Diagrama de secuencia del algoritmo MOS autonomic . . . 58
4.4. Clases de GAGeneticAlgorithm . . . 59
4.5. Tipos de técnicas MOS . . . 63
4.6. Diagrama de clase de genomas MOS . . . 67
4.7. Funcionamiento del conversor MOS . . . 69
4.8. Funcionamiento del serializador MOS . . . 71
5.1. Superficie de la función MaxBit conn=2 . . . 79
5.2. Superficie de la función Griewank conn=2 yd=4000 . . . 86
5.3. Superficie de la función Rastrigin conn=2,ω=2πya=10 . . . 91
5.4. Comparativa de técnicas para el problema Swiss42 . . . 99
5.5. Comparativa de técnicas para el problema Brazil58 . . . 99
5.6. Comparativa de técnicas para el problema Gr120 . . . 100
5.7. Comparativa del fitness con la técnica IntPermOXSIM en Gr120 . . . 101
5.8. Comparativa del tiempo con la técnica IntPermOXSIM en Gr120 . . . 102
5.9. Comparativa de los resultados para el TSP con hibridación MOS central . . . 104
5.10. Evolución de la participación y la calidad. Combinación de 3 técnicas con el TSP gr120 105 5.11. Evolución de la participación y la calidad para una combinación de 3 técnicas en el TSP gr120 sin porcentaje mínimo de participación . . . 107
5.12. Comparativa del fitness para el TSP con hibridación MOS autonomic . . . 109
Índice de figuras
5.14. Comparativa del fitness para el TSP brazil58 con evolución MOS central frente autonomic110
5.15. Comparativa del fitness para el TSP gr120 con evolución MOS central frente autonomic 110
5.16. Comparativa del tiempo para el TSP swiss42 con evolución MOS central frente autonomic111
5.17. Comparativa del tiempo para el TSP brazil58 con evolución MOS central frente
auto-nomic . . . 111
Índice de tablas
1.1. Alternativas para la configuración de un algoritmo evolutivo . . . 4
2.1. Etapas de la paralelización y sus objetivos . . . 21
2.2. Comparativa de herramientas para programación paralela . . . 26
3.1. Algunos de los algoritmos evolutivos más representativos . . . 33
3.2. Ejemplo del cálculo de la probabilidad del método de la ruleta . . . 36
3.3. Ejemplo del cálculo de la probabilidad del método de la ruleta con rangos . . . 38
5.1. Técnicas GA definidas . . . 76
5.2. Técnicas EDA definidas . . . 77
5.3. Equivalencia entre identificadores de técnicas . . . 77
5.4. Resultados para MaxBit con hibridación MOS central yn=12 . . . 80
5.5. Resultados para MaxBit con hibridación MOS central yn=30 . . . 81
5.6. Resultados para MaxBit con hibridación MOS central yn=100 . . . 82
5.7. Resultados para Royal Road con hibridación MOS central,k=4,b=8 yg=7 . . . 84
5.8. Resumen de fitness para el problema Royal Road con técnicas individuales . . . . 85
5.9. Resumen de mejores fitness para el problema Royal Road con hibridación MOS . . . 85
5.10. Resultados para Griewank con hibridación MOS central,n=10 yd=4000 . . . . 87
5.11. Resultados para Griewank con hibridación MOS central,n=20 yd=4000 . . . . 88
5.13. Resumen de fitness de las peores técnicas para la función Griewank . . . 90
5.14. Resultados para Rastrigin con hibridación MOS central,n=5,a=10 yω=2π . . . 92
5.15. Resultados para Rastrigin con hibridación MOS central,n=20,a=10 yω=2π . . 93
5.16. Resultados para Rastrigin con hibridación MOS central,n=30,a=10 yω=2π . . 94
5.17. Resumen fitness técnicas individuales para función Rastrigin . . . 95
5.18. Resumen mejores fitness para función Rastrigin con hibridación MOS yn=20 . . . 96
5.19. Resumen mejores fitness para función Rastrigin con hibridación MOS yn=30 . . . 96
5.20. Resultados para el TSP con las 7 técnicas evolutivas, 1 nodo y 1000 individuos . . . 98
5.21. Fitness con la técnica IntPermOXSIM en Gr120, variando nodos y población . . . . 100
5.22. Tiempo en segundos con la técnica IntPermOXSIM en Gr120, variando el número de
nodos y de individuos . . . 102
5.23. Resultados para el TSP con hibridación MOS central de técnicas GA . . . 104
Índice de algoritmos
3.1. Algoritmo genético básico . . . 35
Acrónimos y abreviaturas
UP Unidad de Proceso
SISD Single Instruction Single Data
MISD Multiple Instruction Single Data
SIMD Single Instruction Multiple Data
MIMD Multiple Instruction Multiple Data
UMA Uniform Memory Access
NUMA Non Uniform Memory Access
cc-NUMA Cache Coherent Non Uniform Memory Access
SMP Symmetric Multi-Processing
CeSViMa Centro de Supercomputación y Visualización de Madrid
UPM Universidad Politécnica de Madrid
SCI Scalable Coherent Interface
IEEE Institute of Electrical and Electronics Engineers
PCI Peripheral Component Interconnect
HPF High Performance Fortran
HPF-2 High Performance Fortran versión 2.0
F95 Fortran 95
PVM Parallel Virtual Machine
MPI Message Passing Interface
MPI-2 Message Passing Interface versión 2.0
MPI I/O Message Passing Interface In/out
MPICH Message Passing Interface Chameleon
MPICH2 Message Passing Interface Chameleon versión 2.0
LAM/MPI Local Area Multicomputer Message Passing Interface
OpenMPI Open Message Passing Interface
OMP Open Multi Processing
IBM International Business Machines
IA Inteligencia Artificial
GA Genetic Algorithms
EDA Estimation of Distributions Algorithms
MGP Modelo Gráfico Probabilístico
UMDA Univariate Marginal Distribution Algorithm
PBIL Population Based Incremental Learning
MIMIC Mutual Information Maximization for Input Clustering
COMIT Combining Optimizers with Mutual Information Trees
BMDA Bivariate Marginal Distribution Algorithm
EBNA Estimation of Bayesian Network Algorithm
0. Acrónimos y abreviaturas
EMNA Estimation of Multivariate Normal Algorithm
EGNA Estimation of Gaussian Network Algorithm
GALib Genetic Algorithm Library
GAEDALib Genetic Algorithm Estimation of Distribution Algorithms Library
MOS Multiple Offspring Sampling
TSP Traveling Salesman Problem
RAND Research and Development
AX Aritmetic Crossover
UC Uniform Crossover
OX Order Crossover
CX Cycle Crossover
EOC Even Odd Crossover
OPC One Point Crossover
TPC Two Points Crossover
BC Blended Crossover
REM Repeated Exchange Mutation
SIM Simple Inversion Mutation
UM Uniform Mutation
GM Gaussian Mutation
SM Swap Mutation
PI Permutation Initializer
SC Simple Comparator
UI Uniform Initializer
PLSC Partial Least Squares Correct
BIC Bayesian Information Criterion
Parte I
Capítulo 1
Introducción y objetivos
1.1.
Introducción
Los algoritmos evolutivos son métodos adaptativos que suelen usarse para solucionar problemas de
búsqueda y optimización no lineales y con espacios de búsqueda que pueden ser muy grandes. Dada
una población de posibles soluciones a un problema concreto, la computación evolutiva expande esta
población con nuevas y mejores soluciones, obtenidas a partir de los individuos de la población anterior.
Este patrón de funcionamiento se inspira en la teoría de la evolución postulada por Darwin en 1859 [6].
Los genes sirven para codificar la representación de un individuo en el que modelizamos una solución al
problema.
Los padres se irán cruzando o combinando de alguna manera y sufriendo alteraciones para generar
los genes de los hijos. El objetivo es conseguir que la población vaya mejorando de generación en
genera-ción produciendo nuevos individuos que mejoren a los anteriores. Siguiendo esta tendencia intentaremos
llegar a una solución válida.
Inicialmente, estos algoritmos fueron considerados desde un punto de vista teórico sin una
aplica-ción muy extendida en el mundo real. Sin embargo, la actividad investigadora en este área ha llegado a
desarrollar todo un modelo teórico y madurar lo suficiente como para poder aplicarse en la solución de
problemas reales en muchos ámbitos. Además, el rápido avance de la tecnología permite disponer cada
vez de forma más sencilla y económica de una gran potencia de cálculo, necesaria para sacar partido a
esta aproximación teórica. Esto ha provocado que los algoritmos evolutivos estén ciertamente en auge,
siendo su uso cada vez más extendido para solucionar problemas en muy diversos campos.
Estas técnicas de optimización están siendo cada vez más utilizadas en diversos escenarios de
solu-ciones que crecen de forma no lineal, lo cual incluye campos tan dispares como la química molecular, la
resistencia de materiales, la robótica o la teoría de juegos, entre otros.
El concepto de algoritmo evolutivo engloba toda una familia de técnicas y enfoques teóricos que
tienen en común el mismo patrón de iteración evolutiva y codificación de soluciones como individuos.
Dos de las vertientes más destacables hoy en día son los GA y los algoritmos EDA que, junto con algunas
otras técnicas evolutivas, han conseguido resultados muy interesantes.
El enfoque de los GA fue desarrollado por J.H. Holland en torno a 1975 [15]. Éste es el enfoque más
clásico en el que los padres son seleccionados de una manera arbitraria y recombinados mediante ciertos
operadores de cruce y mutación, dando lugar a una nueva descendencia.
En el enfoque de los algoritmos más avanzados como los EDA los operadores de cruce y mutación
son sustituidos por un modelo probabilístico que es construido a partir de la población actual y a partir
del cual se inferirán los individuos que formarán la siguiente población.
La continua investigación en el área de los algoritmos evolutivos plantea nuevos retos
constantemen-te y propone nuevas técnicas, variaciones o configuraciones, que aportan mejoras a los modelos más
básicos.
1.2.
Objetivos
Una de las cuestiones que se nos plantean a la hora de intentar solucionar un problema con un
algorit-mo evolutivo es saber qué aproximaciones y configuraciones son las más adecuadas a nuestro problema.
Como ya hemos visto anteriormente, existen diferentes enfoques de algoritmos evolutivos y, dentro de
éstos, muchas formas de ajustarlos definiendo diferentes operadores, probabilidades, codificaciones y
otros parámetros.
En la tabla 1.1 se presenta un resumen de los elementos a considerar en un algoritmo evolutivo.
Parámetro Opciones
Tipo de algoritmo GA, EDA con redes bayesianas, EDA con redes gaussianas...
Codificación binaria, entera, real...
Operadores cruce, mutación, evaluación, comparación...
Otros parámetros tamaño de la población, probabilidad de cruce y mutación...
1.2. Objetivos
La elección y combinación de todos estos elementos supone un problema de optimización en sí
mis-mo. Este proyecto tiene como objetivo la implementación de un nuevo algoritmo evolutivo, denominado
Multiple Offspring Sampling (MOS), que sea capaz de combinar dinámicamente diferentes algoritmos,
codificaciones, operadores y parámetros para llegar a la mejor solución posible de la manera más rápida.
Para poder aplicar este nuevo enfoque basado en una arquitectura de hibridación de algoritmos es
necesario desarrollar un mecanismo para evaluar la calidad de la población durante la ejecución. También
es necesario desarrollar el concepto de “técnica” como combinación de posibles parámetros y permitir
un ajuste dinámico de la participación de las mismas.
En resumen, los objetivos de este proyecto serían los siguientes:
Implementación de un algoritmo con soporte para diferentes técnicas evolutivas.
Desarrollo de la capacidad de evaluación de la calidad de una técnica evolutiva.
• Definición e implementación de estas medidas de calidad.
Orquestación de las técnicas.
• Ajuste dinámico de la participación en base al rendimiento utilizando medidas de calidad.
• Facilitar el diseño y la introducción de nuevas técnicas de recombinación.
Definición de genomas con soporte para múltiples codificaciones.
• Conversión entre codificaciones.
• Serialización de codificaciones.
Con la introducción de todas estas novedades al concepto clásico de hibridación pretendemos mejorar
los resultados obtenidos hasta ahora con algoritmos evolutivos tradicionales o, en el peor de los casos, ser
capaces de detectar la mejor técnica de recombinación de entre todas las disponibles sin un conocimiento
a priori del rendimiento de las mismas. Del mismo modo, pretendemos dar un soporte para el desarrollo
de nuevas investigaciones sobre la materia y la implementación de nuevas técnicas y operadores que
podrán ser incluidos de forma rápida y sencilla.
Estas metodologías a pesar de proponer un método depurado de búsqueda, siguen requiriendo una
cantidad notable de recursos computacionales, concretamente de consumo de procesador. Por ello un
factor muy importante y que va de la mano de los algoritmos evolutivos es el de paralelismo y
compu-tación de altas prestaciones. Además la propia formalización y estructura de los algoritmo evolutivos los
Para demostrar las ventajas de este nuevo modelo lo aplicaremos para solucionar problemas clásicos
en la literatura, como el problema del Traveling Salesman Problem (TSP) y problemas de optimización
de funciones matemáticas clásicas en el mundo de la computación evolutiva.
1.3.
Estructura de la memoria
La memoria del proyecto está organizada en seis partes. Tras esta primera parte de introducción y
objetivos del proyecto tenemos la parte dedicada al estado de la cuestión, desglosada en dos capítulos.
El primero está dedicado al estado de la cuestión en lo relativo a computación de altas prestaciones y el
segundo dedicado a la teoría de algoritmos evolutivos.
La siguiente parte, compuesta por los capítulos cuatro y cinco, desglosa al detalle el diseño y
desarro-llo de la solución propuesta para la implementación del algoritmo MOS. En este apartado se expondrán
detalladamente todas las decisiones de diseño adoptadas así como la arquitectura del sistema. En
con-creto, se detallarán especialmente el diseño y funcionamiento de las técnicas MOS, los genomas MOS,
la conversión entre genomas y la serialización de las poblaciones MOS.
En la cuarta parte se hará un detallado análisis de los resultados obtenidos sobre diferentes
proble-mas de búsqueda y optimización para varias combinaciones de parámetros aplicando el algoritmo MOS.
Asimismo, se hará una comparativa de los mejores enfoques para solucionar cada problema. A
continua-ción, en el capítulo séptimo, se presentarán las conclusiones y las futuras líneas de investigación en este
campo. Por último, se incluirá el capítulo de anexos, con información complementaria al desarrollo de
Parte II
Capítulo 2
Computación de altas prestaciones con
arquitecturas paralelas
En este capítulo se da una visión general de la evolución de las arquitecturas paralelas para
compu-tación de altas prestaciones, centrándonos fundamentalmente en los multicomputadores y su aplicación
en el campo de la computación científica. Se analizará también la necesidad de estos sistemas, las
ten-dencias actuales y las últimas tecnologías para llevar a cabo desarrollos con programación paralela.
2.1.
Introducción
Una de las constantes a lo largo de la historia de la informática ha sido la necesidad de incrementar
constantemente la potencia de cálculo disponible. La implementación de algoritmos y aplicaciones cada
vez más complejas y con un coste computacional más alto, ha permitido ir resolviendo problemas más
complejos y llegar a soluciones más precisas manejando grandes volúmenes de datos.
La ejecución de aplicaciones científicas de cálculo intensivo ha puesto de manifiesto la necesidad
de unas arquitecturas hardware de alto rendimiento capaces de satisfacer los fuertes requisitos de estas
aplicaciones.
A pesar de la vertiginosa evolución de las arquitecturas hardware, y de la continua capacidad de la
industria de ofrecer sistemas con mayor capacidad de cálculo, el desarrollo de software con mayores
necesidades de recursos siempre es mucho más rápido. Esta relación no lineal entre el hardware ofrecido
por los fabricantes y las necesidades del software desarrollado en el mundo científico plantea la necesidad
de proponer nuevos modelos capaces de adaptarse a las necesidades de los científicos e ingenieros de una
Frente a la imposibilidad de construir procesadores con capacidad suficiente para llevar a cabo estas
tareas con un coste y en un tiempo razonables, es necesario buscar alternativas. Ante esta perspectiva
la solución más razonable es la introducción de paralelismo. El paralelismo se basa en la ejecución
simultánea en varios procesadores, bien en la misma o en diferentes máquinas. El reparto del trabajo entre
varias instancias permite avanzar mucho más rápido para alcanzar los objetivos y, por tanto, aumentar
notablemente las prestaciones.
El concepto de paralelismo es una revolución en contraposición con la computación secuencial
tra-dicional, ya que permite abaratar de manera espectacular los costes y afrontar retos antes inimaginables,
proporcionando unos sistemas de enormes prestaciones que permiten a los científicos e ingenieros
reali-zar nuevos experimentos y diseños.
Por otro lado, la computación paralela plantea nuevos y complejos retos para los programadores, que
deben de amoldarse a la nueva filosofía y abandonar su concepción de programas secuenciales. Se debe
ser capaz de fragmentar las tareas a realizar de manera adecuada para que éstas puedan ejecutarse de
for-ma paralela. Esto supone una for-mayor complejidad en el diseño y entran en juego nuevas preocupaciones
que antes no teníamos como el acceso a los datos, la sincronización de los procesos o el intercambio de
información. Todo esto hace muy compleja la programación paralela y es necesario dominar la
arquitec-tura y las herramientas existentes para obtener realmente una ganancia y sacar el máximo partido a las
arquitecturas paralelas.
2.2.
Arquitecturas paralelas: Taxonomía
Existen varios modelos de arquitecturas paralelas. Una de las clasificaciones clásicas y generalmente
aceptada es la realizada por el profesor de la Universidad de Stanford Michael J. Flynn en 1972 [11]. Esta
clasificación conocida como “la taxonomía de Flynn” diferencia entre paralelismo de datos y paralelismo
de instrucciones.
El paralelismo de datos se refiere a la posibilidad de realizar una misma operación sobre varios
datos de forma paralela, mientras que el paralelismo de instrucciones hace referencia a la posibilidad de
ejecutar de forma paralela diferentes instrucciones.
La tabla 2.1 muestra las posibles combinaciones al hacer paralelismo de datos y de instrucciones
2.2. Arquitecturas paralelas: Taxonomía SISD MISD C on ju nt o D at os Conjunto Instrucciones UP SISD C on ju tn o D at os Conjunto Instrucciones UP UP MISD SIMD MIMD C on ju nt o D at os Conjunto Instrucciones UP UP UP UP SIMD C on ju nt o D at os Conjunto Instrucciones UP UP UP UP UP UP UP UP MIMD
Figura 2.1:Taxonomía de Flynn
Single Instruction Single Data(SISD): Modelo secuencial tradicional. Las instrucciones se eje-cutan secuencialmente y cada instrucción se ejecuta sobre un solo dato.
Single Instruction Multiple Data(SIMD): Ejecución secuencial de instrucciones, pero aplicando cada instrucción a un conjunto de datos de forma paralela. Un ejemplo de esto es Altivec, un
conjunto de instrucciones para coma flotante desarrollado por Apple, IBM y Motorola y que sigue
la filosofía SIMD. Otro ejemplo es la tecnología SSE introducida, también para cálculos en coma
flotante, por Intel en su familia de procesadores Pentium III como extensión para el juego de
instrucciones MMX. Otro campo en el que se ha explotado esta tecnología es el de los procesadores
gráficos, de gran auge en los últimos años.
Multiple Instruction Single Data(MISD): Este modelo tiene poco sentido en computación tra-dicional. Su desarrollo se limita al campo de la investigación, por ejemplo en los procesadores
Multiple Instruction Multiple Data(MIMD): Estas arquitecturas son las más interesantes y las que implementan la mayoría de computadores paralelos. La idea es tener varios procesadores que
ejecuten instrucciones de forma paralela sobre conjuntos de datos independientes entre sí.
Como hemos comentado anteriormente, las arquitecturas más interesantes y extendidas, en lo que se
refiere a computadores paralelos, son las MIMD. Ahora bien, dentro de este contexto paralelo existen
diferencias sustanciales entre distintas máquinas que lo implementan. La característica más importante a
estudiar es el tipo de mapa de memoria utilizado y cómo accedemos a él.
Inicialmente distinguiremos entre multiprocesadores, si se trata de máquinas con un único espacio
de direcciones, y multicomputadores, si son máquinas con múltiples espacios de direcciones, uno para
cada procesador.
2.2.1. Multiprocesadores
Los multiprocesadores son máquinas con varias unidades de proceso pero una memoria común. El
acceso de todos los procesadores a esta memoria común hace muy compleja la construcción de estas
má-quinas, elevando su coste, pero le da la facilidad al programador de ver un único mapa y poder compartir
la memoria. El acceso a esta memoria se puede realizar fundamentalmente de dos formas:
UMA(Uniform Memory Access): La memoria es compartida y el acceso es uniforme desde todos
los procesadores.
NUMA(Non Uniform Memory Access): Todos los procesadores pueden acceder a toda la
memo-ria, pero no de manera uniforme. Dependiendo de la memoria a la que queramos acceder tendrá
un coste u otro.
UMA NUMA
Bus de conexión
M M M M
UP UP UP UP
UMA
Bus de conexión
M M M M
UP UP UP UP
NUMA
2.2. Arquitecturas paralelas: Taxonomía
Las máquinas Non Uniform Memory Access (NUMA) son más escalables y, generalmente,
imple-mentan complejos algoritmos de coherencia de caches cc-NUMA, cuyo objetivo es minimizar los accesos
a la parte de memoria más costosa de acceder. Algunas máquinas NUMA que han tenido éxito comercial
son el SGI Origin y el Cray T3.
Las máquinas Uniform Memory Access (UMA) son más costosas de implementar y menos
esca-lables. No es habitual que tengán muchos procesadores. En la literatura se usan indistintamente los
términos UMA y Symmetric Multi-Processing (SMP) para referirse a este tipo de arquitecturas.
Algu-nos ejemplos de máquinas UMA son los nodos de máquinas SMP de Sun o HP y, más recientemente,
procesadores comerciales como los Intel Core y los AMD Athlon entre otros.
2.2.2. Multicomputadores
La característica fundamental de los multicomputadores es que son arquitecturas con memoria
dis-tribuida no compartida, de manera que cada procesador tiene su propio mapa de memoria. El conjunto
de procesador, memoria y, en ocasiones, dispositivos de entrada/salida se denomina nodo. Los nodos se
comunicarán entre sí mediante un sistema o red de interconexión a través de paso de mensajes.
Multicomputador
Red de conexión
M
UP
Multicomputador
M
UP M
UP M
UP
Figura 2.3:Arquitectura de un multicomputador
Los multicomputadores son más sencillos de construir y más escalables que los multiprocesadores,
pero incorporan la dificultad a la hora de programar aplicaciones, ya que la paralelización la debe realizar
el programador explicitamente mediante paso de mensajes, con toda la complejidad que esto implica.
En muchos casos, uno o varios de los nodos de un multicomputador son, a su vez, multiprocesadores
con varios núcleos.
2.2.2.1. Clúster
Una evolución del concepto de multicomputador son los clúster. Un clúster es un multicomputador
cuyos nodos son computadores de componentes comunes y relativamente baratos y que están conectados
por una red de alta velocidad mediante un switch. El objetivo de un clúster es obtener una máquina de
mayor potencia a partir de computadores no necesariamente muy potentes y a un precio razonable. Al
usar componentes más o menos comunes y habituales en el mercado, el coste de un clúster en relación a
la potencia de cálculo obtenida es bajo.
El modelo de programación de un clúster es necesariamente paso de mensajes entre nodos a través
de la red. Para ello existe una capa de software intermedio, o middleware de comunicaciones, que facilita
esta labor. Un clúster es tremendamente escalable y muy flexible, ya que se le pueden añadir o sustituir
nodos con relativa facilidad. No es necesario que todos los nodos de un clúster tengan la misma
arqui-tectura, ni siquiera es necesario que tengan el mismo sistema operativo. Esto es lo que se denomina un
clúster heterogéneo, frente al concepto de clúster homogéneo, donde sí son iguales todos los nodos.
2.2.2.2. Magerit
Un ejemplo de un clúster lo podemos ver en la figura 2.4. Este clúster, llamado Magerit, es una
máquina perteneciente al Centro de Supercomputación y Visualización de Madrid (CeSViMa), el centro
de supercomputación ubicado en la Universidad Politécnica de Madrid (UPM). Magerit es actualmente
la segunda máquina más potente de España y, en el momento de su instalación, llegó a ser la 34a más
potente del mundo. Es un clúster compuesto por 1204 nodos eServer BladeCenter JS20 y JS21, con dos y
cuatro procesadores IBM PowerPC single-core 970FX de 64 bits a 2’2 GHz. Están conectados mediante
una red Myrinet de alta velocidad. Magerit tiene una potencia pico de 20 Tflops aproximadamente.
2.3. Topologías y redes de interconexión
2.3.
Topologías y redes de interconexión
Uno de los aspectos clave en computación paralela es la comunicación entre los nodos. Al trabajar de
forma paralela en muchas ocasiones los nodos van a necesitar intercambiarse información y comunicarse
unos con otros para sincronizarse. La necesidad de obtener un alto rendimiento nos obliga a tener muy en
cuenta los tiempos y las latencias de comunicación, ya que podrían suponer un enorme cuello de botella.
Aunque tuviésemos muchos nodos muy potentes, si la red de comunicaciones no es capaz de realizar el
intercambio de información a una velocidad razonable, perderíamos gran parte de nuestra potencia de
cálculo. En la sección 2.3.1 repasaremos algunas de las tecnologías más relevantes para interconexiones
de multicomputadores y multiprocesadores.
Otro aspecto importante, sobre todo en multiprocesadores, es la topología de la red de interconexión
que diseñemos, ya que podemos tener modelos en los que no todos los procesadores estén directamente
conectados entre sí. Esto da lugar a diferentes topologías o formas de colocar y conectar nuestros nodos.
La topología más adecuada dependerá del número de nodos que tengamos, la velocidad de nuestra red y
el tipo de aplicaciones paralelas que vayamos a ejecutar.
En la literatura existen dos conceptos que nos ayudan a definir las topologías de nuestra red:
Anchura de bisección:Número mínimo de conexiones a cortar para obtener dos sistemas iguales.
Ancho de banda en bisección: Ancho de banda a través de los nodos cortados al obtener la anchura de bisección.
Estos conceptos caracterizan una topología de red y nos permiten estudiar facilmente cual será su
escalabilidad.
Existen multitud de topologías de red. La figura 2.5 recoge algunas de las topologías más clásicas
y que más se implementan en sistemas reales. La topología que elijamos definirá en gran medida las
características de nuestra red y, por lo tanto, influirá de manera significativa en el rendimiento y coste
de nuestro sistema. Para profundizar más en este tema, se puede consultar alguna de las referencias
existentes en la literatura, de entre las que destacan las obras de P. de Miguel [8] y D. Culler[5], más
Lineal Malla Anillo Árbol
Cubo 3D Estrella Conexión completa Barras cruzadas
Figura 2.5:Topologías de red
2.3.1. Tecnologías de interconexión
Algunas de las tecnologías de interconexión más relevantes, tanto por la tecnología aportada como
por su éxito comercial, se detallan a continuación, junto con algunas de sus carácterísticas más
intere-santes.
SCI:Scalable Coherent Interface. Estándar IEEE desde 1992, conforma una estructura en anillo de
1, 2 ó 3 dimensiones. Es capaz de mantener la coherencia entre las caches de los procesadores que
conecta, de manera que podría sustituir a un bus de un multiprocesador, aunque su uso en clústers
es sólo como conexión entre nodos. Puede ser la base para implementar una memoria compartida
virtual. Alcanza velocidades de 2500 MB/s obteniendo latencias de 1-2 microsegundos, por lo que
es adecuado para envío de mensajes cortos.
QsNet:QsNet: Quadrics. Evolución de las redes de interconexión de las Meiko Computing Sur-face, usadas después en las Alphaserver SC. Se compone de un switch (de 16 ó 128 puertos)
y tarjetas adaptadoras PCI que alcanzan hasta 350 MB/s. Se desarrolló una segunda versión en
2003, llamada QsNet II, que alcanza hasta 1.3 GB/s con conexiones bidireccionales y latencias
entre 3 y 5 microsegundos. Internamente usa una topología fat tree.
2.4. Rendimiento en computación paralela
principales características es que el procesamiento de las comunicaciones de red se realiza a través
de chips integrados en las tarjetas de red, liberando a la cpu de esta labor. Sus características hacen
que sea altamente escalable, por lo que es la tecnología más utilizada en grandes clústers.
Infiniband: Puede ser usado para conexiones entre subsistemas o entre procesadores. Hoy por hoy tiene un precio alto, pero es muy versátil ya que tiene especificaciones para conexiones de
cobre y de fibra óptica. Está compuesto por switches de 8 a 124 puertos, que proporcionan 7
microsegundos de latencia en mensajes cortos. Permite diferentes configuraciones y puede llegar
a velocidades de 12 GB/s. Las especificaciones son libres, no está ligado directamente a ninguna
empresa.
2.4.
Rendimiento en computación paralela
Cuando paralelizamos un programa o algoritmo para ejecutarlo en un multiprocesador o un
multi-computador nuestro principal objetivo es acelerar su ejecución sacando el máximo partido posible a la
máquina que tenemos por debajo. Existen diferentes medidas que nos ayudan a estudiar el rendimiento
real de nuestro programa, así como las posibilidades de paralelizarlo y obtener un mejor rendimiento.
2.4.1. Factor de aceleración: Speedup
El speedup es la principal medida que nos indica la ganancia que obtenemos con nuestra
paraleli-zación. Se calcula como el cociente entre el tiempo de cálculo en una máquina secuencial y el mismo
cálculo en una máquina paralela con determinado número de procesadores. Obviamente, el speedup de
un programa variará de una máquina paralela a otra, y en función de cómo se haya realizado la
paraleli-zación. Cuanto más alto sea el speedup, más ganancia habremos obtenido con nuestra paraleliparaleli-zación.
Speedup=Tsecuencial Tparalelo
(2.1)
Otra medida de interés relacionada con el speedup es la eficiencia. Se define como el cociente entre
el speedup y el número de procesadores en los que ejecutamos, y su valor está comprendido entre 0 y 1.
E f iciencia= Speedup Nprocesadores
(2.2)
Nos interesa que la eficiencia tenga un valor lo más cercano a 1 que sea posible, aunque
general-mente obtendremos un valor menor. En el hipotético caso de que la eficiencia fuera 1, significaría que
los procesadores. Llegar a esta situación es casi imposible. La dificultad de repartir equitativamente el
tiempo de proceso estriba en gran medida en cómo sea nuestro algoritmo y lo fácil que sea de paralelizar.
Suele ser muy habitual que haya partes de nuestro algoritmo que no podamos paralelizar de ninguna
ma-nera. Al margen de esto, el hecho de paralelizar siempre supone una mínima carga adicional en concepto
de sincronización y comunicación entre nodos y, en ocasiones, intercambios de datos de un tamaño más
que considerable. Esto hace que nuestra paralelización nunca vaya a ser perfecta, en el sentido de que
frecuentemente obtendremos un rendimiento inferior a 1. En cualquier caso, el objetivo siempre ha de
ser obtener una eficiencia lo más alta posible.
Por otro lado existen algunos casos, bastante atípicos, en los que debido a la propia naturaleza del
algoritmo o a la arquitectura de la máquina que utilicemos, es posible alcanzar una ganancia mayor que
uno. Esta circunstancia se denomina superlinealidad y se da en circunstancias muy concretas.
2.4.2. Ley de Amdahl
En 1967 el ingeniero Gene Amdahl definió una fórmula, conocida como la Ley de Amdahl [1], que
probaba que, a partir de cierto punto, el hecho de agregar más procesadores a una máquina paralela no
producía una mejora significativa en la velocidad de ejecución.
La Ley de Amdahl distingue entre las partes de un programa que son paralelizables (Pparalelizable)
y las que son intrínsecamente secuenciales (Psecuencial) y nunca podremos paralelizar. De manera que
siempre se cumple:
Pparalelizable+Psecuencial=1 (2.3)
Si sustituimos en la fórmula 2.1 del speedup y simplificamos usando la fórmula 2.3 obtenemos:
Speedup=Pparalelizable+Psecuencial Psecuencial+
Pparalelizable
Nprocesadores
= 1
Psecuencial+
Pparalelizable
Nprocesadores
(2.4)
La fórmula 2.4 calcula el factor máximo de aceleración en función de las partes de nuestro programa
2.4. Rendimiento en computación paralela 20.00 18.00 16.00 14.00 12.00 10.00 8.00 6.00 4.00 2.00 0.00 S p e e d u p
1 2 4 8 16 32 64
1 2 8 2 5 6 5 1 2 1 0 2 4 2 0 4 8 4 0 9 6 8 1 9 2 1 6 3 8 4 3 2 7 6 8 6 5 5 3 6
Número de procesadores
Ley de Amdahl
Porcentaje Paralelización 50% 75% 90% 95% 100%
Figura 2.6:Ley de Amdahl
En la figura 2.6 podemos ver gráficamente el speedup que obtendríamos, en función del número
de procesadores, para programas con diferentes porcentajes de código paralelizable. Como se puede
observar claramente, llega un momento en que, para un determinado número de procesadores, no es
posible incrementar más el speedup, ya que éste se estanca. Esto sucede en todos los casos salvo en
el trazo pintado en amarillo que representa problemas que son 100 % paralelizables. En este caso la
relación entre el número de procesadores y el speedup es totalmente lineal (los ejes están escalados) y
crece constantemente.
Existen pocos problemas que sean 100 % paralelizables y que alcancen speedups lineales. Los que lo
son se definen por su naturaleza intrínsecamente paralela en la que el problema se puede descomponer en
tareas totalmente independientes y, generalmente, la solución final es una agregación de las soluciones
parciales. Algún ejemplo de este tipo de problemas es la búsqueda de claves criptográficas por fuerza
bruta o la búsqueda de jugadas en un programa de ajedrez.
2.4.3. Ley de Gustafson
En contraposición a la Ley de Amdahl (sección 2.4.2) el ingeniero y científico John L. Gustafson hizo
una revisión de la misma en 1988, lo que dio lugar a lo que se conoce como la Ley de Gustafson [14].
Guftanson afirmaba que los cálculos de Amdahl eran incorrectos, porque éste consideraba constantes
Psecuencial yPparalelizable, lo que no es cierto en un programa que ejecuta de forma paralela. Lo correcto
era usar los valores medios en un sistema paralelo, que se definen comoPsecuencial0 yPparalelizable0 . Según
tanto, deberíamos de reevaluar la fórmula del factor de aceleración definida por Amdahl (fórmula 2.4),
lo que da lugar a la nueva Ley de Gustafson, que es lineal:
Speedup=P
0
secuencial+P
0
paralelizableNprocesadores
Psecuencial0 +Pparalelizable0 =Nprocesadores+ (1−Nprocesadores)P
0
secuencial (2.5)
En cualquier caso, tanto la Ley de Amdahl como la de Gustafson son simplificaciones. La
escala-bilidad y el factor de aceleración de un sistema paralelo hay que estudiarlos para una implementación
concreta de un algoritmo sobre una máquina dada.
2.5.
Proceso de paralelización: Principios de diseño
Dado un programa secuencial, el hecho de paralelizarlo es una tarea muy laboriosa y compleja que
requiere una buena metodología y planificación.
En primer lugar es necesario definir una serie de conceptos que fijen el marco de trabajo del proceso
de paralelización:
Tarea:Es la unidad mínima de cómputo. Se ejecuta siempre secuencialmente y no se puede des-componer más. Existe concurrencia sólo entre tareas. Pueden existir tareas de grano fino frente a
tareas de grano grueso.
Proceso:Entendemos el proceso como una entidad abstracta que realiza las tareas asignadas a los procesadores. Los procesos se comunican y sincronizan para realizar las tareas.
Procesador:Máquina física sobre la que se ejecuta un proceso.
Una vez hechas estas definiciones podemos comprender cómo debemos diseñar la paralelización.
Para poder afrontar con una mínimas garantías la labor de paralelización de un programa es necesario
llevar a cabo las siguientes cuatro fases [5]:
Descomposición:Partición de la carga computacional secuencial en tareas.
Asignación:Reparto de las tareas a los procesos.
Orquestación:Coordinación de los accesos necesarios a los datos, la comunicación y sincroniza-ción entre los procesos.
2.5. Proceso de paralelización: Principios de diseño
La figura 2.7 muestra gráficamente las diferentes etapas del proceso de paralelización y la relación
entre ellas.
Figura 2.7:Etapas del proceso de paralelización
La tabla 2.1 recoge los principales objetivos que se espera conseguir en cada una de estas etapas con
el fin de obtener el mejor rendimiento posible en la paralelización que vamos a realizar:
Etapa Dependencia de la arquitectura Principales objetivos
Descomposición Probablemente no Análisis de la concurrencia.
Asignación Probablemente no Balanceo de carga. Minimizar comunicación.
Orquestación Sí Reducir comunicación para acceso a datos.
Reducir comunicación y sincronización.
Pla-nificar tareas para evitar dependencias.
Despliegue Sí Explotar al máximo la localidad en la
topolo-gía de red.
Tabla 2.1:Etapas de la paralelización y sus objetivos
A continuación comentaremos en profundidad cada una de estas etapas del proceso de paralelización.
2.5.1. Descomposición
Para esta primera fase de descomposición debemos centrarnos inicialmente en el algoritmo. Nuestro
núme-ro de tareas, y buscando que sean descomposiciones de grano lo más fino posible. Esto nos dará más
flexibilidad para la agrupación posterior.
Existen dos enfoques a la hora de afrontar esta tarea:
Descomposición del dominio: En primer lugar, determinamos una partición de los datos, para asociar después unos cálculos sobre estos datos.
Descomposición funcional: Primero descompondremos los cálculos para asignarles depués los datos que vayan a necesitar.
Debemos tener cuidado en la redundancia tanto en el cómputo como en el almacenamiento de los
datos, ya que en la mayoría de los casos supone una penalización, aunque en ocasiones pueda ser
benefi-cioso. De la misma manera debemos de poner especial énfasis en minimizar, en la medida de lo posible,
las dependencias entre tareas, para evitar sincronizaciones y comunicaciones. Tenemos que procurar
también que las tareas representen cantidades similares de trabajo.
El límite de la concurrencia que podemos obtener viene definido por la ley de Amdahl (sección
2.4.2).
La figura 2.8 muestra un ejemplo de un algoritmo implementado de forma secuencial que podemos
dividir en dos fases. En este ejemplo, la segunda fase depende de los resultados de la primera. Podemos
paralelizar cada fase independientemente y obtener una aceleración casi lineal.
2.5. Proceso de paralelización: Principios de diseño
2.5.2. Asignación
La etapa de asignación pretende asignar las tareas, definidas en la fase anterior, a los procesos.
De-bemos buscar equilibrio en la carga de trabajo que asignemos a cada proceso, así como procurar reducir
al máximo la comunicación y sincronización necesarias entre procesos.
A la hora de equilibrar la carga, debemos tener en cuenta algoritmos de planificación por si fuese
ne-cesario equilibrar las funciones. Equilibrar la carga puede ser una tarea muy compleja si hemos definido
pocas tareas, si éstas son de grano gordo o si tienen muchas dependencias entre ellas.
Para reducir la comunicación debemos procurar asignar tareas que ejecutan concurrentemente a
di-ferentes procesos, y asignar tareas que se comunican muy frecuentemente a un mismo proceso.
Fundamentalmente existen dos esquemas de asignación:
Asignación estática: Definimos la asignación de los procesadores al comienzo de la ejecución. Esto no nos supone muchas sobrecargas más que al comienzo, pero tiene el problema de que el
equilibrado de la carga puede ser malo y no podremos hacer ya nada para corregirlo en tiempo de
ejecución.
Asignación dinámica: La asignación se va ajustando a medida que ejecutamos en función de la carga de cada nodo del sistema. Permite hacer un balanceo adecuado de la carga, pero nos
introduce retardos debido al coste en tiempo y consumo de procesador que supone hacer esta
asignación dinámica.
2.5.3. Orquestación
El objetivo de la orquestación es estructurar la comunicación entre los procesos, estableciendo la
sin-cronización entre los mismos. También es necesario definir la manera en la que nombramos y manejamos
los datos por parte de los distintos procesos.
En cuanto a la comunicación entre procesos, existen varios patrones de comunicación que la definen,
y que repasaremos en las siguientes subsecciones.
2.5.3.1. Comunicación unicast vs. broadcast
Cuando hablamos de comunicación unicast a nivel de proceso nos referimos a la comunicación que
se establecerá entre un proceso y algunos de los otros procesos que se estén ejecutando en ese momento.
A su vez, estos procesos se comunicarán con otros procesos. La clave de este paradigma unicast frente
mucho más escalable, aunque en ocasiones más costoso, en contraposición con la comunicación global o
broadcast, donde un proceso se ha de comunicar con todos los demás. Existen mecanismos, generalmente
hardware, que nos permiten sacar un gran rendimiento de la comunicación broadcast, en comparación al
envío unicast de un número similar de mensajes.
(a)Comunicación unicast (b)Comunicación broadcast
Figura 2.9:Comunicación unicast vs. broadcast
2.5.3.2. Comunicación estructurada vs. no estructurada
La comunicación estructurada se refiere a si el patrón de comunicación que implementarán los
pro-cesos responde a una topología o estructura determinada, con el fin de alcanzar la mejor solución. Por el
contrario, cuando usamos comunicación no estructurada la solución que buscamos no depende de la
es-tructura de comunicación entre nodos y sus comunicaciones se realizan en ocasiones de forma aleatoria,
o al menos no siguen una estructura definida.
(a)Comunicación estructurada (b)Comunicación no estructurada
2.5. Proceso de paralelización: Principios de diseño
2.5.3.3. Comunicación estática vs. dinámica
Este patrón de comunicación simplemente define si la comunicación será la misma durante toda la
ejecución o irá cambiando en función de las necesidades o reglas que se hayan definido. Una
comunica-ción estática es más fácil de definir, mientras que una comunicacomunica-ción dinámica puede resultar más difícil
de implementar y de equilibrar.
2.5.3.4. Comunicación síncrona vs. asíncrona
Cuando al enviar información de un proceso a otro esperamos a que el receptor reciba el mensaje
estamos hablando de comunicación síncrona, los dos procesos se sincronizan en la comunicación, ya
que uno espera al otro. Si enviamos el mensaje y seguimos ejecutando sin esperar la confirmación de
recepción del otro proceso estamos hablando de comunicación asíncrona.
En el caso de la comunicación asíncrona tiene la ventaja de que los procesos no se quedan bloqueados
en la comunicación, ya que envían la información y siguen ejecutando. Sin embargo, con este mecanismo
no podremos sincronizar unos procesos con otros y, en ocasiones, esto es necesario.
(a)Comunicación síncrona (b)Comunicación asíncrona
Figura 2.11:Comunicación síncrona vs. asíncrona
2.5.4. Despliegue
El objetivo de esta etapa es asignar los procesos a los procesadores en los que ejecutarán. Sólo tiene
sentido cuando paralelicemos en multicomputadores. En ocasiones puede ser necesario migrar procesos
de un procesador a otro, pero esto puede suponer muchos problemas, ya que la memoria es local a cada
2.6.
Herramientas de programación paralela
Existen diferentes herramientas que facilitan la labor del programador a la hora de implementar
una paralelización de un programa. Las diferentes herramientas se orientan a un modelo y arquitectura
diferentes, siendo más adecuada una u otra dependiendo del caso. Estas herramientas consisten en un
Application Programming Interface (API), que nos da una capa de abstracción (de alto o bajo nivel,
según veremos) y que es utilizada por el programador para paralelizar su algoritmo.
En este caso vamos a analizar las herramientas High Performance Fortran (HPF), Message Passing
Interface (MPI) y Open Multi Processing (OMP), ya que son las tres más relevantes en cuanto a su
historia, lo extendido de su uso y filosofía de operación.
La tabla 2.2 muestra una breve comparativa de las principales característias de cada una de estas tres
tecnologías.
HPF MPI OMP
Año primera versión 1993 1994 1997
Versión actual HPF-2 MPI-2 OMP 3.0
Lenguajes soportados Fortran Fortran, C/C++, Java... Fortran, C/C++
Modelo programación Directivas Llamadas biblioteca Directivas
Arquitecturas SIMD, MIMD... SIMD, MIMD... SMP
Uso y repercusión Disminuyendo. Muy extendido. En auge.
Extensiones MPI I/O
Tabla 2.2:Comparativa de herramientas para programación paralela
2.6.1. HPF
Se trata de un lenguaje de programación completo basado en Fortran. Su objetivo es la programación
paralela en máquinas de tipo SIMD con paralelismo de datos. Fue pensado para cálculo intesivo
cien-tífico. Tiene un buen rendimiento y es compatible con Fortran 95 (F95). La mayoría de las llamadas se
hacen en forma de directivas en el programa fuente.
El proceso de compilación es complejo y el rendimiento obtenido es difícil de prever. La primera
versión surgió en 1993 en la Universidad de Rice y su desarrollo hoy en día va por la versión 2.0. Al
estar pensado para programar en lenguaje Fortran su uso no está excesivamente extendido, fuera de los
2.6. Herramientas de programación paralela
2.6.2. MPI
MPI surge como un acuerdo entre empresas, universidades y centros de investigación para definir
una interfaz común de paso de mensajes. MPI se ha convertido en el estándar de facto del modelo de
paso de mensajes orientado a multicomputadores. Una alternativa, anterior a MPI, es Parallel Virtual
Machine (PVM), se trata de una serie de herramientas software que permiten la paralelización. PVM
Apareció en 1989 y fue desarrollado por el Oak Ridge National Laboratory.
La primera versión de MPI apareció en 1994. En 1997 fue lanzada la versión MPI-2, que todavía hoy
sigue vigente y que incorporó la entrada salida paralela con MPI I/O y otras mejoras muy significativas.
En un entorno MPI el programador debe ocuparse de casi todo. MPI únicamente proporciona una
capa de abstracción sobre el hardware, pero dejando al programador la responsabilidad de gestionar la
lógica del intercambio de mensajes.
Existen bindings de MPI para múltiples lenguajes, entre los que se encuentran álgunos de los más
difundidos como Fortran, C, C++, Java o Python. El uso de MPI está extendido en prácticamente todos
los entornos multicomputador tanto a nivel empresarial como en universidades y centros de investigación.
La biblioteca Genetic Algorithm Estimation of Distribution Algorithms Library (GAEDALib), con
la que se ha llevado a cabo este trabajo, se basa en tecnología MPI para soportar el paso de mensajes
entre nodos.
MPI ha triunfado en el sector de los multicomputadores y de la informática general. Esto es debido
al gran esfuerzo que se hizo por parte de las principales empresas y entidades investigadores en ese
momento por conseguir un estándar de facto, pero también se debe a las bondades del diseño de MPI,
que reseñamos a continuación:
Estandarización.
Portabilidad: multiprocesadores, multicomputadores, redes, entornos heterogéneos...
Buenas prestaciones.
Amplia funcionalidad.
Existencia de implementaciones libres.
Una de las características mas atractivas de MPI es que existen varias implementaciones libres
MPICH:Fue la primera implementación que se llevó a cabo, realizada por el Argonne National Laboratory y la Universidad del Estado de Mississippi. Hoy en día ya está disponible MPICH2
que implementa MPI-2.
LAM/MPI:Implementado por el Ohio Supercomputing Center, hoy en día se ha combinado con otros esfuerzos para crear el proyecto OpenMPI que implementa nuevas mejoras.
También existen optimizaciones de alguna implementaciones realizadas por algunos fabricantes. Por
ejemplo la implementación Message Passing Interface Chameleon (MPICH)-GM realizada por la
em-presa Myricom para sus redes Myrinet.
2.6.2.1. Funcionamiento de MPI
Cualquier implementación de MPI consiste en una biblioteca que nos ofrece un interfaz común de
llamadas. Estas llamadas nos permiten realizar todas las acciones necesarias para gestionar el paso de
mensajes. Podemos agrupar las llamadas en cuatro categorías:
1. Llamadas utilizadas para inicializar, administrar y finalizar comunicaciones.
2. Llamadas utilizadas para transferir datos entre un par de procesos.
3. Llamadas para transferir datos entre varios procesos.
4. Llamadas utilizadas para crear tipos de datos definidos por el usuario.
2.6.3. OMP
OMP es un API que permite paralelismo en máquinas con memoria compartida. OMP se basa en una
arquitectura de hilos que realizan tareas paralelas sobre la misma memoria, como muestra la figura 2.12.
Por eso es un requisito que por debajo tengamos memoria compartida aunque cada hilo pueda ejecutarse
en un procesador diferente.
2.6. Herramientas de programación paralela
OMP tiene un modelo de programación basado en directivas que son interpretadas por el compilador.
OMP da una visión de más alto nivel que otras aproximaciones paralelas como MPI, ya que descarga al
programador de la labor de gestionar la lógica de comunicación. La configuración está controlada por
variables de entorno.
OMP surgió en 1997 inicialmente como extensión para el lenguaje fortran y más adelante soportando
también C y C++. Actualmente está disponible la versión 3.0 con múltiples mejoras y extensiones.
El modelo de programación paralela que propone OMP ofrece muchas ventajas al programador:
Simplicidad, no es necesario el paso explícito de mensajes.
El tratamiento y descomposición de los datos es realizado automáticamente por las directivas.
Introducción de paralelismo con muy poco esfuerzo y modificaciones en el código fuente.
Posibilidad de compilación para ejecución secuencial sin modificar el código. Las directivas OMP
son ignoradas por el compilador.
La introducción de directivas no afecta en general a la estructura de nuestros algoritmos, lo que
minimiza la posibilidad de cometer errores.
Posibilidad de hacer paralelismo de grano fino y de grano grueso.
Existen implementaciones de algunos fabricantes muy optimizadas, como la de IBM.
Sin embargo, este modelo también presenta algunos incovenientes:
La concurrencia sólo es eficiente en plataformas SMP.
Necesidad de un compilador específico con soporte para OMP.
La escalabilidad está limitada por la arquitectura de la memoria.
La captura de errores no es fiable.
No es posible sincronizarse entre un subconjunto de hilos.
Obtener una buena optimización requiere conocimientos de la arquitectura.
En resumen, todas estas tecnologías y herramientas vistas a lo largo de este capítulo suponen un
soporte para el desarrollo y ejecución de nuevas aplicaciones de cómputo intensivo. En nuestro caso el
hecho de disponer de este tipo de arquitecturas nos permitirá llevar a cabo la implementación y pruebas
de las aportaciones que propone este proyecto al campo de los algoritmos evolutivos, un área que
tradi-cionalmente ha requerido de gran potencia de cálculo para obtener resultados interesantes en problemas
Capítulo 3
Algoritmos evolutivos
En este capítulo se da una visión general de la teoría de algoritmos evolutivos desarrollada en los
últimos 40 años. Definiremos todos los términos utilizados en este campo. Igualmente, comentaremos
algunos ejemplos de problemas clásicos que se solucionan con este tipo de algoritmos.
Nos centraremos fundamentalmente en los algoritmos genéticos, analizando algunos de los
ope-radores clásicos. En general, definiremos su funcionamiento y la aproximación que hace la biblioteca
GAEDALib [9] al respecto.
También nos interesará conocer la aproximación de los algoritmos EDA y comentaremos brevemente
su estructura basada en redes y métodos de aprendizaje y simulación.
Por último, analizaremos algunos aspectos sobre la ejecución de algoritmos evolutivos paralelos y
sobre la hibridación de múltiples algoritmos evolutivos.
3.1.
Introducción
Los algoritmos evolutivos surgen con la necesidad de desarrollar nuevas técnicas avanzadas de
op-timización que sean capaces de resolver problemas complejos de gran magnitud en tiempos razonables.
Surgen dentro del campo de la Inteligencia Artificial (IA) como alternativa de optimización heurística.
Su funcionamiento se basa en una búsqueda guiada pero aún así requieren sistemas de gran capacidad de
cómputo. Su buen rendimiento es posible, en muchos casos, gracias al uso de técnicas de paralelismo,
tal y como se vio en el capítulo 2.
Inspirados en la evolución natural, definida por Charles Darwin en el siglo XIX en su teoría de la
evolución [6], estos algoritmos pretenden superar las limitaciones de los algoritmos de optimización
La aplicación de este enfoque a muchos problemas de optimización en el mundo real ha demostrado
que son una alternativa muy interesante que en muchas ocasiones ha conseguido soluciones de alta
calidad con un alto rendimiento.
Los algoritmos evolutivos suponen un proceso iterativo que consiste en evolucionar o hacer crecer
una población, de manera similar al proceso natural. Los individuos de la población codifican las
solu-ciones a nuestro problema, y son seleccionados en base a su adecuación a la solución óptima buscada,
este comportamiento se inspira en el modelo natural.
Uno de los aspectos más importantes, a la hora de plantearnos solucionar un problema con un
algo-ritmo evolutivo, es encontrar una buena representación para codificar el problema y modelizarlo de la
manera adecuada. Se ha demostrado empíricamente en los últimos años que elegir una representación
adecuada es fundamental para obtener la solución esperada [17].
Del mismo modo, serán decisivos los operadores y parámetros que decidamos utilizar en nuestro
algoritmo para conseguir el éxito.
Los algoritmos evolutivos no dejan de ser una gran familia de algoritmos. Dentro de esta familia
podemos encontrar diferentes aproximaciones que han ido surgiendo a lo largo de la historia y desarrollo
de este campo de investigación. Los pilares de esta taxonomía fueron definidos de forma paralela durante
los años 70 por diferentes científicos e ingenieros que han pasado a la historia como los padres de la
computación evolutiva.
Por citar algún nombre, podemos destacar al profesor de psicología de la Universidad de Míchigan,
J.H. Holland [15], considerado uno de los padres de la computación evolutiva; el profesor de la
Uni-versidad de Dortmund Hans-Paul Schwefel que desarrolló la teoría para la estrategia evolutiva [30]; el
profesor I. Rechenberg de la Universidad Técnica de Berlín que aplicó las estrategias evolutivas al campo
de la aeronáutica [26] y [27]; y, por último, el profesor L.J. Fogel, padre de la programación evolutiva
que también investigó en el campo de la aeronáutica y la cibernética [12].
Algunas de las aproximaciones tradicionales mas relevantes dentro del mundo de los algoritmos
evolutivos las podemos ver en la tabla 3.1. En ocasiones, simplemente difieren en los detalles de la