3 Estado del arte
3.4 Sistemas desarrollados con hardware ad hoc
3.4.3 La utilización de GPUs
No se debe perder de vista que una de las características principales de los Sistemas P es el altísimo nivel de paralelismo que, de manera teórica, pueden presentar. Es esta característica, que se puede conseguir ya de manera inicial con Sistemas P con un número muy alto de membranas o usando sistemas activos con reglas de creación de nuevas membranas, la que hace que, siempre sobre el papel, estén especialmente indicados para la resolución de problemas caracterizados como NP. El cambio es evidente: la cantidad de tiempo (exponencial) para resolver el problema se permuta por un número enorme de recursos destinados a la computación y se reduce el tiempo necesario para la resolución (polinomial).
Este planteamiento, que en la teoría parece claro, en la práctica no es sencillo de resolver ya que los recursos que se pueden destinar están, hasta el momento, limitados siempre por la disponibilidad de “equipos procesadores”. Es, probablemente, el principal obstáculo a la hora de implantar los Sistemas P y por supuesto, objetivo de numerosos trabajos científicos en todo el mundo (incluido el presente trabajo doctoral).
Por otra parte, la resolución de problemas cuya solución parece ser especialmente propensa al paralelismo es un área muy extensa y cada vez se hace más necesario disponer de esos numerosos recursos. Este tipo de problemas se ha resuelto, tradicionalmente, mediante el uso de grupos de ordenadores conectados mediante algún tipo de bus. Sin embargo, esta solución, por muy potentes que sean los equipos disponibles, resulta tremendamente onerosa y por tanto inviable en muchas situaciones. Algunos fabricantes de hardware específico se han dado cuenta de ello y han desarrollado productos cuyo destino es la utilización por parte de los científicos e ingenieros para la resolución de los problemas descritos.
Dentro de esta área se sitúan las nuevas tarjetas de carácter gráfico que algunos fabricantes como Nvidia han desarrollado. Los fabricantes han aprovechado el hecho de que las tarjetas gráficas están destinadas a la computación masiva y en paralelo de cálculos matemáticos orientados a la representación en pantalla de determinado software (en especial el software recreacional cuya exigencia gráfica es muy alta). Estas tarjetas son cada vez más potentes y contienen cada vez un mayor número de unidades de procesamiento denominadas GPUs (Graphics Processing Unit o unidad de procesamiento gráfico). Estas unidades, que normalmente se programan a través de interfaces como OpenGL o
112
DirectX pueden ser utilizadas con propósitos de carácter general. Así surge el nuevo campo denominado GPGPU (General Purpose on GPUs).
Hace algún tiempo Nvidia propuso un modelo de programación sobre la arquitectura CUDA (Compute Unified Device Architecture) que facilitaba la generación de programas de propósito general. A pesar de estas facilidades, hay que considerar que la arquitectura no se adapta fácilmente a cualquier problema ya que está especialmente indicado para aquellos que tienen una fuerte carga computacional que aproveche el alto nivel de paralelismo y que no necesite mucha comunicación entre los diferentes procesos. En [Martínez-del-Amor et al., 2009] el Grupo de Computación Natural de la Universidad de Sevilla junto con el Grupo de Arquitectura y Computación Paralela de la Universidad de Murcia proponen la utilización de este tipo de dispositivos para la simulación de Sistemas de Membranas. A priori, la disponibilidad de un número muy grande de unidades procesadoras en un solo dispositivo parece favorecer el paralelismo inherente a estos sistemas al mismo tiempo que se obtiene a un precio muy competitivo.
Como se ha mencionado CUDA es una arquitectura hardware y un modelo de programación de propósito general que amplía el lenguaje C con funciones específicas para gestionar el paralelismo así como la transferencia de información entre los diferentes módulos de procesamiento y entre las GPUs y la CPU del sistema (al lenguaje se le denomina CUDA C). Los autores del trabajo utilizan una tarjeta gráfica de Nvidia C1060 perteneciente a la familia TESLA de GPUs de propósito general con 30 grupos de unidades de multiproceso, que en total contienen 240 núcleos de proceso. Cada unidad de multiproceso puede ejecutar hasta 1024 hilos de ejecución sin sobrecarga de gestión. Las aplicaciones deben comenzar a ejecutarse en la CPU y desde ella se cargan datos en las GPUs a través de un bus PCI-Express. Cada unidad de multiproceso tiene memoria local de acceso rápido y acceso a memoria compartida, que es mucho más lento. Los programas se desarrollan con código que se ejecutará en la CPU y código que se ejecutará en la GPU y se compilan con un compilador específico de Nvidia para código CUDA. El código de la CPU se encarga de transferir los datos de la memoria principal a la memoria de la GPU y es el encargado de establecer el número de hilos de ejecución y cómo se coordinan.
En cuanto a la utilización de esta GPU para simular un Sistema P, los autores proponen la selección de determinadas partes para su ejecución en la GPU mientras que otras se pueden ejecutar en la CPU del servidor. La idea ha sido utilizar el simulador de Sistemas P de membranas activas que han sido desarrollado para el entorno de P-Lingua (ver más adelante). En este simulador, cada evolución se divide en dos partes: la fase de selección y la fase de ejecución. La fase de selección se encarga de elegir aquellas reglas que van a ser aplicadas en cada una de las membranas, mientras que la fase de ejecución se encarga de la propia aplicación (ejecución) de dichas reglas.
113
La primera fase, de selección, toma como datos de entrada el multiconjunto de la membrana y el conjunto de reglas y la salida es el subconjunto de reglas a ejecutar. Es la fase de ejecución la encargada de modificar los multiconjuntos a base de la aplicación de estas reglas. Ahora bien, dado que la fase de ejecución necesita de una sincronización entre todos los procesos para poder proceder a dichas modificaciones, la ejecución completa de esta fase es llevada a cabo en la CPU, mientras que la primera fase se ejecuta en la GPU.
Los autores mejoran el rendimiento del algoritmo propuesto en la plataforma de P-Lingua y lo denominan simulador secuencial rápido para poder comparar la ejecución con el algoritmo anterior.
Figura 3.5 Utilización de un bloque por membrana ([Martínez-del-Amor et al., 2009])
Como se puede ver en la Figura 3.5 los autores identifican cada membrana con un bloque de ejecución que es absolutamente independiente de los demás y en los que la comunicación entre los diferentes hilos es factible fácilmente en términos de coste de recursos, pero la comunicación entre los diferentes bloques es costosa. En cada uno de los bloques hay un hilo por cada elemento del alfabeto, que se ejecuta en paralelo y selecciona las reglas que usan dicho objeto
Analizando la situación planteada por el uso de este tipo de tarjetas gráficas, parece lógico pensar que la obtención de recursos capaces de procesar en paralelo con un coste razonable es un avance notable. Sin embargo, estudiando la solución planteada se puede llegar a la conclusión de que, hasta el momento de la presentación del trabajo, estaba claramente limitada por la utilización del software paralelo nada más que en la fase de selección y por pasar el peso de la ejecución a la CPU del servidor, donde se pierde la ventaja de los recursos de la GPU. Por otra parte, es asumible pensar que aunque se consiguiese paralelizar en la GPU la segunda fase de ejecución (tal y como parece
114
indicarse en algunos documentos asociados al trabajo), habría que estudiar la posible sobrecarga que se puede llegar a producir en las comunicaciones y sincronización entre las membranas, que por otra parte, es un problema muy común en otras plataformas. Por último, la limitación que existe en cuanto a los niveles de jerarquía en el sistema P a resolver (solo permite dos niveles: la "piel" y las membranas inmediatamente inferiores) excluye muchos de los posibles problemas a solucionar.
Algunos meses más tarde, el mismo grupo presentó otro trabajo [Cecilia et al., 2009] en el que avanzan notablemente al incluir la fase de ejecución dentro de los recursos de la GPU, paralelizando de manera plena todas las fases. Los autores contemplan los Sistemas P de membranas activas, que incluyen las reglas de evolución, envío de objetos dentro de una membrana, salida de objetos de una membrana hacia el exterior y de disolución así como la regla de división que puede producir un número muy alto de membranas en un tiempo pequeño.
El equipo desarrolla una estructura con "kernels" que atienden al proceso de cada uno de los tipos de reglas que se van a aplicar. Así, se dispone del kernel encargado de las reglas de evolución (éste se encarga también de toda la fase de selección) así como otros cuatro encargados respectivamente de la ejecución de las reglas de disolución, entrada de objetos, salida y división.
Aprovechando la estructura de la GPU, en el mencionado documento se vuelve a proponer un sistema por el que se asocia una membrana con cada uno de los bloques multiprocesador y un hilo de ejecución ("thread") para cada uno de los objetos del alfabeto correspondiente al multiconjunto. Todos los bloques presentan ejecución en paralelo en la fase de selección y cada thread se encarga de seleccionar aquellas reglas que afectan al objeto del alfabeto que representan.
Por otra parte, dado que las reglas de evolución en este tipo de Sistemas P no necesitan de sincronización, el mismo kernel encargado de la fase de selección es el que ejecuta todas estas reglas, mientras que cada uno de los otros tipos de reglas (disolución, división, entrada, salida) se ejecuta en los otros kernel.
En principio el sistema contiene las mismas limitaciones propias de la GPU (hardware) que presenta la primera aproximación e incluso mantiene la de permitir un máximo de dos niveles en el sistema (piel y membranas en un solo nivel).
En el propio trabajo se presenta un caso de estudio en el que, para el Sistema P se contemplan la existencia de reglas de evolución y de división en cada una de las membranas de tal manera que a medida que avanzan las configuraciones del sistema, se van generando de manera dinámica membranas y reglas de evolución para todos los objetos existentes en el alfabeto. Se contempla un sistema con:
115
i) Reglas de evolución: [oi oi] ,0in
0 2
ii) Regla de división: 0
2 0 2 0 2 [ ] [ ] ] [d d d
de tal manera que se puede controlar tanto el número de membranas como de reglas y objetos de manera bastante sencilla variando el parámetro n.
Los resultados experimentales que los autores obtienen se refieren a la comparación realizada entre el sistema desarrollado en CUDA y otro sistema secuencial desarrollado en C++ y en general obtienen una mejora de tres órdenes de magnitud en el tiempo de ejecución al hacer crecer el número de membranas y de objetos en el sistema (en el caso de un número menor o igual a 256 objetos en cada membrana, el tiempo en el sistema CUDA permanece casi invariante ya que se aprovechan los 256 threads del bloque de ejecución), llegando a la conclusión de que la utilización de GPUs para simular sistemas de membranas es una buena opción que hace uso del concepto de doble paralelismo (entre las membranas y dentro de las membranas entre las reglas de evolución) que tiene lugar en ellos.
Siguiendo en la misma línea de trabajo con GPUs, en [Cecilia et al., 2012] se presenta un simulador de Sistemas P con membranas activas que resuelve el conocido problema SAT sobre las GPU Tesla C1060 y el sistema Tesla S2050 con cuatro GPUs M2050 que presentan 30 y 14 procesadores respectivamente, con un número elevado de hilos de ejecución por procesador (1.024 y 1.536 respectivamente) además de un tamaño en las memorias caché de nivel 1 y 2 bastante importante así como una memoria global de vídeo también significativa (4Gb y 3Gb) además de un ancho de banda de transferencia de datos de 102GB/s y 144GB/s respectivamente.
En ambos casos la memoria que pueden compartir todos los procesadores es la memoria de vídeo, que es la más lenta, pero cada uno de dichos procesadores dispone de una memoria privada cuya latencia de acceso es mucho menor. La unidad de ejecución aquí es un "thread" (hilo) aunque denominan bloque a un conjunto de threads que pueden cooperar por haber sido asignados al mismo procesador. Para el simulador presentado en el trabajo mencionado se asigna una membrana a un bloque y un hilo de ejecución a cada uno de los objetos de la membrana del multiconjunto inicial. De esta manera los autores hacen hincapié en el doble paralelismo de los sistemas P: por un lado la ejecución paralela para diferentes membranas y por otro el intra-paralelismo interno al asociar un hilo de ejecución a cada objeto.
Para afrontar el problema SAT, el sistema comienza generando inicialmente tantas membranas como procesadores tenga y enviándolas a éstos desde el procesador principal del equipo. Acto seguido, se producen el paralelismo interno (ejecución dentro de cada membrana) según las cuatro fases denominadas "generación" (se generan las
116
asignaciones), "sincronización" (los objetos con valor verdadero se unifican en la membrana), "comprobación" (se determina el número de cláusulas que hay con valor "verdadero" en cada membrana interna) y "salida" (se envía la solución a la membrana externa o piel).
En una comparación con la ejecución del algoritmo sobre una CPU convencional, los autores sostienen que, aunque al principio de la ejecución del algoritmo, la arquitectura CUDA no presenta grandes ventajas ya que se ejecuta un único hilo, en cuanto se pasa a la fase de generación, la ventaja es más que notable, anotando que puede llegar hasta tres órdenes de magnitud más rápido. De hecho la técnica de distribuir los procesos sobre diferentes hilos sin necesidad de accesos a memoria mejora el rendimiento global gracias al acceso a los datos locales.
Por último hay que indicar que en [Martinez-del-Amor, 2013] el autor muestra los resultados de la utilización de una tarjeta más avanzada como es la línea de Nvidia Kepler mejorando los tiempos de proceso en un factor mayor del doble.