• No se han encontrado resultados

Paralelización de algoritmos de optimización Servicios para el uso de clusters

N/A
N/A
Protected

Academic year: 2021

Share "Paralelización de algoritmos de optimización Servicios para el uso de clusters"

Copied!
57
0
0

Texto completo

(1)

UNIVERSIDAD DE LOS ANDES FACULTAD DE INGENIER´IA

Departamento de Sistemas y Computaci ´on

Grupo de construcci ´on de software

Paralelizaci ´on de algoritmos de optimizaci ´on

Servicios para el uso de clusters

Juan Sebasti ´an Jaramillo Londo ˜no

Tesis de grado presentado para optar por el t´ıtulo de Mag´ıster en Ingenier´ıa de Sistemas y Computaci ´on de la

Universidad de los Andes

Enero, 2014

Asesores: Prof. Dr. Rubby Casallas Guti ´errez Prof. David Fernando M ´endez Acu ˜na

(2)
(3)

Resumen

Las plataformas de Computaci´on de Alto Desempe˜no (HPC por sus siglas en ingl´es) son hoy en d´ıa una herramienta fundamental para investigaciones en ´areas de ingenier´ıa, biolog´ıa, qu´ımica, etc. Estas aplicaciones requieren gran capacidad de procesamiento, memoria, almacenamiento, que los PCs no pueden soportar. Es com´un encontrar clusters robustos para HPC en la mayor´ıa de universida-des y centros de investigaci´on en el mundo. Sin embargo, dado que muchos de estos investigadores no son expertos en el uso de los clusters, i.e., enfrentarse a un sistema operacional distinto, ni manejan la programaci´on en paralelo, ellos tienen dificultades en el uso de estas plataformas lo que no les permite sacar mejor provecho de los recursos. El objetivo de este proyecto es ayudar a mejorar la experiencia de los usuarios en la interacci´on con las plataformas de cluster, as´ı como ayudar a los usuarios a paralelizar autom´aticamente ciertos algoritmos que desarrollan en sus actividades de investigaci´on.

(4)

High Performance Computing platforms are today an essential tool for re-search in engineering, biology, chemistry, etc. These applications require high processing power, memory, storage, that Personal Computers can not stand. It is common to find robust clusters for HPC in most universities and research cen-ters in the world. However, since many of these researchers are not experts in the use of clusters, ie, face a different operating system, or handle parallel program-ming, they have difficulties in using these platforms which does not allow them to take best use of resources. The objective of this project is to help improve the user experience in interacting with cluster platforms, as well as help users to automatically parallelize certain algorithms developed in its research.

(5)

Agradecimientos

Quiero agradecer a mi asesora Rubby Casallas por su gu´ıa y apoyo, a David M´endez Acu˜na por todo el esfuerzo dedicado a ayudarme tanto en la programa-ci´on como en la elaboraci´on del documento y a mi familia por su incondicional apoyo.

(6)
(7)

´Indice general

Resumen I Abstract I Agradecimientos II Tabla de contenidos V 1 Introducci´on 3

2 Servicios para uso de un cluster 5

2.1 Introducci´on . . . 5

2.1.1 Problem´atica . . . 5

2.1.2 Justificaci´on . . . 6

2.1.3 Propuesta . . . 6

2.2 Fundamentaci´on y estado del arte . . . 6

2.2.1 Definiciones . . . 6

2.2.2 Estado del Arte . . . 7

2.3 Objetivo . . . 8

2.4 Descripci´on del desarrollo del servicio para uso del cluster . . . . 8

2.4.1 Desarrollo de la API . . . 9

2.4.2 Ejemplo interfaz de usuario del servicio para el uso de clusters 10 2.5 Validaci´on . . . 11 3 Paralelizaci´on de Algoritmos 19 3.1 Introducci´on . . . 19 3.1.1 Problem´atica . . . 19 3.1.2 Justificaci´on . . . 20 3.1.3 Propuesta . . . 20

3.2 Fundamentaci´on y estado del arte . . . 20

3.2.1 Definiciones . . . 20

3.2.2 Antecedentes . . . 22

3.2.3 Estado del Arte . . . 23

3.3 Objetivo . . . 23

3.4 Alcance . . . 23

3.5 Restricciones . . . 23

3.6 Estrategia paralelizaci´on de algoritmos . . . 24

3.6.1 Descripci´on de la cadena de transformaci´on . . . 24

3.6.2 Herramientas usadas en la implementaci´on . . . 24

3.7 Validaci´on . . . 26

3.7.1 Ejemplo ilustrativo . . . 26 v

(8)

3.8 Pruebas con escenario de Algoritmos de Optimizaci´on - SOFIA . 28 3.8.1 Ejemplo del c´odigo escrito por el programador: . . . 30 3.8.2 Resultado del c´odigo generado: . . . 37

4 Conclusiones y Trabajo Futuro 47

4.1 Conclusiones . . . 47 4.2 Trabajo futuro . . . 47

(9)
(10)

1

Introducci´

on

En la actualidad en ´areas de ingenier´ıa, biolog´ıa, qu´ımica, etc. las plata-formas de Computaci´on de Alto Desempe˜no (HPC por sus siglas en ingl´es) se han convertido en una herramienta fundamental para el desarrollo de algunas investigaciones ya que exigen gran capacidad de procesamiento, memoria y/o al-macenamiento. Sin embargo muchas de las personas que trabajan en estas ´areas no necesariamente son expertos en el uso de los clusters, ni saben desarrollar sus aplicaciones de manera que se ejecuten en paralelo, debido a esto no obtie-nen el mejor provecho de la plataforma o por su forma de trabajar saturan los servidores en los que ejecutan los trabajos.

Este trabajo tiene como prop´osito general promover y facilitar el uso de la plataforma de HPC por parte de los usuarios finales, por medio de herramientas que faciliten la interacci´on con la misma. Para lograr esto, hemos realizado dos estrategias. La primera consiste en la construcci´on de unos servicios para el usua-rio final que le permita interactuar con el cluster. La segunda es una primera aproximaci´on para transformar de manera autom´atica algoritmos secuenciales en algoritmos en paralelo. Este es un problema aun abierto por lo complejo. El alcance de nuestro trabajo en este punto est´a restringido a un tipo particular algoritmos de scheduling. En estos algoritmos el desarrollador sabe que algu-nas partes iterativas de su c´odigo puede ser ejecutado de manera paralela, sin embargo no necesariamente sabe como hacerlo.

Este documento presenta las dos estrategias realizadas de forma separada. El cap´ıtulos 2 se ocupa de la estrategia para resolver el problema del mejoramiento de la interacci´on de los usuarios con el cluster.En el cap´ıtulo 3 se presenta la estrategia para automatizar la transformaci´on de c´odigo secuencial en paralelo.

(11)
(12)

2

Servicios para uso de un cluster

2.1

Introducci´

on

Es importante ayudar a los nuevos usuarios de un cluster a familiarizarse con el mismo, facilitando la interacci´on y reduciendo la curva de aprendizaje; es as´ı como el desarrollo de un servicio para uso de clusters que tenga una interfaz web para lanzar los trabajos resulta de gran utilidad para personas que requieran utilizar la infraestructura pero que por desconocimiento de la plataforma t´ecnica no pueden hacerlo.

Gracias a este servicio el usuario puede ver el estado de sus trabajos, ver la sali-da de los mismos, puede enviar trabajos al cluster as´ı como terminar un trabajo determinado.

Se espera que esto ayude a incrementar el porcentaje de uso de la infraestructura y que ´esta sea utilizada de manera ´optima.

El servicio para el uso del cluster cuenta con una API 2.4.1 que est´a dise˜nada para que los comandos del cluster est´en desacoplados del c´odigo fuente, esto facilita para los administradores del cluster la configuraci´on en caso de actua-lizaciones de la versi´on del sistema operativo e incluso que sea portable entre varios tipos de cluster.

2.1.1. Problem´atica

Como administradores del cluster del MOX de la Facultad de Ingenier´ıa y en entrevistas con administradores de clusters en la Universidad Washington y Purdue, al momento de crear nuevas cuentas de usuario se han identificado varias problem´aticas :

1. Los usuarios por lo general no est´an familiarizados con ambientes de l´ınea de comandos, por el contrario son usuarios que han trabajado en entornos gr´ afi-cos Windows, Mac o Linux.

(13)

6 2.2. Fundamentaci´on y estado del arte

2. Para la ejecuci´on de los trabajos los usuarios no conocen los comandos para que los trabajos se ejecuten en el cluster y los ejecutan en el nodo maestro, con lo cual no obtienen ventajas al usar el cluster y saturan dicho servidor ha-ciendo que los dem´as usuarios no puedan tener un buen desempe˜no al correr sus trabajos.

