El Procesamiento Distribuido y su aplicación al Tratamiento de Imágenes. Miguel Hernández Vázquez. Carlos Platero Dueñas

Tamaño: px
Comenzar la demostración a partir de la página:

Download "El Procesamiento Distribuido y su aplicación al Tratamiento de Imágenes. Miguel Hernández Vázquez. Carlos Platero Dueñas"

Transcripción

1 El Procesamiento Distribuido y su aplicación al Tratamiento de Imágenes Autor: Tutor: Miguel Hernández Vázquez Carlos Platero Dueñas

2

3 A mis padres y a mi hermano, que tanto me han ayudado y apoyado durante toda mi vida. A mis compañeros de laboratorio Laura, Isaac y Fran, gracias por haberme soportado durante todos estos meses. A mis amigos de la EUITI: Javi, Marina, Patricia, José, Pablo, Antonio, Palomo, Arturo, Bea, Rayito, Rafa, Iván, Lorenzo, Fran, Dani, Alberto sin ellos esto no hubiera sido lo mismo. A Carlos Platero, mi tutor del proyecto.

4

5 Los obstáculos son esas cosas que las personas ven cuando dejan de mirar sus metas E. JOSEPH COSSMAN No hay nada imposible para quién sabe esperar ANÓNIMO

6

7 Resumen En este proyecto vamos a tratar de dar una visión sobre los diferentes métodos que existen en la actualidad de procesamiento distribuido como pueden ser MPI, MatlabMPI, etc, así como las nuevas implementaciones para el lenguaje de programación C++: PVM y CORBA. Además, también nos centraremos en la aplicación de este procesamiento distribuido a las aplicaciones de renderizado y procesamiento de imágenes, en especial, en el campo de las imágenes médicas. El proyecto se ha realizado dentro del Grupo de Visión Artificial de la Escuela Universitaria de Ingeniería Técnica Industrial (EUITI). Se finalizó en el año 2005.

8

9 Abstract In this project we will try to give a vision on the different methods that exist at the present time of distributed processing - as they can be MPI, MatlabMPI, etc, as well as the new implementations for the programming language C++: PVM AND CORBA. Also, we will also center ourselves in the application from this distributed processing to the renderizado applications and image processing, especially, in the field of the medical images. The project has been carried out inside the Group of Artificial Vision of the University School of Engineering Industrial technique (EUITI). You concluded in the year 2005.

10

11 1 INTRODUCCIÓN OBJETIVOS SUMARIO DEL PROYECTO ESTADO DE LA TÉCNICA INTRODUCCIÓN AL PROCESAMIENTO DISTRIBUIDO VENTAJAS DEL PROCESAMIENTO DISTRIBUIDO DESVENTAJAS DEL PROCESAMIENTO DISTRIBUIDO OTRAS VENTAJAS ASOCIADAS AL PROCESAMIENTO DISTRIBUIDO QUÉ ES UN CLUSTER? CARACTERÍSTICAS DE UN CLUSTER CATALOGACIÓN DE LOS CLUSTERS TIPOS DE CLUSTERS CLUSTERS DE ALTO RENDIMIENTO (HP) CLUSTERS DE ALTA DISPONIBILIDAD (HA)...27

12 2.8.3 CLUSTERS DE ALTA CONFIABILIDAD (HR) PROCESAMIENTO DISTRIBUIDO CON MPI QUÉ ES MPI? OBJETIVOS Y LIMITACIONES DE MPI ESTRUCTURA BÁSICA DE LOS PROGRAMAS MPI LA COMUNICACIÓN EN MPI: COMUNICACIÓN PUNTO A PUNTO MODELOS DE COMUNICACIÓN MODOS DE ENVÍO EN MPI COMUNICACIÓN BÁSICA RECEPCIÓN POR ENCUESTA TIPOS DE DATOS MANEJADOS POR MPI ETIQUETAS Y COMUNICADORES EN MPI OPERACIONES COLECTIVAS EN MPI BARRERAS DE SINCRONIZACIÓN BROADCAST (DIFUSIÓN) GATHER (RECOLECCIÓN) SCATTER (DISTRIBUCIÓN) REDUCCIÓN COMUNICACIÓN TODOS CON TODOS (ALL-TO- ALL) MODULARIDAD INSTALACIÓN Y CONFIGURACIÓN DE MPICH INSTALACIÓN CONFIGURACIÓN... 52

13 3.10GENERACIÓN DE APLICACIONES MPI CON VISUAL STUDIO C UN EJEMPLO CONCRETO PROCESAMIENTO DISTRIBUIDO DE IMÁGENES GENÉRICO CON VTK QUÉ ES VTK? ARQUITECTURA DE VTK EL NÚCLEO DE C LA CAPA DE INTERPRETACIÓN GRAPHICS MODEL LA VENTANA DE RENDERIZADO RENDERS, MAPPERS Y PROPS RENDERIZADO 3D DE DATOS GEOMÉTRICOS RENDERIZADO 3D DE DATOS VOLUMÉTRICOS COMBINACIÓN DE LA GEOMETRÍA Y LAS LUCES RENDERIZADO DE DATOS 2D LUCES, CÁMARAS E INTERACTUACIÓN DE LOS DIFERENTES OBJETOS VISUALIZATION MODEL ARQUITECTURA DEL PIPELINE LOS DATA OBJECTS LOS PROCESS OBJECTS EJEMPLOS PROCESAMIENTO DE LAS IMÁGENES CON VTK

14 4.7 CREACIÓN DE UNA APLICACIÓN GRÁFICA CON VTK GENERACIÓN DE PROYECTOS MEDIANTE VTK EJECUCIÓN DE LAS APLICACIONES VTK UTILIZACIÓN DE VTK CON MPI UN EJEMPLO CONCRETO PROCESAMIENTO DISTRIBUIDO DE LAS IMÁGENES GENÉRICO CON MATLAB QUÉ ES MATLABMPI? REQUISITOS DEL SISTEMA INSTALACIÓN Y EJECUCIÓN IMPLEMENTACIÓN DE UN PROGRAMA DE MATLABMPI LANZAMIENTO Y ARCHIVOS DE ENTRADA/SALIDA MANEJO DE LOS ERRORES EJECUCIÓN DE MATLABMPI SOBRE LINUX EJECUCIÓN DE MATLABMPI SOBRE MacOSX EJECUCIÓN DE MATLABMPI SOBRE PC INSTALACIÓN EN PC (AUTÓNOMO) INSTALACIÓN EN PC Y UN CLUSTER DE LINUX INSTALACIÓN EN PC Y UN CLUSTER DE PC s RESOLUCIÓN DE PROBLEMAS OPTIMIZACIONES PARA UN MEJOR RENDIMIENTO EJECUCIÓN POR LOTES OTRAS CARACTERÍSTICAS.. 129

15 5.13DIAGNÓSTICO Y RESOLUCIÓN DE PROBLEMAS PASOS A SEGUIR EN LA EJECUCIÓN DE LAS APLICACIONES DE MATLABMPI CONSEJOS PARA LOS USUARIOS ARCHIVOS ANCHO DE BANDA CONCLUSIONES Y PRÓXIMOS DESARROLLOS UN EJEMPLO PRÁCTICO: APLICACIÓN PARALELA PARA EL FILTRADO DE IMÁGENES PROCESAMIENTO DISTRIBUIDO DE LAS IMÁGENES GENÉRICO CON PARAVIEW QUÉ ES PARAVIEW? CARACTERÍSTICAS DE PARAVIEW OBJETIVO DE PARAVIEW INSTALACIÓN DE PARAVIEW CONFIGURACIÓN DE PARAVIEW EJECUCIÓN SOBRE UNIX EJECUCIÓN SOBRE WINDOWS FICHEROS SOPORTADOS POR PARAVIEW TIPOS DE DATOS ADMITIDOS POR PARAVIEW PRINCIPALES COMANDOS UTILIZADOS POR PARAVIEW PARAVIEW CON MPI.. 160

16 7 RENDERIZACIÓN DE UNA NEURONA INTRODUCCIÓN WIREFRAME RENDER SÓLIDO SOMBREADO GOURAUD PSEUDOCÓDIGO PARA EL SOMBREADO GOURAUD VENTAJAS E INCONVENIENTES SOMBREADO PHONG PSEUDOCÓDIGO PARA EL SOMBREADO PHONG VENTAJAS E INCONVENIENTES RADIOSIDAD PARALELISMO EN EL PROCESO DE RENDERIZACIÓN EL PARALELISMO FUNCIONAL EL PARALELISMO DE DATOS EL PARALELISMO TEMPORAL MÉTODOS HÍBRIDOS CONCEPTOS ALGORÍTMICOS EJEMPLO: UNA POSIBLE OPCIÓN DE RENDERIZACIÓN DE UNA NEURONA Y SU POSTERIOR RECONSTRUCCIÓN 3D CÓDIGO FUENTE PROCESAMIENTO DISTRIBUIDO CON C++ 188

17 8.1 BREVE INTRODUCCIÓN A C ESTÁNDARES PARA LA PROGRAMACIÓN PARALELA EN C EL ESTÁNDAR MPI EL ESTÁNDAR PVM EL ESTÁNDAR CORBA EL PROCESAMIENTO DISTRIBUIDO EN C++ A TRAVÉS DEL ESTÁNDAR PVM INTRODUCCIÓN A PVM QUÉ ES PVM? VENTAJAS DE USO DE PVM DESVENTAJAS DEL USO DE PVM INSTALACIÓN DE PVM REQUISITOS NECESARIOS PARA TRABAJAR CON PVM INSTALACIÓN DE PVM EN LINUX CONFIGURACIÓN DE PVM PVM SOBRE UNA ÚNICA MÁQUINA FÍSICA PVM SOBRE VARIAS COMPUTADORAS EJECUCIÓN DE APLICACIONES PVM COMANDOS Y FUNCIONES MÁS IMPORTANTES DE PVM COMANDOS FUNCIONES FUNCIONES DE CONTROL DE PROCESOS FUNCIONES DE INFORMACIÓN FUNCIONES DE CONFIGURACIÓN DE GRUPOS

18 FUNCIONES DE EMPAQUETAMIENTO DE DATOS Y CONTROL DE BUFFERS FUNCIONES DE ENVÍO DE MENSAJES FUNCIONES DE RECEPCIÓN DE MENSAJES PASOS PARA REALIZAR LA PARALELIZACIÓN DE UN PROGRAMA USANDO PVM. EJEMPLOS EJEMPLO 1: COMUNICACIÓN MAESTRO ESCLAVO PROGRAMA MAESTRO PROGRAMA ESCLAVO ARCHIVO MAKEFILE EXPLICACIÓN DEL PROGRAMA ANTERIOR EJEMPLO 2: PROGRAMA DE SUMA CABECERAS COMUNES PROGRAMA MAESTRO PROGRAMA ESCLAVO ARCHIVO MAKEFILE EXPLICACIÓN DEL PROGRAMA EL PROCESAMIENTO DISTRIBUIDO EN C++ A TRAVÉS DEL ESTÁNDAR CORBA INTRODUCCIÓN OBJETIVOS DE CORBA VENTAJAS DE CORBA DESARROLLOS DE CORBA EL ORB DE CORBA ESTRUCTURA DE UN ORB CORBA INVOCACIÓN DE MÉTODOS CORBA ESTÁTICOS CONTRA DINÁMICOS EL LADO DEL SERVIDOR DE CORBA. EL ADAPTADOR DE OBJETOS

19 INICIALIZACIÓN DE CORBA IDL Y EL REPOSITORIO DE INTERFACES EL IDL DE CORBA Y SU ESTRUCTURA EL REPOSITORIO DE INTERFACES EL ELNGUAJE IDL CONSIDERACIONES ACERCA DEL MARSHALLING COMUNICACIÓN VÍA CORBA IMPLEMENTACIÓN DE OBJETOS CORBA EL SERVICIO DE CICLO DE VIDA DE OBJETOS DE CORBA EL SERVICIO DE EVENTOS DE CORBA CONCLUSIONES Y LÍNEAS DE MEJORA CONCLUSIONES SOBRE MPI MPI CON VTK Y PARAVIEW PROCESAMIENTO DISTRIBUIDO CON MATLAB PROCESAMIENTO DISTRIBUIDO CON C LÍNEAS DE MEJORA BIBLIOGRAFÍA

20

21 1 Introducción La resolución de problemas mediante el procesamiento distribuido no es nuevo; de hecho esta basado en el viejo y conocido método de divide y vencerás utilizado para resolver problemas matemáticos, físicos o cualquier tipo de problema de carácter general. Un sistema distribuido es un conjunto de computadoras conectadas en red que le dan la sensación al usuario de ser una sola computadora. A pesar que agregar complejidad al software y disminuir los niveles de seguridad, los sistemas de procesamiento distribuidos brindan una buena relación precio-desempeño y pueden aumentar su tamaño de manera gradual al aumentar la carga de trabajo. GVA ELAI UPM PFC

22 Introducción Miguel Hernández Vázquez El objetivo principal del paralelismo es el reducir el número de ciclos de ejecución de un programa, en relación al número de procesadores que existen en el sistema. 1.1 OBJETIVOS Los objetivos que persigue el proyecto son dar una visión más en profundidad de lo que entendemos por procesamiento distribuido: el conocimiento y manejo de las implementaciones existentes a la hora de realizar este procesamiento distribuido, como pueden ser MPI y MatlabMPI; la aplicación de estas diversas técnicas de procesamiento distribuido al tratamiento y procesado de imágenes; y por último, dar una introducción a las implementaciones existentes para desarrollar el procesamiento distribuido en otros lenguajes, como es el lenguaje C++: PVM y CORBA. 1.2 SUMARIO DEL PROYECTO Este proyecto está compuesto por nueve capítulos. En el segundo capítulo veremos el estado actual de la técnica de procesamiento distribuido y una serie de conceptos y definiciones previas. En el tercer capítulo introduciremos el procesamiento distribuido a través de la implementación MPI / MPICH, así como sus principales características y ejemplos. En el cuarto capítulo introduciremos las librerías de visualización VTK. En el quinto capítulo introduciremos el procesamiento distribuido a través de Matlab, en la implementación MatlabMPI. 12 GVA-ELAI-UPM PFC

23 Miguel Hernández Vázquez Introducción En el sexto capítulo introduciremos las librerías de visualización Paraview. En el séptimo capítulo veremos una aplicación concreta de este procesamiento distribuido a la hora de realizar la renderización de una neurona. En el octavo capítulo daremos una introducción al procesamiento distribuido en C++, e intentaremos dar una visión de las diferentes implementaciones para lograrlo. En el noveno capitulo se exponen las conclusiones y líneas de mejora del proyecto, y en el décimo la bibliografía. GVA ELAI UPM PFC

24 Introducción Miguel Hernández Vázquez 14 GVA-ELAI-UPM PFC

25 2 Estado de la Técnica En este primer capítulo vamos a tratar de dar una visión general de lo que llamamos procesamiento distribuido, así como sus principales características. En los capítulos siguientes veremos en mayor profundidad los diferentes métodos que existen para llevar a cabo la implementación del procesamiento distribuido en el tratamiento genérico de imágenes. GVA ELAI UPM PFC

26 Estado de la Técnica Miguel Hernández Vázquez 2.1 INTRODUCCIÓN AL PROCESAMIENTO DISTRIBUIDO Un sistema distribuido es un conjunto de computadoras conectadas en red de forma que le da la sensación al usuario de ser una sola computadora. Estos sistemas brindan una serie de ventajas: compartición de recursos, la concurrencia, alta escalabilidad, y tolerancia a fallos. Los sistemas de procesamiento distribuidos brindan una buena relación precio-desempeño y pueden aumentar su tamaño de manera gradual al aumentar la carga de trabajo. 2.2 VENTAJAS DEL PROCESAMIENTO DISTRIBUIDO Entre las principales ventajas que presenta el procesamiento distribuido encontramos las siguientes: 1. Economía: la relación precio rendimiento es mayor que en los sistemas centralizados sobretodo cuando lo que se buscan son altas prestaciones. 2. Velocidad: llega un momento en el que no se puede encontrar un sistema centralizado suficientemente potente, con los sistemas distribuidos siempre se podrá encontrar un sistema más potente uniendo esos mismos nodos. Se han hecho comparativas y los sistemas distribuidos especializados en cómputo han ganado a los mayores mainframes. 3. Distribución de máquinas: podemos tener unas máquinas inherentemente distribuidas por el tipo de trabajo que realizan. 4. Alta disponibilidad: cuando una máquina falla no tiene que caer todo el sistema sino que este se recupera de las caídas y sigue funcionando con quizás algo menos de velocidad. 16 GVA-ELAI-UPM PFC

27 Miguel Hernández Vázquez Estado de la Técnica 5. Escalabilidad: puedes empezar un cluster con unas pocas máquinas y según se descubre que la carga es elevada para el sistema, se añaden más máquinas, no hace falta tirar las máquinas antiguas ni inversiones iniciales elevadas para tener máquinas suficientemente potentes. 6. Comunicación: los ordenadores necesariamente están comunicados, para el correcto y eficaz funcionamiento del cluster se crean unas nuevas funcionalidad es avanzadas de comunicación. Estas nuevas primitivas de comunicación pueden ser usadas por los programas y por los usuarios para mejorar sus comunicaciones con otras máquinas. 7. Sistema de ficheros con raíz única: este sistema de ficheros hace que la administración sea más sencilla (no hay que administrar varios discos independientemente) y deja a cargo del sistema varias de las tareas. 8. Capacidad de comunicación de procesos y de intercambio de datos universal: podemos enviar señales a cualquier proceso del cluster, así mismo podemos hacer trabajo conjunto con cualquier proceso e intercambiar con los datos, por lo tanto podríamos tener a todos los procesos trabajando en un mismo trabajo. Figura 2.1: Sistemas distribuidos. Escalabilidad de servicios GVA ELAI UPM PFC

28 Estado de la Técnica Miguel Hernández Vázquez 2.3 DESVENTAJAS DEL PROCESAMIENTO DISTRIBUIDO La principal desventaja de estos sistemas es la complejidad que implica su creación. Básicamente se tienen todos los problemas que se puedan tener en un nodo particular pero escalados. Existen varias desventajas asociadas a las ventajas anteriormente reseñadas: 1. Alta disponibilidad: podemos conseguir alta disponibilidad pues al tener varios nodos independientes, hay muchas menos posibilidades de que caigan todos a la vez. Pero esto por sí sólo no nos da alta disponibilidad. Tenemos que implantar los mecanismos necesarios para que cuando una máquina caiga, se sigan dando todos los servicios. 2. Escalabilidad: el problema es que un mayor número de nodos suele implicar más comunicación, por lo que tenemos que diseñar un sistema lo más escalable posible. 3. Comunicación: un cluster tiene más necesidades de comunicación que los sistemas normales por lo tanto tenemos que crear nuevos métodos de comunicación lo más eficientes posibles. 4. Sistemas de ficheros con raíz única: tenemos que independizar los sistemas de ficheros distintos de cada uno de los nodos para crear un sistema de ficheros general. 5. Capacidad de comunicación de procesos y de intercambio de datos universal: para conseguir este objetivo necesitamos una forma de distinguir unívocamente cada proceso del cluster. La forma más sencilla es dando a cada proceso un PID único, que llamaremos CPID (cluster process ID). Este CPID podría estar formado por el número de nodo y el número de proceso dentro de ese nodo. Una vez podemos direccionar con que proceso queremos comunicarnos, para enviar señales necesitaremos un sencillo mecanismo de comunicación y seguramente el mismo sistema operativo en el otro extremo que entienda las señales. Para compartir datos, podemos enviarlos por la red o podemos crear memoria compartida a lo largo del cluster. 18 GVA-ELAI-UPM PFC

29 Miguel Hernández Vázquez Estado de la Técnica 2.4 OTRAS VENTAJAS ASOCIADAS AL PROCESAMIENTO DISTRIBUIDO Otra ventaja de los sistemas distribuidos es que cumple con todos los criterios de transparencia. Pero conseguir estos criterios implica ciertos mecanismos que se tienen que implementar: 1. Transparencia de acceso: Implica tener que mantener el viejo sistema para el nuevo cluster, por ejemplo mantener un árbol de directorios usual para manejar todos los dispositivos de almacenamiento del cluster. No se tienen que romper las APIs para introducir las nuevas funcionalidades. 2. Transparencia de localización: A nivel más bajo tenemos que implantar una forma de conocer donde se encuentran los recursos, tradicionalmente se han usado servidores centralizados que lo sabían todo, ahora ya se va consiguiendo que esta información se distribuya por la red. 3. Transparencia de concurrencia: Se han desarrollado varios métodos para conseguirlo. El mayor problema es la desincronización de los relojes pues es muy complejo que todos los relojes hardware lleven exactamente la misma temporización por tanto algunos ordenadores ven los acontecimientos como futuros o pasados respecto a otros ordenadores. 4. Transparencia de replicación: Básicamente el problema es que el sistema sepa que esas réplicas están ahí y mantenerlas coherentes y sincronizadas. También tiene que activar los mecanismos necesarios cuando ocurra un error en un nodo. 5. Transparencia de fallos: Aunque existan fallos el sistema seguirá funcionando. Las aplicaciones y los usuarios no sabrán nada de estos fallos o intentarán ser mínimamente afectados, como mucho, el GVA ELAI UPM PFC

30 Estado de la Técnica Miguel Hernández Vázquez sistema funcionará más lentamente. Este punto está muy relacionado con la transparencia de replicación. 6. Transparencia de migración: Se tienen que solucionar problemas sobre las decisiones que se toman para migrar un proceso, hay que tener en cuenta las políticas de migración, ubicación, etc. Además se tienen que ver otros aspectos prácticos como si al nodo al que se va se puede encontrar los recursos que se necesitan, etc. La aplicación no tiene que saber que fue migrada. 7. Transparencia para los usuarios: Implica una buena capa de software que de una apariencia similar a capas inferiores distintas. 8. Transparencia para programas: La más compleja. Implica que los programas no tienen porque usar llamadas nuevas al sistema para tener ventaja del cluster. 2.5 QUÉ ES UN CLUSTER? De forma genérica, podemos definir un cluster como un conjunto de máquinas unidas por una red de comunicación trabajando por un objetivo conjunto. Según el tipo puede ser dar alta disponibilidad, alto rendimiento etc... Sin embargo no existe una definición estricta, por lo que cada autor puede tener diferente concepto sobre la noción de cluster: Un cluster consiste en un conjunto de máquinas y un servidor de cluster dedicado, para realizar los relativamente infrecuentes accesos a los recursos de otros procesos, se accede al servidor de cluster de cada grupo del libro Operating System Concepts de Silberschatz Galvin. 20 GVA-ELAI-UPM PFC

31 Miguel Hernández Vázquez Estado de la Técnica Un cluster es la variación de bajo precio de un multiprocesador masivamente paralelo (miles de procesadores, memoria distribuida, red de baja latencia), con las siguientes diferencias: cada nodo es una máquina quizás sin algo del hardware (monitor, teclado, ratón, etc.), el nodo podría ser SMP o PC. Los nodos se conectan por una red de bajo precio como Ethernet o ATM aunque en clusters comerciales se pueden usar tecnologías de red propias. El interfaz de red no está muy acoplado al bus I/O. Todos los nodos tienen disco local. Cada nodo tiene un sistema operativo UNIX con una capa de software para soportar todas las características del cluster del libro Scalable Parallel Computing de Kai Hwang y Khiwei Xu. Es una clase de arquitectura de computador paralelo que se basa en unir máquinas independientes cooperativas integradas por medio de redes de interconexión, para proveer un sistema coordinado, capaz de procesar una carga del autor Dr Thomas Sterling. 2.6 CARACTERÍSTICAS GENERALES DE UN CLUSTER Para crear un cluster se necesitan al menos dos nodos. Una de las características principales de estas arquitecturas es que exista un medio de comunicación (red) donde los procesos puedan migrar para computarse en diferentes estaciones paralelamente. Un solo nodo no cumple este requerimiento por su condición de aislamiento para poder compartir información. Las arquitecturas con varios procesadores en placa tampoco son consideradas clusters, bien sean máquinas SMP o mainframes debido a que el bus de comunicación no suele ser de red, sino interno. Podemos resumir las características de un cluster en las siguientes: 1. Un cluster consta de 2 o más nodos. Los nodos necesitan estar conectados para llevar a cabo su misión. GVA ELAI UPM PFC

32 Estado de la Técnica Miguel Hernández Vázquez 2. Los nodos de un cluster están conectados entre sí por un canal de comunicación funcional. 3. Los clusters necesitan software especializado. Existen varios tipos de software que pueden conformar un cluster: Software a nivel de aplicación, es decir, software generado por bibliotecas especiales dedicadas a clusters. Estas bibliotecas de carácter general que permiten la abstracción de un nodo a un sistema conjunto, permitiendo crear aplicaciones en un entorno distribuido de manera lo más abstracta posible. Este tipo de software suele generar elementos de proceso del tipo rutinas, procesos o tareas, que se ejecutan en cada nodo del cluster y se comunican entre sí a través de la red. Software a nivel de sistema. Este tipo de software se sitúa a nivel de sistema, suele estar implementado como parte del sistema operativo de cada nodo, o ser la totalidad de este. Es más crítico y complejo, por otro lado suele resolver problemas de carácter más general que los anteriores y su eficiencia, por norma general, es mayor. Figura 2.2: Cluster a nivel de sistema y a nivel de aplicación 22 GVA-ELAI-UPM PFC

33 Miguel Hernández Vázquez Estado de la Técnica 4. Dependiendo del tipo de software, el sistema puede estar más o menos acoplado. Entendemos por acoplamiento del software a la integración que tengan todos los elementos software que existan en cada nodo. Gran parte de la integración del sistema la produce la comunicación entre los nodos, y es por esta razón por la que se define el acoplamiento; otra parte es la que implica cómo de crítico es el software y su capacidad de recuperación ante fallos. Aquí hay que hacer un pequeño inciso para decir que todo esto depende de si el sistema es centralizado o distribuido. En cualquier caso, el acoplamiento del software es una medida subjetiva basada en la integración de un sistema cluster a nivel general. En este punto podemos distinguir tres tipos de acoplamiento: Acoplamiento fuerte: El software que entra en este grupo es software cuyos elementos se interrelacionan mucho unos con otros, y hacen la mayoría de las funcionalidades del cluster de manera altamente cooperativa. Un ejemplo de este tipo de acoplamiento son los clusters SSI. Acoplamiento medio: A este grupo pertenece un software que no necesita un conocimiento tan exhaustivo de todos los recursos de otros nodos, pero que sigue usando el software de otros nodos para aplicaciones de muy bajo nivel. Un ejemplo de este tipo de acoplamiento serían los clusters openmosix. Acoplamiento débil: Son los casos en los que los programas se dividen en diversos nodos y por tanto se necesitan pero que no están a un nivel tan bajo. Generalmente se basan en aplicaciones construidas por bibliotecas preparadas para aplicaciones distribuidas, agrupadas en un conjunto de aplicaciones específicos que generan el cluster en sí: PVM, MPI, CORBA, RPC, etc. Por sí mismos no funcionan y hay que dotarles de una estructura superior que utilice las capacidades del cluster para que éste funcione. GVA ELAI UPM PFC

34 Estado de la Técnica Miguel Hernández Vázquez 5. Todos los elementos del cluster trabajan para cumplir una funcionalidad conjunta, sea esta la que sea. Es la funcionalidad la que caracteriza el sistema. 2.7 CATALOGACIÓN DE LOS CLUSTERS En general la catalogación de los clusters se hace en base a cuatro factores de diseño bastante ortogonales entre sí: Acoplamiento: este factor ya lo hemos analizado en el punto anterior. Es, quizás, el factor más importante a la hora de catalogar un cluster. Control: El parámetro de control implica el modelo de gestión que propone el cluster. Este modelo de gestión hace referencia a la manera de configurar el cluster y es dependiente del modelo de conexionado o colaboración que surgen entre los nodos. Puede ser de dos tipos: I. Centralizado: en un modelo centralizado, se hace uso de un nodo llamado maestro desde el cual se puede configurar el comportamiento de todo el sistema. Tiene la ventaja de poder realizar una mejor gestión del cluster. II. Descentralizado: en un modelo distribuido cada nodo debe administrarse y gestionarse en un principio por sí mismo, aunque también pueden ser gestionados mediante aplicaciones de más alto nivel de manera centralizada. Es propio de sistemas distribuidos. Tiene la ventaja de que presenta más tolerancia a fallos como sistema global, y como 24 GVA-ELAI-UPM PFC

35 Miguel Hernández Vázquez Estado de la Técnica desventajas que la gestión y administración de los equipos requiere más tiempo. Homogeneidad: Se entiende por homogeneidad del cluster a la homogeneidad de los equipos y recursos que conforman a éste. Existen dos tipos de clusters: I. Homogéneos: formados por equipos de la misma arquitectura. Todos los nodos tienen una arquitectura y recursos similares, de manera que no existen muchas diferencias entre cada nodo. II. Heterogéneos: formados por nodos con distinciones que pueden estar en los siguientes puntos: Tiempos de acceso distintos, arquitectura distinta, sistema operativo distinto, rendimiento de los procesadores o recursos sobre una misma arquitectura. Seguridad 2.8 TIPOS DE CLUSTERS Existen tres tipos fundamentales de clusters: clusters de ALTO RENDIMIENTO (HP); clusters de ALTA DISPONIBILIDAD (HA); y, por último, clusters de ALTA CONFIABILIDAD (HR). GVA ELAI UPM PFC

36 Estado de la Técnica Miguel Hernández Vázquez CLUSTERS DE ALTO RENDIMIENTO (HP) Los clusters de alto rendimiento han sido creados para compartir el recurso más valioso de un ordenador, es decir, el tiempo de proceso. Generalmente se utilizan en ambientes científicos, o en grandes empresas donde se utilizan para la compilación o renderización. Cualquier operación que necesite altos tiempos de CPU y millones de operaciones puede ser implementada en un cluster de alto rendimiento, siempre que se encuentre un algoritmo que sea paralelizable. Existen clusters que pueden ser denominados de alto rendimiento tanto a nivel de sistema como a nivel de aplicación. A nivel de sistema tenemos OpenMosix, mientras que a nivel de aplicación se encuentran otros como MPI, PVM, Beowulf y otros muchos. La misión de este tipo de clusters es mejorar el rendimiento en la obtención de la solución de un problema. Esto supone que cualquier cluster que haga que el rendimiento del sistema general aumente respecto al de uno de los nodos individuales puede ser considerado cluster de alto rendimiento. Generalmente, los problemas que se le plantean a un ordenador, suelen ser de carácter computacional. Se podría definir estos sistemas como sistemas distribuidos (en cada nodo) en los cuales se resuelve de manera distribuida un problema de cómputo. Generalmente estos problemas de cómputo suelen estar ligados a problemas matemáticos relativos a problemas científicos, renderizaciones de gráficos, compilación de programas, compresión de cualquier tipo, descifrado de códigos, rendimiento del sistema operativo, etc. Las técnicas utilizadas dependen de a qué nivel trabaje nuestro cluster. Los clusters implementados a nivel de aplicación, no suelen implementar balanceo de carga; suelen basar todo su funcionamiento en una política de localización que sitúa las tareas en los diferentes nodos del cluster, y las comunica mediante las librerías abstractas. Resuelven problemas de cualquier tipo de los que se han visto anteriormente, pero, se deben diseñar y codificar aplicaciones propias para cada tipo para poderlas utilizar dentro de estos clusters. Por otro lado están los sistemas de alto rendimiento implementados a nivel de sistema. Estos clusters basan todo su funcionamiento en comunicación y colaboración de los nodos a nivel de sistema operativo, lo que implica generalmente que son clusters de nodos de la misma arquitectura y que basan su funcionamiento en compartición de recursos a cualquier nivel, balanceo de la carga de manera dinámica, funciones de scheduling especiales y otros tantos factores que componen el sistema. Se intentan acercar al sistema SSI; el problema esta en que para obtener un sistema SSI hay que ceder en el apartado de compatibilidad con los sistemas actuales, por lo cual se suele llegar a un factor de compromiso. 26 GVA-ELAI-UPM PFC

37 Miguel Hernández Vázquez Estado de la Técnica CLUSTERS DE ALTA DISPONIBILIDAD (HA) Los clusters de alta disponibilidad son bastante ortogonales en lo que se refieren a funcionalidad con respecto a un cluster de alto rendimiento. Los clusters de alta disponibilidad son clusters donde la principal funcionalidad es estar controlando y actuando para que un servicio o varios se encuentren activos durante el máximo periodo de tiempo posible. En estos casos se puede comprobar como la monitorización de otros es parte de la colaboración entre los nodos del cluster. Los clusters de alta disponibilidad han sido diseñados para que proporcionen la máxima disponibilidad sobre los servicios que presenta el cluster. Este tipo de clusters son la competencia que abarata los sistemas redundantes, de manera que ofrecen una serie de servicios durante el mayor tiempo posible. Para poder dar estos servicios, los clusters de este tipo se implementan en base a tres factores: confiabilidad, disponibilidad y dotación de servicio. La mayoría de los problemas que tratan de resolver este tipo de clusters están ligados a la necesidad de dar servicio continuado de cualquier tipo a una serie de clientes de manera ininterrumpida. A esta funcionalidad se suele oponer la ley del caos en una de sus vertientes informáticas. Se suelen producir fallos inesperados en las máquinas; estos fallos provocan la aparición de dos eventos en el tiempo: uno es el tiempo en el que el servicio está inactivo y el otro es el tiempo de reparación del problema. Ambos tiempos no tienen por que estar relacionados, aunque a menudo si lo estén. Entre los problemas que solucionan se encuentran: sistemas de información redundante, sistemas tolerantes a fallos, balanceo de carga entre varios servidores, balanceo de conexiones entre varios servidores, etc. Las técnicas que emplean este tipo de cluster a la hora de atajar estos problemas se basan en principios muy simples que pueden ser desarrollados hasta crear sistemas complejos especializados para cada entorno particular. En cualquier caso, las técnicas de estos sistemas suelen basarse en excluir del sistema aquellos puntos críticos que pueden producir un fallo y por tanto la pérdida de disponibilidad de un servicio, para esto se suelen implementar desde enlaces de red redundantes hasta disponer de N máquinas para hacer una misma tarea de manera que si caen N-1 máquinas el servicio permanece activo sin pérdida de rendimiento. GVA ELAI UPM PFC

38 Estado de la Técnica Miguel Hernández Vázquez CLUSTERS DE ALTA CONFIABILIDAD (HR) Estos clusters tratan de aportar la máxima confiabilidad en un entorno en el cual se necesite saber que el sistema se va a comportar de una manera determinada. Este tipo de clusters son los más difíciles de implementar, ya que generalmente se basan en no solamente conceder servicios de alta disponibilidad, sino en ofrecer un entorno de sistema altamente confiable. Esto implica en sí mismo mucha sobrecarga en el sistema, son también clusters muy acoplados. Dar a un cluster SSI capacidad de alta confiabilidad implica gastar los recursos necesarios para evitar que aplicaciones caigan. Generalmente este tipo de clusters suele ser utilizado para entornos de tipo empresarial y esta funcionalidad solamente puede ser efectuada por hardware especializado. No existe ninguno de estos clusters implementados como software de manera eficiente en tiempo real. Esto se debe a limitaciones de la latencia de la red, así como a la complejidad de mantener los estados. Estos clusters deberían ser una mezcla de clusters de alto rendimiento y alta disponibilidad mejorados. Necesitarían características de cluster SSI, tener un único reloj de sistema conjunto y otras acciones más. Dada la naturaleza asíncrona actual en el campo de los clusters, este tipo de clusters aún será difícil de implementar hasta que no se abaraten las técnicas de comunicación utilizadas en entornos que actualmente consideramos inalcanzables para la mayoría de las organizaciones o con no suficiente coste/rendimiento. 28 GVA-ELAI-UPM PFC

39 Miguel Hernández Vázquez Estado de la Técnica GVA ELAI UPM PFC

40 Estado de la Técnica Miguel Hernández Vázquez 30 GVA-ELAI-UPM PFC

41 3 Procesamiento Distribuido con MPI En este capítulo vamos a dar una visión sobre lo que es MPI (Message Passing Interface), los objetivos que persigue, limitaciones y en definitiva, sus características y partes constituyentes. Más adelante añadiremos una serie de ejemplos prácticos para una mayor y mejor comprensión de la implementación MPI. Este capítulo será un paso previo para poder entender en mayor medida las implementaciones realizadas en los capítulos posteriores. GVA ELAI UPM PFC

42 Procesamiento Distribuido con MPI Miguel Hernández Vázquez 3.1 QUÉ ES MPI? MPI (acrónimo de Message Passing Interface) es un interfaz estandarizado para la implementación de aplicaciones paralelas basadas en paso de mensajes. El modelo de programación en el que se fundamenta MPI es MIMD (acrónimo de Multiple Instruction streams, Multiple Data streams), aunque también existe otro modelo de programación sobre el que se puede fundamentar, el modelo SPMD (acrónimo de Single Program Multiple Data). Figura 3.1: Logo de MPI MPI es, como su nombre indica, un interfaz, lo que quiere decir que el estándar no exige una determinada implementación del mismo. Lo importante es dar al programador una colección de funciones para que éste diseñe su aplicación, sin que tenga necesariamente que conocer el hardware concreto sobre el que se va a ejecutar, ni la forma en la que se han implementado las funciones que emplea. Los elementos básicos de MPI son una definición de un interfaz de programación independiente de lenguajes, más una colección de bindings o concreciones de ese interfaz para los lenguajes de programación más extendidos en la comunidad usuaria de computadores paralelos: C y FORTRAN. Un programador que quiera emplear MPI para sus proyectos trabajará con una implementación concreta de MPI, que constará de, al menos, estos elementos: Una biblioteca de funciones para C, más el fichero de cabecera mpi.h con las definiciones de esas funciones y de una colección de constantes y macros. Una biblioteca de funciones para FORTRAN + mpif.h. 32 GVA-ELAI-UPM PFC

43 Miguel Hernández Vázquez Procesamiento Distribuido con MPI Comandos para compilación, típicamente mpicc, mpif77, que son versiones de los comandos de compilación habituales (cc, f77) que incorporan automáticamente las bibliotecas MPI. Comandos para la ejecución de aplicaciones paralelas, típicamente mpirun. Herramientas para monitorización y depuración. MPI no es, evidentemente, el único entorno disponible para la elaboración de aplicaciones paralelas. Existen muchas alternativas, entre las que destacamos las siguientes: Utilizar las bibliotecas de programación propias del computador paralelo disponible: NX en el Intel Paragon, MPL en el IBM SP2, etc. PVM (Parallel Virtual Machine): de características similares a MPI, se desarrolló con la idea de hacer que una red de estaciones de trabajo funcionase como un multicomputador. Funciona también en multicomputadores, normalmente como una capa de software encima del mecanismo de comunicaciones nativo. Usar, si es posible, lenguajes de programación paralelos (FORTRAN 90) o secuenciales (C, FORTRAN 77) con directivas de paralelismo. Usar lenguajes secuenciales junto con compiladores que paralicen automáticamente. Como ya hemos comentado, MPI está especialmente diseñado para desarrollar aplicaciones SPMD. Al arrancar una aplicación se lanzan en paralelo N copias del mismo programa (procesos). Estos procesos no avanzan sincronizados instrucción a instrucción sino que la sincronización, cuando sea necesaria, tiene que ser explícita. Los procesos tienen un espacio de memoria completamente separado. El intercambio de información, así como la sincronización, se hacen mediante paso de mensajes. GVA ELAI UPM PFC

44 Procesamiento Distribuido con MPI Miguel Hernández Vázquez Se dispone de funciones de comunicación punto a punto (que involucran sólo a dos procesos), y de funciones u operaciones colectivas (que involucran a múltiples procesos). Los procesos pueden agruparse y formar comunicadores, lo que permite una definición del ámbito de las operaciones colectivas, así como un diseño modular. 3.2 OBJETIVOS Y LIMITACIONES DE MPI MPI ha sido desarrollado por el MPI FORUM - grupo formado por investigadores de universidades, laboratorios y empresas involucrados en la computación de altas prestaciones. Los objetivos fundamentales que persigue el MPI FORUM son: Definir un entorno de programación único que garantice la portabilidad de las aplicaciones paralelas. Definir totalmente el interfaz de programación, sin especificar cómo debe ser la implementación del mismo. Ofrecer implementaciones de calidad, de dominio público, para favorecer la extensión del estándar. Convencer a los fabricantes de computadores paralelos para que ofrezcan versiones de MPI optimizadas para sus máquinas. Los elementos básicos de que consta MPI son: 1. Definición de un interfaz de programación independiente de lenguajes. 2. Una colección de bindings o concreciones de ese interfaz para los lenguajes de programación más extendidos: C y FORTRAN. 34 GVA-ELAI-UPM PFC

45 Miguel Hernández Vázquez Procesamiento Distribuido con MPI Sin embargo, todavía existen algunas limitaciones en cuanto al desarrollo del MPI. Algunas de ellas podrían ser: No existe un mecanismo estandarizado de entrada/salida paralela. La creación dinámica de procesos: MPI asume un número de procesos constante, que es establecido al arrancar la aplicación. Las variables compartidas: el modelo de comunicación estandarizado por MPI sólo tiene en cuenta el paso de mensajes. Desarrollo de bindings para otros lenguajes: C++ y ADA. Soporte para las aplicaciones de tiempo real: MPI no recoge en ningún punto restricciones de tiempo real. Las interfaces gráficas: no se define ningún aspecto relacionado con la interacción mediante GUIs con una aplicación paralela. Figura 3.2: ubicación de MPI en el proceso de programación de aplicaciones paralelas GVA ELAI UPM PFC

46 Procesamiento Distribuido con MPI Miguel Hernández Vázquez 3.3 ESTRUCTURA BÁSICA DE LOS PROGRAMAS MPI MPI está especialmente diseñado para desarrollar aplicaciones SPMD (acrónimo de Single Program Multiple Data). Al arrancar una aplicación se lanzan en paralelo N copias del mismo programa (N procesos). Estos procesos no están sincronizados instrucción a instrucción, sino que esta, en el caso de que sea necesaria, tiene que ser indicada explícitamente, y se realiza a través del paso de mensajes, al igual que el intercambio de la información. Además, estos procesos tienen un espacio de memoria separado. Existen diversos tipos de funciones: funciones de comunicación punto a punto en las que intervienen dos procesos únicamente; funciones colectivas en las que intervienen varios procesos. La estructura típica de un programa MPI, usando el binding para C, es la siguiente: # include "mpi.h" main (int argc, char **argv) { int nproc; /* Número de procesos */ int yo; /* Mi dirección: 0<=yo<= (nproc-1) */ MPI_Init (&argc, &argv); MPI_Comm_size (MPI_COMM_WORLD, &nproc); MPI_Comm_rank (MPI_COMM_WORLD, &yo); /* CUERPO DEL PROGRAMA */ } MPI_Finalize (); 36 GVA-ELAI-UPM PFC

47 Miguel Hernández Vázquez Procesamiento Distribuido con MPI En esta estructura típica de programa MPI podemos observar cuatro de las funciones más utilizadas de MPI: 1. MPI_Init (), que utilizamos para iniciar la aplicación paralela. 2. MPI_Comm_size (), que utilizamos para averiguar el número de procesos que toman parte en la aplicación en cuestión. 3. MPI_Comm_rank (), que se utiliza para que cada proceso averigüe su dirección (identificador) dentro del conjunto de diferentes procesos que componen la aplicación en cuestión. 4. MPI_Finalize (), que utilizamos para dar por finalizada la aplicación. int MPI_Init(int *argc, char ***argv); int MPI_Comm_size (MPI_Comm comm, int *size); int MPI_Comm_rank (MPI_Comm comm, int *rank); int MPI_Finalize(void); La mayor parte de las funciones MPI devuelven un entero; si el valor devuelto es MPI_SUCCESS, la función se ha realizado con éxito. La palabra clave MPI_COMM_WORLD hace referencia al comunicador universal, un comunicador predefinido por MPI que incluye a todos los procesos de la aplicación. Todas las funciones de comunicación de MPI necesitan como argumento un comunicador. GVA ELAI UPM PFC

48 Procesamiento Distribuido con MPI Miguel Hernández Vázquez 3.4 LA COMUNICACIÓN EN MPI: COMUNICACIÓN PUNTO A PUNTO Un gran número de funciones de MPI se dedican a la comunicación entre pares de procesos. Existen diversas formas de intercambiar un mensaje entre dos procesos, en función del modelo y el modo de comunicación elegido MODELOS DE COMUNICACIÓN MPI define dos modelos de comunicación: bloqueante (blocking) y no bloqueante (non-blocking). La elección de uno u otro tipo de modelo está en función del tiempo que un proceso pasa bloqueado tras llamar a una función de comunicación. Así, una función bloqueante (blocking) mantiene a un proceso bloqueado hasta que la operación solicitada finalice. Una no bloqueante (non-blocking) supone ordenar al sistema la realización de una operación, recuperando el control inmediatamente, sin preocuparnos por el momento si la operación ha finalizado o no. Esto nos presenta un problema: cuando dar por finalizada la comunicación. En el caso del receptor, damos por finalizada la comunicación cuando en el buffer tengamos un mensaje nuevo. En el caso del emisor este aspecto es más difícil de determinar. Se define que el proceso de comunicación ha terminado cuando el emisor puede volver a utilizar el buffer en el que estaba contenido el mensaje a emitir MODOS DE ENVÍO EN MPI MPI define 4 modos de envío: BÁSICO (BASIC): en el modo de envío básico no se especifica la forma en la que se completa la operación: es algo dependiente de la implementación. 38 GVA-ELAI-UPM PFC

49 Miguel Hernández Vázquez Procesamiento Distribuido con MPI CON BUFFER (BUFFERED): en el envío con buffer se guarda, en un buffer en el emisor, una copia del mensaje. La operación se da por completa en cuanto se ha efectuado esta copia. Si no hay espacio en el buffer, el envío fracasa. SÍNCRONO (SYNCHRONOUS): en el envío síncrono, la operación se da por terminada sólo cuando el mensaje ha sido recibido en el destino. LISTO (READY): únicamente se puede hacer si antes el otro extremo está preparado para una recepción inmediata COMUNICACIÓN BÁSICA El resultado de la combinación de dos modelos y cuatro modos de comunicación nos da 8 diferentes funciones de envío. Funciones de recepción sólo hay dos, una por modelo. Presentamos a continuación los prototipos de las funciones más habituales. Empezamos con MPI_Send () y MPI_Recv que son, respectivamente, las funciones de envío y recepción básicas bloqueantes: int MPI_Send (void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); int MPI_Recv (void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status); El significado de los parámetros es el siguiente: Buf, count y datatype forman el mensaje a enviar o recibir: count copias de un dato del tipo datatype que se encuentran (o se van a dejar) en memoria a partir de la dirección indicada por buf. Dest es, en las funciones de envío, el identificador del proceso destinatario del mensaje. Source es, en las funciones de recepción, el identificador del emisor del cual esperamos un mensaje. Si no importa el origen del mensaje, podemos poner MPI_ANY_SOURCE. Tag es una etiqueta que se puede poner al mensaje. El significado de la etiqueta lo asigna el programador. Suele emplearse para distinguir entre diferentes clases de mensajes. El emisor pone siempre una etiqueta a los mensajes, y el receptor puede elegir entre recibir sólo los mensajes que tengan una etiqueta dada, o aceptar cualquier etiqueta, poniendo MPI_ANY_TAG como valor de este parámetro. Comm es un comunicador; en muchas ocasiones se emplea el comunicador universal MPI_COMM_WORLD. Status es un resultado que se GVA ELAI UPM PFC

50 Procesamiento Distribuido con MPI Miguel Hernández Vázquez obtiene cada vez que se completa una recepción, y nos informa de aspectos tales como el tamaño del mensaje recibido, la etiqueta del mensaje y el emisor del mismo. La definición d e la estructura MPI_Status es la siguiente: typedef struct { int MPI_SOURCE; int MPI_TAG; /* otros campos no accesibles */ } MPI_Status; Podemos acceder directamente a los campos.mpi_source y.mpi_tag, pero a ningún otro más. Si queremos saber el tamaño de un mensaje, lo haremos con la función MPI_Get_count (): int MPI_Get_count (MPI_Status *status, MPI_Datatype datatype, int *count); MPI_Isend () y MPI_Irecv () son las funciones de emisión/recepción básicas no bloqueantes. int MPI_Isend (void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request); int MPI_Irecv (void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request); int MPI_Wait (MPI_Request *request, MPI_Status *status); int MPI_Test (MPI_Request *request, int *flag, MPI_Status *status); int MPI_Cancel (MPI_Request *request); Las funciones no bloqueantes manejan un objeto request del tipo MPI_Request. Este objeto es una especie de recibo de la operación solicitada. Más adelante se podrá utilizar este recibo para saber si la operación ha terminado o no. La función MPI_Wait () toma como entrada un recibo, y bloquea al proceso hasta que la operación correspondiente termina. Por lo tanto, hacer un MPI_Isend () 40 GVA-ELAI-UPM PFC

51 Miguel Hernández Vázquez Procesamiento Distribuido con MPI seguido de un MPI_Wait () equivale a hacer un envío bloqueante. Sin embargo, entre la llamada a la función de envío y la llamada a la función de espera el proceso puede haber estado haciendo cosas útiles, es decir, consigue solapar parte de cálculo de la aplicación con la comunicación. Cuando no interesa bloquearse, sino simplemente saber si la operación ha terminado o no, podemos usar MPI_Test (). Esta función actualiza un flan que se le pasa como segundo parámetro. Si la función ha terminado, este flag toma el valor 1, y si no ha terminado pasa a valer 0. Por último, MPI_Cancel () nos sirve para cancelar una operación de comunicación pendiente, siempre que ésta aún no se haya completado. A continuación, proponemos un programa de ejemplo de las funciones MPI_Send y MPI_Recv: char msg [100]; if (my_rank==0) { printf (msg,"\n\n\t Esto es un mensaje del proceso %d al proceso %d", source, dest); MPI_Send (msg, 100, MPI_CHAR, dest, TAG, MPI_COMM_WORLD); printf ("\n Mensaje enviado a %d", dest); } else if (my_rank==1) { MPI_Recv (msg, 100, MPI_CHAR, source, TAG, MPI_COMM_WORLD, &status); printf ("\n Mensaje recibido en %d", dest); printf (msg); } RECEPCIÓN POR ENCUESTA Las funciones de recepción de mensajes engloban en una operación la sincronización con el emisor (esperar a que haya un mensaje disponible) con la de GVA ELAI UPM PFC

52 Procesamiento Distribuido con MPI Miguel Hernández Vázquez comunicación (copiar ese mensaje). A veces, sin embargo, conviene separar ambos conceptos. Por ejemplo, podemos estar a la espera de mensajes de tres clases, cada una asociada a un tipo de datos diferente, y la clase nos viene dada por el valor de la etiqueta. Por lo tanto, nos gustaría saber el valor de la etiqueta antes de leer el mensaje. También puede ocurrir que nos llegue un mensaje de longitud desconocida, y resulte necesario averiguar primero el tamaño para así asignar dinámicamente el espacio de memoria requerido por el mensaje. Las funciones MPI_Probe () y MPI_Iprobe () nos permiten saber si tenemos un mensaje recibido y listo para leer, pero sin leerlo. A partir de la información de estado obtenida con cualquiera de estas sondas, podemos averiguar la identidad del emisor del mensaje, la etiqueta del mismo y su longitud. Una vez hecho esto, podemos proceder a la lectura real del mensaje con la correspondiente llamada a MPI_Recv () o MPI_Irecv (). int MPI_Iprobe (int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status); int MPI_Probe (int source, int tag, MPI_Comm comm, MPI_Status *status); MPI_Probe () es bloqueante: sólo devuelve el control al proceso cuando hay un mensaje listo. MPI_Iprobe () es no bloqueante: nos indica en el argumento flag si hay un mensaje listo o no es decir, realiza una encuesta. 3.5 TIPOS DE DATOS MANEJADOS POR MPI Los mensajes gestionados por MPI son secuencias de count elementos del tipo datatype. MPI define una colección de tipos de datos primitivos, correspondientes a los tipos de datos existentes en C. Estos son: 42 GVA-ELAI-UPM PFC

53 Miguel Hernández Vázquez Procesamiento Distribuido con MPI Aunque una aplicación desarrollada en C trabaja con los tipos de datos habituales, cuando se realice un paso de mensajes habrá que facilitar a MPI un descriptor del tipo equivalente, tal como lo define MPI. La idea de fondo es la siguiente: los procesadores que participan en una aplicación MPI no tienen por qué ser todos iguales. Es posible que existan diferencias en la representación de los datos en las distintas máquinas. Para eliminar los problemas que puedan surgir, MPI realiza, si son necesarias, transformaciones de sintaxis que posibilitan la comunicación en entornos heterogéneos. La excepción la constituyen los datos de tipo MPI_BYTE, que se copian sin más de una máquina a otra. 3.6 ETIQUETAS Y COMUNICADORES EN MPI Todo mensaje que se envía con MPI necesariamente ha de ir etiquetado. Este etiquetado se realiza a través del parámetro tag. Mediante el establecimiento de estas etiquetas, podemos diferenciar las diferentes clases de información que pueden intercambiarse los diferentes procesos. La comunicación se produce dentro de un comunicador (entorno de comunicación), que es básicamente un conjunto de procesos. El comunicador universal MPI_COMM_WORLD está siempre definido, e incluye a todos los procesos que forman parte de la aplicación. Los comunicadores permiten que diferentes grupos de procesos actúen sin interferir, así como dividir la aplicación en GVA ELAI UPM PFC

54 Procesamiento Distribuido con MPI Miguel Hernández Vázquez fases no solapadas. MPI garantiza la entrega ordenada de mensajes dentro de un mismo comunicador. 3.7 OPERACIONES COLECTIVAS EN MPI Muchas aplicaciones de MPI son diseñadas o bien requieren la comunicación entre más de dos procesos; es decir, son funciones colectivas. Las funciones colectivas tiene que ser invocadas por todos los participantes en dichas operaciones; además, la mayor parte de estas requieren la designación de un proceso como root, o raíz de la operación. MPI incluye una serie de operaciones colectivas que exponemos a continuación: BARRERAS DE SINCRONIZACIÓN Las barreras de sincronización, - (MPI_Barrier ()) -, no exigen ninguna tipo de intercambio de información entre los procesos, ya que esta operación es únicamente de sincronización, de manera que bloquea los procesos de un comunicador hasta que todos ellos pasan por la barrera establecida. int MPI_Barrier(MPI_Comm comm); BROADCAST (DIFUSIÓN) El envío de información en modo difusión, - (MPI_Broadcast ()) -, sirve para que el proceso raíz envíe un mensaje a todos los miembros del comunicador. En esta función todos los participantes en el proceso invocan la misma función, designando un mismo proceso como raíz de la misma. int MPI_Bcast (void* buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm); 44 GVA-ELAI-UPM PFC

55 Miguel Hernández Vázquez Procesamiento Distribuido con MPI Figura 3.3: Esquema de la operación colectiva MPI_Broadcast (): Buffer envío indica los contenidos de los bufferes de envío antes de proceder a la operación colectiva. Buffer recepción indica los contenidos de los bufferes de recepción tras completarse la operación. A continuación exponemos un ejemplo de BroadCast: Char msg [100]; if (my_rank==source) { printf (msg,"\n Esto es un mensaje del proceso %d a todos los demás", source); MPI_Bcast (msg, 100, MPI_CHAR, source, MPI_COMM_WORLD); printf ("\n Mensaje enviado a todos desde %d", source); } else { MPI_Bcast(msg, 100, MPI_CHAR, source, MPI_COMM_WORLD); printf ("\n Mensaje recibido en %d desde %d", my_rank, source); printf (msg); } GVA ELAI UPM PFC

56 Procesamiento Distribuido con MPI Miguel Hernández Vázquez GATHER (RECOLECCIÓN) En el envío de información en modo recolección, - (MPI_Gather ()) -, se realiza una recolección de datos en el proceso raíz. Este proceso recopila un vector de datos, al que contribuyen todos los procesos del comunicador con la misma cantidad de datos. El proceso raíz almacena las contribuciones de forma consecutiva. Es el proceso raíz el único que debe preocuparse de los distintos parámetros en juego (recvbuf, recvcount y recvtype). Por el contrario, los valores válidos para los parámetros sendbuf, sendcount y sendtype han de ser facilitados por todos los procesos que entran en juego en el proceso. También existe una variación de esta función de recolección, llamada MPI_Gatherv (), con la cual podemos almacenar los datos recolectados de forma no consecutiva, y que cada proceso contribuya con bloques de datos de diferente tamaño. La tabla recvcounts establece el tamaño del bloque de datos aportado por cada proceso, y displs indica cuál es el desplazamiento entre bloque y bloque. int MPI_Gather (void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm); SCATTER (DISTRIBUCIÓN) En el envío de información en modo distribución, - (MPI_Scatter ()) -, se realiza la operación simétrica a MPI_Gather (). El proceso raíz posee un vector de elementos, uno por cada proceso del comunicador. Tras realizar la distribución, cada proceso tiene una copia del vector inicial. Si los datos a enviar no están almacenados de forma consecutiva en memoria, o los bloques a enviar a cada proceso no son todos del mismo tamaño, tenemos la función MPI_Scatterv (), que actúa de forma análoga a lo comentado en el apartado anterior para la función MPI_Gather (). int MPI_Scatter (void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm); 46 GVA-ELAI-UPM PFC

57 Miguel Hernández Vázquez Procesamiento Distribuido con MPI REDUCCIÓN Una reducción es una operación realizada de forma cooperativa entre todos los procesos de un comunicador, de tal forma que se obtiene un resultado final que se almacena en el proceso raíz. MPI define una colección de operaciones del tipo MPI_Op que se pueden utilizar en una reducción: MPI_MAX (máximo), MPI_MIN (mínimo), MPI_SUM (suma), MPI_PROD (producto), MPI_LAND (and lógico), MPI_BAND (and bit a bit), MPI_LOR (or lógico), MPI_BOR (or bit a bit), MPI_LXOR (xor lógico), MPI_BXOR (xor bit a bit), etc. La operación a realizar puede ser cualquiera. En general se emplean operaciones conmutativas y asociativas, es decir, cuyo resultado no depende del orden con el que se procesan los operandos. Eso se indica con el valor 1 en el parámetro conmute. Si la operación no es conmutativa (conmute = 0) entonces se exige que la reducción se realice en orden de dirección (se empieza con el proceso 0, luego con el 1, con el 2, etc.). En ocasiones resulta útil que el resultado de una reducción esté disponible para todos los procesos. Aunque se puede realizar un broadcast tras la reducción, podemos combinar la reducción con la difusión usando MPI_Allreduce (). Si el resultado de la reducción es un vector que hay que distribuir entre los procesadores, podemos combinar la reducción y la distribución usando MPI_Reduce_scatter (). int MPI_Reduce (void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm); Un ejemplo de MPI_Reduce es: int value; int result; value = my_rank; GVA ELAI UPM PFC

58 Procesamiento Distribuido con MPI Miguel Hernández Vázquez MPI_Reduce (&value, &result, 1, MPI_INT,MPI_SUM,source,MPI_COMM_WORLD); if (my_rank==source) { printf ("\n Resultado de la suma colectiva %d", result); } Figura 3.4: Esquema de la operación colectiva MPI_Gather () Figura 3.5: Esquema de la operación colectiva MPI_Scatter () Figura 3.6: Esquema de comunicación de MPI_Scatter 48 GVA-ELAI-UPM PFC

59 Miguel Hernández Vázquez Procesamiento Distribuido con MPI COMUNICACIÓN TODOS CON TODOS (ALL-TO-ALL) La comunicación de todos los nodos con todos los nodos supone que, inicialmente, cada proceso tiene un vector con tantos elementos como procesos hay en el comunicador. Para i, j y k entre 0 y N-1 (donde N es el número de procesos del comunicador), cada proceso i envía una copia de sendbuf[j] al proceso j, y recibe del proceso k un elemento, que almacena en recvbuf[k]. MPI_Alltoall () equivale, por tanto, a una sucesión de N operaciones de distribución, en cada una de las cuales el proceso i toma el rol de raíz. int MPI_Scatter (void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm); Figura 3.7: Esquema de la operación colectiva MPI_Alltoall () 3.8 MODULARIDAD MPI permite definir grupos de procesos. Un grupo de procesos es una colección de procesos, y define un espacio de direcciones (desde 0 hasta N-1, donde N es el tamaño del grupo). Los miembros del grupo tienen asignada una dirección dentro de él. Un proceso puede pertenecer simultáneamente a varios grupos, y tener una dirección distinta en cada uno de ellos. GVA ELAI UPM PFC

60 Procesamiento Distribuido con MPI Miguel Hernández Vázquez Un comunicador consiste en un grupo de procesos, y un contexto de comunicación. Las comunicaciones producidas en dos comunicadores diferentes nunca interfieren entre sí. Este concepto se introdujo para facilitar la elaboración de bibliotecas de programas: el programa de un usuario se ejecuta en un comunicador, y las funciones de la biblioteca en otro diferente. De esta forma no existe el riesgo de que se mezclen mensajes del usuario con mensajes privados de las funciones de la biblioteca, y tampoco hay problemas a la hora de usar etiquetas. Entre las funciones más comunes sobre comunicadores podemos encontrar las siguientes: MPI_Comm_size (): utilizada para averiguar el número de procesos de un comunicador. Su estructura es: int MPI_Comm_size (MPI_Comm comm, int *size); MPI_Comm_rank (): utilizada para que un proceso obtenga su identificación dentro del comunicador. Su estructura es: int MPI_Comm_rank (MPI_Comm comm, int *rank); MPI_Comm_dup (): esta función nos permite crear un nuevo comunicador, con el mismo grupo de procesos, pero diferente con texto. Se puede usar antes de llamar a una función de una biblioteca. Su estructura es: int MPI_Comm_dup (MPI_Comm comm, MPI_Comm *newcomm); MPI_Comm_dup (MPI_COMM_WORLD, &newcomm); /* llamada a función, que se ejecutará dentro */ /* de newcomm */ MPI_Comm_free (&newcomm); 50 GVA-ELAI-UPM PFC

61 Miguel Hernández Vázquez Procesamiento Distribuido con MPI MPI_Comm_free (): esta función destruye un comunicador que ya no es empleado. MPI_Comm_split (): a través de esta función creamos, a partir de un comunicador inicial, varios comunicadores diferentes, cada uno con un conjunto disjunto de procesos. El color determina en qué comunicador queda cada uno de los procesos. Su estructura es: int MPI_Comm_split (MPI_Comm comm, int color, int key, MPI_Comm *newcomm); Figura 3.8: Utilización de un comunicador para aislar una función de biblioteca. Figura 3.9: Arriba: una colección de procesos en el comunicador MPI_COMM_WORLD. Abajo, dos comunicadores: uno con los procesos con dirección global par, y otro con los procesos con dirección global impar. GVA ELAI UPM PFC

62 Procesamiento Distribuido con MPI Miguel Hernández Vázquez Figura 3.10: Creación de un intercomunicador entre los dos comunicadores de la Figura INSTALACIÓN Y CONFIGURACIÓN DE MPICH INSTALACIÓN Para poder llevar a cabo la realización de aplicaciones basadas en el procesamiento paralelo, es necesario la instalación y configuración de la herramienta adecuada para ello. En este caso emplearemos el software MPICH, que podemos encontrar en la web de MPI ( En esta sección tendremos que descargarnos los dos ejecutables (mpich.nt exe y mpich.nt src.exe). Para que el programa funcione satisfactoriamente será necesario realizar su instalación en cada uno de los nodos de que se compone nuestro cluster. Con la instalación de MPICH en nuestro equipo se crean una serie de aplicaciones: 1. MPICH JOB MANAGER: permite comprobar si los nodos del cluster tienen trabajos pendientes. 2. MPI UPDATE TOOL: herramienta que permite la actualización del software. 52 GVA-ELAI-UPM PFC

63 Miguel Hernández Vázquez Procesamiento Distribuido con MPI 3. MPI CONFIGURATION TOOL: permite acceder a la configuración de MPI en cada uno de los nodos donde se encuentre instalado. 4. MPIRUN: ejecutable que lanza la aplicación CONFIGURACIÓN Tendremos que configurar MPICH en cada uno de los nodos de nuestro cluster. Para ello, deberemos seguir los siguientes pasos: 1. Lanzamos la aplicación MPI CONFIGURATION TOOL. Nos aparece un GUI en donde deberemos añadir los nodos en donde está instalado MPICH. Pinchamos en el botón SELECT y nos aparece otra pantalla con en nombre de select hosts. Pinchamos en el botón ACTION y dentro de este, en scan hosts. El programa reconoce los nodos en donde MPICH está instalado. Pinchamos a continuación en OK, después en APPLY y por último en OK: GVA ELAI UPM PFC

64 Procesamiento Distribuido con MPI Miguel Hernández Vázquez 2. Lanzamos el ejecutable de MPICH, MPIRUN.exe. Para poder llevar a cabo la ejecución del programa, es necesario que la aplicación que queramos que se ejecute de forma paralela se encuentre en el mismo directorio en todos los nodos del cluster. 3. Finalmente seleccionamos los hosts en donde queremos que se ejecute nuestra aplicación paralela y pulsamos RUN. En la ventana de OUTPUT nos deberá aparecer el host en donde se está ejecutando el proceso y el propio ejecutable: 54 GVA-ELAI-UPM PFC

65 Miguel Hernández Vázquez Procesamiento Distribuido con MPI 3.10 GENERACIÓN DE APLICACIONES MPI CON VISUAL STUDIO C++ Los pasos a seguir serán los siguientes: 1. Debemos crear un nuevo proyecto del tipo WIN32 CONSOLE APLICATION. En cuanto al tipo de archivo, será un C++ SOURCE FILE. 2. Escribimos la aplicación a ejecutar, con la estructura que marca el punto Vamos a las propiedades del proyecto dentro de PROYECT SETTINGS. Seleccionamos C/C++. Configuramos las propiedades para WIN32 DEBUG. En la pestaña Use run-time library, seleccionamos la opción Multithreaded. GVA ELAI UPM PFC

66 Procesamiento Distribuido con MPI Miguel Hernández Vázquez 4. Configuramos las propiedades para WIN32 RELEASE. En la pestaña Use run-time library, seleccionamos la opción Multithreaded. 5. Configuramos las propiedades para ALL CONFIGURATIONS. En la pestaña de Additional include directories, incluimos el path en donde se encuentre la carpeta Include de MPICH. 56 GVA-ELAI-UPM PFC

67 Miguel Hernández Vázquez Procesamiento Distribuido con MPI 6. Seleccionamos LINK y dentro de este apartado, la opción INPUT. En la pestaña de Additional library path, incluimos el path en donde se encuentre la carpeta Lib de MPICH. GVA ELAI UPM PFC

68 Procesamiento Distribuido con MPI Miguel Hernández Vázquez 7. Configuramos las propiedades para WIN32 DEBUG. En la pestaña de Object/library modules, añadimos lo siguiente: mpichd.lib. 8. Configuramos las propiedades para WIN32 RELEASE. En la pestaña de Object/library modules, añadimos lo siguiente: mpich.lib. 58 GVA-ELAI-UPM PFC

69 Miguel Hernández Vázquez Procesamiento Distribuido con MPI 9. Para ALL CONFIGURATIONS. En la pestaña de Object/library modules, añadimos lo siguiente: ws2_32.lib. 10. Pinchamos en OK y salimos. 11. Construimos el proyecto. GVA ELAI UPM PFC

70 Procesamiento Distribuido con MPI Miguel Hernández Vázquez 3.11 UN EJEMPLO CONCRETO A continuación vamos a exponer un ejemplo de una aplicación paralela que utiliza MPICH para su ejecución y que ha sido implementada a través de Microsoft Visual Studio. La aplicación consiste en un cluster compuesta por tres nodos, que en nuestro caso serán los procesadores EINSTEIN (nodo 0), GAUSS (nodo 1) y NEWTON (nodo 2). El objetivo del programa es sencillo; básicamente es un conversor de euros a pesetas, con la siguiente estructura: El nodo 0 (EINSTEIN) es el encargado de lanzar la aplicación y en donde ejecutamos el menú de selección de la conversión que queremos realizar (pesetas euros o euros pesetas). También es el encargado de recibir la cantidad a convertir. El nodo 1 (GAUSS) es el encargado de realizar la conversión de euros a pesetas. Este nodo recibe del nodo 0 la cantidad de euros a convertir, realiza la conversión, y posteriormente, envía el resultado de vuelta al nodo 0. El nodo 2 (NEWTON) es el encargado de realizar la conversión de pesetas a euros. Este nodo recibe del nodo 0 la cantidad de pesetas a convertir, realiza la conversión, y posteriormente, envía el resultado de vuelta al nodo 0. El programa tiene la siguiente estructura: #include "stdio.h" #include "conio.h" #include "mpi.h" #define K int main(int argc, char **argv) { int ME, Nproc; int namelen; char processor_name[mpi_max_processor_name]; 60 GVA-ELAI-UPM PFC

71 Miguel Hernández Vázquez Procesamiento Distribuido con MPI MPI_Status status; MPI_Init (&argc, &argv); MPI_Comm_rank (MPI_COMM_WORLD, &ME); MPI_Comm_size (MPI_COMM_WORLD, &Nproc); MPI_Get_processor_name (processor_name, &namelen); fprintf(stderr,"proceso %d ejecutado en el procesador %s\n",me, processor_name); fflush (stderr); if (ME==2) { int resultado,pesetas; MPI_Recv (&pesetas, 0, MPI_INT, 0, 45, MPI_COMM_WORLD, &status); Resultado=pesetas/K; MPI_Send (&resultado, 2, MPI_INT,0,45,MPI_COMM_WORLD); }; if(me==1) { int resultado,euros; MPI_Recv (&euros, 0, MPI_INT, 0, 45, MPI_COMM_WORLD, &status); resultado=euros*k; MPI_Send (&resultado, 1, MPI_INT, 0, 45, MPI_COMM_WORLD); }; if(me==0) { int opcion; printf("bienvenido al menu de seleccion. Por favor, escoge una opcion:\n"); printf("1: Conversion de pesetas a euros\n"); printf("2: Conversion de euros a pesetas\n"); printf("3: Salir del programa\n"); scanf ("%d",&opcion); if (opcion<1 opcion>3){ printf("ha escogido una opcion erronea\n"); getch(); } if(opcion==1){ int pesetas,resultado; printf("ha escogido la conversion de pesetas a euros\n"); GVA ELAI UPM PFC

72 Procesamiento Distribuido con MPI Miguel Hernández Vázquez printf("por favor, escriba la cantidad en pesetas a convertir: \n"); scanf ("%f",&pesetas); MPI_Send (&pesetas, 0, MPI_INT, 2, 45, MPI_COMM_WORLD); MPI_Recv (&resultado, 2, MPI_INT, 2, 45, MPI_COMM_WORLD, &status); printf("%f pesetas son %f euros\n",pesetas,resultado); } if(opcion==2){ int euros,resultado; printf ("Ha escogido la conversion de euros a pesetas\n"); printf ("Por favor, escriba la cantidad en euros a convertir: \n"); scanf ("%f", &euros); MPI_Send (&euros, 0, MPI_INT, 1, 45, MPI_COMM_WORLD); MPI_Recv (&resultado, 1, MPI_INT, 1, 45, MPI_COMM_WORLD, &status); printf ("%f euros son %f pesetas\n", euros, resultado); } if (opcion==3) { printf ("Ha escogido salir del programa. Que tenga un buen dia\n"); getch (); } getch (); } } Una vez ejecutado la aplicación, en el GUI de MPICH tendrá que aparecer una pantalla similar a esta, que nos indicará que el programa se ha ejecutado correctamente: 62 GVA-ELAI-UPM PFC

73 Miguel Hernández Vázquez Procesamiento Distribuido con MPI GVA ELAI UPM PFC

74 Procesamiento Distribuido con MPI Miguel Hernández Vázquez 64 GVA-ELAI-UPM PFC

75 4 Procesamiento Distribuido de Imágenes Genérico con VTK En este tercer capítulo vamos a tratar en profundidad una de las implementaciones que vamos a utilizar para llevar a cabo la realización de aplicaciones paralelas: VTK. Veremos como se implementan aplicaciones paralelas sencillas basadas en VTK y también como VTK trata el procesamiento distribuido de imágenes genérico. GVA ELAI UPM PFC

76 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez 4.1 QUÉ ES VTK? VTK (Visualization ToolKit) son un conjunto de librerías que se utilizan para la visualización y el procesamiento de imágenes, aunque también se usan para la generación de objetos gráficos 2D y 3D. Las librerías VTK constan de código abierto y software orientado a objetos. A pesar de ser muy extensas y complejas, se han diseñado con vistas a ser usadas por cualquier lenguaje de programación orientado a objetos, como puedan ser C++, Java, Tcl, Python, etc. Figura 4.1: Logo de VTK VTK nos proporciona un sistema de visualización por software que nos permite, además de poder visualizar geometría, soportar una amplia variedad de algoritmos de visualización y otras modernas de modelado. Aunque VTK no proporciona ningún componente de interfaz de usuario, puede ser integrado con Tk o X/Motíf. VTK proporciona una variedad de representaciones de datos, incluyendo conjunto de puntos desorganizados, datos poligonales, imágenes, volúmenes y mallas estructuradas, rectilíneas y destructuradas. VTK incluye lectores/importadores y escritores/exportadores para intercambiar datos con otras aplicaciones. Cientos de filtros de procesamiento de datos son capaces de operar con estos datos, oscilando entre la convolución de imágenes y la triangulación Delaunay. El modelo de renderizado de VTK soporta 2D, poligonal, volumétrico y texturas aprovechando que puede ser utilizado en cualquier combinación. VTK es uno de los sistemas de visualización que podemos utilizar hoy en día. AVS fue uno de los primeros sistemas puestos a disposición de los usuarios. IBM s Data Explorer (DX), originalmente un producto comercial, es ahora una aplicación open-source (código abierto) conocida como OpenDX. NAG Explorer y Template Graphics Amira son otras aplicaciones populares. VTK es un sistema de propósito general usado en una gran variedad de aplicaciones, como podemos ver en la figura GVA-ELAI-UPM PFC

77 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK Figura 4.2: VTK puede ser usado en diversas áreas incluyendo la visualización médica (izquierda) y aplicaciones de inspección industrial (derecha) Debido a que VTK es una aplicación open-source, es de gran difusión en muchas universidades, - como la Universidad de Nueva York, la Universidad de Ohio, Stanford, etc. Laboratorios nacionales como Los Álamos están adaptando VTK al procesamiento paralelo a gran escala. VTK también puede aplicarse a otros muchos campos: la visualización médica, la exploración petrolífera, la mecánica de fluidos, la reconstrucción de superficies a partir de la digitalización con láser, etc. 4.2 ARQUITECTURA DE VTK VTK consta de dos partes fundamentales: un núcleo compilado (implementado en C++) y una capa de interpretación generada automáticamente. La capa de interpretación soporta Tcl, Java y Pitón El NÚCLEO DE C++ Las estructuras de datos, los algoritmos y las funciones de sistema de tiempo crítico están implementadas en el núcleo de C++. Los modelos de diseño más comunes como los objetos y las funciones virtuales aseguran portabilidad y extensibilidad. Debido a que VTK es independiente de cualquier interfaz gráfico de usuario (GUI), no depende del sistema de ventanas que estemos empleando. Se acopla dentro del sistema que estemos utilizando e incluso permite su portabilidad a otro tipo de aplicaciones. GVA ELAI UPM PFC

78 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez LA CAPA DE INTERPRETACIÓN Mientras el núcleo nos proporciona velocidad y eficiencia, la capa de interpretación nos ofrece flexibilidad y extensibilidad. Por ejemplo, usando herramientas como Tcl/Tk, Pitón/Tk o Java AWT nos permite el desarrollo de aplicaciones rápidamente. 4.3 GRAPHICS MODEL VTK consta de dos grandes subsistemas el graphics model y el visualization model. El graphics model forma una capa abstracta por encima del lenguaje de los gráficos (por ejemplo, OpenGL) para asegurar la portabilidad entre las diferentes plataformas. Cuando el desarrollo de VTK comenzó en 1993, la plataforma de cada computadora tenía su propio lenguaje gráfico XGL para Sun, Starbase para HP y gl para Silicon Graphics. Los conceptos de gráficos abstractos y capas independientes de los dispositivos crearon el modelo gráfico. Desde ese momento la industria ha adoptado el estándar de OpenGL. Aunque ahora este es sólo uno de los lenguajes gráficos de bajo nivel que soporta VTK, la capa abstracta no ha sido abandonada. En el futuro, nuevos lenguajes gráficos serán más populares pudiendo incluso llegar a remplazar a OpenGL como estándar. El mantenimiento de esta capa abstracta nos permite actualizar a VTK con nuevos desarrollos tecnológicos sin afectar a la compatibilidad con desarrollos anteriores. Hemos tomado los nombres de las clases en el graphics model de la industria cinematográfica. Luces, cámaras, actores y props son clases que el usuario necesita para crear una escena. Encontraremos que el modelo usado para el renderizado de polígonos 3D (luces, cámaras, actores) es análogo al usado para el volumen u otro tipo de renderizados (luces, cámaras, actores). 68 GVA-ELAI-UPM PFC

79 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK Figura 4.3: Dos renders en una ventana de renderizado combinando volumen, superficie y renderizado 2D. El render de la izquierda contiene un cubo; el de la derecha contiene una superficie poligonal y el renderizado del volumen de un electrón. Mediante la combinación de todos los objetos que componen el Graphics Model creamos una escena. Los objetos principales que componen el Graphics Model son los siguientes: vtkactor, vtkactor2d, vtkvolume: representa lo que vemos en escena. No se representan directamente su geometría, sino que esta se ve referida a mappers, una de cuyas funciones es la de representación de los datos. vtklight: se usan para representar y manipular la iluminación de la escena. Solo se emplean en visualizaciones 3D. vtkcamera: controla cómo la geometría 3D es proyectada en imagen 2D durante el proceso de renderización. Tiene varios métodos para posicionar y orientar, controla la perspectiva de la proyección y la visión estéreo. vtkproperty, vtkproperty2d. vtkmapper, vtkmapper2d: se usa para transformar y renderizar geometría. El mapper proporciona la interfaz entre el pipeline de visualización y el graphics model. vtktransform. GVA ELAI UPM PFC

80 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez vtklookuptable, vtkcolortransferfunction: se usan para transformar y renderizar geometría. VtkLookupTable es una subclase de vtkscalarstocolors, también lo es vtkcolortransferfunction, la cual se usa para renderizar volúmenes. Las subclases de vtkscalarstocolors son responsables de mapear los valores de los datos a color. vtkrenderer: se usa para dirigir la interfaz entre la máquina gráfica y el sistema de ventanas del ordenador. vtkrenderwindow: se usan para dirigir la interfaz entre la máquina gráfica y el sistema de ventanas del ordenador. La render window es la ventana del ordenador donde el renderer crea el objeto. vtkrenderwindowinteractor: es uno de los métodos utilizados en VTK para interactuar con los datos de la escena. Es una herramienta que utilizamos para manipular la cámara, mover objetos, etc LA VENTANA DE RENDERIZADO (WINDOW RENDER) Para poder visualizar nuestros datos, lo primero que necesitamos es abrir una ventana en la pantalla de nuestro ordenador. VtkRenderWindow es una superclase abstracta que utilizamos para la representación de objetos que hemos dibujado en uno o más renders. Para la mayor parte de los objetos gráficos, automáticamente seleccionan el dispositivo correcto en cada plataforma para su visualización. VtkRenderWindow es una clase contenedora para objetos vtkrenderer, y múltiples renders pueden ser colocados en una única ventana de renderizado para crear visualizaciones complejas. En el siguiente ejemplo, colocaremos dos renders con colores de fondo diferentes uno junto a otro en una misma ventana de renderizado: vtkrenderwindow renwin renwin SetSize vtkrenderer ren1 ren1 SetViewport GVA-ELAI-UPM PFC

81 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK ren1 SetBackground renwin AddRenderer ren1 vtkrenderer ren2 ren1 SetViewport ren1 SetBackground renwin AddRenderer ren2 RenWin Render El objeto vtkrenderwindow controla el proceso, de forma que una única llamada a Render provocará la aparición de una ventana y los renders actualizarán su contenido. En este ejemplo sólo aparecerá un único color de fondo debido a que no hemos definido ningún prop RENDERS, MAPPERS Y PROPS Los props son los objetos añadidos al render para crear una escena. La clase vtkprop es una superclase abstracta válida para todos los props 2D y 3D y contiene información sobre visibilidad, orientación, tamaño y posición. Los props se asocian con los mappers y las propiedades del objeto. Los mappers se refieren a los objetos de entrada, y saben la forma de renderizar estos objetos. Las propiedades de los objetos contienen parámetros del renderizado como el color y las características del material RENDERIZADO 3D DE DATOS GEOMÉTRICOS Una subclase específica de vtkprop que puede ser empleada para la representación 3D de datos geométricos en una escena es vtkactor. El actor generará automáticamente un vtkproperty object por defecto, pero requiere que el usuario GVA ELAI UPM PFC

82 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez especifique una subclase de vtkmapper. Dependiendo de la naturaleza de la geometría referida al mapper, debemos usar bien la subclase vtkdatasetmapper o vtkpolydatamapper. Si los datos contienen puntos, líneas y polígonos representados usando vtkpolydata, entonces usaremos vtkpolydatamapper. De otra manera usaremos vtkdatasetmapper. A continuación presentaremos un ejemplo. El siguiente fragmento de código Tcl puede ser usado para crear un cubo y colocarlo en una escena: vtkcubesource cubedata vtkpolydatamapper cubemapper cubemapper SetInput \ [cubedata GetOutput] vtkactor cubeactor cubeactor SetMapper cubemapper ren1 AddProp cubeactor ren1 ResetCamera RenWin Render Como la salida de vtkcubesource es un dato poligonal, emplearemos vtkpolydatamapper. El siguiente fragmento de código Tcl gira el cubo y cambia su color: cubeactor RotateX 30.0 cubeactor RotateY 20.0 [cubeactor GetProperty] \ SetColor renwin Render 72 GVA-ELAI-UPM PFC

83 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK RENDERIZADO 3D DE DATOS VOLUMÉTRICOS El objeto vtkimagedata puede ser usado para representar imágenes de 1, 2 o 3 dimensiones. Como subclase de vtkdataset, vtkimagedata puede ser representado por un vtkactor y renderizado con un vtkdatasetmapper. En 3D estos datos pueden ser considerados como un volumen. Como alternativa, puede ser representado por un vtkvolume y renderizado por una subclase de vtkvolumemapper. Como algunas subclases de vtkvolumemapper usan técnicas geométricas para renderizar los volúmenes, la distinción entre volúmenes y actores aumenta. VTK soporta actualmente tres tipos de renderizado de volúmenes ray tracing, 2D texture mapping y un método que usa VolumePro graphics borrad. A continuación veremos un ejemplo que utiliza 2D texture mapping. Para comenzar con nuestro ejemplo, partiremos de una estructura 3D conformada de valores unsigned y la usaremos como entrada para vtkvolumetecturemapper2d: vtkslcreader negreader negreader SetFileName neghip.slc vtkvolumetexturemapper2d negmapper negmapper SetInput \ [negreader GetOutput] El paso más complicado en la visualización de volúmenes es frecuentemente la definición de las funciones de transferencia que transforman los datos escalares en color y opacidad: vtkpiecewisefunction negopacity negopacity AddPoint negopacity AddPoint vtkcolortransferfunction negcolor NegColor AddRGBPoint NegColor AddRGBPoint NegColor AddRGBPoint GVA ELAI UPM PFC

84 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez El primer valor que definimos cuando añadimos un punto a una función de transferencia es siempre el valor escalar, con un valor seguido por vtkpiecewisefunction o un RGB triple seguido de vtkcolortransferfunction. Como estamos visualizando datos de 8 bits, los valores escalares van desde 0 a 255. A continuación definimos las dos funciones de transferencia requeridas para la definición de las propiedades del volumen y la creación del volumen: vtkvolumeproperty negproperty negproperty SetColor negcolor negproperty SetScalarOpacity \ negopacity vtkvolume negvolume negvolume SetMapper negmapper negvolume SetProperty negproperty ren2 AddProp negvolume ren2 ResetCamera RenWin Render 74 GVA-ELAI-UPM PFC

85 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK Figura 4.4: Objetos dataset en VTK GVA ELAI UPM PFC

86 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez COMBINACIÓN DE LA GEOMETRÍA Y LAS LUCES El proceso de renderizado de VTK puede combinar múltiples actores y volúmenes en la misma escena. En el siguiente ejemplo una superficie poligonal es representada combinada con un volumen: vtkpolydatareader posreader posreader SetFileName \ poshipsurface.vtk vtkpolydatamapper posmapper posmapper SetInput \ [posreader GetOutput] vtkactor posactor posactor SetMapper posmapper ren2 AddProp posactor RenWin Render El proceso combinado de renderización de VTK tiene una serie de limitaciones: 1. VTK no soporta la translucidez de los datos geométricos debido a que las primitivas no están ordenadas de atrás hacia delante antes del renderizado. 2. Múltiples volúmenes pueden ser renderizados en la misma escena sólo si los límites de los volúmenes no se solapan. 76 GVA-ELAI-UPM PFC

87 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK RENDERIZADO DE DATOS 2D Además de volúmenes y datos 3D, VTK también visualiza datos 2D como imágenes y texto. El concepto de actores, mappers y propiedades se puede aplicar tanto a datos 2D como a 3D, aunque algunos parámetros específicos cambian. Veamos el siguiente ejemplo: vtktextmapper titlemapper titlemapper SetInput \ This is a Pink Cube titlemapper \ SetJustificationToCentered vtkactor2d titleactor titleactor SetMapper titlemapper [titleactor GetProperty] \ SetColor set pc [titleactor \ GetPositionCoordinate] $pc SetCoordinateSystemToNormalized- Viewport $pc SetValue ren1 AddProp titleactor RenWin Render Figura 4.5: Una red de visualización de VTK. Los Process objects (filtros) aparecen como esferas rojas y los Data objects como cubos azules. Los otros objetos representan props, propiedades, el render y la ventana de renderizado. GVA ELAI UPM PFC

88 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez El código necesario para cambiar el color del texto puede parecerse al código para cambiar el color del cubo. Sin embargo, los actores 3D son posicionados usando World coordinates, mientras que elegimos la posición del actor 2D a través de un sistema de coordenadas normalizado. Como los datos 2D son frecuentemente utilizados para la anotación, VTK ofrece varios objetos que combinan múltiples actores 2D y mappers en un solo actor 2D. Por ejemplo, vtkscalarbaractor combina texto y polígonos 2D para mostrar una representación: vtkscalarbaractor scalarbar scalarbar SetLookupTable negcolor scalarbar SetTitle Density set spc \ [scalarbar GetPositionCoordinate] $spc SetCoordinateSystemTo- NormalizedViewport $spc SetValue ren2 AddProp scalarbar renwin Render LUCES, CÁMARAS E INTERACTUACIÓN DE LOS DIFERENTES OBJETOS Muchas aplicaciones nunca crean explícitamente un vtklight o vtkcamera, sino que el render los crea automáticamente si no son definidos en el primer render. Una vez que el sistema crea una cámara, puedes acceder a ella desde el render para cambiar los parámetros de la cámara, como la posición, el punto focal y el campo de visión. La cámara posee algunos métodos adecuados para el giro de la posición y el punto focal como Azimuth, Elevation, Roll, Pitch y Yaw: set cam [ren2 GetActiveCamera] $cam Azimuth 20.0 $cam Elevation 10.0 RenWin Render 78 GVA-ELAI-UPM PFC

89 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK La luz creada automáticamente es una luz blanca con la misma posición y punto focal que el de la cámara. Si usamos un interactor, esta luz seguirá a la cámara. Podemos usar el siguiente código para añadir una segunda luz a la escena de renderizado del volumen. Esta luz viene de la derecha y es verde. Como la iluminación está desactivada por defecto, la luz verde no alterará el volumen: vtklight light light SetFocalPoint light SetPosition light SetColor light SetIntensity 0.5 ren2 AddLight light renwin Render Preferimos usar el ratón para controlar la posición de la cámara y su orientación, y los props en la escena. VtkRenderWindowInteractor proporciona esta funcionalidad y puede ser activado de la siguiente forma: vtkrenderwindowinteractor iren iren SetRenderWindow renwin iren Initialize El interactor puede ser colocado en modo joystick o trackball usando las teclas j o t. El botón izquierdo del ratón controla la rotación; el botón central controla la traslación del plano focal; el botón derecho controla el zoom. La tecla r se usa para resetear todas las funciones de la cámara. VTK también proporciona interactuación entre el usuario y la aplicación, como muestra el siguiente código: proc changetitle {} { titlemapper SetInput [.top.entry \ get] renwin Render } GVA ELAI UPM PFC

90 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez Toplevel.top Entry.top.entry.top.entry insert 0 \ {This is a Pink Cube} Pack.top.entry Bind.top.entry <Return> changetitle 4.4 VISUALIZATION MODEL El pipeline de procesamiento de datos de VTK transforma los datos de forma que puedan ser visualizados en los subsistemas gráficos descritos con anterioridad. Por ejemplo, podemos leer un conjunto de puntos desorganizados, crear una red poligonal a través de la triangulación Delaunay para después visualizarlos usando el renderizado poligonal. El modelo Visualization Model es el encargado de construir la representación geométrica que será renderizada por el pipeline gráfico. Los objetos principales que componen el Visualization Model son los siguientes: vtkdataobject: Los data objects representan datos de varios tipos. La clase vtkdataobject puede interpretarse como un conjunto genérico de datos. A los datos que tienen una estructura formal se les llama dataset (de la clase vtkdataset). vtkprocessobject: Los process objects, también llamados filtros, operan en los data objects para generar nuevos data objects. Representan los algoritmos del sistema. Process y data objects se conectan para formar los pipelines de visualización ARQUITECTURA DEL PIPELINE El pipeline, o de forma alternativa, la red de visualización, se construye conectando Process objects y Data objects. Los Data objects representan y 80 GVA-ELAI-UPM PFC

91 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK proporcionan el acceso a los datos, y los Process objects operan sobre los Data objects. Estas redes pueden ser elaboradas y pueden incluir ramas y vueltas. En la implementación, los conectores pueden hacerse usando SetInput ()/GetOutput (): afilter SetInput [bfilter \ GetOutput] ADVERTENCIA: los Data objects no se crean explícitamente. Una vez construido, la ejecución de la visualización del pipeline debe ser cuidadosamente controlada. Los filtros sólo deberían reejecutarse cuando su estado interno cambie o cuando la salida del filtro cambie. VTK emplea un proceso de actualización distribuido. Cada objeto en VTK mantiene un tiempo interno que es automáticamente actualizado cuando el estado del objeto cambia (generalmente como resultado del establecimiento del valor de una variable). Los Process y Data objects mantienen tiempos adicionales que son actualizados cuando se ejecuta el pipeline. El sistema compara estos tiempos (cada uno de los cuales es único, monótonamente creciente, de valor unsigned) para determinar cuales objetos están desfasados y por lo tanto que parte de la red debemos reejecutar. Muchos sistemas de visualización utilizan un control ejecutivo para controlar la ejecución de la red, lo que puede llegar a producir cuellos de botella en grandes aplicaciones paralelas. El mecanismo de ejecución distribuida de VTK permite un procesamiento paralelo escalable LOS DATA OBJECTS La figura muestra los Data objects que soporta VTK. Los Data objects representan información muy general como un campo (un array o arrays). Los Data sets son una especialización de los Data objects con estructura topológica y geométrica. Además de su estructura, los Data sets también tiene attribute data asociados con su topología y/o estructura. Los attribute data consisten en escalares, vectores, tensores, normales, etc. GVA ELAI UPM PFC

92 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez LOS PROCESS OBJECTS VTK ofrece varios cientos de Process objects. Muchos de los filtros operan sobre un único tipo de dato (por ejemplo, los filtro de procesamiento de imágenes). Algunos filtros como vtkcontourfilter acepta como entrada un solo tipo (volumen) y genera una salida de otro tipo (polígonos). Los Process objects son asemejados normalmente a filtros. Específicamente, VTK clasifica a los Process objects en tres categorías: fuentes, filtros y mappers. Las fuentes no tienen entradas de datos de VTK, pero producen una o más salidas; los filtros aceptan una o más entradas y generan una o más salidas; los mappers finalizan la visualización del pipeline, bien acoplándolo al subsistema gráfico o escribiendo sus datos en un disco o en una red. 82 GVA-ELAI-UPM PFC

93 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK 4.5 EJEMPLOS A continuación vamos a crear un pipeline complejo. Este ejemplo lee un conjunto de datos poligonales generados desde una digitalización de láser, y aplicando una serie de filtros, genera una superficie normal: vtkbyureader reader reader SetGeometryFileName fran.g A continuación generamos el pipeline, consistente en un decimator, smoother y un generador normal: vtkdecimatepro deci deci SetInput [reader GetOutput] deci SetTargetReduction 0.9 deci PreserveTopologyOn vtksmoothpolydatafilter smoother smoother SetInput [deci GetOutput] vtkpolydatanormals normals normals SetInput [smoother \ GetOutput] normals SetFeatureAngle 60 vtkpolydatamapper mapper mapper SetInput [normals GetOutput] vtkactor fran fran SetMapper mapper [fran GetProperty] \ SetColor La primera entrada es un Data set que contiene algunos puntos; la segunda define un glyph representado con datos poligonales. Usamos el filtro vtkmaskpoints para seleccionar al azar los puntos del glyph: GVA ELAI UPM PFC

94 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez vtkmaskpoints ptmask ptmask SetInput [normals GetOutput] ptmask SetOnRatio 10 ptmask RandomModeOn vtkconesource cone cone SetResolution 6 vtktransform transform transform Translate vtktransformpolydatafilter \ TransformF transformf SetInput [cone GetOutput] transformf SetTransform transform vtkglyph3d glyph glyph SetInput [ptmask GetOutput] glyph SetSource [transformf \ GetOutput] glyph SetVectorModeToUseNormal glyph SetScaleModeToScaleByVector glyph SetScaleFactor vtkpolydatamapper spikemapper spikemapper SetInput [glyph GetOutput] vtkactor spikeactor spikeactor SetMapper spikemapper [spikeactor GetProperty] \ SetColor A continuación añadimos los dos actores al render y renderizamos la escena: vtkrenderer ren3 vtkrenderwindow renwin2 renwin2 AddRenderer ren3 84 GVA-ELAI-UPM PFC

95 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK vtkrenderwindowinteractor iren2 iren2 SetRenderWindow renwin2 ren3 AddActor fran ren3 AddActor spikeactor renwin2 Render Figura 4.6: esta figura muestra una malla poligonal adquirida de un escáner de láser que ha sido decimated, smoothed y glyphed para indicar la superficie normal. GVA ELAI UPM PFC

96 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez 4.6 PROCESAMIENTO DE LAS IMÁGENES CON VTK VTK tiene un extenso número de métodos para el procesamiento de imágenes y renderización de volúmenes. Los datos de imágenes 2D y 3D vienen dados por la clase vtkimagedata. En un dataset de imagen los datos son ordenados en un vector regular alineado con los ejes. Mapas de bits y mapas de píxeles son ejemplos de datasets de imágenes 2D, y volúmenes (pilas de imágenes 2D) lo son de datasets de imágenes 3D. Los process objects en un pipeline de imagen siempre tienen como entradas y salidas data objects de imagen. Debido a la naturaleza regular y simple de los datos, el pipeline de imagen tiene otros rasgos importantes. La renderización de volumen se usa para visualizar objetos 3D de la clase vtkimagedata, y visores especiales de imágenes se usan para ver objetos 2D. La mayoría de los process objets en el pipeline de imagen están multiensamblados y son capaces de hacer fluir los datos por partes (para hacer un uso satisfactorio del límite de memoria). Los filtros detectan de forma automática el número disponible de procesos en el sistema y crean el mismo número de uniones durante la ejecución; igualmente separan automáticamente los datos en partes que fluyen a través del pipeline. 4.7 CREACIÓN DE UNA APLICACIÓN GRÁFICA CON VTK Crear aplicaciones gráficas con VTK es un proceso que consiste en dos partes básicas: 1. Construcción de un pipeline de datos para procesar los datos: es decir, conectar fuentes (crear datos), filtros (procesar datos) y mappers (transformar datos en gráficos). Están disponibles muchos tipos distintos de fuentes, filtros y mappers, en función del tipo de datos que se estén procesando y de la funcionalidad que se desee. 86 GVA-ELAI-UPM PFC

97 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK 2. Creación de los objetos gráficos necesarios para interpretar esos datos. Para crear objetos gráficos los pasos típicos pueden ser: 1. Crear una ventada de renderización para trabajar en ella. 2. Crear un render. 3. Crear un interactor (que permite interactuar con los datos). 4. Crear uno o más actores (cada uno de los cuales es unido a un mapper). 5. Renderizar. 4.8 GENERACIÓN DE PROYECTOS MEDIANTE VTK Los pasos a seguir para llevar a cabo la generación de proyectos con VTK serán los siguientes: 1. Debemos instalar la herramienta Cmake, que podremos encontrar en 2. A continuación debemos instalar también el conjunto de librerías VTK que podremos encontrar en En las opciones de instalación, seleccionaremos la compatibilidad para Python, Java y Tcl. 3. Copiamos la carpeta VTK-SRC-WINDOWS desde el CD de la aplicación hasta el directorio del disco duro donde hallamos instalado las librerías VTK. GVA ELAI UPM PFC

98 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez 4. Creamos una nueva carpeta en el directorio del disco duro donde se encuentre VTK con el nombre de DEBUGBUILD, en donde almacenaremos la configuración de VTK. 5. Iniciamos la aplicación Cmake, ejecutando CmakeSetup.exe. a continuación debemos configurar VTK. 6. En el directorio del código fuente, establecemos el path en donde se encuentre el source de VTK. 7. En el directorio de destino, donde se crearán las dll s y los build de VTK, establecemos lo siguiente: 8. Seleccionamos el compilador a utilizar. 9. Pinchamos en CONFIGURE. En el GUI se nos resaltan unas opciones en rojo. Activamos la casilla VTK_USE_PARALLEL. 88 GVA-ELAI-UPM PFC

99 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK 10. Pinchamos en CONFIGURE. Activamos la opción VTK_USE_MPI. GVA ELAI UPM PFC

100 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez 11. Pinchamos en CONFIGURE. Nos informará de que no encuentra el lugar donde se encuentra el ejecutable de MPI, el include y sus librerías; añadimos la información requerida: MPIRUN.exe:.\MPICH\MPD\BIN\MPIRUN.exe INCLUDE PATH:.\MPICH\SDK\INCLUDE LIBRARY PATH:.\MPICH\SDK\ LIB\MPICH.lib 12. Pinchamos en CONFIGURE. Después pinchamos en OK. 90 GVA-ELAI-UPM PFC

101 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK 4.9 EJECUCIÓN DE LAS APLICACIONES VTK 1. Lanzamos el compilador con el que estemos trabajando (en nuestro caso, Microsoft Visual Studio C++ 6.0). 2. Generamos un nuevo archivo *.cpp a través de la pestaña NEW FILES C++ SOURCE FILE. 3. Escribimos el programa a ejecutar y lo guardamos. 4. A continuación tenemos que crear el archivo de configuración CMakeLists.txt. Este archivo suele tener la siguiente estructura: PROJECT (nombre del proyecto) INCLUDE (${CMAKE_ROOT}/Modules/FindVTK.cmake) IF (USE_VTK_FILE) INCLUDE (${USE_VTK_FILE}) ENDIF (USE_VTK_FILE) LINK_LIBRARIES ( vtkrendering vtkgraphics vtkimaging vtkfiltering vtkcommon ) ADD_EXECUTABLE (nombre del proyecyo nombre del proyecto.cpp) GVA ELAI UPM PFC

102 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez 5. Guardamos el archivo *.txt con el nombre de CMakeLists. Tanto el archivo *.cpp como el *.txt han de estar localizados en una misma carpeta. 6. Lanzamos la aplicación Cmake. En el código fuente, incluimos el path del directorio donde se encuentren los archivos *.cpp y *.txt. En el destino, la carpeta donde queremos que se genere la aplicación: 7. Pinchamos en CONFIGURE. Nos informa de que no encuentra el path de VTK_DIR. Ponemos el path donde se encuentra ese directorio, que será.\vtk\debugbuild. Pinchamos en CONFIGURE y después en OK. 8. Lanzamos el compilador que hallamos seleccionado (en nuestro caso, Visual Studio C++ 7.0). Seleccionamos OPENWORKSPACE y abrimos el archivo *.dsw que se encontrará en el directorio de resultados. 9. Ejecutamos la aplicación y, si no se encuentran errores, nos pedirá que le proporcionemos la ruta del ejecutable a utilizar, que en nuestro caso será VTK.exe:.\VTK\BIN\VTK.exe 10. Vamos al directorio de resultamos, y ejecutamos la aplicación obtenida. A continuación vamos a ver un ejemplo sencillo de la utilización de VTK. En este ejemplo vamos a desarrollar una simple ventana de ejecución de VTK en donde incluiremos un cubo con el que podremos obtener sus diferentes vistas: #include "vtkcubesource.h" #include "vtkpolydatamapper.h" #include "vtkrenderwindow.h" #include "vtkrenderwindowinteractor.h" #include "vtkrenderer.h" 92 GVA-ELAI-UPM PFC

103 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK Static HANDLE hinst; long FAR PASCAL WndProc(HWND, UINT, UINT, LONG); class myvtkapp { public: myvtkapp (HWND parent); ~myvtkapp (); private: vtkrenderwindow *renwin; vtkrenderer *renderer; vtkrenderwindowinteractor *iren; vtkcubesource *cube; vtkpolydatamapper *cubemapper; vtkactor *cubeactor; }; int PASCAL WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpszcmdparam, int ncmdshow) { static char szappname[] = "Win32Cube"; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; if (!hprevinstance) { wndclass.style = CS_HREDRAW CS_VREDRAW CS_OWNDC; wndclass.lpfnwndproc = WndProc ; wndclass.cbclsextra = 0 ; wndclass.cbwndextra = 0 ; wndclass.hinstance = hinstance; wndclass.hicon = LoadIcon (NULL, IDI_APPLICATION); wndclass.hcursor = LoadCursor (NULL, IDC_ARROW); wndclass.lpszmenuname = NULL; wndclass.hbrbackground = (HBRUSH) GetStockObject (BLACK_BRUSH); wndclass.lpszclassname = szappname; RegisterClass (&wndclass); } GVA ELAI UPM PFC

104 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez hinst = hinstance; hwnd = CreateWindow ( szappname, "Draw Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 480, NULL, NULL, hinstance, NULL); ShowWindow (hwnd, ncmdshow); UpdateWindow (hwnd); while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return msg.wparam; } long FAR PASCAL WndProc (HWND hwnd, UINT message, UINT wparam, LONG lparam) { static HWND ewin; static myvtkapp *thevtkapp; switch (message) { case WM_CREATE: { ewin = CreateWindow("button","Exit", WS_CHILD WS_VISIBLE SS_CENTER, 0,400,400,60, hwnd,(hmenu)2, (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE), NULL); 94 GVA-ELAI-UPM PFC

105 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK thevtkapp = new myvtkapp(hwnd); return 0; } case WM_COMMAND: switch (wparam) { case 2: PostQuitMessage (0); if (thevtkapp) { delete thevtkapp; thevtkapp = NULL; } break; } return 0; case WM_DESTROY: PostQuitMessage (0); if (thevtkapp) { delete thevtkapp; thevtkapp = NULL; } return 0; } return DefWindowProc (hwnd, message, wparam, lparam); } myvtkapp::myvtkapp(hwnd hwnd) { this->renderer = vtkrenderer::new(); this->renwin = vtkrenderwindow::new(); this->renwin->addrenderer(this->renderer); this->renwin->setparentid(hwnd); this->iren = vtkrenderwindowinteractor::new(); this->iren->setrenderwindow(this->renwin); this->cube = vtkcubesource::new(); GVA ELAI UPM PFC

106 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez this->cube->setxlength( 5 ); this->cube->setylength( 5 ); this->cube->setzlength( 5 ); this->cubemapper = vtkpolydatamapper::new(); this->cubemapper->setinput(this->cube->getoutput()); this->cubeactor = vtkactor::new(); this->cubeactor->setmapper(this->cubemapper); this->renderer->addactor(this->cubeactor); this->renderer->setbackground(0.2,0.4,0.3); this->renwin->setsize(400,400); this->renwin->render(); } myvtkapp::~myvtkapp() { renwin->delete(); renderer->delete(); iren->delete(); cube->delete(); cubemapper->delete(); cubeactor->delete(); } A continuación el fichero Cmake.lists que necesitaremos generar será el siguiente: PROJECT (Win32Cube) INCLUDE (${CMAKE_ROOT}/Modules/FindVTK.cmake) IF (USE_VTK_FILE) INCLUDE(${USE_VTK_FILE}) ENDIF (USE_VTK_FILE) LINK_LIBRARIES( vtkrendering vtkgraphics vtkimaging vtkio 96 GVA-ELAI-UPM PFC

107 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK vtkfiltering vtkcommon ) ADD_EXECUTABLE(Win32Cube WIN32 Win32Cube.cxx) El resultado de nuestra aplicación será el siguiente: GVA ELAI UPM PFC

108 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez 4.10 UTILIZACIÓN DE VTK CON MPI Para poder utilizar MPI con VTK es necesario haber realizado la instalación de VTK en nuestra máquina. VTK dispone de una serie de clases preparadas para su aplicación en el procesamiento en paralelo. Estas clases están desarrolladas para que puedan hacer uso de la librería MPI. Entre las más destacadas se encuentran las siguientes: vtkmpicontroller: es una clase concreta que lleva a cabo los métodos de mando de multi-proceso definida en vtkmultiprocesscontroller que usa MPI. También proporciona la funcionalidad específica a MPI y no el presente en el vtkmultiprocesscontroller. vtkmpicommunicator: se ocupa de la supervisión de los comunicadores definidos por el propio usuario. vtkmpigroup: se ocupa de la supervisión de los comunicadores definidos por el propio usuario. vtkmpieventlog vtkmultiprocesscontroller El uso de comunicadores definidos por el usuario se realiza a través de vtkmpicommunicator y vtkmpigroup. Notar que un duplicado del comunicador definido por el usuario se usa para las comunicaciones interiores (RMIs). Este communicator tiene las mismas propiedades como el usuario uno sólo que tiene un nuevo contexto que impide a los dos communicators interferir entre sí. Las funciones que más se utilizan de esta clase, para conseguir que funcione correctamente el procesamiento en paralelo son las siguientes: 98 GVA-ELAI-UPM PFC

109 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK Inicialize (int *argc, char ***argv): Es necesario llamar a esta función para iniciar los procesos. Se tiene que poner solo una vez. GetLocalProcessId (): Sirve para que cada proceso averigüe su dirección (identificador) dentro de la colección de procesos que componen la aplicación. GetNumberOfProcesses (): Sirve para averiguar el número de procesos que participan en la aplicación. Finalize (): Sirve para dar por finalizada la aplicación. Se dispone también de una gran cantidad de funciones de envío y recepción de datos. Tiene funciones configuradas para enviar y recibir todo tipo de datos incluso imágenes (vtkdataobject): 1. Funciones de envío bloqueantes Send (int *data, int length, int remoteprocessid, int tag) Send (unsigned long *data, int length, int remoteprocessid, int tag) Send (char *data, int length, int remoteprocessid, int tag) Send (unsigned char *data, int length, int remoteprocessid, int tag) Send (float *data, int length, int remoteprocessid, int tag) Send (double *data, int length, int remoteprocessid, int tag) GVA ELAI UPM PFC

110 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez Send (vtkdataobject *data, int remoteid, int tag) Send (vtkdataarray *data, int remoteid, int tag) 2. Funciones de recepción bloqueantes Receive (int *data, int length, int remoteprocessid, int tag) Receive (unsigned long *data, int length, int remoteprocessid, int tag) Receive (char *data, int length, int remoteprocessid, int tag) Receive (unsigned char *data, int length, int remoteprocessid, int tag) Receive (float *data, int length, int remoteprocessid, int tag) Receive (double *data, int length, int remoteprocessid, int tag) Receive (vtkdataobject *data, int remoteid, int tag) Receive (vtkdataarray *data, int remoteid, int tag) 100 GVA-ELAI-UPM PFC

111 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK Figura UN EJEMPLO CONCRETO A continuación vamos a presentar un ejemplo que nos permite la reconstrucción en 3D a partir de una serie de imágenes superpuestas. El programa a continuación descrito está basado sobre la plataforma Microsoft Visual Studio: // // Llamamos a los archivos de cabecera de VTK para hacer posible la ejecución de todos // los comandos de VTK // #include "vtkactor.h" #include "vtkcamera.h" #include "vtkcontourfilter.h" #include "vtkgenericrenderwindowinteractor.h" #include "vtkimagedata.h" GVA ELAI UPM PFC

112 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez #include "vtkinteractorstyletrackballcamera.h" #include "vtklight.h" #include "vtkoutlinefilter.h" #include "vtkpolydata.h" #include "vtkpolydatamapper.h" #include "vtkpolydatanormals.h" #include "vtkproppicker.h" #include "vtkproperty.h" #include "vtkrenderwindow.h" #include "vtkrenderer.h" #include "vtkstripper.h" #include "vtkvolume16reader.h" int main( int argc, char *argv[] ) { // // Creamos un Renderer, una ventana de renderizado y un interactor para la ventana de // renderizado // vtkcamera *acamera = vtkcamera::new(); acamera->setclippingrange( , ); acamera->setdistance( ); acamera->setfocalpoint(100.8, 100.8, 69); acamera->setposition( , , ); acamera->setviewangle(30); acamera->setviewup( , , ); acamera->setparallelprojection(0); acamera->setusehorizontalviewangle(0); vtkrenderer *arenderer = vtkrenderer::new(); arenderer->setactivecamera(acamera); arenderer->setbackground(1, 1, 1); arenderer->setlightfollowcamera(1); vtkrenderwindow *renwin = vtkrenderwindow::new(); renwin->addrenderer(arenderer); renwin->setsize(500, 406); 102 GVA-ELAI-UPM PFC

113 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK vtkrenderwindowinteractor *iren = vtkrenderwindowinteractor::new(); iren->setrenderwindow(renwin); iren->setlightfollowcamera(1); // // Creamos el pipeline de VTK // vtkvolume16reader *v16 = vtkvolume16reader::new(); v16->setdatadimensions(64, 64); v16->setdataspacing(3.2, 3.2, 1.5); v16->setfileprefix("f:/proyecto/vtkgui101/vtkdata/data/headsq/quarter"); v16->setimagerange(1, 93); v16->setdatabyteorder(1); vtkcontourfilter *skinextractor = vtkcontourfilter::new(); skinextractor->setinput((vtkdataset *) v16->getoutput()); skinextractor->setvalue(0, 500); skinextractor->setcomputenormals(1); skinextractor->setcomputescalars(1); vtkpolydatanormals *skinnormals = vtkpolydatanormals::new(); skinnormals->setinput((vtkpolydata *) skinextractor->getoutput()); skinnormals->setfeatureangle(60); skinnormals->setcomputecellnormals(0); skinnormals->setcomputepointnormals(1); skinnormals->setflipnormals(0); skinnormals->setsplitting(1); vtkstripper *skinstripper = vtkstripper::new(); skinstripper->setinput((vtkpolydata *) skinnormals->getoutput()); skinstripper->setmaximumlength(1000); vtkpolydatamapper *skinmapper = vtkpolydatamapper::new(); skinmapper->setinput((vtkpolydata *) skinstripper->getoutput()); skinmapper->setnumberofpieces(1); skinmapper->setscalarrange(0, 1); skinmapper->setcolormode(0); skinmapper->setresolvecoincidenttopology(0); GVA ELAI UPM PFC

114 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez skinmapper->setscalarmode(0); skinmapper->setimmediatemoderendering(0); skinmapper->setscalarvisibility(0); skinmapper->setuselookuptablescalarrange(0); vtkactor *skin = vtkactor::new(); skin->setmapper(skinmapper); skin->getproperty()->setambientcolor(1, 1, 1); skin->getproperty()->setcolor(1, , ); skin->getproperty()->setdiffusecolor(1, 0.49, 0.25); skin->getproperty()->setopacity(1); skin->getproperty()->setinterpolation(1); skin->getproperty()->setrepresentation(2); skin->getproperty()->setbackfaceculling(0); skin->getproperty()->setedgevisibility(0); skin->getproperty()->setfrontfaceculling(0); skin->setorigin(0, 0, 0); skin->setposition(0, 0, 0); skin->setscale(1, 1, 1); skin->setpickable(1); skin->setvisibility(1); vtkcontourfilter *boneextractor = vtkcontourfilter::new(); boneextractor->setinput((vtkdataset *) v16->getoutput()); boneextractor->setvalue(0, 1150); boneextractor->setcomputenormals(1); boneextractor->setcomputescalars(1); vtkpolydatanormals *bonenormals = vtkpolydatanormals::new(); bonenormals->setinput((vtkpolydata *) boneextractor->getoutput()); bonenormals->setfeatureangle(60); bonenormals->setcomputecellnormals(0); bonenormals->setcomputepointnormals(1); bonenormals->setflipnormals(0); bonenormals->setsplitting(1); vtkstripper *bonestripper = vtkstripper::new(); 104 GVA-ELAI-UPM PFC

115 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK bonestripper->setinput((vtkpolydata *) bonenormals->getoutput()); bonestripper->setmaximumlength(1000); vtkpolydatamapper *bonemapper = vtkpolydatamapper::new(); bonemapper->setinput((vtkpolydata *) bonestripper->getoutput()); bonemapper->setnumberofpieces(1); bonemapper->setscalarrange(0, 1); bonemapper->setcolormode(0); bonemapper->setresolvecoincidenttopology(0); bonemapper->setscalarmode(0); bonemapper->setimmediatemoderendering(0); bonemapper->setscalarvisibility(0); bonemapper->setuselookuptablescalarrange(0); vtkactor *bone = vtkactor::new(); bone->setmapper(bonemapper); bone->getproperty()->setambientcolor(1, 1, 1); bone->getproperty()->setcolor(1, 1, ); bone->getproperty()->setdiffusecolor(1, 1, ); bone->getproperty()->setopacity(1); bone->getproperty()->setinterpolation(1); bone->getproperty()->setrepresentation(2); bone->getproperty()->setbackfaceculling(0); bone->getproperty()->setedgevisibility(0); bone->getproperty()->setfrontfaceculling(0); bone->setorigin(0, 0, 0); bone->setposition(0, 0, 0); bone->setscale(1, 1, 1); bone->setpickable(1); bone->setvisibility(1); vtkoutlinefilter *outlinedata = vtkoutlinefilter::new(); outlinedata->setinput((vtkdataset *) v16->getoutput()); vtkpolydatamapper *mapoutline = vtkpolydatamapper::new(); mapoutline->setinput((vtkpolydata *) outlinedata->getoutput()); mapoutline->setnumberofpieces(1); mapoutline->setscalarrange(0, 1); GVA ELAI UPM PFC

116 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez mapoutline->setcolormode(0); mapoutline->setresolvecoincidenttopology(0); mapoutline->setscalarmode(0); mapoutline->setimmediatemoderendering(0); mapoutline->setscalarvisibility(1); mapoutline->setuselookuptablescalarrange(0); vtkactor *outline = vtkactor::new(); outline->setmapper(mapoutline); outline->getproperty()->setambientcolor(0, 0, 0); outline->getproperty()->setcolor(0, 0, 0); outline->getproperty()->setdiffusecolor(0, 0, 0); outline->getproperty()->setopacity(1); outline->getproperty()->setinterpolation(1); outline->getproperty()->setrepresentation(2); outline->getproperty()->setbackfaceculling(0); outline->getproperty()->setedgevisibility(0); outline->getproperty()->setfrontfaceculling(0); outline->setorigin(0, 0, 0); outline->setposition(0, 0, 0); outline->setscale(1, 1, 1); outline->setpickable(1); outline->setvisibility(1); // // Insertamos todos los actores en el render // arenderer->addactor( outline ); arenderer->addactor( skin ); arenderer->addactor( bone ); // // Reseteamos la camera y la inicializamos // arenderer->resetcamera(); arenderer->resetcameraclippingrange(); renwin->render(); iren->initialize(); 106 GVA-ELAI-UPM PFC

117 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK iren->start(); // // Eliminamos las instancias de VTK creadas // acamera->delete(); arenderer->delete(); bone->delete(); boneextractor->delete(); bonemapper->delete(); bonenormals->delete(); bonestripper->delete(); iren->delete(); mapoutline->delete(); outline->delete(); outlinedata->delete(); renwin->delete(); skin->delete(); skinextractor->delete(); skinmapper->delete(); skinnormals->delete(); skinstripper->delete(); v16->delete(); } return 0; A continuación, deberemos crear el archivo Cmake.lists necesario para ejecutar la aplicación. Este archivo deberá tener la siguiente estructura: PROJECT (1.cpp) INCLUDE (${CMAKE_ROOT}/Modules/FindVTK.cmake) IF (USE_VTK_FILE) INCLUDE(${USE_VTK_FILE}) ENDIF (USE_VTK_FILE) GVA ELAI UPM PFC

118 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez ADD_EXECUTABLE(1 1.cpp) TARGET_LINK_LIBRARIES(1 vtkrendering vtkio vtkcommon) Una vez ejecutado el programa, el resultado que obtenemos es el siguiente: 108 GVA-ELAI-UPM PFC

119 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con VTK GVA ELAI UPM PFC

120 Procesamiento Distribuido de Imágenes Genérico con VTK Miguel Hernández Vázquez 110 GVA-ELAI-UPM PFC

121 5 Procesamiento Distribuido de Imágenes Genérico con Matlab En este capítulo vamos a tratar otra forma de realizar el procesamiento distribuido con MPI. Si hasta ahora, a la hora de realizar aplicaciones paralelas las implementábamos en lenguaje C, ahora vamos a introducir una nueva implementación de nuevo desarrollo: el MatlabMPI, es decir, la implementación de aplicaciones paralelas en lenguaje Matlab. GVA ELAI UPM PFC

122 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez 5.1 QUÉ ES MATLABMPI? Hoy en día, los verdaderos costos del gran desarrollo de la computación están dominados por el software. Para poder controlar estos costos es necesario migrar a lenguajes de alta productividad como Matlab. Figura 5.1: logo de MPI y Matlab Matlab es el lenguaje de programación predominante y más extendido para la implementación de cómputos numéricos, y es ampliamente usado también para el desarrollo e implementación de algoritmos, simulación, reducción de datos, comprobación y evaluación de sistemas. La popularidad de Matlab se debe a la alta tasa de productividad y rendimiento que logra, ya que una única línea de código en Matlab puede remplazar a diez líneas de código en C o FORTRAN. Muchos programas de Matlab pueden beneficiarse de su ejecución en sistemas distribuidos, ya que estos son mucho más rápidos. Ha habido muchos intentos previos de proporcionar un mecanismo eficiente para poder ejecutar aplicaciones y programas de Matlab en sistemas distribuidos paralelas. En el mundo del cómputo paralelo, MPI (Message Passing Interface) es el estándar empleado para la implementación de programas en múltiples computadoras. MPI define funciones de lenguaje C para realizar la comunicación punto a punto en aplicaciones paralelas. MPI ha demostrador ser un modelo efectivo para esta implementación de aplicaciones paralelas y es usado en la mayor parte de las aplicaciones más demandadas en el mundo, como podrían ser modelos climáticos, simulación armamentística, diseño aeronáutico y simulación de procesos de señales. MatlabMPI es una implementación para Matlab de MPI (Message Passing Interface) que permite que cualquier programa creado bajo Matlab pueda ser ejecutado en múltiples procesadores. MatlabMPI consiste en un conjunto de 112 GVA-ELAI-UPM PFC

123 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB instrucciones de Matlab que implementan un subconjunto de MPI, permitiendo que cualquier programa de Matlab pueda ser ejecutado en una computadora paralela. Además, MatlabMPI podrá ejecutarse en cualquier sistema de computadoras que soporten Matlab. Actualmente MatlabMPI implementa las seis funciones básicas que son el núcleo de la comunicación estándar MPI punto a punto. Esta implementación ha sido probada tanto en sistemas distribuidos de memoria compartida como en sistemas de memoria distribuida (SUN, SGI, HP, IBM Y LINUX). La innovación técnica que introduce MatlabMPI es que implementa el look and feel de MPI en el estándar de los ficheros de entrada/salida de Matlab; con esto lo que conseguimos es que esta implementación tenga tres características principales: Que obtengamos una implementación extremadamente compacta (aproximadamente 100 líneas de código). Que resulte una implementación muy pura. Esta implementación funcionará en cualquier punto en donde Matlab también funcione. MatlabMPI puede igualar el ancho de banda de comunicación del lenguaje C basado en MPI en el envío de mensajes de gran tamaño. 5.2 REQUISITOS DEL SISTEMA En sistemas de memoria compartida, MatlabMPI sólo necesita de una única licencia de Matlab a partir de la cual cualquier usuario es capaz de lanzar múltiples sesiones de Matlab. En un sistema de memoria distribuida, MatlabMPI necesita de una licencia de Matlab por máquina. Debido a que MatlabMPI utiliza archivos de entrada/salida para establecer la comunicación, también deberá existir un directorio, que deberá ser GVA ELAI UPM PFC

124 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez visible para cualquier máquina (este aspecto normalmente también se requiere a la hora de instalar Matlab). 5.3 INSTALACIÓN Y EJECUCIÓN Los pasos básicos a seguir para llevar a cabo la instalación y posterior ejecución de MatlabMPI son los siguientes: 1. Copiar el directorio de MatlabMPI en una localización que sea visible para todas las computadoras. 2. Añadir el directorio MatlabMPI/src al path de Matlab en nuestro archivo MATLAB/startupsav.m, que se encuentra en ~\Matlab7\toolbox\local: addpath ~/MatlabMPI/src ADVERTENCIA: puede ser necesario introducir un path diferente al anterior dependiendo de donde se realizara la instalación de MatlabMPI. 3. OPCIONAL: configurar rsh o ssh, incluir el path al ejecutable de Matlab. 4. Escribir help MatlabMPI para conseguir una lista de todas las funciones de MatlabMPI. 5. Escribir help function_name para conseguir más información sobre una función en particular. 114 GVA-ELAI-UPM PFC

125 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB 6. Ir al directorio de ejemplos dentro de MatlabMPI. 7. Para realizar la ejecución de cualquier programa de MatlabMPI desde la línea de comandos de Matlab, tendremos que escribir: eval( MPI_Run('xbasic', 2,machines) ); eval( MPI_Run('basic', 2,machines) ); eval( MPI_Run('multi_basic',2,machines) ); eval( MPI_Run('probe', 2,machines) ); eval( MPI_Run('speedtest', 2,machines) ); eval( MPI_Run('basic_app', 2,machines) ); eval( MPI_Run('broadcast', 2,machines) ); eval( MPI_Run('blurimage', 2,machines) ); MPI_Run tiene tres argumentos: el nombre del programa de MatlabMPI (sin la extensión *.m), el número de procesadores en donde queremos que se ejecute el programa y el argumento machines, que contiene una lista de los nombres de los procesadores en donde se ejecutará el programa. Si el usuario configura MPI_Run para usar N procesadores y la lista de machines contiene M nombres, donde M > N, entonces MPI_Run ejecutará el programa en los N primeros procesadores de la lista. El argumento machines puede estar expresado de las siguientes maneras: machines = {}; Ejecución el en procesador local. machines = {'machine1' 'machine2'}) ); Ejecución en múltiples procesadores. machines = {'machine1:dir1' 'machine2:dir2'})); Ejecución en multiprocesador y comunicación vía dir1 y dir2, los cuales deben ser visibles para ambos procesadores GVA ELAI UPM PFC

126 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez 8. Para ejecutar los programas de MatlabMPI usando el compiler de Matlab, debemos primero iniciar Matlab y después escribimos: eval( MPI_Run( MPI_cc('xbasic'), 2,machines) ); o MPI_cc('xbasic'); eval( MPI_Run( 'compiled xbasic.exe'), 2,machines) ); ADVERTENCIA: el comando MPI_cc sólo funcionará si tenemos adecuadamente configurado los paths de forma que nuestro código compilará (por ejemplo, nuestro LD_LIBRARY_PATH, etc ), lo que nos puede llevar un pequeño esfuerzo. En sistemas que funcionan bajo Linux, tendremos que añadir (como mínimo): matlab/extern/lib/glnx86 matlab/bin/glnx86 matlab/sys/os/glnx IMPLEMENTACIÓN DE UN PROGRAMA DE MATLABMPI A continuación, proponemos un ejemplo de un programa de MatlabMPI básico basado en el envío y recepción de mensajes: MPI_Init; comm = MPI_COMM_WORLD; comm_size = MPI_Comm_size(comm); my_rank = MPI_Comm_rank(comm); source = 0; dest = 1; tag = 1; if(comm_size == 2) % Initialize MPI. % Create communicator. % Get size. % Get rank. % Set source. % Set destination. % Set message tag. % Check size. 116 GVA-ELAI-UPM PFC

127 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB if (my_rank == source) data = 1:10; MPI_Send(dest,tag,comm,data); end if (my_rank == dest) data=mpi_recv(source,tag,comm); end end MPI_Finalize; exit; % If source. % Create data. % Send data. % If destination. % Receive data. % Finalize MatlabMPI. % Exit Matlab La estructura del programa anterior es muy similar a los programas de MPI escritos para C o Fortran, pero con la particularidad de un lenguaje de alto nivel. La primera parte del programa establece el MPI world; la segunda parte establece el rango y ejecuta el programa; la tercera parte cierra MPI world y sale de Matlab. Si el programa anterior fuera escrito en un archivo de Matlab llamado SendRecieve.m, este se ejecutaría llamando al siguiente comando desde el prompt de Matlab: eval( MPI_Run( SendReceive,2,machines) ); Donde el argumento machines puede tener cualquiera de la siguientes formas: machines = {}; Ejecución en el procesador local. machines = { machine1 machine2 }; Ejecución en múltiples procesadores. machines = { machine1:dir1 machine2:dir2 }; Ejecución en múltiples procesadores y comunicación usando dir1 y dir2, que deben ser visibles para ambas máquinas. El comando MPI_Run lanza un script de Matlab en las máquinas especificadas con la salida redirigida a un archivo. Si el proceso de rango 0 está siendo ejecutado en la máquina local, MPI_Run devuelve una cadena conteniendo los comandos para inicializar MatlabMPI, lo que permite a MatlabMPI ser invocado GVA ELAI UPM PFC

128 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez dentro de un programa de Matlab de la misma manera que el modelo empleado en OpenMP. El ejemplo SendRecieve nos muestra las seis funciones básicas de MPI (además de MPI_Run) que han sido implementadas en MatlabMPI: MPI Run MPI Init MPI Comm size Ejecuta un script de Matlab en paralelo. Inicia MPI. Obtiene el número de procesadores en la comunicación. MPI Comm rank Obtiene el rango del procesador dentro de la comunicación. MPI Send MPI Recv Envía un mensaje a un procesador (no bloqueante). Recibe un mensaje de un procesador (bloqueante). MPI Finalize Finaliza MPI. Por conveniencia, tres funciones adicionales han sido implementadas que proporcionan una funcionalidad importante a MatlabMPI: MPI Abort Función para eliminar todos los trabajos comenzados por MatlabMPI. MPI Bcast MPI Probe MatMPI Save messages MatMPI Delete all Informa sobre un mensaje (bloqueante). Devuelve una lista de todos los mensajes entrantes. Función de MatlabMPI que previene que los mensajes sean borrados. Función de MatlabMPI utilizada para eliminar todos los archivos creados por MatlabMPI. 118 GVA-ELAI-UPM PFC

129 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB 5.5 LANZAMIENTO Y ARCHIVOS DE ENTRADA/SALIDA El lanzamiento desde la línea de comandos de Matlab usando eval (MPI_Run ( )) permite una variedad de comportamientos. MPI_Run ( ) hace dos cosas. Primero, lanza un script de Matlab en los procesadores especificados con salida redirigida a un archivo. Segundo, si el rango es igual a 0 el proceso está siendo ejecutado en el procesador local, MPI_Run ( ) retorna un string.h conteniendo los comandos para inicializar MatlabMPI, que permite a MatlabMPI ser llamado desde cualquier programa de Matlab. Este lanzamiento y el comportamiento de salida es resumido en el cuadro a continuación: Machine MPI Rank = 0 MPI Rank > 0 Local exec() > screen unix > file Remote rsh > file rsh > file Los archivos que contiene el programa de salida son almacenados en el directorio MatMPI, que es creado por MPI_Run. Los nombres de los archivos son de la forma: program.rank.out Donde program es el nombre del programa de MatlabMPI y rank es el rango del proceso de MatlabMPI que genera el archivo de salida. GVA ELAI UPM PFC

130 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez 5.6 MANEJO DE LOS ERRORES MatlabMPI maneja errores bastante similares a los existentes en Matlab; sin embargo, la ejecución de cientos de procesos simultáneamente conlleva ciertos puntos adicionales: Si un error es encontrado y el script de Matlab tiene una sentencia exit (lo que debería ser), entonces todos los procesos de Matlab deberían finalizar correctamente. Si un trabajo de Matlab está esperando un mensaje que nunca llegará, entonces tendremos que finalizarlo a mano para comenzar una nueva sesión de Matlab y escribir: MPI_Abort Si esto no funciona, necesitaremos iniciar la sesión en cada procesador, escribir top y finalizar los procesos de Matlab uno a uno. MatlabMPI puede dejar una gran variedad de archivos tirados, los cuales son mejor eliminar una vez que se produce un error, comenzado Matlab y escribiendo: MatMPI_Delete_all Si esto no funciona, podemos eliminar los archivos a mano. Los archivos pueden encontrarse en dos lugares el directorio de ejecución y el directorio de comunicación (que por defecto están en el mismo lugar). forma: En el directorio de ejecución podemos tener archivos sobrantes de la 120 GVA-ELAI-UPM PFC

131 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB MatMPI/* En el directorio de comunicación podemos tener archivos sobrantes de la forma: p<rank>_p<rank>_t<tag>_buffer.mat p<rank>_p<rank>_t<tag>_lock.mat Es muy importante que se eliminen estos archivos. En general, si estamos usando un directorio público para realizar la comunicación (por ejemplo, /tmp), deberíamos crear primero un subdirectorio (por ejemplo, /tmp/joe), y usar este directorio para la comunicación. 5.7 EJECUCIÓN DE MATLABMPI SOBRE LINUX MatlabMPI también puede ser implementado en clusters basados en Linux. La clave consiste en cambiar el parámetro acdirmin desde 30 segundos a 0.1 segundos cuando nuestro NFS lanza el archivo del sistema que es usado para la comunicación. El comando lazador que encontramos tendrá la siguiente forma: mount -o acdirmin=0.1, \ rw,sync,hard,intr,rsize=8192,wsize=8192,nfsvers=2,udp \ node-a:/export/gigabit /wulf/gigabit ADVERTENCIA: si elegimos establecer estos parámetros en el automounter, debemos reiniciar el automounter en cada máquina que este en la lista. GVA ELAI UPM PFC

132 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez ADVERTENCIA: existe un error con la interfaz gráfica (GUI) de Matlab bajo Linux. Puede que nos encontremos con el siguiente error (o cualquier otro error extraño):??? Error using ==> mkdir tcsh: No entry for terminal type "'MATLAB Command Window'"tcsh: using dumb terminal settings. Si nos encontramos con este error, podemos intentar una de las siguientes soluciones: 1. Ejecutar el siguiente comando y reiniciar Matlab: setenv MATLAB_SHELL /bin/sh Si esto soluciona el problema, entonces puede que queramos añadir esta línea a nuestro.bashrc (o archivo equivalente *.dot si utilizamos una máscara diferente). 2. Si el establecimiento de las variables de entorno de MATLAB_SHELL no soluciona el problema, intentaremos eliminar nuestro directorio ~/.matlab y reiniciaremos Matlab desde la línea de comandos usando el comando: matlab nojvm 122 GVA-ELAI-UPM PFC

133 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB 5.8 EJECUCIÓN DE MATLABMPI SOBRE MacOSX MatlabMPI trabaja sobre MacOSX sin ninguna modificación. La mayor parte de las veces tendremos que usar ssh en ves de rsh. 5.9 EJECUCIÓN DE MATLABMPI SOBRE PC La instalación y ejecución de MatlabMPI sobre PC requiere una serie de pasos adicionales. A continuación vamos a describir la instalación de MatlabMPI en un PC. Si estamos instalando MatlabMPI como una parte de otro paquete (por ejemplo, Matlab), entonces tenemos que reemplazar todas las referencias a MatlabMPI con el packagename\matlabmpi (por ejemplo Matlab\MatlabMPI) INSTALACIÓN EN PC (AUTÓNOMO) Los pasos a seguir si queremos realizar este tipo instalación son los siguientes: 1. Si estamos instalando directamente sobre un PC, recuerde que el archivo startupsav.m se encuentra típicamente en: ~matlabroot/toolbox/local Lo que en nuestro caso sería: C:\MATLAB7\toolbox\local\startupsav.m GVA ELAI UPM PFC

134 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez 2. Agregamos.\ MatMPI al path en el archivo startupsav.m: addpath.\ MatMPI 3. Si no hemos agregado MatlabMPI\src al path, por ejemplo: addpath C:\MatlabMPI\src INSTALACIÓN EN PC Y UN CLUSTER DE LINUX Los pasos a seguir si queremos realizar este tipo instalación son los siguientes: 1. Si estamos instalando directamente sobre un PC, recuerde que el archivo startupsav.m se encuentra típicamente en: ~matlabroot/toolbox/local Lo que en nuestro caso sería: C:\MATLAB7\toolbox\local\startupsav.m 2. Agregamos.\ MatMPI al path en el archivo startupsav.m: addpath.\ MatMPI 3. Si no hemos agregado MatlabMPI\src al path, por ejemplo: 124 GVA-ELAI-UPM PFC

135 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB addpath C:\MatlabMPI\src INSTALACIÓN EN PC Y CLUSTER DE PC s Los pasos a seguir si queremos realizar este tipo instalación son los siguientes: 1. Debemos tener un sistema de archivos montado de forma cruzada de forma que todos nuestros PCs puedan ver los mismos archivos. Asumimos que este sistema a sido montado en la unidad Z:. 2. Copiamos MatlabMPI a Z:\MatlabMPI 3. Agregamos la siguiente sentencia a Z:\matlab\startupsav.m: addpath Z:\MatlabMPI\src addpath.\matmpi 4. En cada uno de los PCs añadimos lo siguiente a nuestro fichero local startupsav.m: addpath Z:\matlab startup 5. ADVERTENCIA: asegúrese que la licencia de Matlab flexlm está ejecutándose en cada PC. Una forma de asegurarse es simplemente iniciar la sesión de la consola en cada máquina. GVA ELAI UPM PFC

136 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez 6. ADVERTENCIA: los PCs no deben estar registrados por varios usuarios al mismo tiempo, por lo que debemos procurar que esto no ocurra. 7. Cada vez que lo ejecutemos deberíamos usar el siguiente sintaxis relativo al nombre de las máquinas, lo que explícitamente informa a Matlab los tipos de máquinas sobre los que estamos ejecutando nuestra aplicación: machines = {'mypc:pc' 'node-1:pc' 'node-2:pc'} 8. IMPORTANTE: el comando de MatlabMPI MPI_Abort sólo puede eliminar procesos en máquinas remotas que operen bajo Windows XP. Esto se debe a que XP es la única versión de Windows que cuenta con el comando taskkill, que permite eliminar procesos. Una utilidad para eliminar procesos para otras versiones de Windows se incluye en los kits de actualización. También es posible el empleo de utilidades gratuitas. MPI_Abort puede ser modificado por estas utilidades. 9. IMPORTANTE: el comando de MatlabMPI MPI_Abort eliminará todos los procesos de MatlabMPI en una máquina remota bajo Windows XP que se estén ejecutando en la sesión del usuario. Esto puede causar problemas si el usuario está ejecutando Matlab en otros procesadores RESOLUCIÓN DE PROBLEMAS Los nombres de las computadoras en Windows se escriben en mayúsculas. Esto puede causar problemas si el nombre de la computadora es especificado en la lista de máquinas en minúscula y la computadora no tiene un rsh daemon instalado. Por ejemplo, supongamos que el nombre de una computadora es MYCOMP. Si el nombre de la computadora es especificado en la lista de máquinas como mycomp : machines = {'mycomp:pc'...} 126 GVA-ELAI-UPM PFC

137 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB Esto causará que MatlabMPI intente rsh en MYCOMP en vez de ejecutar el programa directamente. Si iniciamos Matlab en un directorio que no contenga un directorio de MatlabMPI, aparecerá un mensaje de advertencia como este: Warning: Name is nonexistent or not a directory:.\ MatMPI. > In C:\MATLAB7\toolbox\matlab\general\path.m at line 116 In C:\MATLAB7\toolbox\matlab\general\addpath.m at line 88 In z:\matlab\startupsav.m at line 6 In C:\MATLAB7\toolbox\local\startupsav.m at line 2 In C:\MATLAB7\toolbox\local\matlabrc.m at line 199 Si queremos ocultar este error, debemos modificar el archivo startupsav.m de la siguiente forma: warning off: addpath.\matmpi warning on; La llamada al comando de advertencia suprimirá cualquier advertencia posterior. El comando MPI_Abort, por defecto, trabajo sólo bajo Windows XP. Esto es debido a que XP es la única versión de Windows que contiene la utilidad taskkill.exe para eliminar procesos. Una herramienta similar, kill.exe, es utilizable bajo Windows Para usar MPI_Abort con Win2K, será necesario actualizar nuestra versión de Windows y sustituir el comando kill.exe por taskkill.exe en el archivo MPI_Abort.m. Si no nos es posible actualizar nuestra versión de Windows 2000, existen otras herramientas gratuitas que nos proporcionan la misma función, como las Pstolos de Sysinternals (que podemos conseguir en GVA ELAI UPM PFC

138 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez Desafortunadamente, Windows 2000 no proporciona un contexto de usuario. Como consecuencia, cuando se ejecuta MPI_Abort, este eliminará todos los procesos de Matlab que se estén ejecutando en la máquina, sin tener en cuenta el usuario que esta ejecutando cada proceso. La utilidad taskkill evita este problema, eliminando sólo los procesos de Matlab que pertenezcan al usuario que ejecute el comando MPI_Abort OPTIMIZACIONES PARA UN MEJOR RENDIMIENTO Para proporcionar un mejor rendimiento de MatlabMPI en un cluster, podemos intentar realizar los siguientes pasos: 1. Instalar una copia de Matlab en cada nodo. 2. Montar de forma cruzada todos los discos locales de forma que cada nodo reciba los archivos sobre su propio disco. ADVERTENCIA: con estas optimizaciones, puede que algunas veces Matlab se ejecute demasiado rápido, de forma que surjan errores NFS como resultado. Una forma de evitar que surjan estos errores es eliminando todas las sentencias de path desde nuestro archivo.cshrc. De la misma forma, podemos encontrarnos con comportamientos extraños cuando trabajamos con mensajes de gran tamaño (~100 Mbyte); la forma de solucionarlo sería tratando de trabajar con mensajes de menor tamaño. También algunas veces una gran cantidad de tráfico NFS GETATTR puede ser generado si estamos esperando durante mucho tiempo la recepción de los archivos. Podemos comprobar este tráfico registrando el servidor NFS como raíz y escribiendo snoop Grez <machine-name>, y buscando los paquetes GETATTR. 128 GVA-ELAI-UPM PFC

139 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB 5.11 EJECUCIÓN POR LOTES Existen varios métodos para tratar la ejecución por lotes: 1. Solicitar una cola interactiva (muchos sistemas lo permiten). 2. Escribir un script de Matlab que contenga nuestro comando MPI_Run (por ejemplo, RUN.m) y añadir en nuestro batch script lo siguiente: matlab nojvm nosplash display null < RUN.m 3. Si queremos hacer las cosas de forma manual, la mejor manera es ver lo que ocurre cuando ejecutamos un programa en una máquina inexistente ; por ejemplo: MPI_Run ('xbasic', 2, {'unknown'}); Launching MPI rank: 1 on: unknown Launching MPI rank: 0 on: unknown unix_launch = rsh unknown -n 'cd /home/kepner/matlabmpi/examples; /bin/sh./matmpi/unix_commands.unknown.0.sh &' & El resultado de arriba nos muestra el comando exacto rsh que es generado. Podemos copiar y editar este comando para ejecutar nuestro programa. Además, deberíamos examinar el archivo que contiene las llamadas a Matlab, y que es: GVA ELAI UPM PFC

140 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez./MatMPI/Unix_Commands.unknown.0.sh 5.12 OTRAS CARACTERÍSTICAS El archivo: MatlabMPI/src/MatMPI_Comm_settings.m Puede ser editado por los usuarios de Matlab para modificar el comportamiento de MatlabMPI. Actualmente, las características incluidas son: Unix vs. Windows (deshabilitado) Rsh vs. Ssh (método que empleamos para ejecutar procesos de MatlabMPI sobre máquinas remotas) Establecimiento de la localización del ejecutable de Matlab Los usuarios podemos, bien editar este archivo directamente, o bien copiarlo en el directorio que estamos empleando y modificarlo localmente. Por defecto, MatlabMPI emplea rsh. Desafortunadamente, el cambio de rsh a ssh requiere algo más que cambiar simplemente las propiedades de machine_db_settings.remote_launch. El siguiente procedimiento nos permitirá usar ssh sin ser preguntado por una contraseña (un requisito necesario para MatlabMPI): 130 GVA-ELAI-UPM PFC

141 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB 1. Colocar machine_db_settings.remote_launch dentro de MatMPI_Comm_settings.m 2. Crear una llave RSA con el siguiente comando (acepta todos por defecto): ssh-keygen -t rsa 3. Añadir la llave RSA a la lista de llaves autorizadas: cat ~/.ssh/id_rsa >> ~/.ssh/authorized_hosts 4. Iniciar la sesión en cada una de las máquinas en donde MatlabMPI ejecutará los procesos y aceptar cada una de las claves de las mismas DIAGNÓSTICO Y RESOLUCIÓN DE PROBLEMAS 1. Asegúrese de que ha iniciado Matlab: escriba which matlab en cada una de las máquinas en donde estemos intentando ejecutarlo. Si nos aparece la siguiente sentencia: matlab: Command not found Entonces necesitaremos ponerlo en nuestro path. También podemos codificar el path dentro de MatlabMPI editando el archivo MatlabMPI/src/MatMPI_Comm_settings.m y cambiando la línea: GVA ELAI UPM PFC

142 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez matlab_location = ' matlab '; Asegúrese que todavía se puede ejecutar Matlab desde la línea de comandos de la máquina en la cual estemos ejecutando nuestro programa de MatlabMPI. 2. Comprobar que MatlabMPI está incluido en nuestro path: iniciamos Matlab y escribimos: help MatlabMPI Si nos aparece el siguiente error: MatlabMPI not found Entonces necesitaremos incluir MatlabMPI/src en nuestro path de la misma manera que lo hicimos en el apartado de INSTALACIÓN Y EJECUCIÓN PASOS A SEGUIR EN LA EJECUCIÓN DE LAS APLICACIONES DE MATLABMPI A continuación vamos a mostrar una serie de ejemplos que mostrarán los pasos a seguir para realizar la inicialización de los programas de MatlabMPI: 1. (Este paso es común y se realizará de la misma manera en todos los ejemplos que veamos a continuación) Vamos al directorio de 132 GVA-ELAI-UPM PFC

143 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB ejemplos que se encuentra dentro del directorio de MatlabMPI. Editamos el archivo RUN.m de forma que sólo se ejecute el archivo *.m que queramos ejecutar (que según los casos podrá ser xbasic, basic, multi_basic, speedtest, blurimage, etc). También deberemos modificar la variable machines de forma que el programa de MatlabMPI sólo se ejecute en las máquinas que nosotros deseemos. Guardamos los cambios realizados en el archivo RUN.m 2. Iniciamos Matlab y ejecutamos el archivo RUN.m. Esto debería llevar unos pocos segundos y, si todo ha funcionado correctamente, debería aparecer un mensaje en la command window de Matlab con la frase SUCCESS. 3. Finalizamos Matlab y miramos la salida de los otros procesadores escribiendo, por ejemplo: more MatMPI/*.out 5.15 CONSEJOS PARA LOS USUARIOS Eliminar copias antiguas de MatlabMPI antes de ejecutar nuestro programa. Usar el script RUN.m incluido en el directorio de ejemplos de MatlabMPI para ejecutar nuestros programas: RUN.m elimina procesos sobrantes de la ejecución de un programa de MatlabMPI anterior, elimina el directorio MatMPI y ejecuta nuestro programa. Asegúrese que el directorio que contiene el programa de MatlabMPI no está protegido contra la escritura, ya que MatlabMPI necesita crear y escribir en el directorio MatMPI. GVA ELAI UPM PFC

144 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez Asegúrese que cuando instale una nueva versión de MatlabMPI, todo el código fuente de la versión anterior es eliminado o que el path sólo contenga las especificaciones de la nueva versión. Será necesario comprobar que no existen copias de cualquier código fuente de antiguas versiones de MatlabMPI en el directorio de trabajo. No cambiar la estructura del directorio de MatlabMPI. Asegúrese de que nuestro programa no usa clear o clear all en cualquier punto del código de MatlabMPI. Cuando ejecutamos: eval( MPI_Run('...',...,...) ); Se crea una variable local llamada MPI_COMM_WORLD. Casi todas las funciones de MatlabMPI requieren la información contenida en esta variable. Asegúrese que nuestra aplicación no cambia su directorio de trabajo durante su ejecución. De otra forma, MatlabMPI no puede encontrar/acceder al directorio MatMPI. El reinicio de Matlab entre ejecuciones de programas de MatlabMPI puede mejorar el rendimiento. El reinicio de Matlab conlleva una serie de tareas, como por ejemplo, el limpiado de memoria, cerrado de archivos, etc. que pueden mejorar el desarrollo de una nueva sesión de Matlab. 134 GVA-ELAI-UPM PFC

145 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB 5.16 ARCHIVOS Descripción de los archivos/directorios que podemos encontrar en el paquete de software de MatlabMPI: doc/ examples/ src/ Documentación sobre MatlabMPI. Directorio que contiene los ejemplos y programas. Código fuente de MatlabMPI. doc/ README.vX.X credit mit_license todo Lo que es nuevo en esta versión. Créditos. MIT Licencia. Lista. examples/ xbasic.m basic.m multi_basic.m probe.m broadcast.m Programa de MatlabMPI que imprime por pantalla el rango de cada procesador. Programa de MatlabMPI que envía datos desde el procesador con rango 1 al procesador con rango 0. Programa de MatlabMPI que envía datos desde el procesador con rango 1 al procesador con rango 0 varias veces. Programa de MatlabMPI que demuestra el uso de MPI_Probe para comprobar la recepción de mensajes. Comprueba el comando de MatlabMPI broadcast. basic_app.m basic_app2.m basic_app3.m basic_app4.m Ejemplos de los usos más comunes de MatlabMPI. Ejemplos de los usos más comunes de MatlabMPI. Ejemplos de los usos más comunes de MatlabMPI. Ejemplos de los usos más comunes de MatlabMPI. GVA ELAI UPM PFC

146 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez blurimage.m speedtest.m synch_start.m machines.m unit_test.m unit_test_all.m unit_test_mcc.m unit_test_all_mcc.m MatlabMPI comprueba la aplicación de procesamiento paralelo de imágenes. Cronometra MatlabMPI para una gran variedad de mensajes. Función para sincronizar los inicios. Ejemplo de script para la creación de descripciones de las máquinas. Envoltura para usar un ejemplo como unit test. Llama a todos los ejemplos comprobando la librería completa. Envoltura para usar un ejemplo como mcc unit test. Llama a todos los ejemplos usando MPI_cc comprobando la librería completa. src/ Core Lite Profile MPI_Run.m MPI_Init.m MPI_Comm_size.m MPI_Comm_rank.m MPI_Send.m MPI_Recv.m MPI_Finalize.m Ejecuta un script de Matlab en paralelo. Inicializa el comienzo de MatlabMPI. Obtiene el número de procesadores en un comunicador. Obtiene el rango del procesador actual con un comunicador. Envía un mensaje a un procesador (no bloqueante). Recibe un mensaje desde un procesador (bloqueante). Finaliza MatlabMPI Core Profile MPI_Abort.m MPI_Bcast.m MPI_Probe.m MPI_cc.m Función para finalizar todos los trabajos de Matlab iniciados por MatlabMPI. Informa de un mensaje (bloqueante). Devuelve una lista de todos los mensajes entrantes. Compila usando Matlab mcc Core Plus Profile [Ninguna función por el momento.] 136 GVA-ELAI-UPM PFC

147 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB User Utility functions MatMPI_Comm_dir.m Función de MatlabMPI para el cambio de directorio usado para llevar a cabo la comunicación. MatMPI_Save_messages.m Función de MatlabMPI para prevenir que los mensajes sean eliminados. Útil para procesos de depuración. MatMPI_Delete_all.m Función de MatlabMPI para eliminar todos los archivos. MatMPI_Comm_settings.m Puede ser editado por los usuarios para cambiar las características de MatlabMPI (unix/windows, rsh/ssh,...) Library Utility functions MatMPI_Buffer_file.m Función de MatlabMPI para generar archivos de nombre buffer. Usada por MPI_Send and MPI_Recv. MatMPI_Lock_file.m Función de MatlabMPI para generar archivos de nombre lock. Usada por MPI_Send and MPI_Recv. Función de MatlabMPI para generar comandos. Usada por MatMPI_Commands.m MPI_Run. MatMPI_Comm_init.m Función de MatlabMPI para crear MPI_COMM_WORLD. Usada por MPI_Run. MatMPI_mcc_wrappers/ Contiene funciones de envoltorio para usar con MPI_cc ANCHO DE BANDA La gran mayoría de las aplicaciones de MATLAB son raramente aplicaciones paralelas, por lo que requieren de una mínima parte del potencial de implementación de MATLAB MPI. Estas aplicaciones raramente explotan todas las posibilidades de comunicación. MATLAB MPI ha sido ejecutado en SUN, HP, IBM, SGI Y LINUX. Los resultados indican que para mensajes de gran tamaño (es decir, de aproximadamente 1 Mbyte), MATLAB MPI es capaz de igualar el resultando de la implementación de MPI en lenguaje C. Para mensajes de menor tamaño, MATLAB MPI se ve limitado por su latencia (aproximadamente de 35 milisegundos), la cual es significativamente más elevada que para la implementación en C de MPI (ver Figura 4.3). GVA ELAI UPM PFC

148 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez Figura 5.2: Ancho de banda en un cluster de LINUX. Figura 5.3: Ancho de banda. Ancho de banda en función del tamaño del mensaje probado en el SGI ORIGIN MATLAB MPI iguala la implementación en lenguaje C en mensajes de gran tamaño. 138 GVA-ELAI-UPM PFC

149 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB Para comprobar más en profundidad la escalabilidad de MATLAB MPI se utilizo una simple aplicación consistente en el filtrado de una imagen. La aplicación del procesamiento de la imagen fue ejecutada con una carga constante por procesador (imagen de 1024 x 1024 píxeles por procesador) en grandes sistemas de memoria compartida/distribuida (el IBM SP2 en el MAUI HIGH PERFORMANCE COMPUTING CENTER). En dichas pruebas, se consiguió unas velocidades de 300 en 304 CPUs y un pico de sistema del 15% (450 gigaflops) (ver Figura 4.4 y Figura 4.5). Figura 5.4: velocidad de la memoria paralela compartida Figura 5.5: velocidad paralela compartida/dist ribuida GVA ELAI UPM PFC

150 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez El objetivo que se busca a la hora de ejecutar MATLAB en sistemas distribuidos es el poder incrementar la productividad del programador y disminuir el gran costo en software al usar sistemas HPC. La figura 4.6 muestra el coste en software (medido en líneas de software de código o SLOCs) en función del máximo rendimiento obtenido (medido en unidades de pico de procesador), para la misma aplicación de filtrado de imagen implementada con diferentes librerías y lenguajes (USIPL, MPI, OPENMP, C++, C y MATLAB). Los datos muestran que aquellos lenguajes de nivel superior necesitan un menor número de líneas para implementar el mismo nivel de funcionalidad. Para la obtención de resultados más extensos, se requiere de un número mayor de líneas de código. Para medir la productividad del software en los grandes sistemas distribuidos se han desarrollado dos medidas de gran utilidad: los gigaflops/sloc y las CPUs/SLOC. Los resultados de la aplicación anterior obtuvieron unos resultados de 0.85 gigaflops/sloc y 4.4 CPUs/SLOC. Figura 5.6: Productividad vs rendimiento. Las línea de código como función del máximo rendimiento alcanzado (medido en unidades de pico de procesador) para diferentes implementaciones para la misma aplicación de filtrado de imagen 140 GVA-ELAI-UPM PFC

151 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB 5.18 CONCLUSIONES Y PRÓXIMOS DESARROLLOS MATLAB MPI demuestra que el estándar propuesto para escritura de las aplicaciones paralelas en C y FORTRAN, es también válido en MATLAB. Además usando archivos de MATLAB de entrada/salida, es posible implementar completamente MATLAB MPI con el desarrollo de MATLAB, haciéndolo en seguida migrable a todas las computadoras en donde se ejecute MATLAB. La mayor parte de aplicaciones paralelas de MATLAB son triviales y no necesitan de un gran desarrollo. Sin embargo, MATLAB MPI puede igualar los resultados de la implementación en C de MPI para grandes mensajes. Además, el uso de archivos de entrada/salida como mecanismo de comunicación paralela no es nuevo y es ahora cada vez más factible con la disponibilidad de los bajos costos de los discos de alta velocidad. Por otra parte, el uso de estos archivos de entrada/salida tiene varias ventajas funcionales adicionales, que lo hacen fácil para implementar bufferes de gran tamaño, etc. por último, MATLAB MPI es aplicable a cualquier lenguaje (IDL, PYTHON, PERL). MATLAB MPI proporciona la mayor productividad posible en el desarrollo de aplicaciones paralelas. Sin embargo, debido a que es una librería de comunicación punto a punto, una cantidad considerable de código debe ser añadida a cualquier aplicación para poder realizar aplicaciones paralelas básicas. En la aplicación comprobada con anterioridad, el número de líneas de código MATLAB se incremento de 35 a 70. Mientras que una aplicación paralela de 70 líneas es extremadamente pequeña, esto representaría un aumento significativo en el caso de que contáramos con un único procesador. La simplicidad y funcionalidad de MATLAB MPI lo hace una elección muy aconsejable para programadores que quieran acelerar sus códigos MATLAB en computadoras paralelas. El trabajo para el futuro será el de crear objetos de mayor rango (como, por ejemplo, matrices distribuidas). El resultado será la construcción de una capa de comunicaciones dentro de MATLAB MPI, que permita a un usuario lograr un aceptable desarrollo paralelo sin un aumento de las líneas de código. GVA ELAI UPM PFC

152 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez Figura 5.7: futura arquitectura en forma de capas: diseño de unas herramientas paralelas de Matlab las cuales crearán una estructura de datos distribuida y objetos dataflow construidos en la cima de MatlabMPI 5.19 UN EJEMPLO PRÁCTICO: APLICACIÓN PARALELA PARA EL FILTRADO DE IMÁGENES MPI_Init; comm = MPI_COMM_WORLD; comm_size = MPI_Comm_size(comm); my_rank = MPI_Comm_rank(comm); % Inicia MPI. % Crea el comunicador. % Obtiene el tamaño. % Obtiene el rango. % Sincroniza el comienzo. starter_rank = 0; 142 GVA-ELAI-UPM PFC

153 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB delay = 30; % Segundos. synch_start(comm,starter_rank,delay); n_image_x = 2.^(10+1)*comm_size; % Establece el tamaño de la imagen % (usa potencia de 2). n_image_y = 2.^10; n_point = 100; % Número de puntos para poner en % cada subimágen. % Establece el tamaño del filtro (usa potencias de 2). n_filter_x = 2.^5; n_filter_y = 2.^5; n_trial = 2; % Establece el número de veces que % se realizará el filtrado. % Calcular el número de operaciones. total_ops = 2.*n_trial*n_filter_x*n_filter_y*n_image_x*n_image_y; if(rem(n_image_x,comm_size )~= 0) disp( ERROR: processors need to evenly divide image ); exit; end disp([ my_rank:,num2str(my_rank)]); left = my_rank - 1; % Imprimir por pantalla el rango. % Establece quién es la fuente y % quién es el destino. if (left < 0) left = comm_size - 1; GVA ELAI UPM PFC

154 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez end right = my_rank + 1; if (right >= comm_size) right = 0; end tag = 1; % Crea una etiqueta de identificación % para el mensaje. start_time = zeros(n_trial); end_time = start_time; zero_clock = clock; % Pone el reloj a 0. n_sub_image_x = n_image_x./comm_size; % Calcula las subimágenes para % cada procesador. n_sub_image_y = n_image_y; % Crea la imágen original y las imagines con las que trabajaremos. sub_image0 = rand(n_sub_image_x,n_sub_image_y).^10; sub_image = sub_image0; work_image = zeros(n_sub_image_x+n_filter_x,n_sub_image_y+n_filter_y); % Crea el núcleo. x_shape = sin(pi.*(0:(n_filter_x-1))./(n_filter_x-1)).ˆ2; y_shape = sin(pi.*(0:(n_filter_y-1))./(n_filter_y-1)).ˆ2; kernel = x_shape * y_shape; % Crea los índices. 144 GVA-ELAI-UPM PFC

155 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB lboxw = [1,n_filter_x/2,1,n_sub_image_y]; cboxw = [n_filter_x/2+1,n_filter_x/2+n_sub_image_x,1,n_sub_image_y]; rboxw = [n_filter_x/2+n_sub_image_x+1,n_sub_image_x+n_filter_x,1,n_sub_image_y]; lboxi = [1,n_filter_x/2,1,n_sub_image_y]; rboxi = [n_sub_image_x-n_filter_x/2+1,n_sub_image_x,1,n_sub_image_y]; start_time = etime(clock,zero_clock); % Set start time. for i_trial = 1:n_trial work_image(cboxw(1):cboxw(2),cboxw(3):cboxw(4)) = sub_image; if (comm_size > 1) ltag = 2.*i_trial; % Create message tag. rtag = 2.*i_trial+1; % Envía la subimágen izquierda. l_sub_image = sub_image(lboxi(1):lboxi(2),lboxi(3):lboxi(4)); MPI_Send( left, ltag, comm, l_sub_image ); % Recibe la parte derecha. r_pad = MPI_Recv( right, ltag, comm ); work_image(rboxw(1):rboxw(2),rboxw(3):rboxw(4)) = r_pad; % Envía la subimágen derecha. r_sub_image = sub_image(rboxi(1):rboxi(2),rboxi(3):rboxi(4)); MPI_Send( right, rtag, comm, r_sub_image ); GVA ELAI UPM PFC

156 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez % Recibe la parte izquierda. l_pad = MPI_Recv( left, rtag, comm ); work_image(lboxw(1):lboxw(2),lboxw(3):lboxw(4)) = l_pad; end work_image = conv2(work_image,kernel, same ); % Compute convolution. % Extrae la subimágen. sub_image = work_image(cboxw(1):cboxw(2),cboxw(3):cboxw(4)); end end_time = etime(clock,zero_clock); % Obtiene el tiempo de finalización. total_time = end_time - start_time % Imprime por pantalla los resultados. % Imprime por pantalla los cálculos computacionales. gigaflops = total_ops / total_time / 1.e9; disp([ GigaFlops:,num2str(gigaflops)]); MPI_Finalize; % Finaliza MatlabMPI. exit; 146 GVA-ELAI-UPM PFC

157 Miguel Hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con MATLAB GVA ELAI UPM PFC

158 Procesamiento Distribuido de Imágenes Genérico con MATLAB Miguel Hernández Vázquez 148 GVA-ELAI-UPM PFC

159 6 Procesamiento Distribuido de Imágenes Genérico con Paraview En este capítulo vamos a tratar otra de las formas que existen a la hora de realizar el procesamiento distribuido de imágenes genérico. En este caso vamos a emplear la herramienta Paraview. Esta herramienta es una de las existentes en el mercado para llevar a cabo la implementación de aplicaciones paralelas. En este capítulo veremos sus principales características y algunos ejemplos prácticos. GVA ELAI UPM PFC

160 Procesamiento Distribuido de Imágenes Genérico con Paraview Miguel Hernández Vázquez 6.1 QUÉ ES PARAVIEW? ParaView es una aplicación que se utiliza para visualizar datos en dos o tres dimensiones. Esta aplicación puede ser utilizada en un solo puesto de trabajo o también en un cluster de ordenadores (conjunto de ordenadores interconectados entre sí). Esto último permite a ParaView ejecutar grandes cadenas de datos mediante la utilización de procesamiento distribuido. Figura 6.1: Logo de ParaView 6.2 CARACTERÍSTICAS DE PARAVIEW Las características más importantes de ParaView son las siguientes: Es una aplicación de visualización multiplataforma de libre distribución. Soporta procesamiento distribuido para procesar grandes cantidades de datos. Dispone de una flexible e intuitiva interfaz de usuario. Desarrolla una extensible arquitectura basada en estándares abiertos. ParaView usa Visualization ToolKit (VTK) para procesar los datos y como motor de renderización y tiene un interfaz de usuario escrito usando una única mezcla de Tcl/Tk y C++. Esta arquitectura hace que ParaView sea una muy potente y flexible herramienta de visualización. Los datos fuente de VTK y los 150 GVA-ELAI-UPM PFC

161 Miguel hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con Paraview datos procesados por los filtros son inmediatamente accesibles o pueden ser añadidos escribiendo un simple fichero de configuración. Además, el uso de lenguaje Tcl permite que los usuariospuedan modificar el motor de procesado y el interfaz de usuario de ParaView ajustándolo a sus necesidades. Figura 6.2: Pantalla de inicio de ParaView 6.3 OBJETIVO DE PARAVIEW El objetivo de ParaView es desarrollar una herramienta paralela escalable que realice procesamiento distribuido de memoria. ParaView incluye algoritmos en paralelo, infraestructura de entrada y salida, ayuda, y dispositivos de demostración. Una característica significativa es que todo el software desarrollado está hecho como código abierto, por lo que es totalmente gratuito. GVA ELAI UPM PFC

162 Procesamiento Distribuido de Imágenes Genérico con Paraview Miguel Hernández Vázquez 6.4 INSTALACIÓN DE PARAVIEW ParaView utiliza Cmake para la construcción del sistema. Para poder compilar ParaView es necesario tener instalado Cmake, que podremos descargar de la página ParaView completo contiene VTK y Tcl/Tk 8.3.2, por tanto no es necesario bajarse VTK o Tcl/Tk para compilar. Una vez instalado Cmake y Paraview, será necesario realizar la configuración de Paraview para poder llevar a cabo la realización de aplicaciones. Los pasos a seguir para llevar a cabo dicha configuración los veremos en el siguiente punto. 6.5 CONFIGURACIÓN DE PARAVIEW Los pasos a seguir a la hora de realizar la configuración de Paraview son los siguientes: 1. Instalamos la aplicación Cmake, que podemos descargar de la página 2. A continuación debemos instalar la aplicación Paraview, que podemos descargar de la página 3. Descargamos el source de Paraview, y lo instalamos en la carpeta en donde hallamos realizado la instalación de Paraview. 4. Creamos una carpeta en el directorio de Paraview con el nombre de DEBUGBUILD, en donde se almacenarán las dll s y los build. 152 GVA-ELAI-UPM PFC

163 Miguel hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con Paraview 5. Lanzamos la aplicación Cmake a través de su ejecutable Cmake.exe. Una vez lanzada, configuraremos las propiedades para Paraview. 6. En el directorio del código fuente, ponemos el path en donde se encuentra nuestro código de Paraview, que en nuestro caso puede ser: C:\Archivos de programa\paraview En el directorio de destino, ponemos el path en donde queremos que se almacenen las configuraciones de Paraview (DEBUGBUILD): C:\Archivos de programa\paraview 1.8\DebugBuild 8. Por último, debemos seleccionar el compilador a utilizar (en nuestro caso, utilizaremos el Microsoft Visual Studio C++ 6.0). GVA ELAI UPM PFC

164 Procesamiento Distribuido de Imágenes Genérico con Paraview Miguel Hernández Vázquez 9. Pinchamos en CONFIGURE. Activamos la casilla VTK_USE_MPI. 10. Pinchamos en CONFIGURE. Volvemos a incluir el MPIRUN.exe, el include y las librerías: MPIRUN.exe:.\MPICH\MPD\BIN\MPIRUN.exe INCLUDE PATH:. \MPICH\SDK\INCLUDE LIBRARY PATH:. \MPICH\SDK\LIB\MPICH.lib 154 GVA-ELAI-UPM PFC

165 Miguel hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con Paraview 11. Pinchamos en CONFIGURE, y después en OK. 12. Una vez que hemos finalizado con Cmake, debemos lanzar el compilador que hemos especificado en la casilla (en nuestro caso Microsoft Visual Studio C++ 6.0). dentro del compilador seleccionamos File Open Workspace. En este punto seleccionamos el workspace que se nos habrá generado, que tendrá un nombre similar a ParaViewComplete.dsw. A continuación seleccionamos ALL_BUILD project, y construimos el proyecto. Una vez realizados estos pasos, estaremos en disposición de poder llevar a cabo la implementación de aplicaciones paralelas de Paraview. GVA ELAI UPM PFC

166 Procesamiento Distribuido de Imágenes Genérico con Paraview Miguel Hernández Vázquez EJECUCIÓN SOBRE UNIX Si se instalara en un directorio que está actualmente en el path de la búsqueda ($PATH o $path), podemos invocar ParaView desde la línea de comandos: $ paraview Si esto falla, tendremos que modificar el path de la búsqueda o invocar ParaView especificando el path completo del ejecutable. Por ejemplo, si el path de la instalación es /usr/local/bin, el siguiente lanzará la aplicación: $/ el usr/local/bin/paraview ParaView reconoce muchos argumentos de línea de comandos. Para obtener una lista de todos los argumentos disponibles, invoque ParaView con la opción help opcion EJECUCIÓN SOBRE WINDOWS Inicie ParaView seleccionando Todos los Programas ParaView 1.6 paraview desde el menú de inicio. 6.6 FICHEROS SOPORTADOS POR PARAVIEW ParaView soporta los siguientes tipos de ficheros: ParaView Files: Éste es el formato del archivo predefinido para ParaView. Soporta cualquier tipo de archivo de los soportados por ParaView (Image Data, Rectilinear Grid, Structured Grid, 156 GVA-ELAI-UPM PFC

167 Miguel hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con Paraview Unstructured Grid, Polygonal Data).La extensión del archivo es.* pvd. VTK Files: XML es el formato de archivo usado por VTK. Soporta cualquier tipo de archivo de los soportados por ParaView (Image Data, Rectilinear Grid, Structured Grid, Unstructured Grid, Polygonal Data). Las extensiones de los archivos son:.*vtp, para Polygonal Data;.*vti, para Image Data;.*vtr, para Rectilinear Grid;.*vts, para Structured Grid;.*vtu, para Unstructured Grid. Parallel VTK files: los Parallel VTK files contienen información sobre la distribución espacial de los datos. Soporta cualquier tipo de archivo de los soportados por ParaView (Image Data, Rectilinear Grid, Structured Grid, Unstructured Grid, Polygonal Data). Las extensiones de los archivos son:.*pvtp, para Polygonal Data;.*pvti, para Image Data;.*pvtr, para Rectilinear Grid;.*pvts, para Structured Grid;.*pvtu, para Unstructured Grid. Legacy VTK Files: los archivos de este tipo tienen la extensión.*vtk. Soporta cualquier tipo de archivo de los soportados por ParaView (Image Data, Rectilinear Grid, Structured Grid, Unstructured Grid, Polygonal Data). Parallel legacy VTK: los archivos de este tipo tienen la extensión.*pvtk. Soporta cualquier tipo de archivo de los soportados por ParaView (Image Data, Rectilinear Grid, Structured Grid, Unstructured Grid, Polygonal Data). EnSight Files: este formato de archivos es utilizado por CEI s EnSight (disponible en También son soportados formatos como ASCII, binary Ensight 6 y binary Ensight Gold. Tienen la extensión.*case. Soporta cualquier tipo de archivo de los soportados por ParaView (Image Data, Rectilinear Grid, Structured Grid, Unstructured Grid, Polygonal Data). PLOT3D Files: este el formato original de los archivos utilizados por el pack desarrollado por la NASA. Las extensiones son.*xyz para los GVA ELAI UPM PFC

168 Procesamiento Distribuido de Imágenes Genérico con Paraview Miguel Hernández Vázquez archivos de geometría y.*q para las soluciones. Sólo soporta un tipo de formato (Structured Grid). Stereo Lithography: ParaView puede leer archivos estéreo litográficos binarios o ASCII. Sólo soporta un tipo de formato (Polygonal Data). BYU Files: ParaView puede leer archivos MOVIE.BYU. estos archivos tienen la extensión.*g. Sólo soporta un tipo de formato (Polygonal Data). POP Ocean Files: Son ficheros creados para Parallel Ocean Program (POP) software. La extensión del fichero es *.pop. Protein Data Bank Files: es el formato de archivo usado por Protein Data Bank (PDB), un archivo experimental para determinar las tres dimensiones de las macromoléculas biológicas. Estos archivos tienen la extensión.*pdb. Produce una salida del tipo Polygonal Data. Xmol Files: es un archivo utilizado para la representación de moléculas. Tienen la extensión.*xyz. Produce una salida del tipo Polygonal Data. XDMF Files: tienen la extensión.*xmf. Sólo soporta los tipos de formato (Rectilinear Grid y Unstructured Grid). 158 GVA-ELAI-UPM PFC

169 Miguel hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con Paraview 6.7 TIPOS DE DATOS ADMITIDOS POR PARAVIEW Los tipos de datos utilizados por ParaView son: Image Data (rejilla rectilínea uniforme o volumen): Un image dataset es una colección de puntos y celdas colocados en una rejilla rectangular. Las filas, columnas y planos de la rejilla son paralelos a las coordenadas x-y-z del sistema. Rectilinear Grid (rejilla rectilínea no uniforme): El rectilinear dataset es una colección de puntos y celdas colocados en una rejilla rectangular. Las filas, columnas y planos de la rejilla son paralelos a las coordenadas x-y-z del sistema. Mientras la topología de los datos es regular, la geometría es solo parcialmente regular (el espacio entre los puntos puede variar). Structured Grid (rejilla curvilínea): Un structured grid es un dato con topología regular y geometría irregular. La rejilla puede ser desviada en alguna configuración en que las celdas no se corten. Unstructured Grid: es el tipo más general de datos con el que nos podemos encontrar. Tanto la topología como la geometría están completamente destructuradas. Polygonal Data: Polygonal data es una colección de figuras geométricas primarias, normalmente usadas por el motor de renderización para generar las imágenes dispuestas en el Display Area. El polygonal dataset consiste en vértices, polivértices, líneas, polilíneas, polígonos y triángulos GVA ELAI UPM PFC

170 Procesamiento Distribuido de Imágenes Genérico con Paraview Miguel Hernández Vázquez Figura 6.3: tipos de datos de Paraview 6.8 PRINCIPALES COMANDOS UTILIZADOS POR PARAVIEW Existen una serie de comandos que son los que comúnmente utilizamos a la hora de ejecutar ParaView. Distinguiremos tres categorías: General: start-empty, -e: Inicia ParaView sin ningún módulo por defecto. 160 GVA-ELAI-UPM PFC

171 Miguel hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con Paraview disable-registry, -dr: utilizaremos este comando para hacer pruebas sobre ParaView. play-demo, -pd: Ejecuta la demo de ParaView. batch, -b: Carga y ejecuta un específico batch script. stereo: habilita stereo rendering. use-offscreen-rendering, -os: Render offscreen en procesos satélites. render-module: Usa un módulo específico de renderización module (-- rendermodule=...) help: Visualiza los comandos válidos. Paralelo: use-rendering-group, -p: Usa un subconjunto de procesos para renderizar. Permite ejecutar ParaView sobre más de un nodo. group-file, -gf: Cuando usamos las opciones de --use-rendering-group, el número de nodos dónde realizar la renderización, se leen del fichero (usage -- groupfile= fname). use-tiled-display, -td: Duplica el dato final a todos los nodos y el nodo raíz muestra 1-n en una demostración total. tile-dimensions-x, -tdx: -tdx=x, donde X es el número de muestras en cada fila de la muestra. GVA ELAI UPM PFC

172 Procesamiento Distribuido de Imágenes Genérico con Paraview Miguel Hernández Vázquez tile-dimensions-y, -tdy: -tdy=y, donde Y es el número de muestras en cada columna de la muestra. Client/Server: client, -c: Inicia ParaView en modo cliente. server, -v: Inicia ParaView en modo servidor. host: proporciona al cliente cual la identidad del servidor (por defecto -- host=localhost). Usa esta opción junto con la opción --client. Mesa: use-software-rendering, -r: Usa software (Mesa) rendering en todos los nodos. use-satellite-software, -s: Usa software (Mesa) rendering solo en procesos satélites. nodo. Esto es útil cuando el usuario quiere tener una ventana solo en el primer 6.9 PARAVIEW CON MPI Si compilamos ParaView para soportar MPI, ParaView se podrá lanzar como cualquier otra aplicación MPI. El método para comenzar el uso de MPI depende del sistema y de la implementación con la que se haya instalado. 162 GVA-ELAI-UPM PFC

173 Miguel hernández Vázquez Procesamiento Distribuido de Imágenes Genérico con Paraview Una vez que esté comenzado, el interfaz de uso aparecerá el la pantalla con el proceso (proceso con la identificación 0). El display de otros procesos (procesos basados en los satélites), aparecerán ventanas independientes. Éstos no tienen asociados interfaces de uso y no se pueden manipular por el usuario. Observamos que todos los procesos tienen un display para visualizarlo. Esto no requiere la presencia de un monitor. Mientras ParaView pueda abrir ventanas de todos los procesos y leer su contenido, funcionará correctamente. Si varios procesos comparten el mismo display, ocurriría como si las ventanas abiertas por estos procesos se solapasen. Si sucede esto, el contenido de esas ventanas no se puede leer por ParaView y la imagen en la ventana principal (la que está con el interfaz de uso) será errónea. Igualmente pueden suceder si hay otras ventanas que ocultan la parte o toda la ventana de los procesos basados en los satélites. ParaView apoya fuera de la pantalla la representación en nodos basados en los satélites. Para lanzar ParaView en paralelo con MPI hay que realizarlo de igual modo que cualquier otra aplicación MPI, es decir, en la línea de comandos habrá que poner algo como: C:\temp\mpirun np 4 localroot C:\ParaView\bin\debug\ParaView Una vez realizado lo anterior se abrirá la pantalla de ParaView (solo en el nodo raíz) y podremos realizar las operaciones que queramos interactuando con los menús. GVA ELAI UPM PFC

174 Procesamiento Distribuido de Imágenes Genérico con Paraview Miguel Hernández Vázquez 164 GVA-ELAI-UPM PFC

175 7 Renderización de una Neurona En este capítulo vamos a intentar dar una visión de este procesamiento distribuido aplicado a un ejemplo concreto, que sería el renderizado de una neurona. Este renderizado constaría de dos partes: en una primera parte trataríamos la imagen (aplicaríamos filtros a la imagen. Es en este punto en donde se utiliza el procesamiento distribuido); y una segunda parte en la que nos encargaríamos de la reconstrucción 3D de la imagen. GVA ELAI UPM PFC

176 Renderización de una Neurona Miguel Hernández Vázquez 7.1 INTRODUCCIÓN Denominamos Renderización al proceso mediante el cual una estructura poligonal (tridimensional) digital más o menos básica obtiene una definición mucho mayor con juegos de luces, texturas y acentuado y mejorado de los polígonos, simulando ambientes y estructuras físicas. Cuando se está trabajando en un programa profesional de diseño 3D por computadora, no se puede visualizar en tiempo real el resultado del diseño de un objeto o escena compleja ya que esto requiere una potencia de cálculo extremadamente elevada, por lo que luego de diseñar el trabajo con una forma de visualización más simple y técnica, se realiza el proceso de renderización luego del cual se puede apreciar el verdadero aspecto (aspecto final) de una imagen estática o animación. Algunos métodos de Render son: Wireframe Sólido Sombreado Goraud Sombreado Phong Radiosidad 166 GVA-ELAI-UPM PFC

177 Miguel Hernández Vázquez Renderización de una Neurona 7.2 WIREFRAME Wireframe es un algoritmo de renderización del que resulta una imagen semitransparente, de la cual sólo se dibujan las aristas de la malla que constituye al objeto. De ahí su nombre. Casi nunca se emplea en la representación final de una imagen, pero sí en su edición, debido a la escasa potencia de cálculo necesaria (comparada con otros métodos). Para conseguir una imagen en wireframe sólo tenemos que tener en cuenta las posiciones de los puntos en el espacio tridimensional y las uniones entre ellos para formas los polígonos. Habitualmente estas imágenes no tienen en cuenta la presencia de luces en la escena. 7.3 RENDER SÓLIDO El render sólido es un algoritmo de renderización algo más complejo que el Wireframe en el que se usan técnicas de sombreado rudimentarias. Cada malla de la escena está formada por polígonos, cada uno de uno color. El Render sólido calcula el vector normal a cada polígono y calcula (frecuentemente mediante un producto escalar) lo perpendicular que es el polígono a una fuente de luz puntual. De esta forma, cuanto más se acerca el ángulo formado por la normal y el vector que está en el centro del polígono a cero se considera que el polígono debe de estar más iluminado. El sombreado es uniforma para todo el polígono. GVA ELAI UPM PFC

178 Renderización de una Neurona Miguel Hernández Vázquez 7.4 SOMBREADO GOURAUD El sombreado Gouraud es un algoritmo de renderización desarrollado por Henri Gouraud. En este algoritmo la información del color se interpola a través de la cara del polígono para determina el color de cada píxel. Este algoritmo interpola los valores de iluminación en los vértices del polígono teniendo en cuenta la superficie curva mediante la malla. Para calcular las normales en los vértices primero debemos determinar las normales en las caras alrededor del vértice y entonces promediar para obtener la normal. A través de la implementación de este algoritmo, evitamos el aspecto cuadrado que tienen algunos objetos. Esta técnica consiste en realizar el sombreado de un polígono teniendo en cuenta a los otros que le rodean, de esta forma conseguimos una mayor suavidad en las sombras y que una superficie formada por triángulos tenga el aspecto de una superficie curva. Los pasos a seguir para la aplicación del sombreado Gouraud son: 1. Para todos los vértices de las caras visibles: a) Se calcula la normal (UNITARIA) asociada al vértice como promedio de las normales (UNITARIAS) de las caras que contienen el vértice (incluidas las caras ocultas), en RW. 168 GVA-ELAI-UPM PFC

179 Miguel Hernández Vázquez Renderización de una Neurona b) Se calcula la iluminación (color) asociada al vértice, usando esta normal. 2. Iluminación asociada a píxel/punto de la cara como interpolación bilineal de las iluminaciones de los vértices: a) Cara ABC. b) Intersección de scan con AB y AC: P 1, P 2. c) Punto/píxel P, entre P 1 y P 2. d) Iluminaciones en P 1, P 2 como interpolación de iluminaciones en A, B, C: e) Iluminación en P como interpolación de iluminaciones en P 1, P 2 f) Cálculo incremental de iluminación en P: siguiente punto del scan, Q, tiene x Q = x P + 1 GVA ELAI UPM PFC

180 Renderización de una Neurona Miguel Hernández Vázquez También es posible cálculo incremental de I 1, I 2 Figura 7.1: Ejemplo de sombreado Gouraud PSEUDOCÓDIGO PARA ELSOMBREADO GOURAUD rendergouraud(listapolígonos lp, Luces luces, Punto3D puntovista) { para cada polígono poli en lp { Color[] colorvértice; para cada vértice i en poli colorvértice[i]=aplicamodeloiluminación(poli.vértice[i],poli.material, poli.vértice[i].normal,luces,puntovista); para cada (x,y) en poli { color=interpola(x,y,poli,colorvértice); PintaPixel(x,y,color); } } } VENTAJAS E INCONVENIENTES Mejora la representación de superficies curvas. Mala representación de las transiciones abruptas; 170 GVA-ELAI-UPM PFC

181 Miguel Hernández Vázquez Renderización de una Neurona Anomalías debido a la interpolación después de las proyecciones; La interpolación depende de la orientación del polígono (ya que se hace según las horizontales); Malas reflexiones especulares. 7.5 SOMBREADO PHONG El sombreado Phong es un método muy sofisticado de sombreado, que fue desarrollado por Phong Bui-tuong. Este algoritmo de renderización se caracteriza por crear precisos brillos especulares. A cada píxel se le da un color basado en el modelo de iluminación aplicado al punto, por lo que este algoritmo necesitará de mayor nivel de computación que el Gouraud. En gráficas 3D, los polígonos de los que está hecha la imagen necesitan ser sombreados. El sombreado Phong es una de las técnicas más sofisticadas para este propósito. Funciona como sombreado Goraud pero requiere más recursos del computador, aunque entrega mejores resultados. Los pasos a seguir son: 1. Cálculo de la normal (UNITARIA) asociada a cada vértice. GVA ELAI UPM PFC

182 Renderización de una Neurona Miguel Hernández Vázquez 2. Interpolación bilineal de normales para encontrar normal a punto/píxel de la cara: 3. Se calcula iluminación en P a partir de este vector normal : 4. Obtención de y : a) obtener punto P en mundo real correspondiente a píxel bajo estudio es difícil b) se puede aproximar y usar y constantes a toda la cara (p. ej., promedio de los de los vértices) c) se pueden interpolar (vectores o ángulos) a partir de los valores en los vértices Figura 7.2: Ejemplo de sombreado Phong 172 GVA-ELAI-UPM PFC

183 Miguel Hernández Vázquez Renderización de una Neurona PSEUDOCÓDIGO PARA EL SOMBREADO PHONG renderphong(listapolígonos lp, Luces luces, Punto3D puntovista) { para cada polígono poli en lp { para cada (x,y) en poli { Punto3D puntooriginal=poli.puntooriginal(x,y); Vector3D normal=poli.interpolanormal(x,y); Color color=aplicamodeloiluminación(puntooriginal,poli.material, normal,luces,puntovista); PintaPixel(x,y,color); } } } VENTAJAS E INCONVENIENTES Aspecto muy realista. Bastante lento: hay que calcular una ecuación de iluminación por píxel, normalizar e interpolar las normales. Demasiados cálculos, especialmente normalizaciones 7.6 RADIOSIDAD Conjunto de algoritmos de Renderización, que tratan de resolver el problema básico de la renderización de la forma más realista posible. Este algoritmo es el más prefecto de todos los sistemas de renderizado, pero también el más lento. En este algoritmo calculamos las interacciones entre la luz y el color de los objetos más o menos próximos. GVA ELAI UPM PFC

184 Renderización de una Neurona Miguel Hernández Vázquez Este es un sistema perfecto para simulaciones muy realistas en el campo de la arquitectura, especialmente en interiores, ya que ilustra muy bien el comportamiento de la luz en esas condiciones. También se utiliza mucho para crear los escenarios de algunos videojuegos en 3D para aportar realismo. El problema es el transporte de la luz sólo se puede modelar de forma óptima considerando que cada fuente luminosa emite un número enorme de fotones, que rebotan al chocar contra una superficie describiendo una cantidad de trayectorias imposibles de simular en un computador. La radiosidad emplea métodos como el de Monte Carlo para resolver este problema de forma estadística. El auge de la radiosidad y otros métodos eficientes de renderización han posibilitado un auge en la infografía, siendo muy habitual encontrar por ejemplo películas que aprovechan estas técnicas para realizar efectos especiales. 7.7 PARALELISMO EN EL PROCESO DE RENDERIZACIÓN Existen diferentes tipos de paralelismo aplicables al proceso de renderización; entre ellos destacan por su importancia: 1. El paralelismo Funcional 2. El paralelismo de Datos 3. El paralelismo Temporal 4. Métodos híbridos 174 GVA-ELAI-UPM PFC

185 Miguel Hernández Vázquez Renderización de una Neurona Estos tipos básicos pueden combinarse en sistemas híbridos que emplean diferentes formas de paralelismo EL PARALELISMO FUNCIONAL Consiste en dividir el proceso de renderización en una serie de etapas que pueden aplicarse de forma sucesiva a un conjunto de datos. Si se asigna una o varias de estas etapas a cada procesador, de modo que los datos van recorriendo los procesadores de uno en uno, entonces se forma una segmentación (pipeline) del proceso. Cuando una de las unidades de procesamiento acaba de procesar un conjunto de datos, env a su resultado hacia la unidad siguiente, y recibe nuevos datos para procesar de la unidad anterior. Idealmente, una vez que la red se completa, el grado de paralelismo alcanzado es igual al número de unidades funcionales. Este enfoque funciona especialmente bien para la visualización de superficies y de polígonos, donde las primitivas geométricas se introducen al comienzo de la red, y a la salida se obtienen los valores de los píxeles. Las dos limitaciones principales de este tipo de paralelismo son las siguientes: Por una parte, el hecho de que la velocidad conjunta queda determinada por su etapa más lenta, con lo que hay que diseñar el algoritmo cuidando mucho el balanceo de la carga. Por otro lado, el paralelismo disponible está limitado por el número de etapas de segmentación. GVA ELAI UPM PFC

186 Renderización de una Neurona Miguel Hernández Vázquez EL PARALELISMO DE DATOS En lugar de aplicarse una secuencia de operaciones consecutivas a un único flujo de datos, existe la posibilidad de dividir los datos en múltiples flujos y operar con ellos en unidades de procesamiento independientes. Este sistema tiene la ventaja de ser más adecuado para números elevados de procesadores, con lo que ha sido adoptado habitualmente en máquinas masivamente paralelas. Dentro del paralelismo de datos, se distingue entre el paralelismo de objeto y el paralelismo de imagen. El primero se refiere a las operaciones realizadas de forma independiente en varias particiones del volumen de datos inicial, e incluye las primeras etapas de la visualización, como las transformaciones de la vista, clipping o el cálculo de la iluminación. El segundo tipo aparece en las últimas fases de la red de visualización, e incluye las operaciones llevadas a cabo para calcular los valores de los píxeles EL PARALELISMO TEMPORAL En la generación de animaciones, a menudo es más importante el tiempo total requerido para renderizar todas las imágenes que el retardo producido en la renderización de cada imagen individual. En este caso, el paralelismo puede obtenerse de forma casi inmediata dividiendo el número de imágenes entre los procesadores disponibles, de modo que la unidad de trabajo sea una imagen completa MÉTODOS HÍBRIDOS Es posible integrar varias formas de paralelismo en un mismo sistema. Por ejemplo, los paralelismos funcional y de datos pueden incorporarse de forma conjunta dividiendo el conjunto de datos en varios fragmentos, que a su vez serán procesados de forma segmentada por varios procesadores. 176 GVA-ELAI-UPM PFC

187 Miguel Hernández Vázquez Renderización de una Neurona 7.8 CONCEPTOS ALGORÍTMICOS La mayor parte de algoritmos paralelos introducen una serie de sobrecargas que no están presentes en sus equivalentes secuenciales. Las causas de dichas sobrecargas pueden ser las siguientes: Comunicación entre procesos Desvíos en el balanceo de la carga Computación redundante Mayor espacio de almacenamiento requerido, debido a estructuras de datos replicadas o auxiliares. La aparición y la importancia de estas sobrecargas están relacionadas con una serie de características, tanto de los algoritmos paralelos en general como de la visualización en particular: Coherencia: la coherencia, en el campo de los gráficos por ordenador, consiste en la tendencia que presentan las características cercanas en el espacio o en el tiempo a tener propiedades similares. Los algoritmos de visualización paralelos deben tener en cuenta la coherencia para reducir las comunicaciones y aumentar el balanceo de la carga. Si no se tiene presente la coherencia, un algoritmo paralelo puede presentar sobrecargas que no están presentes en su equivalente secuencial. La coherencia entre imágenes consecutivas en una animación permite realizar un mejor reparto de la carga. La coherencia entre _las consecutivas de una imagen puede aprovecharse en un algoritmo secuencial de renderización de polígonos para interpolar de forma eficiente los valores de los píxeles entre los vértices de un polígono. GVA ELAI UPM PFC

188 Renderización de una Neurona Miguel Hernández Vázquez Mapeado del espacio de objeto al espacio de imagen: este mapeado no es fijo, sino que depende de las transformaciones y parámetros presentes en el momento en que se visualiza una escena. Si se dividen entre los procesadores tanto el volumen como la imagen, entonces en algún momento de la red de visualización deberá producirse una comunicación entre procesos para componer los resultados de todos ellos. Debido a la naturaleza esencialmente arbitraria de la función de mapeado, no puede establecerse un patrón de comunicación de forma previa. El manejo de esta comunicación es un punto crucial en muchos estudios sobre renderización en paralelo, especialmente en máquinas de memoria distribuida. Descomposición de la tarea y de los datos: los algoritmos basados en el paralelismo de datos se dividen en dos categorías, dependiendo de cómo se produzca la división del problema en tareas individuales. Puede paralelizarse el objeto o volumen a renderizar, en cuyo caso cada uno de los procesadores renderiza una zona concreta de la escena. Según este enfoque, es necesaria una tarea de composición de las imágenes obtenidas por cada procesador. Por otro lado, puede paralelizarse la imagen resultante, con lo que cada procesador debe encargarse de proyectar aquellos voxels o primitivas gráficas que afecten a la zona de la imagen que tiene asignada. En este caso, en cada nueva renderización debe enviarse a cada nodo la porción de datos que necesitará, o bien, si no existen muchas limitaciones en cuanto a memoria disponible, cada uno de los nodos puede contener el volumen completo de forma local. Balanceo de la carga: el principal problema que aparece a la hora de repartir la carga de forma equilibrada entre procesadores es el hecho de que los datos no se distribuyen de forma homogénea por el volumen (ni por la imagen). Por lo tanto, la posibilidad de dividir el volumen (o la imagen) en N fragmentos consecutivos (para N procesadores) de igual tamaño resulta, en general, de escasa eficiencia, ya que unos procesadores tendrán mucha mayor carga computacional que otros. Las estrategias para dividir los datos pueden clasificarse como estáticas y dinámicas. Las primeras realizan una partición fija de los datos. En general esta es la opción más sencilla, pero su problema es que una partición en que los bloques se escojan demasiado grandes resultará en una división no homogénea del trabajo, mientras que una 178 GVA-ELAI-UPM PFC

189 Miguel Hernández Vázquez Renderización de una Neurona división basada en fragmentos demasiado pequeños deja de aprovechar gran parte de la coherencia espacial de los datos. Las técnicas de balanceo dinámico de la carga van ajustando el reparto del trabajo a medida que se realiza la renderización. Los dos esquemas básicos dentro de este grupo son el balanceo bajo demanda, en el cuál el trabajo se reparte en pequeñas tareas independientes, de modo que cuando un procesador termina una de ellas, solicita y recibe otra, y así sucesivamente; mientras que el balanceo adaptativo consiste en retrasar las decisiones relativas a división de trabajo hasta que uno de los procesadores queda libre, momento en el cuál toda la tarea restante se divide de nuevo entre los procesadores. En general las técnicas dinámicas presentan potencialmente un balanceo más preciso, pero también introducen mayores sobrecargas de computación y comunicación, y sólo son eficientes, en general, en máquinas de memoria compartida, mientras que en las máquinas de paso de mensajes suele ser menos costoso el mantenimiento de una estrategia estática. 7.9 EJEMPLO: UNA POSIBLE OPCIÓN DE RENDERIZACIÓN DE UNA NEURONA Y SU POSTERIOR RECONSTRUCCIÓN 3D En este capítulo voy a exponer el código fuente programado en Matlab para la realización de una posible renderización de una neurona. Partimos del código fuente AbrirPic.m. A través de este script lo que hacemos es abrir la imagen de una neurona segmentada en 76 rodajas (slices), con el nombre NUEVO1.PIC. A continuación reducimos las dimensiones de la imagen original (512 x 512 x 3), para reducir el tiempo computacional (128 x 128x 3). A continuación dividimos la imagen abierta en tres subimágenes distintas para llevar a cabo la renderización por separado de cada una de las subimágenes. GVA ELAI UPM PFC

190 Renderización de una Neurona Miguel Hernández Vázquez Una vez realizada la segmentación seleccionamos el algoritmo de filtrado a utilizar (Average, Disk, Gaussian, Motion, Prewitt, Sobel, Unsharp). Después realizamos la visualización conjunta de la imagen y subimágenes originales y de la imagen y subimágenes filtradas. A continuación realizamos la reconstrucción 3D de la imagen filtrada y de las subimágenes CÓDIGO FUENTE % Apertura de la imagen de la neurona img3d = AbrirPic('nuevo1.pic', 38, 40); I = img3d(200: ,200: ,:); ver(:,:,1,:)=i; montage(ver); pause % División de la imagen en tres subimágenes cform = makecform('srgb2lab'); lab_he = applycform(i,cform); ab = double(lab_he(:,:,2:3)); nrows = size(ab,1); ncols = size(ab,2); ab = reshape(ab,nrows*ncols,2); ncolors = 3; [cluster_idx cluster_center] = kmeans(ab,ncolors,'distance','sqeuclidean','replicates',3); pixel_labels = reshape(cluster_idx,nrows,ncols); segmented_images = cell(1,3); rgb_label = repmat(pixel_labels,[1 1 3]); for k = 1:nColors color = I; color(rgb_label ~= k) = 0; segmented_images{k} = color; 180 GVA-ELAI-UPM PFC

191 Miguel Hernández Vázquez Renderización de una Neurona end J = segmented_images{1}; figure, imshow(j), title('subimágen 1'); pause K = segmented_images{2}; imshow(k), title('subimágen 2'); pause L = segmented_images{3}; imshow(l), title('subimágen 3'); pause % Menú De Selección Del Filtro A Utilizar button = listdlg('promptstring','seleccione el filtro a emplear:',... 'SelectionMode','single',... 'ListSize',[ ],... 'Name','GVA-ELAI Miguel 1.0',... 'OKString','Aceptar',... 'CancelString','Cancelar',... 'ListString',{'Average';'Disk';'Gaussian';'Motion';'Prewitt';'Sobel';'Unsharp'}) switch button % Filtro Average case 1 h = fspecial('average'); U = imfilter(i,h); M = imfilter(j,h); Q = imfilter(k,h); X = imfilter(l,h); figure, imshow([i,u]), title('imágen Original e Imágen Original Filtrada'); pause figure, imshow([j,m]), title('subimágen 1 Original y subimágen 1 filtrada'); pause GVA ELAI UPM PFC

192 Renderización de una Neurona Miguel Hernández Vázquez figure, imshow([k,q]), title('subimágen 2 Original y subimágen 2 filtrada'); pause figure, imshow([l,x]), title('subimágen 3 Original y subimágen 3 filtrada'); pause figure, freqz2(h), colorbar, title('filtro Aplicado'); pause % Filtro Disk case 2 h = fspecial('disk'); U = imfilter(i,h); M = imfilter(j,h); Q = imfilter(k,h); X = imfilter(l,h); figure, imshow([i,u]), title('imágen Original e Imágen Original Filtrada'); pause figure, imshow([j,m]), title('subimágen 1 Original y subimágen 1 filtrada'); pause figure, imshow([k,q]), title('subimágen 2 Original y subimágen 2 filtrada'); pause figure, imshow([l,x]), title('subimágen 3 Original y subimágen 3 filtrada'); pause figure, freqz2(h), colorbar, title('filtro Aplicado'); pause % Filtro Gaussian case 3 h = fspecial('gaussian'); U = imfilter(i,h); M = imfilter(j,h); Q = imfilter(k,h); X = imfilter(l,h); figure, imshow([i,u]), title('imágen Original e Imágen Original Filtrada'); pause figure, imshow([j,m]), title('subimágen 1 Original y subimágen 1 filtrada'); 182 GVA-ELAI-UPM PFC

193 Miguel Hernández Vázquez Renderización de una Neurona pause figure, imshow([k,q]), title('subimágen 2 Original y subimágen 2 filtrada'); pause figure, imshow([l,x]), title('subimágen 3 Original y subimágen 3 filtrada'); pause figure, freqz2(h), colorbar, title('filtro Aplicado'); pause % Filtro Motion case 4 h = fspecial('motion'); U = imfilter(i,h); M = imfilter(j,h); Q = imfilter(k,h); X = imfilter(l,h); figure, imshow([i,u]), title('imágen Original e Imágen Original Filtrada'); pause figure, imshow([j,m]), title('subimágen 1 Original y subimágen 1 filtrada'); pause figure, imshow([k,q]), title('subimágen 2 Original y subimágen 2 filtrada'); pause figure, imshow([l,x]), title('subimágen 3 Original y subimágen 3 filtrada'); pause figure, freqz2(h), colorbar, title('filtro Aplicado'); pause % Filtro Prewitt case 5 h = fspecial('prewitt'); U = imfilter(i,h); M = imfilter(j,h); Q = imfilter(k,h); X = imfilter(l,h); figure, imshow([i,u]), title('imágen Original e Imágen Original Filtrada'); pause figure, imshow([j,m]), title('subimágen 1 Original y subimágen 1 filtrada'); pause GVA ELAI UPM PFC

194 Renderización de una Neurona Miguel Hernández Vázquez figure, imshow([k,q]), title('subimágen 2 Original y subimágen 2 filtrada'); pause figure, imshow([l,x]), title('subimágen 3 Original y subimágen 3 filtrada'); pause figure, freqz2(h), colorbar, title('filtro Aplicado'); pause % Filtro Sobel case 6 h = fspecial('sobel'); U = imfilter(i,h); M = imfilter(j,h); Q = imfilter(k,h); X = imfilter(l,h); figure, imshow([i,u]), title('imágen Original e Imágen Original Filtrada'); pause figure, imshow([j,m]), title('subimágen 1 Original y subimágen 1 filtrada'); pause figure, imshow([k,q]), title('subimágen 2 Original y subimágen 2 filtrada'); pause figure, imshow([l,x]), title('subimágen 3 Original y subimágen 3 filtrada'); pause figure, freqz2(h), colorbar, title('filtro Aplicado'); pause % Filtro Unsharp case 7 h = fspecial('unsharp'); U = imfilter(i,h); M = imfilter(j,h); Q = imfilter(k,h); X = imfilter(l,h); figure, imshow([i,u]), title('imágen Original e Imágen Original Filtrada'); pause figure, imshow([j,m]), title('subimágen 1 Original y subimágen 1 filtrada'); pause figure, imshow([k,q]), title('subimágen 2 Original y subimágen 2 filtrada'); 184 GVA-ELAI-UPM PFC

195 Miguel Hernández Vázquez Renderización de una Neurona pause figure, imshow([l,x]), title('subimágen 3 Original y subimágen 3 filtrada'); pause figure, freqz2(h), colorbar, title('filtro Aplicado'); pause end % Reconstrucción 3D de las rodajas seleccionadas figure, colordef(gcf,'black'), title('reconstrucción 3D de la imagen') D = squeeze(u); [x y z D] = subvolume(d, [nan nan nan nan nan 4]); p = patch(isosurface(x,y,z,d, 5), 'FaceColor', 'red', 'EdgeColor', 'none'); p2 = patch(isocaps(x,y,z,d, 5), 'FaceColor', 'interp', 'EdgeColor', 'none'); isonormals(x,y,z,d,p); view(3); daspect([1 1.4]) camva(9); box on lighting gouraud axis tight % Reconstrucción 3D por separado de cada una de las subimágenes % Reconstrucción 3D por separado de la subimágen 1 figure, colordef(gcf,'black'), title('reconstrucción 3D subimágen 1') D = squeeze(m); [x y z D] = subvolume(d, [nan nan nan nan nan 4]); p = patch(isosurface(x,y,z,d, 5), 'FaceColor', 'red', 'EdgeColor', 'none'); p2 = patch(isocaps(x,y,z,d, 5), 'FaceColor', 'interp', 'EdgeColor', 'none'); isonormals(x,y,z,d,p); view(3); daspect([1 1.4]) camva(9); box on lighting gouraud axis tight % Reconstrucción 3D por separado de la subimágen 1 GVA ELAI UPM PFC

196 Renderización de una Neurona Miguel Hernández Vázquez figure, colordef(gcf,'black'), title('reconstrucción 3D subimágen 2') D = squeeze(q); [x y z D] = subvolume(d, [nan nan nan nan nan 4]); p = patch(isosurface(x,y,z,d, 5), 'FaceColor', 'red', 'EdgeColor', 'none'); p2 = patch(isocaps(x,y,z,d, 5), 'FaceColor', 'interp', 'EdgeColor', 'none'); isonormals(x,y,z,d,p); view(3); daspect([1 1.4]) camva(9); box on lighting gouraud axis tight % Reconstrucción 3D por separado de la subimágen 1 figure, colordef(gcf,'black'), title('reconstrucción 3D subimágen 3') D = squeeze(x); [x y z D] = subvolume(d, [nan nan nan nan nan 4]); p = patch(isosurface(x,y,z,d, 5), 'FaceColor', 'red', 'EdgeColor', 'none'); p2 = patch(isocaps(x,y,z,d, 5), 'FaceColor', 'interp', 'EdgeColor', 'none'); isonormals(x,y,z,d,p); view(3); daspect([1 1.4]) camva(9); box on lighting gouraud axis tight 186 GVA-ELAI-UPM PFC

197 Miguel Hernández Vázquez Renderización de una Neurona Figura 7.1 Figura 7.2 Figura 7.3 GVA ELAI UPM PFC

198 Renderización de una Neurona Miguel Hernández Vázquez Figura 7.4 Figura 7.5: reconstrucción 3D de la imagen 188 GVA-ELAI-UPM PFC

199 Miguel Hernández Vázquez Renderización de una Neurona GVA ELAI UPM PFC

200 Renderización de una Neurona Miguel Hernández Vázquez 190 GVA-ELAI-UPM PFC

201 8 PROCESAMIENTO DISTRIBUIDO CON C++ En este capítulo vamos a dar una pequeña introducción acerca de la implementación del procesamiento distribuido en el lenguaje de programación C++. Veremos las principales implementaciones que existen, así como una pequeña aproximación a dos de las implementaciones menos estudiadas: PVM y CORBA. GVA ELAI UPM PFC

202 Procesamiento Distribuido con C++ Miguel Hernández Vázquez 8.1 BREVE INTRODUCCIÓN A C++ El lenguaje C++ proviene del lenguaje C. El lenguaje C nació en los laboratorios Bell de AT&T de la mano de Kernighan y Ritchie en los años 70. Su eficiencia y claridad, y la posibilidad de realizar tanto acciones de bajo como de alto nivel han hecho de este lenguaje el principal tanto en el mundo del desarrollo de sistemas operativos como de aplicaciones tanto industriales como de ofimática. Con el tiempo y la experiencia el lenguaje fue evolucionando para dotarlo de mayor eficiencia desde el punto de vista del programador. En 1980 se añaden al lenguaje C características como las clases como resultado de la evolución de las estructuras, chequeo del tipo de los argumentos de una función y su conversión si es posible etc, dando como resultado lo que en ese momento se llamó C con clases. Su Bjarne Stroustrup. En 1983 este lenguaje fue rediseñado y comenzó a utilizarse fuera de AT&T. Se introdujeron las funciones virtuales, la sobrecarga de funciones y operadores. Tras refinamientos y modificaciones menores, este nuevo lenguaje apareció documentado y listo para su uso bajo el nombre de C++. Posteriormente C++ ha sido ampliamente revisado lo que ha dado lugar a añadir nuevas características como la herencia múltiple, las funciones miembro static y const, miembros protected, tipos de datos genéricos o plantillas, y la manipulación de excepciones. Se revisaron aspectos de la sobrecarga y manejo de memoria, se incremento la compatibilidad con C, etc. El éxito alcanzado por el lenguaje fue arrollador por lo que la AT&T se vió en la necesidad de promover su estandarización internacional. En 1989 se convocó el comité de la ANSI que más tarde entró a formar parte de la estandarización ISO. El trabajo conjunto de estos comités permitió publicar en 1998 el estandar ISO C++ (ISO/IEC 14882) de forma que el lenguaje pase a ser estable y el código generado utilizable por distintos compiladores y en distintas plataformas. Dentro de esta estandarización se incluye un conjunto de clases, algoritmos y plantillas que constituyen la librería estandar de C++. Esta librería introduce facilidades para manejar las entradas y salidas del programa, para la gestión de listas, pilas, colas, vectores, para tareas de búsqueda y ordenación de elementos, para el manejo de operaciones matemáticas complejas, gestión de cadenas de caracteres, 192 GVA-ELAI-UPM PFC

203 Miguel Hernández Vázquez Procesamiento Distribuido con C++ tipos de datos genéricos, etc. A este conjunto de algoritmos, contenedores y plantillas, se los denomina habitualmente por las siglas STL (Standard Template Library). El resultado de todo ello es un potente lenguaje de programación que admite la programación procedural (al igual que en C) y la programación orientada a objetos. El resultado es mucho mejor que C, soportando la abstracción de datos, y la programación genérica gracias a las plantillas. La parte de C incluida en C++ es conocida como C- y puede compilarse en C++ sin ningún problema. La sintaxis y las reglas de edición en general son iguales, por lo que a las modificaciones introducidas por C++ a la edición de código procedural (es decir, como si se tratase de C) se las denomina modificaciones menores ya que son fácilmente asumibles por un programador de C. A las modificaciones introducidas para soportar la programación orientada a objetos y la programación genérica, se las denomina modificaciones mayores, puesto que requieren para su uso de un cambio radical en la filosofía de programación. 8.2 ESTÁNDARES PARA LA PROGRAMACIÓN PARALELA EN C++ El lenguaje C++ no incluye ninguna primitiva para poder realizar la implementación de aplicaciones paralelas. No existe ninguna manera a través del lenguaje C++ para especificar que dos o más instrucciones deberían ser ejecutadas de forma paralela. Aunque existen versiones especiales de C++ que implementan la programación paralela, vamos a presentar una serie de métodos sobre cómo la programación paralela puede ser implementada usando el estándar de ISO para C++. La librería que da soporte a la programación paralela es la más flexible. Las librerías del sistema y las librerías del usuario pueden ser empleadas para soportar el paralelismo en C++. Las librerías del sistema son aquellas librerías que son proporcionadas por el propio sistema operativo. Por ejemplo, la librería POSIX (Portable Operating System Interface) es un conjunto de llamadas del sistema que GVA ELAI UPM PFC

204 Procesamiento Distribuido con C++ Miguel Hernández Vázquez puede ser usado conjuntamente con C++ para soportar la programación paralela. Estas librerías forman parte de una nueva especificación de UNIX EL ESTÁNDAR MPI MPI es la implementación estándar para llevar a cabo la comunicación basándose en el intercambio de mensajes. MPI fue desarrollado para su ejecución tanto en máquinas paralelas como en clusters de estaciones de trabajo. Para trabajar con MPI utilizamos la implementación MPICH. MPICH es una implementación de MPI libre y portable. MPICH proporciona al programador de C++ un conjunto de APIs y librerías que soportan programación paralela. MPI es especialmente útil para la programación SPMD (Single Program Multiple Data) y MPMD (Multiple Program Multiple Data). En los capítulos anteriores hemos podido ver las principales características de MPI y su implementación en diversas aplicaciones EL ESTÁNDAR PVM PVM significa Parallel Virtual Machine. Esta implementación es relativamente nueva ya que sus inicios se remontan al verano de 1989 en el Oak Ridge National Laboratory. Es un software que permite ejecutar aplicaciones paralelas distribuidas en redes de ordenadores heterogéneos. PVM es, junto con MPI, uno de los paquetes de software más utilizados para implementar aplicaciones paralelas. PVM explota el paralelismo en un ambiente de varias computadoras unidas mediante una red, siendo lo más común una red Ethernet; por tal motivo se tendrá un ambiente heterogéneo en cuanto a procesadores, y la memoria será distribuida. PVM es un paquete de software que permite a una colección heterogénea de computadoras conectarse mutuamente a través de una red para ser utilizadas como una gran computadora paralela. El objetivo de un sistema PVM es permitir que una colección de computadoras puedan ser utilizadas para la computación paralela. PVM soporta: Heterogeneidad en términos de máquinas, redes y aplicaciones 194 GVA-ELAI-UPM PFC

205 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Modelos de pase de mensajes explícitos Computación basada en procesos Soporte multiprocesador (MPP, SMP) Acceso al hardware: las aplicaciones bien pueden ignorar o aprovechar las diferencias entre el hardware. Lista de host configurable dinámicamente: los procesadores pueden ser añadidos o eliminados y se pueden incluir procesadores mixtos. PVM es el desarrollo más fácil y flexible disponible para la programación de tareas básicas paralelas que requieran la intervención de diferentes tipos de computadoras que trabajen sobre diferentes sistemas operativos. La librería PVM es especialmente útil para sistemas de varios procesadores que pueden ser conectados juntos para formal un procesador virtual paralelo. Además es el estándar para llevar a cabo la implementación de clusters heterogéneos y está disponible gratuitamente y es muy utilizado. Proporciona un soporte excelente para MPMD Multiple Program Multiple Data (MIMD Multiple Instruction Multiple Data) y SPMD Single Program Multiple Data (SIMD Single Instruction Multiple Data). Un programa paralelo en PVM, generalmente, constará de un proceso maestro y varios procesos esclavos, realizando cada esclavo una parte del trabajo global. En la figura 6.1 se ven dos posibles (no son los únicos) esquemas de trabajo para programas realizados en PVM. GVA ELAI UPM PFC

206 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Figura 8.1: Esquemas Maestro-Esclavo Un programa PVM también puede explotar una arquitectura multiprocesador con memoria compartida, ya que se generaría y se repartirían automáticamente los procesos que creados. Sin embargo esta dirigido para utilizar varias computadoras unidas por algún mecanismo como puede ser una red ethernet o redes mucho más especializadas para explotar este paralelismo. Se trabajará bajo el modelo de paso de mensajes, el cual se realizará bajo primitivas de tipo bloqueante, con lo que obtendremos un método de sincronización bastante sencillo EL ESTÁNDAR CORBA En computación, Common Object Request Broker Architecture (CORBA) es un estándar que establece una plataforma de desarrollo de sistemas distribuidos facilitando la invocación de métodos remotos bajo un paradigma orientado a objetos. CORBA fue definido y está controlado por el Object Management Group (OMG) que define las APIs, - el protocolo de comunicaciones y los mecanismos 196 GVA-ELAI-UPM PFC

207 Miguel Hernández Vázquez Procesamiento Distribuido con C++ necesarios para permitir la interoperabilidad entre diferentes aplicaciones escritas en diferentes lenguajes y ejecutadas en diferentes plataformas -, lo que es fundamental en computación distribuida. En un sentido general CORBA "envuelve" el código escrito en otro lenguaje en un paquete que contiene información adicional sobre las capacidades del código que contiene, y sobre cómo llamar a sus métodos. Los objetos que resultan pueden entonces ser invocados desde otro programa (u objeto CORBA) desde la red. En este sentido CORBA se puede considerar como un formato de documentación legible por la máquina, similar a un archivo de cabeceras pero con más información. CORBA utiliza un lenguaje de definición de interfaces (IDL) para especificar los interfaces con los servicios que los objetos ofrecerán. CORBA puede especificar a partir de este IDL la interfaz a un lenguaje determinado, describiendo cómo los tipos de dato CORBA deben ser utilizados en las implementaciones del cliente y del servidor. Implementaciones estándar existen para Ada, C, C++, Smalltalk, Java y Python. Hay también implementaciones para Perl y TCL. Al compilar una interfaz en IDL se genera código para el cliente y el servidor (el implementador del objeto). El código del cliente sirve para poder realizar las llamadas a métodos remotos. Es el conocido como stub, el cual incluye un proxy (representante) del objeto remoto en el lado del cliente. El código generado para el servidor consiste en unos skeletons (esqueletos) que el desarrollador tiene que rellenar para implementar los métodos del objeto. CORBA se encarga habitualmente de los siguientes aspectos en los sistemas distribuidos: Registro de objetos Localización de objetos Activación de objetos Gestión de errores GVA ELAI UPM PFC

208 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Multiplexación y desultiplexación de invocaciones Aplanado y desaplanado de datos Los tipos de componentes de los que consta CORBA son, generalmente: Object Services: independientes de dominio, útiles para muchos programas distribuidos (localización de objetos por nombre o por características, transacciones, notificación de sucesos, etc.) Common Facilities: para aplicaciones de usuarios finales (Distributed Document Component Facility) Domain Interfaces: para dominios específicos (Ej.: para telecomunicaciones) Application Interfaces: para aplicaciones específicas (no normalizados) 8.3 EL PROCESAMIENTO DISTRIBUIDO EN C++ A TRAVÉS DEL ESTÁNDAR PVM Con anterioridad hemos visto una pequeña reseña de PVM. En este apartado intentaremos dar una visión en mayor profundidad de la programación paralela y distribuida en C++ utilizando el estándar PVM. 198 GVA-ELAI-UPM PFC

209 Miguel Hernández Vázquez Procesamiento Distribuido con C INTRODUCCIÓN A PVM Qué es PVM? PVM es un paquete de software (conjunto de librerías) que nos permiten crear y ejecutar aplicaciones concurrentes o paralelas, basándose en el modelo de paso de mensajes. Funciona sobre un conjunto heterogéneo de ordenadores con sistema operativo UNIX conectados por una o mas redes. PVM permite trabajar tanto con arquitecturas de ordenadores diferentes como con redes de varios tipos. PVM tiene dos componentes básicos: 1. El proceso daemon (pvmd3): es un proceso Unix encargado de controlar el funcionamiento de los procesos de usuario en la aplicación PVM y de coordinar las comunicaciones. Tiene las siguientes características: Un daemon se ejecuta en cada máquina configurada en la máquina virtual paralela. Cada daemon mantiene una tabla de configuración e información de los procesos relativa a su máquina virtual (/tmp/pvmd.uid). Los procesos de usuario se comunican unos con otros a través de los daemons. Primero se comunican con el daemon local vía la librería de funciones de interface. Luego el daemon local manda/recibe mensajes de/a daemons de los host remotos. Cada máquina debe tener su propia versión de pvmd3 instalada y construida de acuerdo con su arquitectura y además accesible con $PVM_ROOT. 2. La librería de rutinas de interface (libpvm3.a, libfpvm3.a & libgpvm3.a): GVA ELAI UPM PFC

210 Procesamiento Distribuido con C++ Miguel Hernández Vázquez libpvm3.a: es una librería en lenguaje C de rutinas de interface. Son simples llamadas a Funciones que el programador puede incluir en la aplicación paralela. Proporciona capacidad de iniciar y terminar procesos; empaquetar, enviar, y recibir mensajes; sincronizar mediante barreras; conocer y dinámicamente cambiar la configuración de la máquina virtual paralela. Las rutinas de la librería no se conectan directamente con otros procesos, si no que mandan y reciben la configuración de la máquina virtual paralela. libgpvm3.a: Se requiere para usar grupos dinámicos. libfpvm3.a: Para programas en Fortran Ventajas del uso de PVM Algunas de las ventajas que presenta la utilización de PVM son las siguientes: Fiabilidad: promete cumplir los requerimientos que necesita la computación distribuida del futuro, permitiendo escribir programas que utilicen una serie de recursos capaces de operar independientemente y que son coordinados para obtener un resultado global que depende de los cálculos realizados en todos ellos. Reduce el "wall clock execution time". Fácil instalación y uso: con una interface de programación simple y completa. Extensión: Es un software de dominio público con creciente aceptación y uso. Flexibilidad: se adapta a diversas arquitecturas, permite combinaciones de redes locales con las de área extendida, cada 200 GVA-ELAI-UPM PFC

211 Miguel Hernández Vázquez Procesamiento Distribuido con C++ aplicación "decide" donde y cuando sus componentes son ejecutados y determina su propio control y dependencia, se pueden programar diferentes componentes en diferentes lenguajes, es fácil la definición y la posterior modificación de la propia Máquina Virtual Paralela. Tolerancia a fallos: si por cualquier razón falla uno de los ordenadores que conforman nuestra PVM y el programa que la usa está razonablemente bien hecho, nuestra aplicación puede seguir funcionando sin problemas. Siempre hay alguna razón por la que alguna máquina puede fallar, y la aplicación debe continuar haciendo los cálculos con aquel hardware que continúe disponible. Precio: así como es mucho más barato un computador paralelo que el computador tradicional equivalente, un conjunto de ordenadores de mediana o baja potencia es muchísimo más barato que el computador paralelo de potencia equivalente. Al igual que ocurrirá con el caso del computador paralelo, van a existir factores (fundamentalmente, la lentitud de la red frente a la velocidad del bus del computador paralelo) que van a hacer de que sean necesarios más ordenadores de pequeña potencia que los teóricos para igualar el rendimiento. Sin embargo, aun teniendo esto en cuenta, la solución es mucho más barata. Además, al no ser PVM una solución que necesite de máquinas dedicadas (es decir, el daemon de PVM corre como un proceso más), podemos emplear en el proceso los tiempos muertos de los procesadores de todas las máquinas de nuestra red a las que tengamos acceso. Por ello, si ya tenemos una red Unix montada, el costo de tener un supercomputador paralelo va a ser cero ya disponemos de las máquinas, no tendremos que comprar nada nuevo, y además la biblioteca PVM es software libre, por lo que no hay que pagar para usarla. Heterogeneidad: podemos crear una máquina paralela virtual a partir de ordenadores de cualquier tipo. PVM nos va a abstraer la topología de la red, la tecnología de la red, la cantidad de memoria de cada máquina, el tipo de procesador y la forma de almacenar los datos. Este último punto es de extrema importancia, ya que el principal problema que tendríamos en los sockets era la programación de rutinas de conversión de formato de datos entre todos los ordenadores de la red, puesto que la codificación, tanto de enteros como de flotantes, puede ser distinta. Por último, nos permite incluir en nuestra PVM hasta máquinas paralelas. Una máquina paralela en una PVM se puede comportar tanto como una sola máquina secuencial (caso, por GVA ELAI UPM PFC

212 Procesamiento Distribuido con C++ Miguel Hernández Vázquez ejemplo, del soporte SMP de Linux) o, como ocurre en muchas máquinas paralelas, presentarse a la PVM como un conjunto de máquinas secuenciales. Disponibilidad: la disponibilidad de PVM es completa Desventajas del uso de PVM Algunas de las desventajas que se encuentran asociadas al uso de PVM son: Nos podemos olvidar del paralelismo fuertemente acoplado: si disponemos de una red Ethernet, simplemente la red va a dejar de funcionar para todas las aplicaciones (incluida PVM) de la cantidad de colisiones que se van a producir en caso de que intentemos paralelismo fuertemente acoplado. Si disponemos de una red de tecnología más avanzada, es decir, más cara (como ATM) el problema es menor, pero sigue existiendo. La abstracción de la máquina virtual, la independencia del hardware y la independencia de la codificación tienen un coste: PVM no va a ser tan rápida como son los Sockets. Sin embargo, si el grado de acoplamiento se mantiene lo suficientemente bajo, no es observable esta diferencia INSTALACIÓN DE PVM Requerimientos necesarios para trabajar con PVM Los requerimientos necesarios para trabajar con PVM son: Procesadores Unix conectados en Red (usualmente protocolo Internet). 202 GVA-ELAI-UPM PFC

213 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Daemon PVM, construido para cada arquitectura e instalado en cada máquina. Librerías PVM, construidas e instaladas para cada arquitectura. Ficheros particulares de aplicación específica: Programas (master/slave, SPMD,...), PVM hostfile (define que máquinas físicas componen la máquina virtual propia), ficheros $HOME/.rhosts Instalación de PVM en LINUX Una vez que hemos obtenido el fichero pvm tar.gz, los pasos a seguir serán los siguientes: 1. Descomprimir el ficheropvm tar.gz. Esto generará el archivo pvm tar. 2. Generar la estructura de directorios de pvm tar xvf pvm tar 3. Poner las variables de entorno ( Preferiblemente en el profile): PVM_ROOT = $HOME/pvm3 PVM_ROOT = $HOME/pvm3 PVM_DPATH = $PVM_ROOT/lib/pvmd PVM_ARCH = LINUX Export PVM_ROOT PVM_DPATH PVM_ARCH 4. Ejecutar aimk s c g( en el directorio $HOME/pvm3 ) GVA ELAI UPM PFC

214 Procesamiento Distribuido con C++ Miguel Hernández Vázquez 5. Añadir $PVM_ROOT/lib al path. Para verificar que la instalación es correcta escriba pvm. Esta orden invoca la consola de PVM. Debe aparecer el prompt pvm>. Ahora teclee conf. Se visualiza el nombre y las características técnicas de las computadoras físicas adscritas a la máquina virtual. Un ejemplo de dicha salida por pantalla es: 1 host, 1 data format HOST DTID ARCH SPEED DSIG dixxx.edv.uniovi.es LINUX x pvm> Para finalizar y volver al shell teclee halt. Si durante los pasos anteriores no se produce por pantalla la salida mencionada la instalación NO ES correcta. La instalación de la librería PVM concluye con la etapa de verificación de la instalación descrita. Desde el punto de vista del administrador no hay tareas adicionales que realizar salvo, claro está, las asociadas con la concesión de permisos y la correcta configuración de las máquinas físicas para integrarlas en una red de computadoras. Los siguientes pasos en la configuración de PVM corresponden a los usuarios finales, que son quienes determinas dónde, cuándo y cómo se va a constituir una máquina virtual para soportar la ejecución paralela de una aplicación. Estos pasos se describen en el siguiente apartado CONFIGURACIÓN DE PVM En este apartado se detallan las distintas etapas para poder utilizar PVM desde una cuenta de usuario. El proceso de configuración está dividido en dos etapas: 1. PVM sobre una única máquina física. 204 GVA-ELAI-UPM PFC

215 Miguel Hernández Vázquez Procesamiento Distribuido con C++ 2. PVM sobre varias computadoras, siguiendo una estructura incremental; esto es, lo dicho para una única máquina física es necesario para varias computadoras. Para las explicaciones suponemos que PVM está instalado en el mismo directorio en todas las máquinas físicas. En caso contrario se debe recurrir a los manuales de PVM o a Message Passing with PVM and MPI: Advanced Features and Trends (Markus Fischer), para determinar los parámetros necesarios. Por último, hay que resaltar la importancia de seguir correctamente los pasos que a continuación se van a detallar. En caso contrario puede suceder que la máquina virtual no funcione correctamente. De hecho, los problemas típicos de PVM están ligados a la falta de permisos o a que los daemons no encuentran el resto de procesos o ficheros por una mala configuración. Otra causa habitual de un funcionamiento anómalo de PVM es la modificación de scripts asociados al shell sin haber lanzado un nuevo shell (o entrar otra vez en sesión). Las modificaciones realizadas normalmente no están disponibles hasta que no se lance de nuevo el shell PVM sobre una única máquina física En este supuesto el proceso es muy simple. Para que el funcionamiento de la consola de PVM sea más explícito, se puede crear un fichero en $HOME, con nombre.pvmrc, con un contenido similar al siguiente ejemplo: alias? help alias print_environment spawn -> /bin/env alias h help alias j jobs alias t ps alias tm trace alias v version setenv PVM_EXPORT DISPLAY tm addhosts delhosts halt tm pvm_mytid pvm_exit pvm_parent tm send recv nrecv probe mcast trecv sendsig recvf version id conf GVA ELAI UPM PFC

216 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Ahora, cuando ejecutamos la orden pvm, el resultado por pantalla será:... version id t40001 conf 1 host, 1 data format HOST DTID ARCH SPEED DSIG dixxx.edv.uniovi.es LINUX x pvm> Volveremos al shell desde la consola de PVM tecleando halt PVM sobre varias computadoras Para usar más de un nodo real de proceso, con indicarlo al invocar la consola de PVM es suficiente. Es decir, ejecutar pvm con un argumento, el nombre de un fichero donde se reflejan los nombres lógicos o direcciones físicas de los citados ordenadores. Si el usuario que va ha ejecutar procesos en el seno da la máquina virtual es el mismo en todas las computadoras reales, entonces el fichero tendrá el siguiente aspecto: m1.dominio1.uniovi.es ep=$home/bin:$pvm_root/bin/linux m2.dominio2.uniovi.es ep=$home/bin:$pvm_root/bin/mips m3.dominio3.uniovi.es ep=$home/bin:$pvm_root/bin/alpha Donde el flag ep indica a PVM donde están los ejecutables de nuestra aplicación (por defecto PVM busca en $PVM_ROOT/bin/arquitectura. Si están ahí no es necesario dicho flag) y el flag dx donde reside la instalación de PVM en dicha computadora (este flag solamente es necesario si PVM está instalado en un lugar distinto al usado para instalar PVM en la computadora que arranca la máquina virtual). Obviamente, el usuario, la instalación de PVM, la ubicación de los 206 GVA-ELAI-UPM PFC

217 Miguel Hernández Vázquez Procesamiento Distribuido con C++ ejecutables de las aplicaciones, etc. pueden ser distintos. Los flag asociados a cada caso se pueden consultar en la documentación de PVM, en Message Passing with PVM and MPI: Advanced Features and Trends (Markus Fischer) o en pvm_config. Para el ejemplo propuesto y supuesto que el fichero creado lo hemos llamado pvm_hosts, el resultado de invocar la orden "pvm pvm_hosts" cambiando los nombres ficticios por nombres lógicos reales: 3 host, 3 data formats HOST DTID ARCH SPEED DSIG di137.edv.uniovi.es LINUX x di127.edv.uniovi.es LINUX x00408c41 di133.edv.uniovi.es LINUX x00408d41 pvm> Como siempre, volveremos al shell desde la consola de PVM tecleando halt. El proceso para crear la máquina virtual es el siguiente. Por cada línea del fichero pvm_hosts PVM trata de lanzar la ejecución del proceso pvmd3 en la computadora referenciada por el nombre lógico o la dirección física. Por este motivo, se debe añadir al fichero de configuración de hosts (pvm_hosts en nuestro caso) el nombre lógico de la computadora desde donde estamos lanzando la máquina virtual. Además, hay que recordar que por defecto PVM busca en todas las computadoras el ejecutable pvmd3 usando el path de la máquina que invoca la orden "pvm pvm_hosts", que usa el mismo username, la misma ubicación de los ficheros de la aplicación, el mismo directorio de trabajo temporal, etc. Si hay diferencias se pueden utilizar los flags mencionados anteriormente. Para lanzar la ejecución del proceso pvmd3 en una computadora física distinta a la que ejecuta la orden "pvm pvm_hosts", PVM utiliza el soporte remote shell (rsh, consultar el manual para más información). Entonces, hay que tener la seguridad de que el username utilizado puede lanzar la ejecución remota de comandos de/hacia la computadora origen a las de destino. Además, se debe asegurar que a nivel global los administradores de las máquinas implicadas tienen habilitado dicho servicio (para más información consultar con los administradores de cada computadora). GVA ELAI UPM PFC

218 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Supuesto que no hay restricciones de orden superior, las indicadas en el párrafo anterior, cada usuario debe permitir en cada computadora el acceso desde otro usuario y computadora. En otras palabras, en cada computadora hay que decir qué usuarios de qué computadoras pueden lanzan el proceso pvmd3. Esto se hace mediante un fichero de nombre.rhosts y que debe estar en $HOME. Su formato es (para más información mirar el manual de rsh): computadora_remota1 computadora_remota2 computadora_remota3 username_en_computadora_remota1 username_en_computadora_remota2 username_en_computadora_remota3 Así, los username de las computadoras indicadas en.rhosts son los únicos que podrán lanzar la ejecución de pvmd3. Obviamente, debe haber una concordancia entre lo dicho en pvm_hosts y.rhosts. Finalmente, hay que resaltar que la utilización del.rhosts es peligrosa, ya que los usuarios de las máquinas indicadas en él pueden lanzar la ejecución de cualquier comando del shell, como por ejemplo "rm -rf *". Luego se deben tomar precauciones, como por ejemplo poner en.rhosts lo imprescindible o no utilizar comodines. Otras medidas muy eficientes son cambiarle el nombre cuando no se utilice PVM y eliminar los permisos de acceso a.rhosts a otros usuarios (chmod 600.rhosts) EJECUCIÓN DE APLICACIONES PVM Los pasos necesarios para poder ejecutar un programa PVM serán los siguientes: 1. Configurar las variables de entorno PVM_ROOT, PVM_ARCH y crear un directorio ~/pvm3/bin/arch en cada máquina. 2. Crear/Configurar el fichero ~/.rhosts (opcional) 3. Crear/Configurar el fichero 'hostpvm_file' (Si es necesario) 208 GVA-ELAI-UPM PFC

219 Miguel Hernández Vázquez Procesamiento Distribuido con C++ 4. Iniciar el master pvmd3 con: a) pvmd3 hostpvm_file & b) pvm (Para iniciar la consola) o pvm hostpvm_file 5. Ejecutar la aplicación : a) Desde la línea de comandos: a.out (o como se llame nuestra aplicación) b) Desde consola: spawn a.out 6. Parar PVM usando halt en el prompt de la consola o usando UNIX kill en el servidor y asegurándose de que todos los ficheros /tmp/pvmd.uid han sido borrados en todos los ordenadores que componían la máquina virtual COMANDOS Y FUNCIONES MÁS IMPORTANTES DE PVM Comandos Algunos de los comandos más importantes son: add máquina: incorpora la máquina indicada a la máquina paralela virtual. delete máquina: elimina la máquina indicada del conjunto de máquinas asociadas a la máquina paralela virtual. Como es lógico, no podremos eliminar la máquina desde la que estamos ejecutando el intérprete de comandos. conf: configuración actual de la máquina paralela virtual. GVA ELAI UPM PFC

220 Procesamiento Distribuido con C++ Miguel Hernández Vázquez ps: listado de procesos de la máquina paralela virtual. ps -a lista todos los procesos. halt: apaga la máquina paralela virtual. Esto significa que mata todas las tareas de PVM, elimina el daemon de forma ordenada y sale del programa pvm. help: lista los comandos del programa. Tremendamente útil en los momentos de desesperación. id: imprime el TID de la consola. jobs: genera un listado de los trabajos en ejecución. kill: mata un proceso de PVM. mstat: muestra el estado de una máquina de las pertenecientes a PVM. pstat: muestra el estado de un proceso de los pertenecientes a PVM. quit: sale de la máquina paralela virtual sin apagarla. reset: inicializa la máquina. Eso supone matar todos los procesos de PVM, salvo los programas monitores en ejecución, limpiar las colas de mensajes y las tablas internas y pasar a modo de espera todos los servidores. setenv: lista todas las variables de entorno del sistema. sig señal tarea: manda una señal a una tarea. 210 GVA-ELAI-UPM PFC

221 Miguel Hernández Vázquez Procesamiento Distribuido con C++ spawn: arranca una aplicación bajo PVM. Es un comando bastante complejo cuyas opciones veremos en una sección aparte. trace: actualiza o visualiza la máscara de eventos traceados. alias: define un alias predefinido, es decir, un atajo para teclear un comando. unalias: elimina un alias predefinido. version: imprime la versión usada de PVM Funciones PVM proporciona casi 70 funciones para programar aplicaciones en C. Las podemos dividir en seis tipos diferentes: 1. Funciones de Control de Procesos. 2. Funciones de Información. 3. Funciones de Configuración de grupos. 4. Funciones de Empaquetamiento de datos y control de Buffers. 5. Funciones de Envío de Mensajes. 6. Funciones de Recepción de mensajes. GVA ELAI UPM PFC

222 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Funciones de control de procesos Las funciones de control de procesos son las siguientes: int pvm-mytid (): aparece necesariamente en todo programa escrito para PVM porque es la función que hace entrar el proceso correspondiente en la máquina virtual que simula PVM. Esta rutina no tiene ningún argumento y devuelve el tid correspondiente al proceso desde el que ha sido invocada. int pvm-exit (): permite al proceso salir de PVM, pero no lo termina, por lo que tras la invocación de esta función el proceso puede seguir ejecutándose como cualquier otro proceso Unix. int pvm_spawn (char *task, char **argv, int flag, char *where, int ntask, int *tids) int pvm-kill (int tid): ordena la terminación de la tarea de PVM identificada por tid. No debe usarse esta rutina para eliminar la tarea que la invoca; para ello debe llamarse a pvm_exit () seguido de exit () Funciones de información Las funciones de información son las siguientes: int pvm_parent (): devuelve el tid del proceso que lanzó esta tarea, es decir, aquella desde la que se llama a esta función. En el caso de que esta tarea no haya sido creada por pvm_spawn devuelve PvmNoParent. int pvm_mytid (tid): devuelve el tid correspondiente al proceso desde el que ha sido invocada. 212 GVA-ELAI-UPM PFC

223 Miguel Hernández Vázquez Procesamiento Distribuido con C++ int pvm_pstat (int tid): devuelve el estado de la tarea PVM identificada por tid Si la tarea se está ejecutando devuelve PvmOk, PvmNoTask en caso contrario, y PvmBadParam si tid es inválido. it pvm_config (int *nhost, int *narch, struct hostinfo **hostp): proporciona información sobre la configuración de la máquina virtual int info = pvm_config( int *nhost, int *narch, - struct hostinfo **hostp): Struct hostinfo { int hi_tid; char *hi_name; char *hi_arch; int hi_speed; }hostp; Funciones de configuración de grupos Las funciones de configuración de grupos son las siguientes: int pvm_joingroup (²mygroup²): devuelve el número de instancia del proceso en el grupo y le hace miembro del grupo llamado mygroup. int pvm_gsize (²mygroup²): devuelve el número de miembros del grupo. int pvm_gettid (²mygroup², inum): devuelve el tid del proceso que tiene el número de instancia inum en el grupo mygroup. int pvm_getinst (²mygroup², tid): devuelve el número de instancia que tiene la tarea tid en el grupo mygroup. GVA ELAI UPM PFC

224 Procesamiento Distribuido con C++ Miguel Hernández Vázquez pvm_bcast (²mygroup²,...,..): emite un mensaje contenido en el buffer de emisión a todos los miembros del grupo salvo al emisor. int pvm joingroup (char *group): añade la tarea que la invoca al grupo de procesos identificado por group. En el caso de ser la primera tarea en unirse a él, la llamada crea el grupo. La función devuelve el número de instancia del proceso en el grupo, entero que puede adoptar valores entre 0 y el número de miembros del grupo menos uno. Por otra parte, una tarea puede formar parte de varios grupos. Si un proceso abandona un grupo y luego vuelve a él, puede obtener un número de instancia distinto, aunque siempre se asigna el menor número de instancia disponible a cualquier nueva tarea. int pvm_lvgroup (char *group): hace que la tarea que la invoca salga del grupo group. int pvm-gettid (char *group, int inum): devuelve el tid del proceso que tiene el número de instancia inum en el grupo group. int pvm-getinst (char *group, int tid): devuelve el número de instancia que tiene la tarea tid en el grupo group. int pvm-gsize (char *group): devuelve el número de miembros del grupo. int pvm-barrier (char *group, int count): bloquea el proceso que la invoca hasta que count procesos del grupo group hayan llamado a pvm_barrier. En general, count debería ser el número de componentes del grupo. Los procesos no pueden llamar a esta función usando como argumento un grupo al que no pertenecen. Además, en una sincronización de barrera dada, todos los procesos que llaman a esta función deberán usar el mismo valor para count. 214 GVA-ELAI-UPM PFC

225 Miguel Hernández Vázquez Procesamiento Distribuido con C Funciones de empaquetamiento de datos y control de buffers Un mensaje antes de ser mandado hacia uno o varios destinatarios debe ser colocado en un buffer. Un buffer permite reservar la memoria poco a poco cuando se van empaquetando los datos.las funciones de empaquetamiento de datos y control de buffers son las siguientes: int pvm-pk*(): es una familia de funciones que se emplean para empaquetar un vector de datos de un tipo dado en el buffer de envío. Pueden ser llamados varias veces para empaquetar un mensaje. Cada mensaje puede constar de varios vectores, cada uno de los cuales puede ser de un tipo distinto. No hay límite a la complejidad de los mensajes empaquetados, pero el receptor debe desempaquetarlos exactamente como los empaquetó el emisor. Las estructuras de C se deben enviar empaquetando sus componentes individuales. Cada función tiene un puntero al primer elemento a ser empaquetado, el número de elementos a empaquetar y la distancia o stride entre cada dos elementos consecutivos a empaquetar. La excepción la constituye pvm_pkstr, que empaqueta un array de caracteres terminado por un NULL. int pvm-initsend (int encoding): limpia el buffer de envío y crea uno nuevo, cuyo identificador devuelve, para empaquetar un nuevo mensaje. El esquema de codificación utilizado viene dado por encoding. Si se usa un solo buffer, que es lo habitual, debe llamarse a esta función antes de empaquetar un nuevo mensaje en el buffer pues, de otra forma, el nuevo mensaje se añadirá al anterior. int pvm-mkbuf (int encoding): crea un nuevo buffer de envío vacío, especificando el método de codificación usado para los mensajes, y devolviendo el identificador del buffer. int pvm-freebuf (int buf id): libera el buffer identificado por bufid. Debería hacerse tras enviar el mensaje que contiene, siempre y cuando no se vaya a necesitar en el futuro. Para usarlo debe haberse llamado antes a pvm_mkbuf para crear el buffer. No es necesario llamar a ninguna de estas dos funciones si se emplea pvm_initsend. GVA ELAI UPM PFC

226 Procesamiento Distribuido con C++ Miguel Hernández Vázquez int pvm_getsbuf (): devuelve el identificador del buffer de envío activo. int pvm_getrbuf (): devuelve el identificador del buffer de recepción de activo. int pvm-setsbuf (int buf id): convierte al buffer identificado por bufid en el nuevo buffer de envío activo, guardando el estado del buffer anterior, cuyo identificador devuelve. Si bufid es 0, el buffer actual es guardado y no hay buffer activo. int pvm-setrbuf (int bufid): convierte al buffer identificado por bufid en el nuevo buffer de recepción activo, guardando el estado del buffer anterior, cuyo identificador devuelve. Si bufid es 0, el buffer actual es guardado y no hay buffer activo Funciones de envío de mensajes Las funciones de envío son las siguientes: int pvm-send (int tid, int msgtag): etiqueta con el identificador entero msgtag el mensaje que se encuentra en el buffer de envío y lo manda al proceso identificado por tid. Es muy importante tener en cuenta que esta rutina no bloquea al proceso que la llama, es decir, cuando una tarea envía datos puede seguir su ejecución normalmente, sin tener que esperar a que el destinatario reciba los datos ni a que éstos sean enviados de forma efectiva int pvm-mcast (int *tids, int ntask, int msgtag): etiqueta el mensaje con el identificador msgtag y lo difunde a todas las tareas especificadas en el vector tids de números enteros, cuya longitud viene dada por ntask. 216 GVA-ELAI-UPM PFC

227 Miguel Hernández Vázquez Procesamiento Distribuido con C Funciones de recepción de mensajes Las funciones de recepción son las siguientes: int pvm_nrecv (int tid, int msgtag): devuelve 0, retornando inmediatamente, si no se ha recibido ningún mensaje etiquetado con el valor de msgtag procedente de la tarea tid, permitiéndose el uso del valor comodín (-1) en ambos casos. Si, por el contrario, se ha recibido un mensaje de esas características, lo sitúa en el buffer activo de recepción, que es creado por nrecv, y devuelve el identificador de dicho buffer. El buffer de recepción anterior es borrado, a no ser que se haya llamado a pvm_setrbuf. int pvm_recv (int tid, int msgta): es una rutina de recepción con bloqueo, es decir, que no devuelve el control a la rutina que la invoca hasta que recive un mensaje. El mensaje debe tener la etiqueta msgtag y proceder de la tarea identificad por tid. int pvm-upk: es la familia de funciones que realizan la tarea opuesta a la de las funciones pvm_pk*, es decir, desempaquetan los datos que se encuentran en el buffer de recepción activo. La lista completa de las funciones que conforman este grupo es la siguiente, en donde podemos encontrar las funciones complementarias a las de empaquetamiento en el mismo orden. int pvmjoingroup (): añade la tarea que la invoca al grupo de procesos identificado por group. En el caso de ser la primera tarea en unirse a él, la llamada crea el grupo. La función devuelve el número de instancia del proceso en el grupo, entero que puede adoptar valores entre 0 y el número de miembros del grupo menos uno. Por otra parte, una tarea puede formar parte de varios grupos. Si un proceso abandona un grupo y luego vuelve a él, puede obtener un número de instancia distinto, aunque siempre se asigna el menor número de instancia disponible a cualquier nueva tarea. GVA ELAI UPM PFC

228 Procesamiento Distribuido con C++ Miguel Hernández Vázquez 8.4 PASOS PARA REALIZAR LA PARALELIZACIÓN DE UN PROGRAMA USANDO PVM. EJEMPLOS Los pasos a seguir son los siguientes: 1. Incluir el programa en PVM e identificar el maestro. 2. Crear procesos esclavos y redireccionar su salida EJEMPLO 1: COMUNICACIÓN MAESTRO ESCLAVO En este programa, el maestro enviará una cadena al esclavo, a la cual el esclavo convertirá en mayúsculas y enviará de regreso al maestro. El maestro y el esclavo se muestran a continuación. Para compilar los programas, se teclea el comando make -f makefile.demo Programa Maestro /* * * master_pvm.c * * * * Programa maestro para una simple demostración de PVM * * */ #include <stdio.h> #include <stdlib.h> #include <pvm3.h> #include <string.h> int main() { int mytid; /* nuesto ID de tarea */ int slave_tid; /* el ID del esclavo */ int result; 218 GVA-ELAI-UPM PFC

229 Miguel Hernández Vázquez Procesamiento Distribuido con C++ char message[] = "hello pvm"; /* nos incluimos al sistema PVM y obtenemos nuestro ID */ mytid = pvm_mytid(); /* creamos al esclavo */ result = pvm_spawn("slave_pvm", (char**)0, PvmTaskDefault, "", 1, &slave_tid); /* comprobamos que el esclavo se creo adecuadamente */ if(result!= 1) { fprintf(stderr, "Error: Cannot spawn slave.\n"); /* salimos del sistema PVM*/ pvm_exit(); exit(exit_failure); } /* se inicializa el buffer de datos para transmitir los datos al esclavo*/ pvm_initsend(pvmdatadefault); /* se "empaqueta'' la cadena dentro del buffer*/ pvm_pkstr(message); /* se envia la cadena al esclavo con una etiqueta de mensaje igual a 0 */ pvm_send(slave_tid, 0); /* se espera y recibe el resultado del esclavo*/ pvm_recv(slave_tid, 0); /* se "desempaca'' el resultado del esclavo */ pvm_upkstr(message); /* se muestra el resultado del esclavo*/ printf("data from the slave : %s\n", message); /* salimos del sistema PVM*/ pvm_exit(); exit(exit_success); } /* fin del main() */ /* fin del master_pvm.c */ GVA ELAI UPM PFC

230 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Programa esclavo /* * * slave_pvm.c * * * * Este es el program esclavo para una simple demostración de PVM * * */ #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <pvm3.h> #define MSG_LEN 20 void convert_to_upper(char*); int main() { int mytid; int parent_tid; char message[msg_len]; /* nos incluimos dentro del sistema PVM */ mytid = pvm_mytid(); /* se obtiene el ID del maestro*/ parent_tid = pvm_parent(); /* se recibe la cadena origina del maestro */ pvm_recv(parent_tid, 0); pvm_upkstr(message); /* se convierte la cadena a mayúsculas*/ convert_to_upper(message); /* se envia la cadena convertida al maestro */ pvm_initsend(pvmdatadefault); pvm_pkstr(message); pvm_send(parent_tid, 0); /* se sale del sistema PVM*/ pvm_exit(); exit(exit_success); } /* fin del main() */ 220 GVA-ELAI-UPM PFC

231 Miguel Hernández Vázquez Procesamiento Distribuido con C++ /* funcion para convertir una cadena dada a mayúsculas */ void convert_to_upper(char* str) { while(*str!= '\0') { *str = toupper(*str); str++; } } /* end convert_to_upper() */ /* fin del slave_pvm.c */ Archivo Makefile # Make file para el programa de demostración de PVM.SILENT : # rutas para incluir archivos y librerías INCDIR=-I/usr/share/pvm3/include LIBDIR=-L/usr/share/pvm3/lib/LINUX # ligas a la librería de PVM LIBS=-lpvm3 CFLAGS=-Wall CC=gcc TARGET=all # este es el directorio donde se crearán los programas PVM_HOME=$(HOME)/pvm3/bin/LINUX all : $(PVM_HOME)/master_pvm $(PVM_HOME)/slave_pvm $(PVM_HOME)/master_pvm : master_pvm.c $(CC) -o $(PVM_HOME)/master_pvm master_pvm.c $(CFLAGS) $(LIBS) \ $(INCDIR) $(LIBDIR) $(PVM_HOME)/slave_pvm : slave_pvm.c $(CC) -o $(PVM_HOME)/slave_pvm slave_pvm.c $(CFLAGS) $(LIBS) \ $(INCDIR) $(LIBDIR) GVA ELAI UPM PFC

232 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Explicación del programa anterior A continuación vamos a ver como trabaja el programa anterior. Antes de nada, para usar las funciones PVM, necesitaremos incluir el archivo de cabecera pvm3.h en nuestro programa (#include <pvm3.h>, tanto en el programa maestro como en el esclavo). También al compilar los programas, necesitamos ligarlos con la librería PVM. Esto se hace especificando la opción -lpvm3 al compilador. Además, necesitamos especificar al compilador las rutas de los archivos cabecera y las librerias, como se hace en el makefile. En el programa maestro, primero se obtiene el task ID del maestro haciendo una llamada a la función pvm_mytid (). El sistema PVM asigna a cada proceso un identificador único un entero de 32 bits llamado task ID de la misma manera que Linux asigna a cada proceso un identificador de proceso. De cualquier forma, el maestro no emplea este identificador (almacenado en mytid). Nuestra intención era solo llamar a la función pvm_mytid (). Esta función enlista al proceso dentro del sistema PVM y genera un identificador único. Si no se enlista explícitamente al proceso, PVM automáticamente agrega a nuestro proceso en la primera llamada de cualquier función PVM. A continuación empleamos pvm_spawn () para crear al proceso esclavo. El primer parámetro de esta, "slave_pvm", es el nombre del ejecutable para el esclavo. El segundo son los argumentos que se desean pasar al esclavo (de manera similar al argv en C). Como no se quieren enviar argumentos, se establece este valor a 0. El tercer parámetro es una bandera con la cual podemos controlar como y donde PVM inicia el esclavo. Como solo tenemos una sola máquina, establecemos esta bandera a PvmTaskDefault, lo cual le indica a PVM que emplee el criterio por omisión para crear al esclavo. El cuarto parámetro es el nombre del host o arquitectura sobre el cual deseamos se ejecute el programa y en este caso se deja vacío. Solo se emplea cuando se usa una bandera diferente a PvmTaskDefault. El quinto parámetro establece el número de esclavos que se crearán y el sexto es un puntero a un arreglo en el cual se regresan los IDs de los esclavos. Esta función regresa el número de esclavos actualmente creados. Un mensaje en PVM consiste básicamente de dos partes: el dato y una etiqueta que identifica el tipo de mensaje. La etiqueta nos ayuda a distinguir entre diferentes mensajes. Podemos asignar al mensaje para el valor intermedio una etiqueta que diga MSG_RESULT la cual se puede #define en cualquier archivo de cabecera y una etiqueta que diga MSG_ERROT para los mensajes que indiquen error. El maestro observará las etiquetas de los mensajes y determinará a que tipo pertenecen. 222 GVA-ELAI-UPM PFC

233 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Para enviar un mensaje, primero se necesita "inicializar" el buffer. Esto se hace llamando a pvm_initsend (). El parámetro para esta función indica el esquema de "codificación" a emplear. Cuando intercambiamos datos entre máquinas de diferentes arquitecturas (por ejemplo, entre una máquina Pentium y una estación de trabajo SPARC) se necesita codificar el dato a enviar y decodificar el dato que se recibe de esta manera el dato es confiable. El parámetro para pvm_initsend () indica el esquema de codificación a emplear. El valor PvmDataDefault indica un esquema de codificación en el cual posibilita que el dato pueda ser intercambiado entre arquitecturas heterogéneas. Una vez que el buffer ha sido inicializado, necesitamos colocar el dato dentro del buffer y codificarlo. En nuestro caso, el dato es una cadena, así que empleamos la función pvm_pkstr () para "empaquetarlo" es decir codificarlo y colocarlo dentro del buffer. Si se requiere enviar un entero, existe la función pvm_pkint (). De forma similar, hay funciones para otros tipos de datos. Una vez que el dato es empaquetado, llamamos a pvm_send () para enviar el mensaje. El primer argumento es el ID del proceso al cual esta destinado el mensaje y el segundo es la etiqueta del mensaje. Como solo tenemos un tipo de mensaje, ponemos este valor a 0. Una vez que el dato se envia al esclavo, el esclavo va a procesarlo y envia el resultado al maestro. Así que ahora llamamos pvm_recv () para recibir el datos del esclavo. De nuevo, el parámetro es le ID del proceso que estamos esperando el mensaje y la etiqueta del mensaje. Si el mensaje deseado aún no es enviado, esta función lo espera y no regresa. Por lo tanto, el maestro espera para que el esclavo procese el dato. Una vez que el mensaje llega, el dato se almacena en el buffer de recepción. Es necesario "desempacar" es decir decodificar para obtener el mensaje original. Esta decodificación se realiza mediante pvm_upkstr (). Por último desplegamos la cadena. Antes que el programa termine, se debe indicar al sistema PVM que se deja este de esta manera los recursos ocupados por el proceso son liberados. Esto se realiza llamando a la función pvm_exit (). Después, el programa termina. El programa esclavo es sencillo de comprender. Primero encontramos el ID del master (el cual es también su padre ya que el maestro creo al esclavo) llamando a la función pvm_parent (). Después recibe la cadena del maestro, la convierte a mayúscula y envia el resultado al maestro. GVA ELAI UPM PFC

234 Procesamiento Distribuido con C++ Miguel Hernández Vázquez EJEMPLO 2: PROGRAMA DE SUMA En este caso tenemos un maestro y 4 esclavos. El maestro crea primero a los 4 esclavos y envia a cada uno de ellos su parte de los datos. El esclavo suma los datos y envia el resultado al maestro. Por lo que, se tienen dos tipos de mensajes: uno cuando el maestro envia un dato a los esclavos, para el cual emplearemos la etiqueta MSG_DATA y otro cuando el esclavo envia el resultado al maestro, para el cual usaremos la etiqueta MSG_RESULT. El programa maestro y esclavo se listan a continuación: Cabeceras comunes /* * * common.h * * * * Esta cabecera define algunas constantes comunes. * * */ #ifndef COMMON_H #define COMMON_H #define NUM_SLAVES 4 /* número de esclavos */ #define SIZE 100 /* tamaño total del dato */ #define DATA_SIZE (SIZE/NUM_SLAVES) /* tamaño para cada esclavo */ #endif /* end common.h */ /* * * tags.h * * * * Esta cabecera define las etiquetas empleadas por los mensajes. * * */ #ifndef TAGS_H #define TAGS_H #define MSG_DATA 101 /* datos del maestro al esclavo*/ #define MSG_RESULT 102 /* resultado del esclavo al maestro*/ #endif /* end tags.h */ 224 GVA-ELAI-UPM PFC

235 Miguel Hernández Vázquez Procesamiento Distribuido con C Programa maestro /* * * master_add.c * * * * Programa maestro para implementar la suma de los elementos de un * * arreglo usando PVM * * */ #include <stdio.h> #include <stdlib.h> #include <pvm3.h> /* PVM constantes y declaraciones */ #include "tags.h" /* etiquetas para los mensajes */ #include "common.h" /* constantes comunes */ int get_slave_no(int*, int); int main() { int mytid; int slaves[num_slaves]; /* arreglo para almacenar los task IDs de los esclavos */ int items[size]; /* datos a ser procesados */ int result, i, sum; int results[num_slaves]; /* resultados de los esclavos */ /* nos enlistamos en el sistema PVM */ mytid = pvm_mytid(); /* inizilizacion del arreglo 'items' */ for(i = 0; i < SIZE; i++) items[i] = i; /* se crean los esclavos */ result = pvm_spawn("slave_add", (char**)0, PvmTaskDefault, "", NUM_SLAVES, slaves); /* se comprueba que los esclavos creados sean suficientes */ if(result!= NUM_SLAVES) { fprintf(stderr, "Error: Cannot spawn slaves.\n"); pvm_exit(); exit(exit_failure); } /* se distribuyen los datos a los esclavos */ for(i = 0; i < NUM_SLAVES; i++) { pvm_initsend(pvmdatadefault); GVA ELAI UPM PFC

236 Procesamiento Distribuido con C++ Miguel Hernández Vázquez pvm_pkint(items + i*data_size, DATA_SIZE, 1); pvm_send(slaves[i], MSG_DATA); } /* se recibe el dato de los esclavos */ for(i = 0; i < NUM_SLAVES; i++) { int bufid, bytes, type, source; int slave_no; /* se recibe el mensaje de cualquiera de los esclavos */ bufid = pvm_recv(-1, MSG_RESULT); /* se obtiene información del buffer*/ pvm_bufinfo(bufid, &bytes, &type, &source); /* se obtiene el número del esclavo que envió el mensaje*/ slave_no = get_slave_no(slaves, source); /* se desempaca la información del esclavo*/ pvm_upkint(results + slave_no, 1, 1); } /* se obtiene el resultado final */ sum = 0; for(i = 0; i < NUM_SLAVES; i++) sum += results[i]; printf("the sum is %d\n", sum); /* se sale del sistema PVM */ pvm_exit(); exit(exit_success); /* end main() */ /* función que regresa el numero del esclavo dado su task ID */ int get_slave_no(int* slaves, int task_id) { int i; for(i = 0; i < NUM_SLAVES; i++) if(slaves[i] == task_id) return i; 226 GVA-ELAI-UPM PFC

237 Miguel Hernández Vázquez Procesamiento Distribuido con C++ return -1; /* end get_slave_no() */ /* end master_add.c */ Programa esclavo /* * * slave_add.c * * * * Programa esclavo para realizar la suma de los elementos de un * * arreglo usando PVM * * */ #include <stdlib.h> #include <pvm3.h> #include "tags.h" #include "common.h" int main() { int mytid, parent_tid; int items[data_size]; int sum, i; /* datos para enviar al maestro*/ /* nos enlistamos dentro del sistema PVM */ mytid = pvm_mytid(); /* se obtiene el identificador del maestro */ parent_tid = pvm_parent(); /* se reciben los datos del maestro */ pvm_recv(parent_tid, MSG_DATA); pvm_upkint(items, DATA_SIZE, 1); /* se encuentra la suma de los elementos*/ sum = 0; for(i = 0; i < DATA_SIZE; i++) sum = sum + items[i]; /* se envia el resultado al maestro */ pvm_initsend(pvmdatadefault); pvm_pkint(&sum, 1, 1); pvm_send(parent_tid, MSG_RESULT); /* se sale del PVM*/ GVA ELAI UPM PFC

238 Procesamiento Distribuido con C++ Miguel Hernández Vázquez pvm_exit(); exit(exit_success); /* end main() */ Archivo Makefile # Make file para el programa suma del PVM - makefile.add.silent : # rutas para los archivos include y librerias del PVM INCDIR=-I/usr/share/pvm3/include LIBDIR=-L/usr/share/pvm3/lib/LINUX # liga a la librería PVM LIBS=-lpvm3 CFLAGS=-Wall CC=gcc TARGET=all # el directorio donde se colocaran los ejecutables PVM_HOME=$(HOME)/pvm3/bin/LINUX all : $(PVM_HOME)/master_add $(PVM_HOME)/slave_add $(PVM_HOME)/master_add : master_add.c common.h tags.h $(CC) -o $(PVM_HOME)/master_add master_add.c $(CFLAGS) $(LIBS) \ $(INCDIR) $(LIBDIR) $(PVM_HOME)/slave_add : slave_add.c common.h tags.h $(CC) -o $(PVM_HOME)/slave_add slave_add.c $(CFLAGS) $(LIBS) \ $(INCDIR) $(LIBDIR) Explicación del programa En primer lugar vamos a analizar el programa esclavo. El esclavo recive los 25 elementos del arreglo del maestro en el arreglo items, obtiene su suma y envía el resultado al maestro con la etiqueta del mensaje MSG_RESULT. A continuación analizamos al maestro. Definimos un arreglo slaves de tamaño igual a NUM_SLAVES el cual contiene los task ID's de los esclavos creados. 228 GVA-ELAI-UPM PFC

239 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Existe otro arreglo results en el cual se almacenan los resultados de los esclavos. El maestro primero inicializa el arreglo items y después crea a los esclavos. Después distribuye los datos a los esclavos. En la llamada a la función pvm_pkint (), el primer parámetro es un puntero al arreglo en el cual los datos se almacenan, el segundo es el número de enteros a empacar y el tercero es el "stride". Stride significa cuantos elementos se saltan cuando se empaca. Cuando es 1, los elementos consecutivos son empacados. Cuando es 2, PVM va saltarse a los elementos 2 dando un paquete con los elementos pares (0, 2, 4...). De ahí que empleemos el 1. Una vez que los datos han sido distribuidos a los esclavos, el maestro espera que los esclavos regresen el valor del resultado intermedio. Una posibilidad para obtener los resultados es que el maestro obtenga primero el resultado del esclavo 0 (es decir del esclavo cuyo ID esta almacenado en slave [0]), después del esclavo 1 y así sucesivamente. En la llamada a pvm_recv (), sabemos que el primer parámetro es el task ID de la fuente del mensaje. Si este valor es -1, significa que los mensajes de cualquier proceso con la etiqueta de mensaje igual a MSG_RESULT van a ser recibidos por el maestro. El mensaje recibido junto con información de control se almacena en un buffer llamado active receive buffer. La llamada regresa un ID único para este buffer. Ahora necesitamos conocer quien envió el mensaje para poder almacenar el resultado en el apropiado elemento del arreglo results. La función pvm_bufinfo () regresa información acerca del mensaje en el buffer, como la etiqueta del mensaje, el número de bits y el task ID de quien lo envió. Una vez que se tiene el ID del remitente, se almacena el resultado enviado en su correcto elemento dentro del arreglo results. 8.5 EL PROCESAMIENTO DISTRIBUIDO EN C++ A TRAVÉS DEL ESTÁNDAR CORBA Con anterioridad hemos visto una pequeña reseña de CORBA. En este apartado intentaremos dar una visión en mayor profundidad de la programación paralela y distribuida en C++ utilizando el estándar CORBA. GVA ELAI UPM PFC

240 Procesamiento Distribuido con C++ Miguel Hernández Vázquez INTRODUCCIÓN CORBA es una arquitectura que facilita la interoperabilidad entre componentes distribuidos, desarrollados en diferentes lenguajes y que se ejecutan sobre distintas plataformas y sistemas operativos. CORBA viene de Common Object Request Broker Architecture, que viene a significar algo así como "arquitectura común para gestores de solicitudes de objetos". Las especificaciones del estándar CORBA las desarrolla la OMG - Object Management Group -, que está conformado por un consorcio internacional de empresas, como pueden ser Sun, HP, DEC, IBM,... El precursor del estándar CORBA fue el proyecto ANSA - Advanced Network Systems Architecture -, que fue desarrollado en el Reino Unido en el año CORBA en sí no es una librería, un componente o una aplicación, sino un conjunto de especificaciones, es decir, de muchos documentos. Básicamente hay tres elementos principales: Un lenguaje de definición de interfaces llamado IDL (InterfaceDefinition Language). Un elemento que se encarga de facilitar la comunicación entre componentes llamado ORB (Object Request Broker). Un protocolo estándar existente en todos los ORB indistintamente del fabricante, llamado IIOP (Internet Inter-ORB Protocol). El desarrollo de una aplicación CORBA, o la adaptación de una aplicación ya existente, comienza por la definición de las interfaces y módulos. Para ello se usa un lenguaje, llamado IDL, que es posteriormente convertido al lenguaje de implementación, que puede ser prácticamente cualquiera, desde COBOL y Visual Basic a C++, Delphi o Java. 230 GVA-ELAI-UPM PFC

241 Miguel Hernández Vázquez Procesamiento Distribuido con C++ En esta conversión, realizada con el compilador de IDL, se generan módulos de código que actúan como intérpretes en el cliente y en el servidor. Estos intérpretes, conocidos habitualmente como stub en el cliente y skeleton en el servidor, son los que se encargan de las tareas más complejas. El stub hace que el cliente CORBA crea estar usando un objeto local, facilitando la obtención de la referencia, preparación de parámetros para su transferencia y descodificación de valores de retorno. El skeleton se encarga del proceso complementario en la parte servidor. Figura 8.2: Descripción de la arquitectura CORBA Si IDL es el elemento de CORBA que facilita la independencia a la hora de trabajar con tipos de datos o definir interfaces, los ORB representan el otro pilar de CORBA. Los ORB forman parte de cliente y servidor, siendo los encargados de permitir la comunicación entre ambos componentes. Para ello usan el protocolo IIOP o algún otro derivado de GIOP, protocolos claramente documentados que permiten que ORBs de distintos fabricantes se comuniquen entre sí. GVA ELAI UPM PFC

242 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Figura 8.3: Descripción de interfaces y objetos Existen ORBs para la mayoría de los lenguajes y plataformas, aunque los más habituales se usan con C++, Java y COBOL. Son muchos los fabricantes que ofertan ORBs, aunque seguramente los productos más importantes y conocidos son Visibroker, de Inprise, y Orbix, de IONA. Inprise Visibroker es un ORB integrado en las versiones superiores de Delphi, C++ Builder y JBuilder, lo cual supone una ventaja puesto que hay, en estas herramientas, asistentes que generan automáticamente el código para crear servidores y clientes CORBA. Además de los ORBs y el protocolo de comunicación, una aplicación CORBA, concretamente un cliente, necesita algún mecanismo para localizar los objetos que necesita. Este mecanismo es un servicio de directorio distribuido, conocido habitualmente como smart agent, en el cual se registran todos aquellos servidores que están en funcionamiento. Estos servidores también pueden activarse bajo demanda, usando un OAD y un repositorio de interfaces que permita identificar el servidor que dispone de la interfaz solicitada OBJETIVOS DE CORBA El objetivo inicial y primordial del grupo de gestión de objetos (OMG de Object Management Group) es crear una verdadera infraestructura abierta para la 232 GVA-ELAI-UPM PFC

243 Miguel Hernández Vázquez Procesamiento Distribuido con C++ distribución de objetos en vez de una aplicación comercial controlada por una compañía. El secreto de su éxito ha sido que OMG ha creado las especificaciones de una interfaz, no el código. Las interfaces que especifica son siempre derivadas de una demostración tecnológica llevada a cabo por las compañías miembro. Las interfaces son escritas en un lenguaje de definición de interfaces (IDL) que define los límites de los componentes VENTAJAS DE CORBA Las ventajas que presenta CORBA son: CORBA proporciona una infraestructura de comunicaciones para la colaboración entre objetos distribuidos heterogéneos (lenguaje de programación, arquitectura de la plataforma). Simplifica la interoperabilidad entre aplicaciones. Proporciona los mimbres para la colaboración entre objetos distribuidos. Pretende aportar a los sistemas distribuidos las ventajas que los lenguajes de programación mediante objetos aportan a la programación no distribuida, por ejemplo: encapsulación, herencia de interfaces, y manejo de excepciones DESARROLLOS CON CORBA Los objetos distribuidos son piezas inteligentes de software que pueden intercambiar mensajes transparentemente en cualquier lugar en el mundo. El lenguaje y compilador que se usa para crear servidores de objetos distribuidos son totalmente transparentes a sus clientes, éstos no necesitan saber donde reside el objeto distribuido ni el sistema operativo en el que se ejecuta; y pueden estar en la misma maquina o bien en cualquier lugar de la red mundial. GVA ELAI UPM PFC

244 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Además de esto podemos añadir que los objetos distribuidos por ser objetos gozan de todas las bondades que estos proveen, por lo que cualquier sistema de objetos proporciona las tres propiedades básicas: encapsulación, herencia y polimorfismo. Estas propiedades le permiten al objeto proporcionar sólo la interfaz deseada a sus clientes; reutilizar código y comportarse de distintas maneras. Sin embargo el interés fundamental de los objetos distribuidos está en cómo esta tecnología puede ser extendida para enfrentarse con problemas complejos que son heredados al crear sistemas cliente/servidor robustos y de imagen simple, es decir como los objetos pueden trabajar juntos a través de una maquina y los limites de una red para crear soluciones cliente servidor. Nos encaminamos a los sistemas cliente servidor basados en objetos en donde se apreciara lo mejor de la grandeza y potencial de éstos EL ORB DE CORBA Un ORB CORBA provee los mecanismos requeridos por los objetos para comunicarse con otros objetos a través de lenguajes heterogéneos, herramientas, plataformas y redes. También provee el entorno para manejar estos objetos, advertir su presencia y describir sus metadatos. Un ORB CORBA es un bus de objetos que se describe así mismo. Usando un ORB, un objeto cliente puede invocar transparentemente un método en un objeto servidor, el cual puede estar en la misma máquina o a través de la red, el ORB intercepta la llamada y es responsable de encontrar el objeto que implemente la petición, pasarle los parámetros, invocar el método, y regresar los resultados. Los papeles de cliente/servidor son sólo usados ara controlar las interacciones entre los objetos, ya que los objetos en el ORB pueden actuar a la vez como cliente y como servidor Estructura de un ORB CORBA En principio señalaremos lo que CORBA hace en el lado del cliente: Los fragmentos (stub) IDL del lado del cliente: proveen la interfaz estática de los servicios del cliente. Estos fragmentos de código precompilados definen como los clientes invocan los servicios correspondientes en los servidores. Estos servicios son definidos usando un IDL, y ambos son 234 GVA-ELAI-UPM PFC

245 Miguel Hernández Vázquez Procesamiento Distribuido con C++ generados por un compilador IDL. Un cliente debe tener un fragmento IDL para cada interfaz en el servidor. Este fragmento incluye código para realizar la comunicación y el paso de parámetros. La interfaz de invocación dinámica (DII): permite descubrir el método a ser invocado en tiempo de ejecución. Las APIs del repositorio de interfaces: permiten obtener y modificar la descripción de todas las interfaces componentes registradas, los métodos que soportan y los parámetros que requieren. Es un repositorio de metadatos dinámico para ORBs. La interfaz ORB: consiste en unas cuantas APIs de servicios locales que pueden ser de interés para una aplicación. Como por ejemplo el convertir la referencia de un objeto a una cadena. El soporte de invocaciones cliente/servidor dinámicas y estáticas así como el repositorio de interfaces le dan a CORBA una ventaja sobre otros entornos de distribución de objetos. Las invocaciones estáticas son más rápidas y fáciles de programar. Las dinámicas proveen una máxima flexibilidad pero son difíciles de programar, aunque son útiles para las herramientas que requieren descubrir los servicios en tiempos de ejecución. El lado del servidor no puede identificar la diferencia entre una invocación estática o dinámica; en ambos casos, el ORB localiza un adaptador del objetos del servidor, le transmite los parámetros, y le transfiere el control a la implementación del objeto a través del fragmente IDL del lado del servidor (esqueleto). A continuación se muestran los elementos de CORBA del lado del servidor. Los fragmentos IDL del lado del servidor: OMG los llama esqueletos, proveen la interfaz estática para cada servicio exportado por el servidor. Estos fragmentos, como los del lado del cliente son creados al usar un compilador IDL. La interfaz de esqueletos dinámica: proveen un mecanismo de unión en tiempo de ejecución para los servidores que necesitan gestionar las llamadas GVA ELAI UPM PFC

246 Procesamiento Distribuido con C++ Miguel Hernández Vázquez de métodos para componentes que no tiene un esqueleto base IDL compilado. Los esqueletos dinámicos son muy útiles para la implementación de puentes genéricos entre ORBs. El adaptador de objetos: provee el entorno en tiempo de ejecución para la instanciación de objetos servidores, pasándoles peticiones, y asignándoles una identificación de objeto (llamada referencia al objeto). El adaptador de objetos también registra las clases que soporta y sus instancias en tiempo de ejecución con el repositorio de implementación. El repositorio de implementación: provee un repositorio de información en tiempo de ejecución acerca de las clases que el servidor soporta, los objetos que están instanciados y sus identificadores. Guarda también información adicional relacionada con los ORBs. La interfaz ORB: consiste en unas cuantas APIs a servicios locales que son idénticas a los del lado del cliente Invocación de métodos CORBA. Estáticos contra Dinámicos La interfaz estática es generada directamente en fragmentos por el precompilador IDL. Son ideales para programas que saben en tiempo de compilación las operaciones particulares que requerirán invocar. Tiene las siguientes ventajas sobre la invocación dinámica: Más fácil de programar. Provee un chequeo de tipos más robusto. Buen desempeño. Es autodocumentada. Los pasos que involucran un llamado estático son los siguientes: 236 GVA-ELAI-UPM PFC

247 Miguel Hernández Vázquez Procesamiento Distribuido con C++ 1. Definir las clases de objetos usando un lenguaje de definición de interfaces (IDL): Las IDLs son el medio por el cual los objetos le dicen a sus clientes potenciales que operaciones están disponibles y como deberían ser invocadas. 2. Ejecutar el fichero IDL a través de un precompilador del lenguaje: se procesa el fichero IDL y se producen los esqueletos para la implementación de clases servidoras. 3. Añadir el código de la implementación a los esqueletos: es decir crear las clases servidoras. 4. Compilar el código: se generan cuatro ficheros de salida que son: ficheros de importación que describen a los objetos en el repositorio de interfaces, fragmentos del cliente para los métodos en las IDLs definidas, fragmentos del servidor que llaman a los métodos en el servidor y el código que implementan las clases en el servidor. 5. Unir las definiciones de clases al repositorio de interfaces: para que se pueda acceder a ellas en tiempo de ejecución. 6. Instanciar los objetos en el servidor: al arrancar, un adaptador de objetos de un servidor debe instanciar los objetos servidor que sirven para la invocación de métodos remotos del cliente. Éstos son instancias de las clases de aplicación del servidor. 7. Registrar los objetos en tiempo de ejecución en el repositorio de implementación: el adaptador de objetos registra en el repositorio de implementación la referencia a un objeto y el tipo de cualquier objeto que se instancia en el servidor. El ORB usa esta información para localizar los objetos activos o para requerir la activación de objetos en un servidor particular. En contraste la invocación de métodos dinámica provee un entorno de mayor flexibilidad, permite añadir nuevas clases al sistema sin requerir cambios en el código del cliente. Es muy útil para herramientas que descubren los servicios que son GVA ELAI UPM PFC

248 Procesamiento Distribuido con C++ Miguel Hernández Vázquez proveídos en tiempo de ejecución. Permiten escribir código genérico con APIs dinámicas. Para invocar un método dinámico en un objeto, el cliente debe desempeñar los siguientes pasos: 1. Obtener la descripción del método del repositorio de interfaces. 2. Crear la lista de argumentos: la lista es creada usando la operación create_list y llamando add_arg tantas veces como se requiera para añadir cada argumento a la lista. 3. Crear la petición: la petición debe especificar la referencia al objeto, el nombre del método, y la lista de argumentos. 4. Invocar la petición: se puede invocar la petición de 3 maneras: 1) la llamada invocada envía la petición y obtiene los resultados; 2) la llamada enviada devuelve el control al programa, el cual debe emitir un get_response; 3) la llamada enviada puede ser definida de un sólo sentido. Como se puede apreciar la invocación dinámica de un método requiere un cierto esfuerzo. Se cambia complejidad y desempeño por añadir flexibilidad. 238 GVA-ELAI-UPM PFC

249 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Figura 8.4: Estructura cliente de CORBA El lado del servidor de CORBA. El adaptador de objetos Lo que una implementación de objetos necesita en el lado del servidor es una infraestructura servidora que registre las clases de la implementación, instancias a nuevos objetos, que les de un únicos identificador, que advierta su existencia, que invoque sus métodos en las peticiones de los clientes y que gestione peticiones concurrentes a sus servicios. La respuesta a quién desempeña este tipo de trabajo es el adaptador de objetos. El adaptador de objetos es el mecanismo primario para que una implementación de un objeto pueda acceder a los servicios de un ORB. Aquí están algunos de los servicios que proporciona: 1. Registrar las clases del servidor en el repositorio de implementación. 2. Instancias los nuevos objetos en tiempo de ejecución. GVA ELAI UPM PFC

250 Procesamiento Distribuido con C++ Miguel Hernández Vázquez 3. Generar y gestionar las referencias únicas a los objetos. 4. Anunciar la presencia de servidores de objetos y sus servicios. 5. Manipular las llamadas provenientes de clientes. 6. Enrutar la llamada hacia el método apropiado. Un adaptador de objetos define como son activados los objetos. Esto lo puede hacer creando un nuevo proceso, creando un nuevo enlace dentro de un proceso existente o usando un enlace o proceso existente. Un servidor puede soportar una variedad de adaptadores de objetos para satisfacer diferentes tipos de peticiones, CORBA especifica un adaptador de objetos básico (BOA de Basic Object Adapter) que puede ser usado por la mayoría de los objetos del ORB y que puede servir como un estándar. CORBA requiere que un adaptador BOA este disponible en cada ORB y necesita que las siguientes funciones sean proveídas por la implementación del BOA: Un repositorio de implementación que permita instalar y registrar la implementación de los objetos. Mecanismos para generar e interpretar las referencias a objetos. Un mecanismo para identificar al cliente que hace la llamada. Activación y desactivación de objetos implementados. Invocación de métodos a través de fragmentos 240 GVA-ELAI-UPM PFC

251 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Un BOA soporta aplicaciones tradicionales y orientadas a objetos. No especifica como son localizados y empaquetados los métodos. Para obtener la más amplia cobertura de aplicación, CORBA define cuatro políticas de activación de objetos que son: Servidor compartido BOA: objetos múltiples pueden residir en el mismo programa. El BOA activa el servidor la primera vez que una petición es realizada sobre cualquier objeto implementado por aquel servidor. El servidor gestiona una petición a la vez y avisa cuando ha terminado para procesar la siguiente. Servidor no compartido BOA: cada objeto reside en un proceso de servidor diferente. Un nuevo servidor es activado la primera vez que una petición es solicitada en el objeto. Un nuevo servidor es iniciado cada vez que se hace una petición a un objeto que aún no esta activado, aunque un servidor para otro objeto con la misma implementación este activo. Servidor por método BOA: un nuevo servidor es comenzado cada vez que una petición es hecha. El servidor se ejecuta solo por el tiempo que dura el método particular. Varios procesos de servidor para el mismo objeto pueden estar activos concurrentemente. Servidor persistente BOA: los servidores son activados por medios externos al BOA. Un vez iniciado el BOA trata a todas las llamadas subsecuentes como llamadas a servidores compartidos; envía activaciones para objetos individuales y llamadas a métodos para un proceso individual. GVA ELAI UPM PFC

252 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Figura 8.5: Estructura servidor de CORBA Inicialización de CORBA Las llamadas que un objeto debe seguir para inicializarse así mismo son: 1. Obtener la referencia al objeto de su ORB. 2. Obtener el puntero a su adaptador de objetos. 3. Descubrir que servicios iniciales están disponibles. 4. Obtener las referencias a los objetos de los servicios que se desean. Para cada uno de los pasos anteriores se debe llamar el método apropiado. Un objeto puede inicializarse así mismo en más de un ORB. 242 GVA-ELAI-UPM PFC

253 Miguel Hernández Vázquez Procesamiento Distribuido con C IDL Y EL REPOSITORIO DE INTERFACES Los metadatos es el ingrediente que permite crear sistemas cliente/servidor ágiles. Un sistema ágil es autodescriptible, dinámico, y reconfigurable. El sistema ayuda a los componentes a descubrirse unos a otros en tiempo de ejecución, y les provee información que le permite interoperar así como crear y gestionar componentes. El lenguaje de metadatos de CORBA es el lenguaje de definición de interfaces (IDL) y el repositorio de metadatos de CORBA es el repositorio de interfaces que es una base de datos que se puede actualizar y cuestionar en tiempo de ejecución y que contiene la información generada por las IDLs IDL de CORBA y su estructura El IDL de CORBA es un lenguajes neutral y totalmente declarativo. Provee interfaces independientes del lenguaje de programación y sistema operativo para todos los servicios y componentes que residen en el bus CORBA. Un contrato IDL incluye una descripción de cualquier servicio que un componente servidor quiera exponer a sus clientes. Los componentes servidores deben soportar dos tipos de clientes: 1) clientes que invoquen sus servicios en tiempo de ejecución; y 2) desarrolladores que usan IDL para extender las funciones de sus componentes existentes por medio de herencia. La gramática IDL es un subgrupo de C++ con palabras reservadas adicionales para soportar los conceptos de distribución, también soporta las características estándar de preprocesamiento de C++. El repositorio de interfaces contiene metadatos que son idénticos a los componentes que se describen en la IDL. De hecho el repositorio de interfaces es simplemente una base de datos activa que contiene versiones compiladas de la información en metadatos capturada vía IDL. GVA ELAI UPM PFC

254 Procesamiento Distribuido con C++ Miguel Hernández Vázquez El compilador de IDL de CORBA genera stubs en el cliente y skeletons en el servidor. Los stubs y los skeletons, junto con el ORB, automatizan las siguientes actividades: Creación de proxies. Aplanamiento/Desaplanamiento de parámetros y resultados. Generación de clases de Implementación de la interfaz. Registro y activación de objetos. Localización y ligadura (binding) de objetos. EL IDL de CORBA es un superconjunto de un subconjunto de C++. No es un lenguaje de programación, sólo sirve para definir interfaces. El IDL de CORBA ofrece: Describe operaciones y parámetros de cada interfaz. Lenguaje declarativo. Sintaxis similar al ANSI C++. Prepocesado como C++ (mas #pragma). Usa el código de caracteres ISO-Latin GVA-ELAI-UPM PFC

255 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Los principales elementos para construir un IDL CORBA son: Los Módulos proveen un namespace para agrupar a un conjunto de descripciones de clases, es decir agrupa varias clases. Las Interfaces definen un conjunto de métodos que los clientes pueden invocar en un objeto. Una interfaz puede tener atributos y puede declarar una o más excepciones. Las operaciones son el equivalente en CORBA de los métodos. Un parámetro tiene un modo que indica si un valor es pasado de el cliente al servidor (in), de el servidor al cliente (out), o en ambos (in/out). Los tipos de datos son usados para describir los valores aceptados de los parámetros, atributos, y valores de retorno de CORBA. Estos tipos de datos son llamados objetos de CORBA que son usados a través de lenguajes múltiples, sistemas operativos y ORBs. El tipo any es muy útil en situaciones dinámicas ya que representa a cualquier tipo de datos IDL posible. CORBA define códigos de tipos que representan cada tipo de datos de la IDL definida. Se usan para crear datos autodescriptibles que puedas ser pasados a través de ORBs y repositorios de interfaces. Cada código de tipo tiene un ID de repositorio globalmente único. Son usados: Por interfaces de invocación dinámica. Por protocolos Inter-ORB. Por repositorios de interfaces. Por el tipo de datos any. GVA ELAI UPM PFC

256 Procesamiento Distribuido con C++ Miguel Hernández Vázquez La interfaz TypeCode de CORBA define un conjunto de métodos que permiten operar con códigos de tipos, compararlos y obtener sus descripciones. Las diferencias más importantes entre IDL y C++ son, fundamentalmente: 1. No hay variables de estado en las clases. 2. No hay punteros. 3. No hay constructores/destructores. 4. No hay sobrecarga de métodos. 5. No existe el tipo int. 6. El IDL permite especificar modos en el paso de parámetros. 7. No hay templates. 8. No hay sentencias de control El repositorio de interfaces Un repositorio de interfaces CORBA es una base de datos en línea de definiciones de objetos. Estas definiciones pueden ser capturadas directamente de un compilador IDL o a través de las nuevas funciones de escritura del repositorio de interfaces. La especificación de CORBA detalla como es organizada y recuperada la información del repositorio. Lo hace creativamente al especificar un conjunto de clases cuyas instancias representan la información que está en el repositorio. La jerarquía de clases refleja la especificación IDL. 246 GVA-ELAI-UPM PFC

257 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Un ORB utiliza las definiciones de objetos en el repositorio para: Proveer un chequeo de tipos de las definiciones de métodos. Ayuda a conectar ORBs. Provee información en metadatos para clientes y herramientas. Proporciona objetos autodescriptibles. Los repositorios de interfaces pueden ser mantenidos localmente o gestionados como recursos departamentales o empresariales. Sirven como una fuente valuable de información en la estructura de clases e interfaces de componentes. Un ORB puede tener acceso a múltiples repositorios de interfaces. El repositorio de interfaces es implementado como un conjunto de objetos que representan la información en él. Estos objetos deben ser persistentes. CORBA agrupa los metadatos en módulos que representan el espacio de nombres. Los nombres de los objetos del repositorio son únicos dentro de un módulo. CORBA define una interfaz para cada uno de sus ocho estructuras IDL: ModuleDef. InterfaceDef. OperationDef. ParameterDef. AttributeDef. GVA ELAI UPM PFC

258 Procesamiento Distribuido con C++ Miguel Hernández Vázquez ConstantDef. ExceptionDef. TypeDef. Además de estas ocho interfaces, CORBA especifica una interfaz llamada Repository que sirve como raíz para todos los módulos contenidos en un namespace del repositorio. Cada repositorio de interfaces es representado por un objeto repository raíz global. Además de estas jerarquías contenidas CORBA definió tres superclases abstractas llamadas IRObject, Contained, y Container. Todos los objetos del repositorio de interfaces heredan de la interfaz IRObject, la cual provee un método destroy. Los objetos que son contenedores heredan operaciones de navegación de la interfaz Container. La interfaz Contained define el comportamiento de los objetos que son contenidos en otros objetos. Todas las clases del repositorio son derivadas de Container, de Contained o de ambas a través de herencia múltiple. Este astuto esquema permite al repositorio de objetos comportarse de acuerdo a sus relaciones de contención. Para acceder a los metadatos del repositorio de interfaces se invocan métodos polimorficamente en diferentes tipos de objetos. Es posible navegar y extraer información del los objetos del repositorio con tan sólo nueve métodos. Cinco de estos métodos son derivados de las clases antecesoras Container y Contained. Los otros cuatro métodos son específicos a las interfaces InterfaceDef y Repository. A partir de CORBA se pueden crear federaciones mundiales de repositorios de interfaces que operen a través de ORBs múltiples. Para prevenir colisiones de nombres, estos repositorios asignan identificadores únicos a interfaces y operaciones globales. Para lograr esto se siguen los siguientes convencionalismos de nombrado: Nombres con alcance los cuales son hechos de uno o más identificadores separados por los caracteres : :. 248 GVA-ELAI-UPM PFC

259 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Identificadores de repositorio que identifican globalmente módulos e interfaces. Son usados para sincronizar las definiciones a través de ORBs y repositorios, existen dos formatos para especificarlos: 1) usando nombres IDL con prefijos únicos y 2) usando identificadores únicos universales DCE El lenguaje IDL Todo servicio precisa definir qué subrutinas forman parte de él. Al conjunto de signaturas de las subrutinas que forman parte de un servicio se le llama la interfaz de un servicio. Un lenguaje de IDL especifica la sintaxis a utilizar para definir dicha lista de signaturas. Al mismo tiempo el lenguaje indica el tipo de estructuras de datos que pueden ser utilizados como parámetros. La estructura del lenguaje indica las capacidades de manejo automático del paso de parámetros. Con el fin de controlar la versión del servicio, se suele incluir la especificación del número de versión del servicio. Finalmente, la definición incluye el nombre dado al servicio. El IDL es procesado por un compilador de IDL. El compilador retorna Stubs y definiciones de estructuras de datos para (C). También retorna cabeceras para las subrutinas a definir en el servidor. Existe un Stub para el cliente y uno para el servidor. Un Stub de cliente es una subrutina que toma los argumentos formales de un procedimiento remoto y se encarga de: Marshaling. GVA ELAI UPM PFC

260 Procesamiento Distribuido con C++ Miguel Hernández Vázquez Efectuar el binding. Ejecutar el envío del mensaje. Esperar la respuesta. Efectuar el Unmarshaling de los parámetros de retorno. Devolver control al código de cliente: El stub de servidor en un sistema RPC típico es más simple que el de cliente. Puede ser visto como la imagen especular del stub del cliente. Recoge el mensaje de petición de servicio. Comprueba la compatibilidad de la versión Efectúa el unmarshal de los parámetros. Efectúa la invocación local de la subrutina del servidor. Efectúa el marshaling de los parámetros de retorno. Envía el mensaje de retorno a través del canal de comunicación establecido al recibir el mensaje de invocación. En IDL, las estructuras de datos se definen con un lenguaje especial que refleja las restricciones de paso de parámetros. El compilador traduce dichas definiciones a estructuras de datos del lenguaje de programación (típicamente C, o C++). 250 GVA-ELAI-UPM PFC

261 Miguel Hernández Vázquez Procesamiento Distribuido con C++ Dichas traducciones quedan reflejadas en ficheros de cabecera que deben ser utilizados por los programas cliente y servidor. Al mismo tiempo el compilador general subrutinas que sirven para realizar el marshaling y unmarshaling de las estructuras de datos definidas. Dichas subrutinas son adoptadas por los stubs para realizar el marshaling/unmarshaling. Las subrutinas emplean funciones de biblioteca especiales para llevar a cabo su función. Los aspectos que debe cubrir un servicio de binding son: Encontrar el nodo más apropiado para el servicio. Establecer la compatibilidad del servicio pedido con el ofertado. Establecer un camino de comunicación entre el cliente y el servicio. Establecer un camino de acceso desde el cliente hasta la función del servidor: en ocasiones, el servicio de binding puede comenzar la ejecución del proceso servidor. Esta operación cara en términos de tiempo empleado aunque tan sólo ocurre una vez por par cliente/servidor. En el caso del Binding para el Servidor el binder debe: Registrar el ejecutable del servidor, asociándolo con el nombre del servicio. Dependiendo del sistema concreto, registrar el número de puerto a utilizar por el servidor. GVA ELAI UPM PFC

262 Procesamiento Distribuido con C++ Miguel Hernández Vázquez En algunos casos establecer un enlace de comunicaciones entre el cliente y el servidor. La última parte del binder corresponde al dispatcher. El dispatcher suele estar integrado en el servidor, a través de las funciones de biblioteca. Para la implementación del Binding: El binder es el servicio del cual todos los demás dependen. Suele tener incorporado algún esquema de soporte de fallos. Encontrar el binder debe ser independiente del servicio de binder mismo. Generalmente disponible en una dirección bien conocida: bien en nodo local o en un puerto estándar Consideraciones acerca del Marshaling 1. La representación de números enteros depende de la CPU utilizada. 2. El alineamiento de datos en algunas arquitecturas, los datos deben alinearse en 32 (64) bits. 3. La representación de números en coma flotante puede diferir. 4. Los punteros, por sí mismos, no son transmisibles. En algunos casos, cuando el tipo apuntado esté claro, será posible efectuar una copia por 252 GVA-ELAI-UPM PFC

263 Miguel Hernández Vázquez Procesamiento Distribuido con C++ recorrido; esto dificulta la semántica de paso por referencia, tan común en llamadas a subrutinas en lenguajes procedurales. 5. La aproximación tomada es el copy-in, copy-out, con características totalmente diferentes en sistemas concurrentes. 6. Incompatibilidades en los tipos básicos de datos, por ejemplo, pasar enteros desde representaciones de 64 a 32 bits COMUNICACIÓN VÍA CORBA Los pasos a seguir en la comunicación vía CORBA son: 1. El cliente invoca el método asociado en el stub que realiza el proceso de marshaling (Stub cliente). 2. El stub solicita del ORB la transmisión de la petición hacia el objeto servidor (ORB cliente). 3. El ORB del servidor toma la petición y la transmite el Adaptador de Objetos asociado, por lo general sólo hay uno (ORB servidor). 4. El Adaptador de Objetos resuelve cuál es el objeto invocado, y dentro de dicho objeto cuál es el método solicitado (Adaptador de Objetos). 5. El skeleton del servidor realiza el proceso de de-marshaling de los argumentos e invoca a la implementación del objeto (Skeleton servidor). 6. La implementación del objeto se ejecuta y los resultados y/o parámetros de salida se retornan al skeleton (Implementación del objeto). GVA ELAI UPM PFC

264 Procesamiento Distribuido con C++ Miguel Hernández Vázquez 7. El proceso de retorno de los resultados es análogo. Figura 8.6: Comunicación vía CORBA IMPLEMENTACIÓN DE OBJETOS CORBA El servicio de nombrado de objetos es el principal mecanismo para que los objetos en un ORB localicen otros objetos. El servicio de nombrado convierte los nombres humanos en referencias a objetos. Se puede opcionalmente asociar uno o más nombres con la referencia a un objeto. Se puede referenciar un objeto CORBA usando una secuencia de nombres que forme un árbol de nombre jerárquico. Resolver un nombre significa encontrar el objeto asociado con el nombre en un contexto dado. Enlazar un nombre es crear una asociación nombre/objeto para un contexto particular. Cada componente nombrado es una estructura con dos atributos: 1) un identificador que es el nombre del objeto; 2) el tipo que es una cadena en donde se puede poner una descripción del nombre del atributo. Las interfaces NamingContext y BindingInterator implementan el servicio de nombrado. Se invoca el método bind en la interfaz NamingContext para asociar el 254 GVA-ELAI-UPM PFC

Message Passing Interface (MPI)

Message Passing Interface (MPI) Message Passing Interface (MPI) INTRODUCCIÓN MPI (Message Passing Interface) como es un interfaz estandarizada para la realización de aplicaciones paralelas basadas en pasaje de mensajes. El modelo de

Más detalles

INTRODUCCIÓN A LA PROGRAMACIÓN DE COMPUTADORES DE MEMORIA DISTRIBUIDA USANDO MPI SISTEMAS PARALELOS Y DISTRIBUIDOS

INTRODUCCIÓN A LA PROGRAMACIÓN DE COMPUTADORES DE MEMORIA DISTRIBUIDA USANDO MPI SISTEMAS PARALELOS Y DISTRIBUIDOS INTRODUCCIÓN A LA PROGRAMACIÓN DE COMPUTADORES DE MEMORIA DISTRIBUIDA USANDO MPI 1 Y DISTRIBUIDOS GRADO EN INGENIERÍA INFORMÁTICA INGENIERÍA DE COMPUTADORES ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA

Más detalles

Paradigma de paso de mensajes

Paradigma de paso de mensajes Paradigma de paso de mensajes Curso 2011-2012 Índice Visión lógica del paradigma de paso de mensajes. Operaciones básicas en paso de mensajes. Operaciones bloqueantes. Operaciones no bloqueantes. MPI:

Más detalles

Programación en Entornos Paralelos: MPI

Programación en Entornos Paralelos: MPI 1-11 Marzo de 2017 FACET -UNT Programación en Entornos Paralelos: MPI Graciela Molina mgracielamolina@gmailcom TRADICIONALMENTE Procesamiento secuencial 2 TRADICIONALMENTE Procesamiento secuencial Si ya

Más detalles

Multiprocesamiento en lenguaje C Introducción a MPI

Multiprocesamiento en lenguaje C Introducción a MPI Multiprocesamiento en lenguaje C Introducción a MPI Message Passing Interface Pertinencia de la enseñanza del cómputo paralelo en el currículo de las ingenierías MPI MPI es un estándar de programación

Más detalles

PROCESAMIENTO DISTRIBUIDO

PROCESAMIENTO DISTRIBUIDO Pág. 1 INTRODUCCIÓN PROCESAMIENTO DISTRIBUIDO Arquitectura de comunicaciones: Software básico de una red de computadoras Brinda soporte para aplicaciones distribuidas Permite diferentes Sistemas Operativos

Más detalles

TEMA 5: PARALELISMO A NIVEL DE HILOS, TAREAS Y PETICIONES (TLP, RLP) (segunda parte)

TEMA 5: PARALELISMO A NIVEL DE HILOS, TAREAS Y PETICIONES (TLP, RLP) (segunda parte) TEMA 5: PARALELISMO A NIVEL DE HILOS, TAREAS Y PETICIONES (TLP, RLP) (segunda parte) SISTEMAS PARALELOS Y DISTRIBUIDOS www.atc.us.es Dpto. de Arquitectura y Tecnología de Computadores. Universidad de Sevilla

Más detalles

MPI Introducción Procesos Envío y recepción simple Envío y recepción no tan simple Comunicación colectiva. Herramientas de depuración y evaluación

MPI Introducción Procesos Envío y recepción simple Envío y recepción no tan simple Comunicación colectiva. Herramientas de depuración y evaluación Tutorial sobre MPI Temario 1 MPI Introducción Procesos Envío y recepción simple Envío y recepción no tan simple Comunicación colectiva Herramientas de depuración y evaluación arqavapar MPI (Introducción)

Más detalles

Arquitecturas: Clusters. Edgar Valderrama Lucio Mederos

Arquitecturas: Clusters. Edgar Valderrama Lucio Mederos Arquitecturas: Clusters Edgar Valderrama Lucio Mederos Qué es un cluster? Es un sistema compuesto por varias computadoras (nodos) unidas por una red que se comporta como una única entidad. De un cluster

Más detalles

1. Introducción 2. S.O. de Red. NFS 3. S.O. Distribuidos 4. Características de Diseño. Tema5: Sistemas Operativos Distribuidos

1. Introducción 2. S.O. de Red. NFS 3. S.O. Distribuidos 4. Características de Diseño. Tema5: Sistemas Operativos Distribuidos Tema 5: Sistemas Operativos Distribuidos 1. Introducción 2. S.O. de Red. NFS 3. S.O. Distribuidos 4. Características de Diseño 1 1. Introducción Sistema Informático Distribuido: Colección de S.I. autónomos

Más detalles

Diseño de Sistemas Distribuidos Máster en Ciencia y Tecnología Informática Curso Presentación e introducción

Diseño de Sistemas Distribuidos Máster en Ciencia y Tecnología Informática Curso Presentación e introducción Diseño de Sistemas Distribuidos Máster en Ciencia y Tecnología Informática Curso 2016-2017 Presentación e introducción Félix García Carballeira Grupo de Aruitectura de Computadores felix.garcia@uc3m.es

Más detalles

Procesamiento Paralelo

Procesamiento Paralelo Procesamiento Paralelo Introducción a MPI Javier Iparraguirre Universidad Tecnológica Nacional, Facultad Regional Bahía Blanca 11 de Abril 461, Bahía Blanca, Argentina jiparraguirre@frbb.utn.edu.ar http://www.frbb.utn.edu.ar/hpc/

Más detalles

Interfaz de Paso de Mensajes MPI. Christian Chinchilla Brizuela

Interfaz de Paso de Mensajes MPI. Christian Chinchilla Brizuela Interfaz de Paso de Mensajes MPI Christian Chinchilla Brizuela Agenda Definición Objetivo principal MPI Historia Ventajas Desventajas Estructura MPI Programa MPI Llamadas de MPI Funciones Principales MPI

Más detalles

Facultad de Ingeniería Industrial y de Sistemas v1.0 MA781U PROCESOS DISTRIBUIDOS

Facultad de Ingeniería Industrial y de Sistemas v1.0 MA781U PROCESOS DISTRIBUIDOS PROCESOS DISTRIBUIDOS Preparado por: Angel Chata Tintaya (angelchata@hotmail.com) Resumen El proceso cliente servidor es la clave para comprender el potencial de los sistemas de información y las redes

Más detalles

Ingeniería en computación Tipos de sistemas operativos

Ingeniería en computación Tipos de sistemas operativos Ingeniería en computación Tipos de sistemas operativos Unidad de competencia III: Sistemas Operativos Distribuidos Ing. Diego Armando Ramírez Avelino 17/10/2017 1 Unidad de competencia I Objetivo Entender

Más detalles

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

PROGRAMACIÓN PARALELA. Modelos de programación paralela Paradigmas de programación paralela PROGRAMACIÓN PARALELA Modelos de programación paralela Paradigmas de programación paralela Tipos de paralelismo Paso de mensajes Paralelismo de datos Memoria compartida Paradigmas de programación paralela

Más detalles

Clústeres y procesamiento en paralelo XE1GNZ J O R G E F BARBOSA J ACOBO F E B R E R O DE 20 17

Clústeres y procesamiento en paralelo XE1GNZ J O R G E F BARBOSA J ACOBO F E B R E R O DE 20 17 Clústeres y procesamiento en paralelo XE1GNZ J O R G E F BARBOSA J ACOBO F E B R E R O DE 20 17 Al escuchar la palabra clúster se piensa en grandes maquinas exclusivas de los grandes de la computación

Más detalles

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

Programación Concurrente y Paralela. Unidad 1 Introducción Programación Concurrente y Paralela Unidad 1 Introducción Contenido 1.1 Concepto de Concurrencia 1.2 Exclusión Mutua y Sincronización 1.3 Corrección en Sistemas Concurrentes 1.4 Consideraciones sobre el

Más detalles

TAREA 1. INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS.

TAREA 1. INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS. 1 TAREA 1. INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS. 1- Cuáles son las principales funciones de un sistema operativo? Los Sistemas Operativos tienen como objetivos o funciones principales lo siguiente; Comodidad;

Más detalles

Instrumentación n / Ing. Quirino Jimenez D.

Instrumentación n / Ing. Quirino Jimenez D. Introducción n a los sistemas distribuidos Hoy en día d a los sistemas de computo están n organizados por varios ordenadores conectados en red, esto es un sistema distribuido. El problema que se plantea

Más detalles

TEMA 4 PROCESAMIENTO PARALELO

TEMA 4 PROCESAMIENTO PARALELO TEMA 4 PROCESAMIENTO PARALELO Tipos de plataformas de computación paralela Organización lógica Organización física Sistemas de memoria compartida Sistemas de memoria distribuida Tipos de plataformas de

Más detalles

MULTIPROCESADORES TIPOS DE PARALELISMO

MULTIPROCESADORES TIPOS DE PARALELISMO Todos los derechos de propiedad intelectual de esta obra pertenecen en exclusiva a la Universidad Europea de Madrid, S.L.U. Queda terminantemente prohibida la reproducción, puesta a disposición del público

Más detalles

6. Enumere tres ventajas de los ULT frente a los KLT.

6. Enumere tres ventajas de los ULT frente a los KLT. 1 Tarea 3 Hilos 1. Cuales bloques de control de proceso deberían pertenecer a un bloque de control de hilo y cuáles a un bloque de control de proceso en un sistema multihilo? Para modelos monohilo deben

Más detalles

UNIVERSIDAD CARLOS III DE MADRID DEPARTAMENTO DE INFORMÁTICA INGENIERÍA EN INFORMÁTICA. ARQUITECTURA DE COMPUTADORES II 19 de junio de 2007

UNIVERSIDAD CARLOS III DE MADRID DEPARTAMENTO DE INFORMÁTICA INGENIERÍA EN INFORMÁTICA. ARQUITECTURA DE COMPUTADORES II 19 de junio de 2007 UNIVERSIDAD CARLOS III DE MADRID DEPARTAMENTO DE INFORMÁTICA INGENIERÍA EN INFORMÁTICA. ARQUITECTURA DE COMPUTADORES II 19 de junio de 2007 Para la realización del presente examen se dispondrá de 2 1/2

Más detalles

Tema 7. Mejora del rendimiento: introducción a la segmentación y a las arquitecturas paralelas

Tema 7. Mejora del rendimiento: introducción a la segmentación y a las arquitecturas paralelas Tema 7. Mejora del rendimiento: introducción a la segmentación y a las arquitecturas paralelas Arquitectura de Computadores Curso 2009-2010 Transparencia: 2 / 21 Índice Introducción Taxonomía de Flynn

Más detalles

Granularidad y latencia

Granularidad y latencia Niveles de paralelismo y latencias de comunicación Niveles de paralelismo. Granularidad o tamaño de grano. Latencia de comunicación. Particionado de los programas. Empaquetado de granos. Planificación

Más detalles

TEMA 10 INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS DISTRIBUIDOS. Introducción Hardware Software Aspectos de diseño

TEMA 10 INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS DISTRIBUIDOS. Introducción Hardware Software Aspectos de diseño TEMA 10 INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS DISTRIBUIDOS Introducción Hardware Software Aspectos de diseño 1 Introducción Aparecen en los 80 Desarrollo de Microprocesadores LAN Sistemas Distribuidos:

Más detalles

Tema 3. Paso de mensajes. mensajes. Bibliografía. Sistemas de paso de mensajes (2) Sistemas de paso de mensajes. Ventajas del paso de.

Tema 3. Paso de mensajes. mensajes. Bibliografía. Sistemas de paso de mensajes (2) Sistemas de paso de mensajes. Ventajas del paso de. Tema 3. Paso de mensajes Bibliografía Programación Concurrente J. Palma, C. Garrido, F. Sánchez, A. Quesada, 2003 Capítulo 7 Principles of Concurrent and Distributed Programming M. Ben-Ari. Prentice Hall,

Más detalles

TEMA 9. SISTEMAS OPERATIVOS DISTRIBUIDOS

TEMA 9. SISTEMAS OPERATIVOS DISTRIBUIDOS TEMA 9. SISTEMAS OPERATIVOS DISTRIBUIDOS Introducción Hardware Software Aspectos de diseño 1 Introducción Aparecen en los 80 Desarrollo de Microprocesadores LAN Sistemas Distribuidos: Gran nº de procesadores

Más detalles

Sistemas Distribuidos.

Sistemas Distribuidos. Escuela Militar de Ingeniería Ingeniería de Sistemas SISTEMAS OPERATIVOS Laboratorio Nombre: Código: Sistemas Distribuidos. 1. Conceptos fundamentales. Definición de un sistema de cómputo distribuido.

Más detalles

ARQUITECTURAS PARA PROCESAMIENTO PARALELO

ARQUITECTURAS PARA PROCESAMIENTO PARALELO 1 de 6 27/11/11 13:08 ARQUITECTURAS PARA PROCESAMIENTO PARALELO Facultad de Ingeniería de Sistemas Información para el Proyecto REYCYT RESUMEN Se presenta información general relativa a las diferentes

Más detalles

Taxonomía de las arquitecturas

Taxonomía de las arquitecturas Taxonomía de las arquitecturas 1 INTRODUCCIÓN 2 2 CLASIFICACIÓN DE FLYNN 3 2.1 SISD (SINGLE INSTRUCTION STREAM, SINGLE DATA STREAM) 3 2.2 SIMD (SINGLE INSTRUCTION STREAM, MULTIPLE DATA STREAM) 4 2.2.1

Más detalles

SISTEMAS PARALELOS Y DISTRIBUIDOS. 3º GIC. PRÁCTICA 9 Departamento de Arquitectura y Tecnología de Computadores Universidad de Sevilla

SISTEMAS PARALELOS Y DISTRIBUIDOS. 3º GIC. PRÁCTICA 9 Departamento de Arquitectura y Tecnología de Computadores Universidad de Sevilla SISTEMAS PARALELOS Y DISTRIBUIDOS. 3º GIC. PRÁCTICA 9 Departamento de Arquitectura y Tecnología de Computadores Universidad de Sevilla PROGRAMACIÓN DE COMPUTADORES DE MEMORIA DISTRIBUIDA USANDO MPI. PREPARACIÓN

Más detalles

Con estas consideraciones, Flynn clasifica los sistemas en cuatro categorías:

Con estas consideraciones, Flynn clasifica los sistemas en cuatro categorías: Taxonomía de las arquitecturas 1 Introducción Introducción En este trabajo se explican en detalle las dos clasificaciones de computadores más conocidas en la actualidad. La primera clasificación, es la

Más detalles

Conceptos generales de sistemas distribuidos

Conceptos generales de sistemas distribuidos Departament d Arquitectura de Computadors Conceptos generales de sistemas distribuidos Sistema distribuido Un sistema en el que los componentes hardware y/o software ubicados en computadores en red, se

Más detalles

Redes de Altas Prestaciones

Redes de Altas Prestaciones Redes de Altas Prestaciones Tema 1: Introducción Características de los sistemas distribuidos Necesidad de las arquitecturas de red de altas prestaciones Organización de la asignatura Características de

Más detalles

HERRAMIENTAS SOFTWARE PARA SISTEMAS DISTRIBUIDOS

HERRAMIENTAS SOFTWARE PARA SISTEMAS DISTRIBUIDOS HERRAMIENTAS SOFTWARE PARA SISTEMAS DISTRIBUIDOS José Luis Pastrana Brincones (pastrana@lcc.uma.es) Departamento de Lenguajes y Ciencias de la Computación de la Universidad de Málaga Introducción. El hombre,

Más detalles

Curso-Taller Programación Paralela con lenguaje C bajo Linux. MCC. Salazar Martínez Hilario

Curso-Taller Programación Paralela con lenguaje C bajo Linux. MCC. Salazar Martínez Hilario Curso-Taller Programación Paralela con lenguaje C bajo Linux MCC. Salazar Martínez Hilario Mayo 2011 Programación Paralela La que se realiza usando procesos separados. Interactúan intercambiando información.

Más detalles

TEMA 1. Introducción a las arquitecturas distribuidas

TEMA 1. Introducción a las arquitecturas distribuidas TEMA 1. Introducción a las arquitecturas distribuidas Tema 1. ARQUITECTURAS DISTRIBUIDAS: CONCEPTOS BÁSICOS 1. Qué es un sistema distribuido? 2. Servicios 3. Arquitectura 4. Definición de AD 5. Modelos

Más detalles

Tema 1: Introducción a los Sistemas Distribuidos. Sistemas Distribuidos Marcos López Sanz [Curso ]

Tema 1: Introducción a los Sistemas Distribuidos. Sistemas Distribuidos Marcos López Sanz [Curso ] Tema 1: Introducción a los Sistemas Distribuidos Sistemas Distribuidos Marcos López Sanz [Curso 2012-2013] Índice Definición Objetivos Propiedades y retos Ventajas y desventajas Tipos y ejemplos Ejercicios

Más detalles

MPI es un estándar de programación en paralelo mediante paso de mensajes que permite crear programas portables y eficientes.

MPI es un estándar de programación en paralelo mediante paso de mensajes que permite crear programas portables y eficientes. Programación paralela en MPI MPI es un estándar de programación en paralelo mediante paso de mensajes que permite crear programas portables y eficientes. Introducción a MPI MPI fue creado en 1993 como

Más detalles

Modelo de paso de mensajes

Modelo de paso de mensajes Modelo de paso de mensajes Miguel Alfonso Castro García mcas@xanum.uam.mx Universidad Autónoma Metropolitana - Izt 17 de noviembre de 2016 Contenido 1 Comunicación punto a punto 2 3 Comunicación punto

Más detalles

En esta unidad vamos a hablar acerca de cómo los equipos utilizan las redes para trabajar juntos. Hay varios modelos ( que en algunos casos son

En esta unidad vamos a hablar acerca de cómo los equipos utilizan las redes para trabajar juntos. Hay varios modelos ( que en algunos casos son En esta unidad vamos a hablar acerca de cómo los equipos utilizan las redes para trabajar juntos. Hay varios modelos ( que en algunos casos son llamados arquitecturas ) que los ordenadores pueden seguir

Más detalles

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

José Matías Cutillas Lozano PROGRAMACIÓN PARALELA Y COMPUTACIÓN DE ALTAS PRESTACIONES José Matías Cutillas Lozano PROGRAMACIÓN PARALELA Y COMPUTACIÓN DE ALTAS PRESTACIONES MÁSTER EN NUEVAS TECNOLOGÍAS EN INFORMÁTICA Diciembre 2010 Introducción Por qué utilizar Matlab paralelo? MATLAB es

Más detalles

Bases de Datos Paralelas. Carlos A. Olarte BDII

Bases de Datos Paralelas. Carlos A. Olarte BDII Carlos A. Olarte (carlosolarte@puj.edu.co) BDII Contenido 1 Introducción 2 Paralelismo de I/O 3 Paralelismo entre Consultas 4 OPS Introducción Por qué tener bases de datos paralelas? Tipos de arquitecturas:

Más detalles

Tema 3: Sistemas de Alta Velocidad

Tema 3: Sistemas de Alta Velocidad Tema 3: Sistemas de Alta Velocidad A qué llamamos Alta Velocidad? Obtención, procesado y distribución de la información con rapidez. Por qué Alta Velocidad? Necesidad de comunicaciones rápidas: Mayor Ancho

Más detalles

Evolución del software y su situación actual

Evolución del software y su situación actual Evolución del software y su situación actual El software es el conjunto de programas que permite emplear la PC, es decir, es el medio de comunicación con la computadora, el control de sus funciones y su

Más detalles

Procesamiento Paralelo

Procesamiento Paralelo Procesamiento Paralelo MPI - Tipos y Topologías Javier Iparraguirre Universidad Tecnológica Nacional, Facultad Regional Bahía Blanca 11 de Abril 461, Bahía Blanca, Argentina jiparraguirre@frbb.utn.edu.ar

Más detalles

Sistemas Distribuidos. Prog. Distribuida bajo Internet

Sistemas Distribuidos. Prog. Distribuida bajo Internet Sistemas Distribuidos Prog. Distribuida bajo Internet Definición Hay muchas definiciones Básicamente, varios computadores o nodos de computación en lazados mediante una red y que comparten datos, procesamiento,

Más detalles

CAPITULO 12: SISTEMAS DE FICHEROS DISTRIBUIDOS Un sistema bien diseñado permite el acceso a un servidor de ficheros (remoto) con eficiencia y

CAPITULO 12: SISTEMAS DE FICHEROS DISTRIBUIDOS Un sistema bien diseñado permite el acceso a un servidor de ficheros (remoto) con eficiencia y CAPITULO 12: SISTEMAS DE FICHEROS DISTRIBUIDOS Un sistema bien diseñado permite el acceso a un servidor de ficheros (remoto) con eficiencia y fiabilidad comparables a las del acceso a los ficheros locales

Más detalles

Medidas de Alta Disponibilidad

Medidas de Alta Disponibilidad Punto 1 Implantación de Medidas de Alta Disponibilidad Juan Luis Cano Alta disponibilidad (High availability) es un protocolo de diseño del sistema y su implementación asociada que asegura continuidad

Más detalles

Introducción al Computo Distribuido

Introducción al Computo Distribuido Introducción al Computo Distribuido Facultad de Cs. de la Computación Juan Carlos Conde Ramírez Distributed Computing Contenido 1 Introducción 2 Importancia del Hardware 3 Importancia del Software 1 /

Más detalles

Sistemas Informáticos Industriales

Sistemas Informáticos Industriales Escuela Técnica Superior de Ingeniería y Diseño Industrial Universidad Politécnica de Madrid Llamadas a Procedimientos Remotos (RPC) Sistemas Informáticos Industriales 2017/2018 Raquel CEDAZO LEÓN

Más detalles

Sistemas Operativos Distribuidos

Sistemas Operativos Distribuidos Contenidos del Tema Gestión de procesos Modelos de sistema Asignación de procesadores Estrategias dinámicas Estrategias estáticas Ejecución remota de procesos Modelos de sistema Organización de los procesadores

Más detalles

Sistemas Distribuidos. Soporte de Sistemas Operativos

Sistemas Distribuidos. Soporte de Sistemas Operativos Soporte de Sistemas Operativos Soporte de Sistemas Operativos Soporte de Sistemas Operativos Soporte de Sistemas Operativos Tareas principales de un SO: Administrar recursos Proveer abstracciones de los

Más detalles

Ingeniería en Computación

Ingeniería en Computación Universidad Autónoma del Estado de México Centro Universitario UAEM Valle de México Ingeniería en Computación Unidad de Aprendizaje: Programación Paralela y Distribuida Tema: Introducción a los Sistemas

Más detalles

Programación Concurrente : Docencia Práctica

Programación Concurrente : Docencia Práctica Programación Concurrente : Docencia Práctica José Luis Herrero, Fabiola Lucio, David Domínguez, Fernando Sánchez {Jherrero, FLucio,Fernando}@unex.es Departamento de Informática Universidad de Extremadura

Más detalles

Introducción a los sistemas operativos. Ing Esp Pedro Alberto Arias Quintero

Introducción a los sistemas operativos. Ing Esp Pedro Alberto Arias Quintero Introducción a los sistemas operativos Ing Esp Pedro Alberto Arias Quintero Unidad 1: Conceptos generales de Sistemas Operativos. Tema 1: Introducción: 1.1 Introducción: Qué es un sistema operativo?. 1.2

Más detalles

IFCD0111 Programación en Lenguajes Estructurados de Aplicaciones de Gestión

IFCD0111 Programación en Lenguajes Estructurados de Aplicaciones de Gestión IFCD0111 Programación en Lenguajes Estructurados de Aplicaciones de Gestión 1. MÓDULO 1. MF0223_3 SISTEMAS OPERATIVOS Y APLICACIONES INFORMÁTICAS UNIDAD FORMATIVA 1. UF1465 COMPUTADORES PARA BASES DE DATOS

Más detalles

Mundo Azul.

Mundo Azul. Sistemas Operativos Abstract En este microtutorial, se describe el concepto y funciones básicas de un sistema operativo. La perspectiva a la hora de tratarlo es más desde un punto de vista de arquitectura

Más detalles

Capítulo 10. Bases de datos distribuidas

Capítulo 10. Bases de datos distribuidas Capítulo 10 Bases de datos distribuidas ÍNDICE CAPÍTULO 10 Conceptos de bases distribuidas Introducción Arquitectura de un DDBMS Fragmentación, replicación y distribución de datos Tipos de sistemas de

Más detalles

6.1 Base De Datos Centralizada

6.1 Base De Datos Centralizada 6. Infraestructura El tipo de infraestructura o bien arquitectura, se debe de elegir pensando en el sistema a ejecutar, las necesidades que este tendrá, el tipo de usuario que lo utilizará, la seguridad

Más detalles

Arquitectura de computadores I

Arquitectura de computadores I Arquitectura de computadores I Perspectiva de alto nivel de los computadores Septiembre de 2017 Contenido Componentes del computador Funcionamiento del computador Estructuras de interconexión Interconexión

Más detalles

Sistemas Operativos. Introducción. Tema 6

Sistemas Operativos. Introducción. Tema 6 Sistemas Operativos Introducción Qué es un sistema operativo? Ubicación de un sistema operativo en un computador Descripción de un sistema operativo: Funcional Estructural Realización Funciones de los

Más detalles

SD Examen 2 EVA. 1 of 11 2/5/2013 8:49 PM. Paralelo 1? Evaluaciones? SD Examen 2 EVA. Comenzado: Feb 5 en 8:50pm

SD Examen 2 EVA. 1 of 11 2/5/2013 8:49 PM. Paralelo 1? Evaluaciones? SD Examen 2 EVA. Comenzado: Feb 5 en 8:50pm Paralelo 1? Evaluaciones? SD Examen 2 EVA SD Examen 2 EVA Comenzado: Feb 5 en 8:50pm Question 1: 1 puntos Los [ Seleccionar ] son la union logica de multiples equipos informaticos que funcionan como uno.

Más detalles

CURSO: DESARROLLADOR PARA APACHE HADOOP

CURSO: DESARROLLADOR PARA APACHE HADOOP CURSO: DESARROLLADOR PARA APACHE HADOOP CAPÍTULO 2: INTRODUCCIÓN A HADOOP www.formacionhadoop.com Índice 1 Qué es Big Data? 2 Qué es Hadoop? 3 Historia de Hadoop 4 Por qué utilizar Hadoop? 5 Core Hadoop

Más detalles

2.- Con qué palabras inglesas se define la parte física del ordenador y cómo se llama la parte de programas, la que no se ve.

2.- Con qué palabras inglesas se define la parte física del ordenador y cómo se llama la parte de programas, la que no se ve. CUESTIONARIO TEMA 2 UNIDADES FUNCIONALES. 1.- Definición de ordenador. Máquina electrónica capaz de almacenar información y tratarla automáticamente mediante operaciones matemáticas y lógicas controladas

Más detalles

Introducción a los sistemas distribuidos. Jorge Iván Meza Martínez

Introducción a los sistemas distribuidos. Jorge Iván Meza Martínez Introducción a los sistemas distribuidos Jorge Iván Meza Martínez jimezam@gmail.com Especialización en Gestión de Redes de Datos Universidad Nacional de Colombia Sede Manizales 1/28 Contenidos Definiciones

Más detalles

MULTIPROCESADORES MODELOS DE INTERCONEXIÓN

MULTIPROCESADORES MODELOS DE INTERCONEXIÓN Todos los derechos de propiedad intelectual de esta obra pertenecen en exclusiva a la Universidad Europea de Madrid, S.L.U. Queda terminantemente prohibida la reproducción, puesta a disposición del público

Más detalles

MPI y sus aplicaciones en infraestructuras Grid

MPI y sus aplicaciones en infraestructuras Grid MPI y sus aplicaciones en infraestructuras Grid Dr. Isabel Campos Plasencia Instituto de Física de Cantabria-IFCA Santander, Spain Grids y e-ciencia 2008, IFIC, Valencia Esquema Introducción a MPI MPI

Más detalles

Programación en Lenguajes Estructurados de Aplicaciones de Gestión. Certificados de profesionalidad

Programación en Lenguajes Estructurados de Aplicaciones de Gestión. Certificados de profesionalidad Programación en Lenguajes Estructurados de Aplicaciones de Gestión Certificados de profesionalidad Ficha Técnica Categoría Informática y Programación Referencia 33002-1404 Precio 170.36 Euros Sinopsis

Más detalles

Computación en Internet: Librería MALLBA para problemas de optimización

Computación en Internet: Librería MALLBA para problemas de optimización Computación en Internet: Librería MALLBA para problemas de optimización Maria J. Blesa Jordi Petit Fatos Xhafa Departament de Llenguatges i Sistemes Informàtics Universitat Politècnica de Catalunya Campus

Más detalles

4. Configuración de la conexión de un sistema LXI

4. Configuración de la conexión de un sistema LXI 4. Configuración de la conexión de un sistema LXI Existen diversas formas de configurar la conexión de un sistema LXI. En este apartado se describen algunos de los métodos más utilizados, pero antes se

Más detalles

Sistemas Operativos. Dr. Wenceslao Palma M.

Sistemas Operativos. Dr. Wenceslao Palma M. Sistemas Operativos Dr. Wenceslao Palma M. www.inf.ucv.cl/~wpalma/so Introducción a los Sistemas Computacionales Un vistazo de alto nivel caracteriza a un sistema computacional

Más detalles

CONCEPTO. Actúa de intermediario entre el hardware y los programas de aplicación.

CONCEPTO. Actúa de intermediario entre el hardware y los programas de aplicación. CONCEPTO ES UN SOFTWARE DE SISTEMA, ES DECIR, UN CONJUNTO DE PROGRAMAS DE COMPUTACIÓN DESTINADOS A REALIZAR MUCHAS TAREAS ENTRE LAS QUE DESTACA LA ADMINISTRACIÓN EFICAZ DE SUS RECURSOS. Se encarga de gestionar

Más detalles

Tema 2. GENERALIDADES SOBRE SISTEMAS OPERATIVOS 1, MAQUINA DESNUDA.

Tema 2. GENERALIDADES SOBRE SISTEMAS OPERATIVOS 1, MAQUINA DESNUDA. Tema 2. GENERALIDADES SOBRE SISTEMAS OPERATIVOS 1, MAQUINA DESNUDA. El término de máquina desnuda se aplica a una computadora carente de sistema operativo, el término es interesante porque resalta el hecho

Más detalles

BASES DE DATOS DISTRIBUIDAS

BASES DE DATOS DISTRIBUIDAS BASES DE DATOS DISTRIBUIDAS BASES DE DATOS DISTRIBUIDAS DANIEL BARRERA NAVARRO JORGE BAUTE RIVERA ROSIRIS MARTINEZ GOMEZ DARWIN MANGA COGOLLO Introducción a las bases de datos distribuidas DEFINICION DE

Más detalles

Taller de Programación Paralela

Taller de Programación Paralela Taller de Programación Paralela Departamento de Ingeniería Informática Universidad de Santiago de Chile April 17, 2008 Motivación Programar aplicaciones paralelas no es una tarea trivial. Paralelismo

Más detalles

Diagrama de despliegue

Diagrama de despliegue Diagrama de despliegue Definición.- Los Diagramas de Despliegue muestran las relaciones físicas de los distintos nodos que componen un sistema y el reparto de los componentes sobre dichos nodos. La vista

Más detalles

Contenido 1. INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS PROCESOS Prólogo...

Contenido 1. INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS PROCESOS Prólogo... 1 Prólogo... xv 1. INTRODUCCIÓN A LOS SISTEMAS OPERATIVOS... 1 1.1. Conceptos generales sobre sistemas operativos... 2 1.1.1. Funciones del sistema operativo... 2 1.1.2. Componentes del sistema operativo...

Más detalles

Concurrencia. Concurrencia

Concurrencia. Concurrencia Concurrencia Procesos y hebras Concurrencia Programación concurrente Por qué usar hebras y procesos? Ejecución de procesos Ejecución de hebras Hebras vs. Procesos Creación y ejecución de hebras La prioridad

Más detalles

Hilos Secciones Stallings:

Hilos Secciones Stallings: Capítulo 4 Hilos Secciones Stallings: 4.1 4.3 Contenido Procesos e hilos. Hilos a nivel de núcleo y a nivel de usuario. Multiprocesador simétrico (SMP). Micronúcleos. 1 Proceso Unidad de propiedad de los

Más detalles

Programación Paralela: Memoria Distribuida

Programación Paralela: Memoria Distribuida Programación Paralela: Memoria Distriuida MPI: Un caso de estudio Introducción Estas máquinas surgen de forma natural al conectar distintas máquinas en red y ponerlas a cooperar. La red será clave. Arquitectura

Más detalles

METODOLOGÍA DE LA PROGRAMACIÓN PARALELA. Modelos de programación paralela Paradigmas de programación paralela

METODOLOGÍA DE LA PROGRAMACIÓN PARALELA. Modelos de programación paralela Paradigmas de programación paralela METODOLOGÍA DE LA PROGRAMACIÓN PARALELA Modelos de programación paralela Paradigmas de programación paralela Tipos de paralelismo Paso de mensajes Paralelismo de datos Memoria compartida Tipos de paralelismo

Más detalles

Sistemas Operativos Distribuidos. Sistemas Operativos Una visión aplicada

Sistemas Operativos Distribuidos. Sistemas Operativos Una visión aplicada Bibliografía Sistemas Operativos Distribuidos Ing. Alfonso Guijarro Rodríguez alfonso_guijarro@yahoo.es Sistemas Operativos Distribuidos Andrew S. Tanenbaum. 1996, Prentice-Hall Capítulo 1 última edición

Más detalles

Tipos de Diseño. Ing. Elizabeth Guerrero V.

Tipos de Diseño. Ing. Elizabeth Guerrero V. Tipos de Diseño Ing. Elizabeth Guerrero V. Tipos de Diseño Tipos de diseño de Procesos: Centralizado, Distribuido y Cooperativo Procesos Centralizados Un sistema centralizado está formado por un computador

Más detalles

Fecha de entrega: Miércoles 4 de Septiembre. Campus: Villahermosa. Carrera : Ingeniería en Sistemas Compuacionales. Nombre del maestro: Carlos Castro

Fecha de entrega: Miércoles 4 de Septiembre. Campus: Villahermosa. Carrera : Ingeniería en Sistemas Compuacionales. Nombre del maestro: Carlos Castro Nombre del estudiante: Giovanna Kristhel Mendoza Castillo Nombre del trabajo: Investigación sobre los Sistemas Operativos distribuidos Fecha de entrega: Miércoles 4 de Septiembre Campus: Villahermosa Carrera

Más detalles

Sistemas Complejos en Máquinas Paralelas

Sistemas Complejos en Máquinas Paralelas Sistemas Complejos en Máquinas Paralelas Clase 1: OpenMP Francisco García Eijó Departamento de Computación - FCEyN UBA 15 de Mayo del 2012 Memoria compartida Las mas conocidas son las máquinas tipo Symmetric

Más detalles

Escalabilidad: El desempeño del software y hardware debe ser eficiente desde un grupo pequeño de procesadores a un grupo muy grande de procesadores.

Escalabilidad: El desempeño del software y hardware debe ser eficiente desde un grupo pequeño de procesadores a un grupo muy grande de procesadores. Página 1 de 8 Introducción a BSP La motivación para el modelo de computación paralela BSP (The Bulk-Synchronous Parallel Model) surge de una comparación con lo que se observa en el mundo de la computación

Más detalles

BASE DE DATOS DISTRIBUIDOS

BASE DE DATOS DISTRIBUIDOS 1 BASE DE DATOS DISTRIBUIDOS Contenido: Base de Datos Distribuidos 1.1. Introducción 1.1.1 Almacenamiento Distribuido 1.2. Sistemas de gestión de bases de datos distribuidos 1.2.1 Funciones y Arquitectura

Más detalles

Introducción a las Computadoras. Capítulo 3 Buses del Sistema

Introducción a las Computadoras. Capítulo 3 Buses del Sistema Introducción a las Computadoras Capítulo 3 Buses del Sistema Concepto de Programa Los sistemas de propósito específico no son flexibles El Hardware de propósito general puede realizar diferentes tareas,

Más detalles

Introduccion a Sistemas Operativos. Ej: Linux

Introduccion a Sistemas Operativos. Ej: Linux Universidad Nacional de Ingeniería Facultad de Ciencias Física Computacional CC063 Introduccion a Sistemas Operativos. Ej: Linux Prof: J. Solano 2012-I Resumen Qué hacen los sistemas operativos? Organización

Más detalles

ARQUITECTURAS. Carlos Reveco D. IN73J Arquitectura, Diseño y Construcción de un Negocio con Apoyo TI.

ARQUITECTURAS. Carlos Reveco D. IN73J Arquitectura, Diseño y Construcción de un Negocio con Apoyo TI. ARQUITECTURAS 1 IN73J Arquitectura, Diseño y Construcción de un Negocio con Apoyo TI Carlos Reveco D. creveco@dcc.uchile.cl Arquitectura de una aplicación 2 Arquitectura: desarrolla un plan general del

Más detalles

Depto. Sistemas I.O. y Computación. informáticos y Computación Univ. La Laguna

Depto. Sistemas I.O. y Computación. informáticos y Computación Univ. La Laguna Sobre el papel de la programación paralela en los nuevos planes de estudios de informática Francisco Almeida Domingo Giménez José M. Mantas Antonio M. Vidal Depto. Estadística, Depto. Informática y Depto.

Más detalles

Computacion de Alto Performance

Computacion de Alto Performance Computacion de Alto Performance Abraham Zamudio Abraham Zamudio Computacion de Alto Performance 1/47 Indice 1 Algunos Aspectos Teoricos 2 Paralelismo Computacional 3 Linux Cluster Hardware Software 4 MPICH

Más detalles

Una arquitectura de componentes provee, desde el punto de vista de un. sistema computacional, la definición de las partes esenciales del proceso de

Una arquitectura de componentes provee, desde el punto de vista de un. sistema computacional, la definición de las partes esenciales del proceso de 2.1 Introducción Una arquitectura de componentes provee, desde el punto de vista de un sistema computacional, la definición de las partes esenciales del proceso de información, en este caso del proceso

Más detalles

Velocidades Típicas de transferencia en Dispositivos I/O

Velocidades Típicas de transferencia en Dispositivos I/O Entradas Salidas Velocidades Típicas de transferencia en Dispositivos I/O Entradas/Salidas: Problemas Amplia variedad de periféricos Entrega de diferentes cantidades de datos Diferentes velocidades Variedad

Más detalles

INFORMATICA III. Cap. I: Plataformas

INFORMATICA III. Cap. I: Plataformas INFORMATICA III Cap. I: Plataformas Plataformas Código nativo y portable Máquinas virtuales Servidores Estaciones de trabajo Clientes delgados Dispositivos embebidos Dispositivos móviles Plataformas Hardware

Más detalles

Ejecución serial: las tareas/instrucciones de un programa son ejecutadas de manera secuencial, una a la vez.

Ejecución serial: las tareas/instrucciones de un programa son ejecutadas de manera secuencial, una a la vez. Paralelismo Conceptos generales Ejecución serial: las tareas/instrucciones de un programa son ejecutadas de manera secuencial, una a la vez. Ejecución paralela: varias tareas/instrucciones de un programa

Más detalles

BASES DE DATOS DISTRIBUIDAS

BASES DE DATOS DISTRIBUIDAS BASES DE DATOS DISTRIBUIDAS Una Base de Datos Distribuida entonces es una colección de datos que pertenecen lógicamente a un sólo sistema, pero se encuentra físicamente esparcido en varios "sitios" de

Más detalles