3. Por restricciones de seguridad, es com´un encontrar que el acceso v´ıa SSH a los ambientes de cluster se encuentra restringido a ciertas redes.

2.1.2. Justificaci´on

Al revisar las falencias que se encontraron en 2.1.1, se evidencia que es nece-sario brindar herramientas que faciliten a los nuevos usuarios de los ambientes de HPC el uso de la plataforma, de manera que su trabajo se concentre en resolver sus problemas mas que en aprender a manejar plataformas de l´ınea de comandos y herramientas de cluster.

2.1.3. Propuesta

Como soluci´on a las problem´aticas identificadas se propone desarrollar un servicio para uso de plataformas de cluster. Este servicio debe permitir que los usuarios finales del cluster puedan:

1. Interactuar por medio de un ambiente gr´afico con el cluster para enviar sus trabajos, terminar los trabajos y verificar el estado y la salida de los mismos sin necesidad de conocer los comandos propios del cluster o del sistema operativo. 2. Manipular v´ıa web sus archivos de trabajo dentro del cluster, en particular debe poder subir, descargar, eliminar y editar dichos archivos.

3. Tener acceso al cluster v´ıa web sin necesidad de interactuar por SSH con el mismo.

2.2

Fundamentaci´

on y estado del arte

En este cap´ıtulo presentamos algunas definiciones importantes para nuestro trabajo referente a los servicios para el uso del cluster, adem´as de mostrar algunos trabajos similares y/o relacionados con el fin de verificar los aspectos similares entre ellos, lo que nos aporta cada uno y al aporte adicional de nuestro trabajo. 2.2.1. Definiciones

Computaci´on de Alto Desempe˜no: HPC son las siglas en ingl´es de High Performance Computing o Computaci´on de Alto Desempe˜no en espa˜nol, se refiere al uso de supercomputadores o grupos de computadores para resolver problemas computacionales que pueden surgir en la investigaci´on cient´ıfica. Los usuarios acuden a usar HPC cuando un problema es muy grande para resolver en un computador convencional porque requiere mucha memoria o espacio en disco, corre muy lento debido a que el algoritmo es muy complejo, el conjunto

(14)

de datos es grande, o el acceso a los datos es lento.

Cluster: Un cluster es un conjunto de computadores conectados entre si de tal manera que trabajen conjuntamente y puede pensarse que trabajan como un ´

unico computador. Normalmente los nodos de un cluster est´an interconectados entre si por redes de alta velocidad como redes Ethernet a 1 o 10 Gbps o Infini-band a 20 o 40 Gbps, cada nodo debe ejecutar una su propio sistema operativo y los nodos son controladas desde un nodo maestro el cual es el encargado de asignar las tareas al resto de nodos, adicionalmente los cluster deben tener un almacenamiento distribuido que debe ser accesible desde todos los nodos con el fin de compartir informaci´on.

Existen varios tipos de cluster de acuerdo a su prop´osito o de acuerdo los nodos que lo conforman.

Algunos cluster est´an pensados para tener un muy buen desempe˜no y pres-taciones en cuanto a procesamiento, memoria o almacenamiento se denominan HPCC (High Performance Computing Cluster), otros cluster est´an pensados en brindar alta disponbilidad y se denominan HACC (High Availability Computing Cluster).

Por otra parte si los cluster est´an conformados por nodos exactamente igua-les se denominan cluster homog´eneos, si los nodos son similares se denominan semi-homog´eneos, o si ´estos son totalmente diferentes ´estos se denominan hete-rog´eneos. Hay un tipo de cluster conformado por computadores de escritorio y se denomina Beowulf cuya ventaja es el bajo costo que tiene.

Rocks: Papadopoulos en [9] nos explica que Rocks es un conjunto de he-rramientas de c´odigo abierto para administrar clusters, ´este se ha usado para construir miles de clusters y tiene una comunidad activa que esta permanente-mente colaborando para mejorar la plataforma. La principal diferencia de Rocks con otras herramientas para administraci´on de clusters consiste en que en lugar de ofrecer un software como tal, ofrece una descripci´on del sistema y con ´esta descripci´on instala el software necesario en los nodos, otras herramientas lo que hacen es tener una copia maestra del sistema operativo de los nodos y los ad-ministradores deben instalarlo en cada uno de ellos y cada uno de ellos debe ser configurado manualmente.

Rocks, maneja el software como paquetes del sistema operativo y la confi-guraci´on la guarda en un grafo de configuraci´on, en este grafo se define cuales paquetes van instalados en cada nodo y su configuraci´on exacta. Gracias a esto los cluster pueden escalar de una manera mas eficiente, basta con encender los servidores y ellos se auto configuran en el arranque desde el nodo maestro del cluster.

2.2.2. Estado del Arte

El proyecto de tesis [14], implementa una interfaz web que sirve para admi-nistrar trabajos en un entorno de cloud computing utilizando un api de Java provisto por Amazon Web Services, en este proyecto el usuario final puede admi-nistrar sus workspaces, enviar trabajos, monitorearlos y descargar los resultados de los mismos, puede ayudar a que proyectos sin recursos o con pocos recursos usen una infraestructura sin la necesidad de tener un GRID o un CLUSTER, pagando ´unicamente por lo que efectivamente se usa. Este trabajo es similar al

(15)

8 2.3. Objetivo

nuestro pero sobre una plataforma diferente, tiene la ventaja de tener un API preexistente provisto por Amazon para la interacci´on con la plataforma, en nues-tro caso esta API tuvo que ser desarrollada y se hizo de una manera gen´erica para que pueda ser usada con diferentes manejadores de colas.

Un proyecto que encontramos y que fue de gran importancia para nuestro trabajo fue PBS4JAVA [3], este es un proyecto de c´odigo abierto y nos ayudo a entender la forma en la que se deb´ıa desarrollar el API, en este proyecto se interactuaba desde c´odigo Java con los comandos del cluster, sin embargo los comandos estaban .alambrados¸con un versi´on particular de PBS, al tratar de

usar dicha API se encontr´o que el trabajo hab´ıa estado en desarrollo y que hab´ıa sido abandonado, nuestro aporte fue separar la l´ogica del API de los comandos del cluster con lo cual se logr´o que nuestra API pudiera ser usada con diferentes administradores de colas.

2.3

Objetivo

Desarrollar servicios para el uso del Cluster de HPC que permitan interactuar con la plataforma sin necesidad de tener conocimientos previos de plataformas de cluster.

2.4

Descripci´

on del desarrollo del servicio para uso del

cluster

Al revisar las implementaciones existentes de interfaces para interactuar con clusters, se evidenci´o que algunas est´an ligadas a los comandos en el sistema operativo del cluster, por lo tanto no pueden ser utilizadas por varios tipos de cluster. En esta soluci´on se resuelve esta problem´atica haciendo que los comandos del sistema operativo se configuren en un archivo de propiedades de manera que al invocarlos desde la interfaz web, se est´a llamando un archivo de procesamiento por lotes que es quien en realidad invoca los comandos del sistema operativo, de esta manera, si se cambia de sistema operativo basta con modificar los archivos de procesamiento por lotes para que entreguen los resultados que requiere la in-terfaz web.

Adicionalmente se agreg´o una interfaz para administraci´on de archivos de usuario en el cluster, la cual simplifica para los usuarios la interacci´on con el mismo.

Al momento de desarrollar la interfaz de usuario del servicio para el uso de clusters se opt´o por usar herramientas sencillas las p´aginas web est´an desarro-lladas usando JSP con un controlador b´asico que es quien maneja el flujo de las p´aginas, la autenticaci´on se hace usando el directorio activo, algo que nos permite un poco mas de flexibilidad al momento de gestionar los usuarios, esto debido a que se cuenta con la administraci´on delegada de una rama en el directorio activo con lo cual se pueden crear usuarios exclusivos para el uso del cluster los cuales son necesarios para usuarios externos de algunos convenios que se han venido haciendo con otras instituciones.

(16)

Figura 2.1: Jobs de un usuario

Desde la interfaz de usuario se llaman las funciones de la API y con esto se logra tener una interacci´on directa de los usuarios con el cluster, enmascarando los comandos de cluster con los que tendr´ıa que familiarizarse un usuario antes de usar el mismo.

2.4.1. Desarrollo de la API

Las API de java existentes tienen limitaciones en cuanto a las funcionalida-des que brindan o presentan problemas de compatibilidad entre versiones, es por eso que la caracter´ıstica principal en que se enfoc´o este trabajo fue desacoplar el c´odigo java de los comandos del sistema operativo y permitir que los comandos del sistema operativo sean configurables a trav´es de un archivo de propiedades. Los comandos que se ejecutan se mapean en este archivo a una propiedad de la aplicaci´on y adicional a esto los comandos se crearon como scripts de procesa-miento por lotes, lo cual hace que en el caso de cambiar la plataforma basta con crear nuevos script que obtengan informaci´on similar.

La API permite a los usuarios realizar operaciones sobre el cluster como el env´ıo de jobs al cluster, verificar el estado de un job y eliminar un job determi-nado.

Ejemplo del API

Para visualizar los trabajos de un usuario en el cluster debe ejecutarse el siguiente comando:

1 q s t a t - g t - u < USER >

Este comando muestra en pantalla una salida como la siguiente 2.1:

Para separar el c´odigo del API del sistema operativo se crea un archivo de procesamiento por lotes llamado list user jobs.sh con el siguiente c´odigo:

1 U S E R \=\ $1

2 q s t a t - g t - u \ $ U S E R | e g r e p - v ’ job - ID |\ -\ -\ - ’

En el archivo de propiedades llamado config.properties se define una propie-dad llamada LIST USER JOBS y a esta propiepropie-dad se le especifica cual comando de procesamiento por lotes ejecutar para obtener los job de un usuario, en este caso el archivo tiene la siguiente informaci´on:

1 S C R I P T S _ P A T H =/ e x p o r t / h o m e / j j a r a m i l l o / c l u s t e r _ a p i _ c o m m a n d s / 2 L I S T _ U S E R _ J O B S = l i s t _ u s e r _ j o b s . sh

(17)

10 2.4. Descripci´on del desarrollo del servicio para uso del cluster

Figura 2.2: Autenticaci´on de los usuarios

Con esto en el c´odigo java solo se invoca el archivo de propiedades y se pre-gunta por una propiedad espec´ıfica, luego se ejecuta el comando que est´a ligado a dicha propiedad y los datos obtenidos de la ejecuci´on se convierten en objetos java que son f´acilmente manipulables desde la interfaz web.

2.4.2. Ejemplo interfaz de usuario del servicio para el uso de clusters

La interfaz web exige autenticaci´on del usuario usando sus credenciales de Directorio Activo:??:

Una vez el usuario se autentica aparecen dos men´us adicionales 2.3, en la opci´on CLUSTER se encuentran las opciones para el env´ıo de tareas, ver el es-tado de las mismas o terminarlas y en el men´u BROWSER se encuentran las opciones para que el usuario pueda interactuar con el sistema de archivos del cluster all´ı puede subir archivos, eliminarlos, descargarlos, modificarlos en linea si son archivos de texto, etc.

Al ingresar al men´u CLUSTER2.4, se encuentran dos partes principales, en la primera se despliegan los nodos del cluster y las tareas del usuario que se est´an ejecutando en cada uno de ellos y en la segunda parte se muestran los archivos que tiene el usuario en su carpeta.

Cuando un archivo se puede ejecutar con alguna aplicaci´on 2.5 (previa confi-guraci´on), el usuario puede buscarlo y hacer click con el bot´on derecho del mouse, en este caso le aparece un men´u contextual que le permite ejecutar el archivo con el software que debe ejecutarse o ejecutar todos los archivos de la carpeta

(18)

Figura 2.3: Interfaz de usuario una vez se autentica el usuario

simult´aneamente.

Al ejecutar alguno de los archivos el sistema de colas del cluster lo env´ıa a uno de los nodos y le muestra al usuario una notificaci´on en otra ventana.2.6

Una vez el programa se est´a ejecutando en el cluster, en uno de los nodos se mostrar´a una entrada con el numero del proceso 2.7, el usuario con el bot´on derecho del mouse puede elegir varias opciones 2.8 entre ellas, ver el estado del trabajo2.9, eliminar el trabajo 2.12, mostrar el log de errores del trabajo 2.11 y la salida est´andar 2.10 que el trabajo genera en el cluster.

Al elegir la opci´on BROWSER le aparecer´an m´ultiples opciones para inter-actuar con los archivos que tiene en su carpeta:2.13

2.5

Validaci´

on

El sistema para el uso de los cluster se est´a usando actualmente en dos clusters de la Universidad de los Andes, se usa en el cluster del Centro de Computaci´on Avanzada de la Facultad de Ingenier´ıa - MOX el cual est´a basado en el sistema

operativo de cluster ROCKS ( http://master-hpc-mox.uniandes.edu.co:8080/Rocks4java ) y que usa como administrador de colas el Sun Grid Engine, esta validado

adi-cionalmente con el cluster de Biolog´ıa que se encuentra en la Direcci´on de Ser-vicios de Informaci´on y Tecnolog´ıa - DSIT de la Universidad de loa Andes ( http://tado.uniandes.edu.co:8080/Rocks4java ), el cual trabaja con el adminis-trador de colas Portable Batch System.

(19)

12 2.5. Validaci´on

Figura 2.4: Ingreso al men´u CLUSTER

(20)

Figura 2.6: Notificaci´on de env´ıo de trabajo al cluster

(21)

14 2.5. Validaci´on

Figura 2.8: Men´u contextual de un trabajo en ejecucion

(22)

Figura 2.10: Salida de un trabajo

(23)

16 2.5. Validaci´on

Figura 2.12: mensaje al eliminar un trabajo desde la interfaz web

(24)

Figura 2.14: Archivo config.properties

Tal como fue dise˜nado bast´o con parametrizar en el archivo config.properties y modificar algunos script para trabajar con los comandos de cada uno de los encoladores y no hubo necesidad de modificar el c´odigo fuente del sistema.

Los cambios que se realizaron en el archivo de configuraci´on se pueden ob-servar en 2.14:

En cuanto a los script que invocan los comandos del sistema operativo del cluster debieron modificarse los siguientes:

El script que muestra un listado de los usuarios del cluster list users.sh SGE:

1 awk - F" : " { ’ p r i n t $1 ’} / etc / p a s s w d

PBS:

1 q c o n f - s u s e r l

El que muestra los jobs de un usuario list user jobs.sh SGE:

1 U S E R = $1

2 q s t a t - ans - u $ U S E R | e g r e p - v " Job ID | - - - " | g r e p $ U S E R | awk - F" . " { ’ p r i n t $1 " 0 0 0 0 0 0 0 "’}

PBS: 1 U S E R = $1

2 q s t a t - g t - u $ U S E R | e g r e p - v ’ job - ID |\ -\ -\ - ’

El que ejecuta un job en una cola run job queue.sh SGE:

(25)

18 2.5. Validaci´on 1 s o u r c e / e x p o r t / h o m e / c l u s t e r _ a p i _ c o m m a n d s / e n v i r o n m e n t . sh 2 U S U A R I O = $1 3 JOB = $2 4 P A R A M E T E R = $3 5 Q U E U E = $4 6 cd $ R O C K S 4 J A V A _ P A T H / $ U S U A R I O 7 if [[ - z " $ Q U E U E " ]] 8 t h e n 9 Q U E U E = all . q 10fi 11su $ U S U A R I O - c " q s u b - cwd - q $ Q U E U E $ J O B $ P A R A M E T E R " PBS: 1 s o u r c e / usr / l o c a l / c l u s t e r _ a p i _ c o m m a n d s / e n v i r o n m e n t . sh 2 U S U A R I O = $1 3 JOB = $2 4 P A R A M E T E R = $3 5 Q U E U E = $4 6 R O C K S 4 J A V A _ P A T H =/ datos - b i o l o g i a 7 cd $ R O C K S 4 J A V A _ P A T H / $ U S U A R I O 8 if [[ - z " $ Q U E U E " ]] 9 t h e n 10 Q U E U E = b i o l o g i a 11fi 12su $ U S U A R I O - c " q s u b - q $ Q U E U E $ J O B - v p a r a m e t r o = $ P A R A M E T E R "

El comando para mostrar el estado de un job enb el cluster: SGE: 1 JOB = $1 2 q s t a t - f - j $ J O B PBS: 1 JOB = $1 2 q s t a t - f $ J O B

El encargado de mostrar los jobs que se est´an ejecutando en un nodo: SGE: 1 U S E R = $1 2 N O D E = $2 3 q c o n f - s u s e r l | awk { ’ p r i n t " q s t a t - g t - u "$1 ’} | g r e p $ U S E R | sh | g r e p $ N O D E PBS: 1 U S E R = $1 2 N O D E = $2

3 q s t a t - ans -1 - u $ U S E R | e g r e p - v " Job ID | - - - " | g r e p $ N O D E | awk - F" . " { ’ p r i n t $1 " 0 0 0 0 0 0 0 "’}

Y por ´ultimo el script que nos muestra los nodos que conforman el cluster: SGE:

1 r o c k s l i s t h o s t | e g r e p - v ’ M E M B E R S H I P |\ -\ -\ - ’

PBS:

1 awk - F" . " { ’ p r i n t $1" : C o m p u t e 8 0 0 os i n s t a l l "’} / r o o t / s i t e i n f o / wn - l i s t . c o n f

Con modificar esto fue suficiente para tener el servicio para el uso del cluster disponible en los dos ambientes y debe funcionar en cualquier sistema adminis-trador de colas de un cluster, con estos cambios b´asicos.

(26)

3

Paralelizaci´

on de Algoritmos

3.1

Introducci´

on

Gracias a la refactorizaci´on utilizando herramientas de Ingenier´ıa Orientada por Modelos para automatizar la paralelizaci´on de c´odigo java, se hace un apor-te para quienes buscan ejecutar sus trabajos en el Clusapor-ter o aun en sus propios equipos y no cuentan con el conocimiento o el tiempo necesarios para modificar su c´odigo fuente para que ´este se ejecute de manera paralela.

Con esta soluci´on solo se debe indicar con una anotaci´on, cu´al parte del c´ odi-go fuente debe ejecutarse en paralelo y el c´odigo para la ejecuci´on en paralelo se genera autom´aticamente, facilitando la tarea de los desarrolladores con el fin de que ellos se dediquen a lo que realmente es importante en el dominio de su problema.

3.1.1. Problem´atica

En el contexto del trabajo del Grupo de Investigaci´on en Producci´on y Log´ıstica (PYLO) de la Facultad de Ingenier´ıa de la Universidad de los Andes, en particular en los trabajos de Problemas de Optimizaci´on, se encontr´o que mu-chas veces el c´odigo que se desarrolla puede ser paralelizado, sin embargo esto no necesariamente es trivial de hacer y/o est´a fuera del campo de acci´on de las personas que desarrollan el software.

Esta misma problem´atica puede presentarse a cualquier persona que desa-rrolle software y que identifique que su c´odigo puede ejecutarse en paralelo.

Adicionalmente cabe anotar que la mayor´ıa de los computadores personales de la actualidad tiene varios procesadores y las capacidades multiprocesador de ´estos no son aprovechadas ya que el c´odigo que desarrollan los usuarios no est´a definido de manera que pueda hacerlo.

(27)

20 3.2. Fundamentaci´on y estado del arte 3.1.2. Justificaci´on

Muchos de los usuarios que desarrollan software en diferentes ´areas del co-nocimiento, no tienen el tiempo o el conocimiento para modificar sus desarrollos para que se ejecuten en paralelo, es por esto que se detecta la necesidad de ayu-dar a dichos usuarios para que de manera autom´atica puedan generar un nuevo c´odigo fuente que se ejecute en paralelo para resolver sus problemas.

3.1.3. Propuesta

Teniendo en cuenta la problem´atica encontrada, se propone desarrollar con la ayuda de la Ingenier´ıa Orientada por Modelos, una cadena de transformaci´on que permita tomar un c´odigo fuente desarrollado en Java, obtener su modelo y generar a partir de ´este modelo los modelos necesarios para generar un c´ odi-go fuente que pueda ejecutarse en paralelo con una parametrizaci´on b´asica del usuario final en la que especifica qu´e parte del c´odigo es la que desea paraleli-zar, para la paralelizaci´on se van a usar pool de threads. La ventaja de generar ´

este c´odigo usando Ingenier´ıa Orientada por Modelos radica en que se abstrae el lenguaje de programaci´on y se transforma en un modelo, gracias a esto se puede generalizar la soluci´on y se abstrae la l´ogica del c´odigo pasando a usar como entidades de primer nivel los elementos del modelo, con esto se puede lograr una separaci´on del lenguaje de programaci´on y se puede con unos cambios peque˜nos en las transformaciones, implementar diferentes alternativas de paralelizaci´on a partir del modelo que es generado autom´aticamente a partir del c´odigo fuente usando JaMoPP.

3.2

Fundamentaci´

on y estado del arte

Con el fin de dar un contexto con relaci´on a la Ingenier´ıa Orientada por Modelos damos algunas definiciones importantes para nuestro trabajo, adem´as de mostrar algunos trabajos similares y/o relacionados con el fin de verificar los aspectos similares entre ellos, lo que nos aporta cada uno y al aporte adicional de nuestro trabajo.

3.2.1. Definiciones Paralelismo:

Una de las principales caracter´ısticas del HPC consiste en utilizar el para-lelismo, es decir, la capacidad de trabajar en muchas tareas simult´aneamente. Cuando una aplicaci´on o algoritmo no explota el paralelismo se le denomina se-cuencial o serial, ya que tiene que ejecutar las tareas de forma individual una tras otra en una secuencia o serie. Los computadores modernos soportan un parale-lismo limitado gracias a los procesadores multi-core. Estos procesadores pueden ejecutar varias tareas simult´aneamente, lo que mejora el desempe˜no de m´ultiples tareas, por ejemplo, ejecutar un navegador web, procesador de textos, cliente de correo electr´onico al mismo tiempo. Pero los sistemas HPC ofrecen paralelismo a una escala mucho mayor, ejecutando cientos o miles de tareas simult´ aneamen-te. El Paralelismo a esta escala plantea algunos retos, algunos algoritmos tienen

(28)

cuellos de botella o puntos de serializaci´on, donde una sola tarea se debe com-pletar antes de que comiencen las otras tareas. En otros casos, varias tareas pueden necesitar compartir los mismos datos o modificar datos en un orden es-pec´ıfico. Escribir software que funcione en paralelo puede ser bastante dif´ıcil, y muchos lenguajes no soportan el paralelismo. En ocasiones paralelizar un softwa-re o algoritmo existente puede softwa-requerir una importante inversi´on en investigaci´on y desarrollo mientras en otros casos, los problemas computacionales se pueden paralelizar f´acilmente, esto debido a que el problema se puede descomponer en muchas peque˜nas tareas que son independientes una de otra.

Ingenier´ıa Orientada por Modelos (MDE):

La Ingenier´ıa Orientada por Modelos o MDE por sus siglas en ingl´es [7] consiste en el uso sistem´atico de modelos 3.2.1como principales artefactos en el proceso de ingenier´ıa de software. La MDE impacta algunos aspectos del desa-rrollo de software como son la productividad, la portabilidad y la mantenibilidad del producto desarrollado. La productividad se puede ver incrementada gracias a que el tiempo para el desarrollo del c´odigo se reduce gracias a la generaci´on autom´atica, los errores son en teor´ıa menos gracias a que el c´odigo es generado. La portabilidad del c´odigo aumenta ya que si cambia la plataforma deber´a bas-tar con cambiar las transformaciones que se apliquen al modelo para generar un nuevo c´odigo que se pueda usar ´esta. El c´odigo puede ser mantenido m´as f´ acil-mente gracias a que se cambia en muchos menos partes a nivel de modelo y de transformaciones para luego generar nuevamente el c´odigo.

Meta-modelos: Seg´un la especificaci´on del OMG (Object Management Group) de MOF (Meta Object Facility), un meta-modelo es un modelo que de-fine el lenguaje para expresar un modelo [4]. Otra definici´on bastante usada es la que encontramos en [12], Un meta-modelo es un modelo de especificaci´on para una clase de sistemas en estudio donde cada sistema en estudio de esa clase es en si mismo un modelo v´alido expresado en un lenguaje de modelado.

Modelos: Un modelo es un conjunto claro de elementos formales que des-criben algo que est´a siendo desarrollado con un prop´osito espec´ıfico y que puede ser analizado usando varios m´etodos[4], entre las caracter´ısticas fundamentales que debe tener un modelo ´este debe ser abstracto, entendible, debe representar precisamente el objeto del mundo real, debe poderse predecir su comportamiento y debe ser menos costoso que lo que est´a representando.

Transformaci´on de Modelos: Consiste en transformar un modelo o re-presentaci´on de un sistema en otro modelo de ´este de acuerdo a la definici´on de la transformaci´on deseada expresada en un lenguaje de transformaci´on [4]

Tipos de Transformaciones: De acuerdo a la forma en la que se definen las trasformaciones, se pueden dividir en declarativas e imperativas, las primeras definen las relaciones entre los modelos de entrada y salida pero no se preocupan por el orden de ejecuci´on de las mismas, las segundas son semejantes a los lengua-jes procedimentales y en ´estas se define que se va a hacer en la transformaci´on como una secuencia de pasos que deben ser ejecutados en un orden espec´ıfi-co. Existen algunos lenguajes que poseen ambas caracter´ısticas y se denominan

(29)

22 3.2. Fundamentaci´on y estado del arte

h´ıbridos.

Teniendo en cuenta la [4] cardinalidad de las relaciones definidas en las trans-formaciones, encontramos que existen transformaciones uno a uno (1..1) en las cuales un modelo de entrada genera un ´unico modelo de salida, uno a varios (1..N) en donde de un ´unico modelo de entrada se pueden generar varios mode-los de salida, varios a uno (N..1) cuando de varios modemode-los de entrada se genera un ´unico modelo de salida y por ultimo puede haber de varios a varios(M..N) donde de varios modelos de origen se generan varios modelos de salida.

Tambi´en puede caracterizarse las transformaciones de acuerdo al tipo de mo-delo que est´an transformando[4], en este caso se pueden definir como Texto-a-Modelo (T2M) en la cual se parte de la representaci´on textual o lenguaje de programaci´on para generar un modelo, Modelo..Modelo (M2M) en las que se parte de un modelo y se llega a otro modelo, Modelo..Texto(M2T) en las que se parte de un modelo y se llega a una representaci´on textual o lenguaje de pro-gramaci´on y las trasformaciones de Refactorizaci´on que toman un modelo y lo reorganizan de acuerdo a algunos criterios definidos.

3.2.2. Antecedentes

En la historia de la programaci´on Sackmann [11] nos explica en su traba-jo como antes no era necesario tener en cuenta la paralelizaci´on por cuanto los computadores solo ten´ıan un procesador y aun hoy en d´ıa es m´as f´acil al desarrollar software hacerlo de manera secuencial y no lidiar con los problemas adicionales que conlleva hacerlo en paralelo.

En el contexto de los problemas de optimizaci´on, el proyecto [10] desarro-lla un framework que permite ejecutar instancias paralelas de un mismo c´odigo fuente con diferentes par´ametros de entrada en un cluster y llega incluso a parale-lizar la evaluaci´on de poblaciones en algoritmos gen´eticos. Se basa en JGA (Java Genetic Algorithms), framework para prototipado r´apido de algoritmos evolucio-narios. Tiene dos restricciones, la informaci´on debe ser auto-contenida y todos los objetos deben implementar la interfaz Serializable, este trabajo nos da una primera aproximaci´on sobre como se pueden ejecutar problemas de optimizaci´on de manera paralela, sin embargo la paralelizaci´on es desarrollada manualmente y lo que cambia en las ejecuciones son los conjuntos de datos con los cuales se ejecuta el programa.

De manera paralela a nuestro proyecto se estaba desarrollando el proyecto de grado [13] en el cual se genera una plataforma web para lanzar instancias de algoritmos de optimizaci´on, en la cual se eligen los par´ametros con los cuales se desea recorrer los espacios de b´usqueda, anterior a este proyecto estos par´ametros deb´ıan ser cambiados en archivos de configuraci´on y se ejecutaban secuencial-mente, el aporte de ´este proyecto consiste en facilitar la experiencia del usuario y mejorar los tiempos de respuesta. Este trabajo est´a relacionado con el nuestro ya que para mejorar los tiempos de respuesta se realiz´o la paralelizaci´on de la ejecuci´on de las instancias usando pool de threads, al elaborar esta paralelizaci´on en conjunto con el asesor com´un entre ambos proyectos David M´endez Acu˜na, se ide´o la forma de generalizar la paralelizaci´on de un ciclo for en java.

(30)

3.2.3. Estado del Arte

Una herramienta fundamental para nuestro desarrollo la Ingenier´ıa Orientada por Modelos, Heiderich en [5] nos muestra como los lenguajes de programaci´on evolucionan con el tiempo y cuando esto ocurre y se tienen peque˜nos proyectos es f´acil hacer los cambios manualmente en el c´odigo fuente, sin embargo nos expli-ca tambi´en como esta tarea se vuelve bastante complicada cuando hablamos de proyectos de gran envergadura, luego concluye explicando como el desarrollo de software orientado por modelos MDSD por sus siglas en ingl´es brinda una gran ayuda, en particular JaMoPP “Java Model Printer and Parser” es una herra-mienta de gran utilidad para estas situaciones ya que permite tomar un c´odigo fuente en Java, pasarlo a un modelo conforme con un metamodelo de java en EMF, el cual puede ser transformado usando herramientas como ATL o QVT-O y una vez se han hecho las transformaciones el mismo JaMoPP se encarga de la generaci´on del c´odigo fuente java del modelo con las transformaciones.

Entre las principales propiedades de JaMoPP tenemos primero que permite hacer parsing e imprimir c´odigo java, gracias a esto se convierte en una herra-mienta para que las herraherra-mientas de trasformaci´on M2M puedan hacer tras-formaciones T2T, en segundo lugar JaMoPP hace an´alisis de tipos del c´odigo fuente y establece enlaces, esto conlleva a que se pueda garantizar la correctitud de la sem´antica del c´odigo java generado y por ´ultimo JaMoPP fue generado usando EMFText lo cual permite que JaMoPP sea extendido extendiendo su metamodelo sin necesidad de modificar el c´odigo fuente, para nuestro trabajo fue fundamental el uso de JaMoPP ya que el primer paso es generar el modelo del c´odigo fuente que deseamos transformar lo cual se realiza automaticamente con JaMoPP, luego de esto viene una serie de transformaciones usando QVTO y por ultimo los modelos resultantes son transformados nuevamente en c´odigo java usando nuevamente JaMoPP.

3.3

Objetivo

Automatizar por medio transformaciones de modelos la conversi´on de un c´odigo fuente dise˜nado para trabajar de manera secuencial en uno que trabaje en paralelo usando Pools de Threads.

3.4

Alcance

La transformaci´on se har´a para ciclos for en la plataforma Java que tengan una variable de control, se anotar´a la variable de control del ciclo con la anotaci´on @Parallelize que se suministra al usuario y debe crearse en la aplicaci´on que se va a paralelizar.

3.5

Restricciones

(31)

24 3.6. Estrategia paralelizaci´on de algoritmos

Figura 3.1: Cadena de transformacion

3.6

Estrategia paralelizaci´

on de algoritmos

Como estrategia para paralelizar c´odigo java de una manera autom´atica se utiliza la Ingenier´ıa basada en modelos, para esto se debe aplicar una cadena de transformaci´on que ser´a explicada mas adelante en este documento con la cual se logra obtener un c´odigo fuente que puede correr en paralelo a partir de un c´odigo que corre secuencial, para este prop´osito se utilizan herramientas como JaMoPP, QVTO y anotaciones de JAVA.

3.6.1. Descripci´on de la cadena de transformaci´on

Para empezar la paralelizaci´on de c´odigo fuente partimos del c´odigo fuente java el cual para este trabajo est´a restringido a ciclos for con variable de control, el c´odigo que se desea paralelizar debe ser anotado con la anotaci´on Parallelize en la variable de control, all´ı se especifica en forma de argumentos cuantos th-reads se van a crear para la ejecuci´on en paralelo del c´odigo y en que variable se va a consolidar el resultado por medio de los argumentos threads y consolidate respectivamente.

Una vez el c´odigo se ha anotado se procede a la transformaci´on del c´odigo fuente a un modelo del programa conforme con el metamodelo de Java utilizando JaMoPP, posteriormente ´este modelo se transforma por medio de QVTo en otro modelo, el cual es conforme tambi´en con el metamodelo de java, luego de esto el modelo se transforma usando JaMoPP nuevamente, en c´odigo fuente Java que puede ejecutarse en paralelo utilizando la cantidad de threads que el usuario defini´o al momento de anotar el c´odigo.

3.6.2. Herramientas usadas en la implementaci´on QVT

QVT por sus siglas en ingl´es Query View Transformation, es el resultado de un RFP (Request For Proposal) que hizo en 2002 la OMG (Object Mana-gement Group), en este se hace un llamado para especificar un lenguaje que pueda expresar queries, vistas y transformaciones en modelos sobre la arqui-tectura de metamodelos MOF 2.0 (Meta-Object Facility). Como resultado se

(32)

dise˜naron tres sublenguajes complementarios como lo describe Jouault en [8], el primero de ellos es el core el cual es un lenguaje declarativo y ofrece las ba-ses para poder desarrollar el segundo lenguaje QVTR o QVT Relacional el cual extiende el core y brinda una sintaxis m´as sencilla, en este lenguaje se pue-den especificar transformaciones como un conjunto de relaciones entre modelos y se puede usar para modificar modelos existentes. El tercer sublenguaje es el QVTo o QVT Operacional [2], este lenguaje extiende el QVTR y le adiciona fun-cionalidad imperativa y OCL (Object Constraint Language), el prop´osito de este lenguaje es declarar de manera imperativa las relaciones y poderlas manipular e interactuar con ellas con estructuras, ciclos, condicionales, etc.

JaMoPP

JaMoPP es la abreviatura de Java Model Parser and Printer, como lo expo-nen sus creadores en [6] convierte java en un lenguaje de modelado gracias a lo siguiente:

Define un metamodelo completo en Ecore de Java el cual permite que los modelos que sean conformes con este metamodelo sean manipulados por la ma-yor´ıa de herramientas que usen Ecore y gracias a esto los modelos se pueden modificar, extender o reutilizar.

Define una sintaxis textual que es conforme con la especificaci´on de Java y gracias a esta genera un parser que permite generar modelos a partir de c´odigo fuente y un printer que permite imprimir c´odigo fuente java a partir de un mo-delo.

El metamodelo de Java refleja la sem´antica est´atica de Java con lo cual al momento de hacer el parse del c´odigo fuente java se generan las relaciones entre los elementos del modelo.

Anotaciones

En [1] Cazzola nos explica como los lenguajes han venido adaptando estra-tegias para adicionar metadata al c´odigo fuente y c´omo han venido utilizando esta metadata para diversos prop´ositos como extraer documentaci´on del c´odigo, perfilar la aplicaci´on para ejecutarse en una determinada arquitectura, para mo-dificar el c´odigo fuente o el comportamiento del c´odigo en tiempo de ejecuci´on, en Java en particular se puede anotar una clase o interfaz, una enumeraci´on, las mismas anotaciones, los objetos declarados al nivel de clase, los m´etodos de las clases, los par´ametros de los m´etodos, los constructores, las variables locales y los paquetes. Existen anotaciones predefinidas en el lenguaje las cuales tienen usos predeterminados y adicionalmente se pueden definir anotaciones en las cuales se debe especificar el alcance de las mismas, que elementos del c´odigo pueden anotar y que par´ametros pueden tener.

(33)

26 3.7. Validaci´on

Figura 3.2: Codigo fuente original

3.7

Validaci´

on

3.7.1. Ejemplo ilustrativo

Se va a describir como trabaja originalmente un programa desarrollado en Ja-va que dada una matriz de n´umeros enteros, la recorre y obtiene el m´aximo valor. En la figura 3.3 la parte del c´odigo que se va a paralelizar se encuentra en color rojo, se puede identificar la anotaci´on @Parallelize aplicada a la variable de control del ciclo en color verde y la variable de consolidaci´on definida en esta anotaci´on en color azul

En este ejemplo se recorre la matriz primero por las filas, por cada fila se recorre luego cada posici´on y se almacena el m´aximo valor en una variable 3.3.

Al transformar el c´odigo secuencial en un c´odigo en paralelo utilizando un pool de threads se requiere tener informaci´on sobre el c´odigo que se va a para-lelizar, una parte de esta informaci´on se puede obtener del c´odigo y otra parte debe ser suministrada por el usuario al momento de anotar el c´odigo fuente con la anotaci´on @Parallelize, en la figura 3.4 se encuentra la informaci´on sobre la fuente de donde proviene la informaci´on necesaria para la transformaci´on:

(34)

Figura 3.3: Recorrido de la matriz para encontrar el m´aximo

Figura 3.4: Fuentes de la informaci´on para la transformaci´on

La variable de consolidaci´on pasa de ser privada a ser publica y est´atica ver 2 en 3.5.

En la clase original se debe importar las clases java.util.concurrent.ExecutorService y java.util.concurrent.Executors ver 1 en 3.5.

Se debe crear una variable de tipo ExecutorService y se inicializa llamando el m´etodo newFixedThreadPool de la clase Executors con el n´umero de threads especificado en la anotaci´on Parallelize como par´ametro ver 3 en 3.5.

Se debe adicionalmente remover el contenido del ciclo que se est´a paralelizan-do y se crea una variable de tipo Runnable que se inicializa invocanparalelizan-do el m´etodo constructor de la nueva clase que se cre´o.

Luego se debe invocar el m´etodo execute de la variable de tipo Executor-Service que se cre´o anteriormente pasando como par´ametro la variable de tipo Runnable que se cre´o ver 4 en 3.5.

Despu´es del ciclo for se debe invocar el metodo shutdown de la variable de tipo ExecutorService y posteriormente se debe validar que todos los threads ha-yan finalizado ver 5 en 3.5.

Se crea una nueva clase con el mismo nombre de la clase original con a ter-minaci´on Thread que implementa la interfaz Runnable ver 1 en 3.6.

Esta nueva clase tiene como variables locales todas las variables que se usan en el ciclo a paralelelizar excepto la variable de consolidaci´on que se especific´o en la anotaci´on @Parallelize, la variable de control del ciclo que se est´a

(35)

paralelizan-28 3.8. Pruebas con escenario de Algoritmos de Optimizaci´on - SOFIA

Figura 3.5: Clase original modificada

do y las variables que sean declaradas dentro del ciclo ver 2 en 3.6..

La clase nueva debe tener un m´etodo constructor que inicialice todas las va-riables ver 3 en 3.6 y se debe crear un m´etodo run que contiene el cuerpo del ciclo que se est´a paralelizando de la clase original ver 4 y 5 en 3.6, la variable de consolidaci´on que se debe usar es la de la clase original que se convirti´o de privada en p´ublica y est´atica anteponi´endole el nombre de la clase original. Ej. ClaseOriginal.variableConsolidacion ver 6 en 3.6.

Una vez el c´odigo se ha transformado, el nuevo c´odigo generado es funcional para trabajar en paralelo usando un pool de threads.

3.8

Pruebas con escenario de Algoritmos de Optimizaci´

on

- SOFIA

Una de las pruebas de concepto que se hicieron fue la ejecuci´on del c´odigo fuente del proyecto SOFIA [13], se aplic´o la transformaci´on y el c´odigo gene-rado mejor´o los tiempos de ejecuci´on significativamente gracias a la ejecuci´on en paralelo as´ı como el hecho de estar corriendo en un ambiente de cluster en el Centro de Computaci´on Avanzada de la Facultad de Ingenier´ıa - MOX de la Universidad de los Andes.

(36)

Figura 3.6: Clase nueva generada

3.7 fue mas sencilla que el caso real de los algoritmos de optimizaci´on donde se observaron varias condiciones adicionales como:

1. En la clase que maneja los threads deben importarse todas las librer´ıas de la clase que se debe paralelizar.

2. Se requiere hacer un casting de una variable manualmente ya que no fue posible hacerlo en la transformaci´on.

3. A los m´etodos de la clase original que se usen dentro del ciclo for se les debe anteponer el nombre de la clase original para invocarlos desde la nueva clase. Se pudo evidenciar que en la ejecuci´on secuencial el tiempo de respuesta fue la sumatoria de los tiempos de ejecuci´on de todas las instancias, mientras que al ejecutarse en paralelo el tiempo de ejecuci´on fue el m´aximo de los tiempos de ejecuci´on entre todas las instancias que se ejecutaron.

As´ı: T ejecuci´onsecuencial = n X i=1 (ti) T ejecuci´onparalelo =m´nax i=1(ti)

Para pruebas realizadas en [13] los resultados de las ejecuciones de algoritmos de optimizaci´on fueron 3.7 :

(37)

30 3.8. Pruebas con escenario de Algoritmos de Optimizaci´on - SOFIA

Figura 3.7: Tiempos de ejecuci´on de las instancias

3.8.1. Ejemplo del c´odigo escrito por el programador:

package launcher; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Properties; import chart.printer.ChartPrinter; import common.utils.ExecutionLogger; import common.utils.ExecutionResults; import algorithm.SchedulingAlgorithm; import algorithm.impl.TrajectoryBasedAlgorithm; import launcher.adapters.ConfigurationAdapter;

public class ConfigurationFileLauncher {

// ---// Constants

public static final String CONFIGURATION_FILE = "./config/ configuration.properties";

public static final String WEB_CONFIGURATION_FILE = "./config/web-configuration.properties";

// ---// Constants

//

---private String userId;

private String executionId;

private String webLocation;

private String benchmark;

private int amountOfExecutionsPerInstance;

(38)

private String structure;

private String neighborCalculator;

private String modifier;

private String control;

private String gammaCalculator;

private String decodingStrategy;

private String considerTravelTimes;

private String considerSetupTimes;

private String showConfigurationTable;

private String showInitialSolutions;

private String showFinalSolutions;

private String showLog;

// ---// Methods

//

---public void launchSofia() throws Exception{

Properties webData = loadPropertiesFile(new File( WEB_CONFIGURATION_FILE));

webLocation = webData.getProperty("web-location");

Properties data = loadPropertiesFile(new File(CONFIGURATION_FILE) );

userId = data.getProperty("userId");

executionId = data.getProperty("executionId");

ArrayList<String> instancesToExecute = new ArrayList<String>();

// 04x04

for (int i = 1;i <= 10;i++) { String key = "04x04_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 05x05

for (int i = 1;i <= 10;i++) { String key = "05x05_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 07x07

for (int i = 1;i <= 10;i++) { String key = "07x07_";

if(i != 10)key += "0"; key += i;

(39)

32 3.8. Pruebas con escenario de Algoritmos de Optimizaci´on - SOFIA if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 10x10

for (int i = 1;i <= 10;i++) { String key = "10x10_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 15x15

for (int i = 1;i <= 10;i++) { String key = "15x15_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 20x20

for (int i = 1;i <= 10;i++) { String key = "20x20_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } }

benchmark = data.getProperty("benchmark");

amountOfExecutionsPerInstance = Integer.parseInt(data.getProperty ("amountOfExecutionsPerInstance"));

initialSolutionBuilder = data.getProperty("initialSolutionBuilder ");

structure = data.getProperty("structure");

neighborCalculator = data.getProperty("neighborCalculator"); gammaCalculator = data.getProperty("gammaCalculator"); modifier = data.getProperty("modifier");

control = data.getProperty("control");

decodingStrategy = data.getProperty("decodingStrategy"); Properties algorithmConfiguration = new Properties(); algorithmConfiguration.setProperty("scheduling. initialSolutionBuilder",initialSolutionBuilder); algorithmConfiguration.setProperty("scheduling.structureFactory", structure); algorithmConfiguration.setProperty("scheduling.neighborCalculator ",neighborCalculator);

(40)

algorithmConfiguration.setProperty("scheduling.gammaCalculator", gammaCalculator);

algorithmConfiguration.setProperty("scheduling.modifier",modifier );

algorithmConfiguration.setProperty("scheduling.control",control); algorithmConfiguration.setProperty("scheduling.parametersLoader",

control + "ParametersLoader");

algorithmConfiguration.setProperty("scheduling.decodingStrategy", decodingStrategy);

algorithmConfiguration.setProperty("params.iterations",data. getProperty("params.iterations"));

algorithmConfiguration.setProperty("params.tabulist-size",data. getProperty("params.tabulist-size"));

algorithmConfiguration.setProperty("params.neighborhodSize",data. getProperty("params.neighborhodSize"));

algorithmConfiguration.setProperty("params.T0",data.getProperty(" params.T0"));

algorithmConfiguration.setProperty("params.Tf",data.getProperty(" params.Tf"));

algorithmConfiguration.setProperty("params.k",data.getProperty(" params.k"));

algorithmConfiguration.setProperty("params.coolingFactor",data. getProperty("params.coolingFactor"));

algorithmConfiguration.setProperty("params.restarts",data. getProperty("params.restarts"));

algorithmConfiguration.setProperty("params.boltzmann",data. getProperty("params.boltzmann"));

algorithmConfiguration.setProperty("params.outerIterations",data. getProperty("params.outerIterations"));

algorithmConfiguration.setProperty("params.strategyLS",data. getProperty("params.strategyLS"));

algorithmConfiguration.setProperty("params.maxLSDepth",data. getProperty("params.maxLSDepth"));

algorithmConfiguration.setProperty("params.maxNeighbors",data. getProperty("params.maxNeighbors"));

algorithmConfiguration.setProperty("params.maxNumberImprovements"

,data.getProperty("params.maxNumberImprovements"));

algorithmConfiguration.setProperty("params.maxExecutionTime",data .getProperty("params.maxExecutionTime"));

algorithmConfiguration.setProperty("params.non-improving-in",data .getProperty("params.non-improving-in"));

algorithmConfiguration.setProperty("params.non-improving-out", data.getProperty("params.non-improving-out"));

considerTravelTimes = data.getProperty("betas.considerTravelTimes ");

considerSetupTimes = data.getProperty("betas.considerSetupTimes") ;

String gammaBKS = null;

if(gammaCalculator.equals(ConfigurationAdapter.CMAX)){ gammaBKS = ConfigurationAdapter.CMAX_BKS; }else if(gammaCalculator.equals(ConfigurationAdapter. MEAN_FLOW_TIME)){ gammaBKS = ConfigurationAdapter.MEAN_FLOW_TIME_BKS; }else if(gammaCalculator.equals(ConfigurationAdapter. TOTAL_FLOW_TIME)){ gammaBKS = ConfigurationAdapter.TOTAL_FLOW_TIME_BKS;

(41)

34 3.8. Pruebas con escenario de Algoritmos de Optimizaci´on - SOFIA

}

String currentBks = "gamma." + gammaBKS + ".bks.";

boolean travelTimesSelected = Boolean.parseBoolean( considerTravelTimes);

boolean setupTimesSelected = Boolean.parseBoolean(

considerSetupTimes);

if(!travelTimesSelected && !setupTimesSelected){ currentBks += "om";

}

else if(!travelTimesSelected &&setupTimesSelected){ currentBks += "om.s";

}

else if(travelTimesSelected && !setupTimesSelected){ currentBks += "om.tt";

}

else if(travelTimesSelected &&setupTimesSelected){ currentBks += "om.tt.s";

}

System.out.println("currentBks: " + currentBks); showConfigurationTable = data.getProperty("report.

consolidationTable");

showInitialSolutions = data.getProperty("report.gantt. initialsolutions");

showFinalSolutions = data.getProperty("report.gantt.bestsolutions ");

showLog = data.getProperty("report.gantt.log");

algorithmConfiguration.setProperty("report.consolidationTable", showConfigurationTable); algorithmConfiguration.setProperty("report.gantt.initialsolutions ",showInitialSolutions); algorithmConfiguration.setProperty("report.gantt.bestsolutions", showFinalSolutions);

algorithmConfiguration.setProperty("report.gantt.log",showLog); String time=""+ System.currentTimeMillis();

if(showLog.equals("true")){

ExecutionLogger.getInstance().setUseLogger(true);

ExecutionLogger.getInstance().initializeLogger (""+ time,userId); }

// Executing instances

for ( int i = 0;i < instancesToExecute.size();i++) {

String instance = instancesToExecute.get(i);

boolean hasOptimal = false;

if(instance.contains("04x04") ||instance.contains("05x05")) hasOptimal = true;

String problemFile = "./data/FilesIndex/" + instance.substring (0,5);

if(benchmark.equals("Parallel")) {

(42)

instance = instance.substring(0,5) + "x02_" + instance. substring(6,8);

}

problemFile += "/" + instance + ".properties";

Properties problem = loadPropertiesFile(new File(problemFile)); SchedulingAlgorithm algorithm = new TrajectoryBasedAlgorithm(

algorithmConfiguration,problem,currentBks,benchmark, hasOptimal);

ArrayList<ExecutionResults> results = new ArrayList< ExecutionResults>();

for(int j = 0;j < amountOfExecutionsPerInstance;j++) {

ExecutionResults result = algorithm.execute(instance, problemFile);

results.add(result); }

ChartPrinter.getInstance().addResults(results); }

File destinationFolder = new File("./results/" + userId);

if(!destinationFolder.exists()){ destinationFolder.mkdirs(); } if(showLog.equals("true")){ ExecutionLogger.getInstance().stopHandler(); } ChartPrinter.getInstance().printGlobalResultsHTML("./results/" + userId + "/experiment-results-" + executionId + ".html", "Log-execution-" + executionId + ".html");

communicateResultsToWeTear("./results/" + userId + "/experiment-results-" + executionId + ".html");

}

private void communicateResultsToWeTear(String path) { String webResult="";

try{

File stream = new File(path);

FileReader in = new FileReader(stream);

BufferedReader reader = new BufferedReader(in); String line= reader.readLine();

while (line != null) { webResult+= line+"\n"; line = reader.readLine(); } reader.close(); in.close(); System.out.println(webResult);

String data = URLEncoder.encode("id", "UTF-8") + "=" + URLEncoder. encode(executionId, "UTF-8");

data += "&" + URLEncoder.encode("result", "UTF-8") + "=" + URLEncoder.encode(webResult, "UTF-8");

URL url = new URL(webLocation);

URLConnection conn = url.openConnection(); conn.setDoInput(true);

(43)

36 3.8. Pruebas con escenario de Algoritmos de Optimizaci´on - SOFIA

conn.setUseCaches(false);

conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

conn.setRequestProperty("Content-Length", ""+ (webResult.length()+ executionId.length()));

DataOutputStream wr= new DataOutputStream(conn.getOutputStream()); wr.writeBytes(data);

BufferedReader rd = new BufferedReader(new InputStreamReader(conn. getInputStream()));

String linew;

while ((linew = rd.readLine()) != null) {

// System.out.println(linew);

} wr.close(); rd.close();

}

catch(Exception e){ e.printStackTrace();

} }

/**

* Loads the information contained in the properties file located * in the path given in the constant CONFIGURATION_FILE

*

* @return data. A properties object containing the information in the file

* @throws IOException If any input/output error occurs */

public static Properties loadPropertiesFile(File propertiesFile)

throws IOException{

Properties data = new Properties();

FileInputStream in = new FileInputStream(propertiesFile ); data.load(in ); in.close( ); return data; } // ---// Main // ---/**

* Main method. Execution start * @param args. Execution arguments */

public static void main(String[] args) { ConfigurationFileLauncher launcher = new

ConfigurationFileLauncher(); try { launcher.launchSofia(); } catch (Exception e) { e.printStackTrace(); }

(44)

} }

En este programa que lanza las diferentes ejecuciones de los algoritmos de optimizaci´on se identific´o que el ciclo que se muestra a continuaci´on no tiene dependencias a si mismo y que cada instancia puede ser lanzada en paralelo:

for (int i = 0;i < instancesToExecute.size();i++) {

String instance = instancesToExecute.get(i);

boolean hasOptimal = false;

if(instance.contains("04x04") ||instance.contains("05x05")) hasOptimal = true;

String problemFile = "./data/FilesIndex/" + instance.substring (0,5);

if(benchmark.equals("Parallel")) {

problemFile += "x02";

instance = instance.substring(0,5) + "x02_" + instance. substring(6,8);

}

problemFile += "/" + instance + ".properties";

Properties problem = loadPropertiesFile(new File(problemFile)); SchedulingAlgorithm algorithm = new TrajectoryBasedAlgorithm(

algorithmConfiguration,problem,currentBks,benchmark, hasOptimal);

ArrayList<ExecutionResults> results = new ArrayList< ExecutionResults>();

for(int j = 0;j < amountOfExecutionsPerInstance;j++) {

ExecutionResults result = algorithm.execute(instance, problemFile);

results.add(result); }

ChartPrinter.getInstance().addResults(results); }

Para el desarrollador de este c´odigo fuente basta con anotar la variable de control del ciclo for que desea paralelizar de la siguiente manera:

for ( @Parallelize(threads="4",consolidate="control") int i = 0;i < instancesToExecute.size();i++)

En esta anotaci´on se parametriza en cuantos threads se quiere dividir la ejecuci´on del programa y en el caso de tener una variable en la cual se consoliden los resultados se especifica el nombre de la misma.

3.8.2. Resultado del c´odigo generado:

El c´odigo generado se divide en dos partes, se genera una nueva clase que ejecuta el contenido del ciclo que se eligi´o para paralelizar con threads y una

(45)

38 3.8. Pruebas con escenario de Algoritmos de Optimizaci´on - SOFIA

modificaci´on a la clase original en la cual se llama a la nueva clase que se genera:

Clase original modificada:

Los cambios a la clase original son los siguientes:

1. Se crea una variable de tipo ExecutorService y se inicia el pool de threads con el numero de threads especificado en la anotaci´on.

ExecutorService executor = Executors.newFixedThreadPool(4);

2. Si se especifica una variable de consolidaci´on en la anotaci´on ´esta debe convertirse en publica y est´atica:

public static String control;

3. El contenido o bloque del ciclo for que se anot´o cambia por una invocaci´on a la nueva clase encargada de ejecutar los threads y algunas instrucciones que se encargan de controlar la ejecuci´on de los mismos:

for ( int i = 0;i < instancesToExecute.size();i++) {

Runnable worker = newConfigurationFileLauncherThread(

amountOfExecutionsPerInstance,benchmark,algorithmConfiguration ,currentBks,i,instancesToExecute); executor.execute(worker); }executor.shutdown(); while (!executor.isTerminated()) { } package launcher; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Properties; import chart.printer.ChartPrinter; import common.utils.ExecutionLogger; import common.utils.ExecutionResults;

(46)

import algorithm.SchedulingAlgorithm; import algorithm.impl.TrajectoryBasedAlgorithm; import launcher.adapters.ConfigurationAdapter; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.lang.Runnable; import launcher.Parallelize;

public class ConfigurationFileLauncher {

ExecutorService executor = Executors.newFixedThreadPool(4);

// ---// Constants

public static final String CONFIGURATION_FILE = "./config/ configuration.properties";

public static final String WEB_CONFIGURATION_FILE = "./config/web-configuration.properties";

// ---// Constants

//

---private String userId;

private String executionId;

private String webLocation;

private String benchmark;

private int amountOfExecutionsPerInstance;

private String initialSolutionBuilder;

private String structure;

private String neighborCalculator;

private String modifier;

public static String control;

private String gammaCalculator;

private String decodingStrategy;

private String considerTravelTimes;

private String considerSetupTimes;

private String showConfigurationTable;

private String showInitialSolutions;

private String showFinalSolutions;

private String showLog;

// ---// Methods

//

---public void launchSofia() throws Exception{

Properties webData = loadPropertiesFile(new File( WEB_CONFIGURATION_FILE));

webLocation = webData.getProperty("web-location");

(47)

40 3.8. Pruebas con escenario de Algoritmos de Optimizaci´on - SOFIA

);

userId = data.getProperty("userId");

executionId = data.getProperty("executionId");

ArrayList<String> instancesToExecute = new ArrayList<String>();

// 04x04

for (int i = 1;i <= 10;i++) { String key = "04x04_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 05x05

for (int i = 1;i <= 10;i++) { String key = "05x05_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 07x07

for (int i = 1;i <= 10;i++) { String key = "07x07_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 10x10

for (int i = 1;i <= 10;i++) { String key = "10x10_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } } // 15x15

for (int i = 1;i <= 10;i++) { String key = "15x15_";

if(i != 10)key += "0"; key += i;

(48)

instancesToExecute.add(key); }

}

// 20x20

for (int i = 1;i <= 10;i++) { String key = "20x20_"; if(i != 10)key += "0"; key += i; if(data.getProperty(key).equals("true")){ instancesToExecute.add(key); } }

benchmark = data.getProperty("benchmark");

amountOfExecutionsPerInstance = Integer.parseInt(data.getProperty ("amountOfExecutionsPerInstance"));

initialSolutionBuilder = data.getProperty("initialSolutionBuilder ");

structure = data.getProperty("structure");

neighborCalculator = data.getProperty("neighborCalculator"); gammaCalculator = data.getProperty("gammaCalculator"); modifier = data.getProperty("modifier");

control = data.getProperty("control");

decodingStrategy = data.getProperty("decodingStrategy"); Properties algorithmConfiguration = new Properties(); algorithmConfiguration.setProperty("scheduling. initialSolutionBuilder",initialSolutionBuilder); algorithmConfiguration.setProperty("scheduling.structureFactory", structure); algorithmConfiguration.setProperty("scheduling.neighborCalculator ",neighborCalculator); algorithmConfiguration.setProperty("scheduling.gammaCalculator", gammaCalculator);

algorithmConfiguration.setProperty("scheduling.modifier",modifier );

algorithmConfiguration.setProperty("scheduling.control",control); algorithmConfiguration.setProperty("scheduling.parametersLoader",

control + "ParametersLoader");

algorithmConfiguration.setProperty("scheduling.decodingStrategy", decodingStrategy);

algorithmConfiguration.setProperty("params.iterations",data. getProperty("params.iterations"));

algorithmConfiguration.setProperty("params.tabulist-size",data. getProperty("params.tabulist-size"));

algorithmConfiguration.setProperty("params.neighborhodSize",data. getProperty("params.neighborhodSize"));

algorithmConfiguration.setProperty("params.T0",data.getProperty(" params.T0"));

algorithmConfiguration.setProperty("params.Tf",data.getProperty(" params.Tf"));

algorithmConfiguration.setProperty("params.k",data.getProperty(" params.k"));

algorithmConfiguration.setProperty("params.coolingFactor",data. getProperty("params.coolingFactor"));

Referencias

Documento similar

Habiendo organizado un movimiento revolucionario en Valencia a principios de 1929 y persistido en las reuniones conspirativo-constitucionalistas desde entonces —cierto que a aquellas

diabetes, chronic respiratory disease and cancer) targeted in the Global Action Plan on NCDs as well as other noncommunicable conditions of particular concern in the European

The part I assessment is coordinated involving all MSCs and led by the RMS who prepares a draft assessment report, sends the request for information (RFI) with considerations,

En este sentido, puede defenderse que, si la Administración está habilitada normativamente para actuar en una determinada materia mediante actuaciones formales, ejerciendo

Este curso se ha diseñado especialmente para guiar a los tutores clínicos de Medicina Intensiva en proporcionar un feedback, estructurado y.. efectivo, a los residentes durante

 Para recibir todos los números de referencia en un solo correo electrónico, es necesario que las solicitudes estén cumplimentadas y sean todos los datos válidos, incluido el

Por lo tanto, el objetivo de este tra- bajo es abordar el modelado basado en agentes desde el punto de vista de la Ingenier´ıa de Sistemas y Autom´atica y proponer una

La determinación molecular es esencial para continuar optimizando el abordaje del cáncer de pulmón, por lo que es necesaria su inclusión en la cartera de servicios del Sistema