Algoritmo de Complejidad Constante para una Gestión Eficiente de FPGAs Dinámicamente Reconfigurables en 2D Román Navarro S., Septién del Castillo J., Mecha López H. Facultad de Informática, UCM, Madrid, Spain, sroman@dacya.ucm.es Resumen. Presentamos un algoritmo simple y rápido para la gestión en tiempo real de recursos hardware dinámicamente reconfigurables, integrado en un sistema operativo extendido con la funcionalidad multitarea para hardware, de complejidad constante. Dividimos el área del dispositivo programable en cuatro particiones de diferente tamaño, cada una de las cuales está asociada con una cola en la que el gestor de hardware va escribiendo las tareas en función de su tamaño y forma. Se pueden rotar tareas y unir particiones adyacentes. Los resultados obtenidos para conjuntos heterogéneos de tareas representativos de entornos multitarea típicos son casi tan buenos como los de otros algoritmos más complejos: el uso medio del área es solo ligeramente inferior al de First Fit y los números de ciclos de reloj empleados para ejecutar un conjunto de tareas es muy similar. Además se evitan los costes de defragmentación. 1 Introducción La evolución a lo largo de los últimos años del hardware reconfigurable, especialmente los Field Programmable Gate Arrays (FPGAs), ha supuesto no sólo un incremento de su tamaño y densidad, sino también la aparición de otras características novedosas cuya descripción detallada podemos encontrar en [1]. Una de las más interesantes es la capacidad de reconfiguración parcial en tiempo de ejecución, es decir, poder reconfigurar una parte de la FPGA con una funcionalidad distinta a la que originalmente se programó. Estas nuevas características han despertado el interés por incorporar la gestión de recursos HW dinámicamente reconfigurables (HWDR) a la funcionalidad del sistema operativo (SO). Brebner [2] fue el primero en considerar esta posibilidad y después otros como Diessel [3] o Merino [4] han intentado aislar los problemas que quedan por resolver comparando la gestión de HWDR con la gestión tradicional de recursos SW, como el tiempo de CPU o la memoria de programa. El continuo incremento en el tamaño de las FPGAs, que previsiblemente seguirá creciendo en el futuro inmediato y a medio plazo, obliga a plantearse un nuevo modelo de recursos con la posibilidad de multitarea HW sobre una FPGA de gran tamaño que sea dinámicamente reconfigurable. Se puede imaginar por tanto un recurso HWDR como una gran superficie de procesamiento que puede contener un conjunto de tareas, cada una de las cuales ha sido compilada a un bitmap HW reubicable con las herramientas de compilación disponibles, y puede ser cargada en una zona libre de la FGPA cuando se precise su ejecución. Cada tarea HW puede cargarse o abandonar la FPGA sin afectar a las otras tareas que se están ejecutando. Si la tarea necesita parámetros de entrada o produce resultados enton- ces hay que proporcionarle líneas de transmisión que la conecten con los pines de entrada y salida del circuito. Esta nueva funcionalidad plantea varios problemas, como dónde ubicar cada tarea o el de la fragmentación que se produce en el HW conforme las tareas van dejando huecos en la FPGA al terminar su ejecución. Esto hace que la forma en que se gestiona el espacio libre de la FPGA y en que se asigna una ubicación a una tarea tenga una influencia decisiva respecto a la aparición de fragmentación y en la eficiencia de uso del recurso HW. Como solución extrema en casos de fragmentación muy alta puede considerarse la reubicación de tareas en ejecución en la FPGA, medida que en la actualidad representa un coste muy elevado en tiempo, resultando poco eficiente. Para FPGAs como la Virtex o la Virtex-II los problemas asociados a la gestión del HW (ubicación, fragmentación y reubicación) se parecen a los que aparecen en la gestión de memoria para SW. Las FPGAs mencionadas, aunque con una disposición interna de los bloques básicos configurables en 2D, solo se pueden configurar en una dimensión: la mínima unidad reconfigurable en tiempo de ejecución es un frame vertical completo (es decir, se pueden reconfigurar por columnas únicamente). El ancho de dichos frames es una fracción de un CLB, y su altura debe cubrir toda la dimensión de la FPGA en vertical. El problema planteado por la fragmentación y reubicación en una dimensión es bien conocido en los casos de gestión de memoria por el SO. Sin embargo, existen herramientas como JBits [5] que permiten reconfigurar dinámicamente secciones de las FPGAs Virtex en 2D, que permiten por tanto hacer un uso más eficiente del espacio disponible en la FPGA. 2 Trabajos relacionados Los trabajos recientes de Diessel et al. [6], Bazargan et al. [7], Walder et al. [8] y Compton et al. [9], tratan los problemas derivados de la gestión dinámica de recursos HWDR en 2D. Todos ellos proponen algoritmos complejos que hacen uso de estructuras de datos complejas para almacenar la información acerca del área disponible en la FPGA. Esta complejidad los convierte en difíciles de implementar en HW real debido a los sobrecostes de tiempo que generarían en un entorno altamente dinámico, y que echarían por tierra las ventajas de uso altamente eficiente del área de la FPGA, aunque quizás se podrían disminuir con una implementación HW del algoritmo de gestión en la propia FPGA. El asignador propuesto por Diessel [6] utiliza una estructura en árbol quad-tree para almacenar la información de área de FPGA disponible y debe recorrerlo para encontrar un hueco adecuado donde situar cada nueva tarea HW que llega. En cada nivel un rectángulo se divide en cuatro rectángulos menores, que se pueden marcar como libres, ocupados o parcialmente libres. Dicho árbol jerárquico se recorre con rapidez, pero esta estructura puede dar lugar a situaciones en las que exista un hueco libre suficientemente grande y que no se identifique debido a que esté repartida entre nodos/ramas diferentes del árbol. El algoritmo de Diessel debe inevitablemente defragmentar la FPGA, para lo cual propone varias técnicas con una complejidad de O(N3). Las soluciones propuestas por Bazargan [7] o Walder [8] utilizan heurísticas de binpacking y aplican algunos de los algoritmos clásicos on-line y off-line que existen para dicho problema teórico, pero todos tienen un orden de complejidad muy alto. Los algoritmos off-line descritos en [7], que utilizan técnicas de optimización muy complejas como el simulated annealing o el branch-and-bound, son completamente inútiles en los entornos mencionados anteriormente. Compton, en [9] considera también la reubicación como la respuesta a la fragmentación, y propone una arquitectura 2D capaz de reubicar tareas residentes fila por fila para hacer hueco a las tareas que van llegando. El coste de dichos procesos de reubicación es muy alto, pues se debe parar toda la actividad de la FPGA para llevarlo a cabo, y supone un sobrecoste adicional que se debe rechazar. La propuesta de Merino et al. [4], por el contrario, intenta evitar dicho problema utilizando un algoritmo de ubicación directo y radical que divide el área de la FPGA en cuatro particiones de igual área. La excesiva área desperdiciada se compensa con la velocidad ganada por éste algoritmo, que no produce ningún sobrecoste y no provoca situaciones de fragmentación. Sin embargo, para un conjunto de tareas de tamaños muy variados como los que se podrían esperar en un entorno como el descrito anteriormente, las tareas pequeñas desperdiciarían mucho área de la FPGA, y muchas tareas grandes se tendrían que rechazar. En un trabajo muy reciente, Walder et al. [10] han incluido algunas ideas parecidas a las presentadas en este trabajo, como la de dividir la FPGA en varios bloques con tamaños diferentes, pero lo han aplicado exclusivamente a casos en 1D y no a FPGAs en 2D como hemos hecho nosotros. 3 Nuestro enfoque Nuestro enfoque hace uso de las ventajas principales de un algoritmo de ubicación directo, que no da lugar a los sobrecostes de ubicación y fragmentación con que se encuentran [6], [7], [8] o [9], y que proporciona una mayor flexibilidad a la hora de gestionar el área de la FPGA que [4]. A continuación describimos los modelos de sistema, de FPGA y de tarea que utilizamos así como las características principales de nuestro gestor HW. Después presentaremos algunos resultados que justifican nuestro enfoque. 3.1 Modelo de sistema, de FPGA y de tarea El modelo de sistema del que partimos es el mostrado en la figura 1a. En principio, cualquier tarea se pueden ejecutar en SW o en HW, dependiendo de sus restricciones temporales, la disponibilidad de recursos SW o HW, y la disponibilidad de código SW y/o HW para cada tarea.. La funcionalidad tradicional del SO se ha extendido con el gestor HWDR, que decide dónde y cuándo ubicar cada nueva tarea que va a ejecutarse en la FPGA. Hemos utilizado un modelo de FPGA en 2 dimensiones que supone la superficie de la FPGA homogénea y dividida en W*H bloques básicos o celdas. En nuestro modelo gestionamos las celdas de la FPGA como si ésta estuviera dividida en cuatro particiones de diferente tamaño (figura 1b), resultado de dividir la superficie con dos líneas x=wp e y=hp. a) b) Fig. 1 – Arquitectura del sistema y particiones y tareas en la FPGA Las particiones resultantes P0, P1, P2 y P3 tienen las siguientes características: Origen: (0,0), (wp,0), (0,hp) y (wp,hp) Tamaños: wp* hp, (W-wp) * hp, wp * (H-hp) y (W-wp )*(H-hp) Las tareas se representan como rectángulos en cuyas áreas están incluidos todos los recursos de procesamiento y rutado necesarios. Cada tarea se ubica en la partición más adecuada a su tamaño, y puede rotarse para conseguir una mejor ubicación. Cada tarea está definida por una tupla Ti = { wi ,hi , tarri , texi , tmaxi } en la que wi es el ancho de la tarea, hi su altura, tarri el ciclo de reloj en el que llega la tarea al gestor, texi el tiempo de ejecución de la tarea y tmaxi la restricción de tiempo para dicha tarea. Aunque las tareas son reubicables, siempre se sitúan en la partición seleccionada, con un criterio “bottom-left” tal como muestra la figura 1b. 3.2 El algoritmo El área de la FPGA está dividida en cuatro particiones diferentes. Cada partición Pi está asociada con una cola Qi, que guarda en orden las tareas pendientes de ejecutar en dicha partición, como se muestra en la figura 2. Cuando llega una nueva tarea, el algoritmo la envía a la cola en la que mejor encaja según su tamaño. Cuando una tarea en una partición termina su ejecución se lee una nueva tarea de la cola asociada a la partición y se envía a la FPGA. Se pueden enviar varias tareas a ejecutar simultáneamente en la FPGA en diferentes particiones. Cada cola tiene un tiempo de espera wti, que es la suma de los tiempos de ejecución de las tareas que esperan en ella más el tiempo que le queda a la tarea que se está ejecutando en la partición asociada para terminar. Cuando a una tarea le corresponden las particiones P1 o P2, se elige la de menor tiempo de espera, rotando la tarea si es preciso. Si la tarea tiene unas dimensiones tales que no cabe en ninguna de las particiones establecidas, entonces se envía a una quinta cola Q4 que contiene la información necesaria para realizar una fusión temporal de dos (o incluso de las cuatro) particiones. Fig. 2- Estructura del gestor de HW Este algoritmo es fácil de codificar y las estructuras de datos necesarias para describir el hardware y su estado son también muy simples, factores que hacen que sea muy factible su implementación hardware. 3.3 Ejemplo de funcionamiento del algoritmo Esta sección muestra en detalle el comportamiento de nuestro algoritmo y lo compara con el de First Fit (FF), que ubica cada tarea en el primer hueco disponible en la FPGA (examinándola de izquierda a derecha y de abajo arriba). El algoritmo de FF es tan eficiente como otros más complicados como Best Fit, Worst Fit, etc. [11] para resolver problemas de bin packing on line. La libertad con que FF sitúa las tareas en la FPGA 2D puede conducir a situaciones de fragmentación del espacio disponible de las que hay que ocuparse en algún momento. En cambio, el rendimiento de nuestro algoritmo directo no se ve afectado por estas incidencias aunque sí muestra un uso máximo del área inferior a FF. Debemos resaltar que nuestro objetivo es mostrar cómo nuestro algoritmo de complejidad constante, O(1), es de una eficiencia similar a la de la de FF, que tiene una complejidad de O(n2), donde n es el número de tareas. Para ello hemos elegido una FPGA de 20x20 bloques básicos configurables. La FPGA se divide en cuatro particiones de tamaños 5x5, 5x15, 15x5 y 15x15. Ejecutamos el conjunto de tareas HW que se muestra en la tabla 1. Tarea T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 Ancho 7 3 14 3 6 2 15 4 8 6 12 Alto 14 4 4 12 4 2 9 13 10 4 5 Ciclo llegada 1 3 5 8 10 12 14 17 20 22 25 Tabla 1 Tiempo ejecución (en clks) 12 14 10 14 11 8 10 6 17 10 8 Los tamaños de las tareas se han adaptado a partir de los tamaños de memoria de un conjunto SW típico en un entorno multitarea, normalizado para el tamaño de FPGA elegido. Los tiempos de llegada y de ejecución son aleatorios. En los ocho primeros ciclos de reloj, ambos algoritmos tienen sitio para todas las tareas que han llegado y por tanto su eficiencia es la misma. Fig.3 Situación en clk=8 Fig.4 Situación en clk=20 Cuando llegan T4 y T5, FF las coloca a la derecha de T3 mientras que nuestro algoritmo las escribe en las colas Q1 y Q0 respectivamente. En clk=14 llega T6 y nuestro algoritmo dispone de espacio para ella mientras que FF la envía a la cola hasta clk=22 (T3 termina). En clk=20 llega T8, otra tarea grande y FF no dispone de espacio para ella en la FPGA por lo que la envía a la cola junto a T6. Nuestro algoritmo también envía T8 a una cola, Q3. Fig.5 Situación en clk=22 Fig.6 Situación en clk=32 Para FF, T4 termina en clk=21 y T3 en clk=22, al mismo tiempo que llega T9. Ahora queda suficiente espacio para ejecutar T6 y T8, que estaban esperando en la cola, así como para T9. Durante un ciclo de reloj FF alcanza su pico en uso de área de la FPGA (72,7%) de este ejemplo. Nuestro algoritmo continua enviando tareas de las colas a la FPGA siempre que sea posible. T10, la última tarea del conjunto, llega en clk=25 y FF lo tiene que enviar a la cola hasta clk=32 (T6 termina) y nuestro algoritmo la envía a Q2 hasta clk= 28 (T7 termina). En clk=26, T9 empieza su ejecución con nuestro algoritmo y en clk=28 empieza T10, última tarea del conjunto, en P2, rotada. La última tarea que termina de ejecutarse con nuestro algoritmo es T8 en clk=41. Para FF, T6 termina en clk=32 y entonces empieza T10. Esta es la última tarea que le queda a FF, y termina en clk=40. Hemos obtenido los siguientes resultados a partir de este ejemplo: FF Nosotros CLKS 40 41 AREA_MEDIA 37,9 34,7 OCCUPACIÓN MÁXIMA 72,7 53,8 Tabla 2 Fig. 7- Evolución del uso de área Podemos observar que las colas de nuestro algoritmo junto a las particiones, tienen un efecto equilibrante gracias a que las colas distribuyen las tareas y alimentan a la FPGA conforme las tareas van terminando su ejecución.. Esta regularidad en el comportamiento del algoritmo se pone de manifiesto cuando el conjunto de tareas es heterogéneo. FF alcanza un uso máximo de área bastante por encima de nuestro algoritmo, y sin embargo el área media utilizada y el número total de ciclos de reloj no es muy distinto al obtenido por nosotros. En este ejemplo FF no se encuentra con situaciones complejas de fragmentación, que obligarían a tomar acciones de defragmentación que penalizarían el rendimiento de FF. Es evidente que si el conjunto de tareas considerado es homogéneo en cuanto a tamaños de las tareas y/o si estas no están distribuidas uniformemente en el tiempo se pueden dar situaciones de saturación de algunas colas mientras otras están vacías, lo que hace perder eficiencia nuestro algoritmo frente a FF precisamente porque su efecto equilibrante se anula. 4. Resultados experimentales y conclusiones Hemos realizado pruebas con seis conjuntos de tareas distintos y hemos obtenido los resultados mostrados en la figura 12 acerca del área media utilizada y el número total de ciclos de reloj empleados para ejecutar el conjunto de tareas completo, comparándolo con FF. 160 45 140 40 120 35 área media 25 utilizada (%) 20 número de 100 80 clks totales 60 15 40 10 20 30 0 5 FF OURS FF 0 s1 s2 s3 s4 s5 s6 s1 s2 s3 s4 s5 s6 OURS a) b) Fig. 8- Resultados para diferentes conjuntos de tareas La mayoría de los conjuntos de tareas son heterogéneos y los resultados que hemos obtenido para ellos son similares o ligeramente por debajo de FF. En cambio el conjunto nº 5 es bastante homogéneo, y el rendimiento de nuestro algoritmo es peor en este caso. Esta- mos trabajando para reducir el efecto negativo de la homogeneidad de tareas por medio de una serie de estrategias que mencionamos en el siguiente apartado. 5 Trabajo futuro Actualmente estamos considerando varias mejoras. La primera de ellas consiste en posibilitar la fusión temporal de particiones para poder ubicar tareas mayores que cualquiera de las particiones. Otras posibles mejoras son la modificación del criterio para selección de la cola (y por tanto de la partición) de manera que además del tamaño de la tarea se tenga en cuenta el tiempo de espera; la posible selección de varias tareas pequeñas para que se ejecuten simultáneamente en una partición mayor, como si se tratase de una hiper-tarea; el ajuste dinámico de los tamaños de las particiones, o la utilización de un número más alto de particiones. La mayoría de estas mejoras no aumentan la complejidad del algoritmo. Agradecimientos Este trabajo ha sido financiado por la CICYT a través del proyecto TIC2002-00160 Referencias 1. K. Compton, S. Hauck, “Reconfigurable Computing: A Survey of Systems and Software”, ACM Computing Surveys, Vol. 34, No. 2. pp. 171-210. June 2002. 2. G. Brebner, "A virtual Operating System for the Xilinx XC6200", In Reiner W. Hartenstein and Manfred Glesner, editors, Field-Programmable Logic: Smart Applications, New Paradigms and Compilers, pp 327-336. Springer-Verlag , 1996. 3. O. F. Diessel, G. Wigley, "Opportunities for Operating Systems Research in Reconfigurable Computing", Technical report ACRC-99-018. Advanced Computing Research Centre, School of Computer and Information Science, University of South Australia, 1999. 4. P. Merino, J.C. López, M. Jerome, "A hardware operating system for dynamically reconfiguration of FPGAs", en Field-Programmable Logic and Applications, FPL'98, De. R. Hartenstein y A. Keevalik, pp 431-435, Springer-Verlag, 1998. 5. S. McMillan, S. Guccione, “Partial Run-Time Reconfiguration Using JRTR”. Proceedings of the 10th International Workshop on Field-Programmable Logic and Applications, FPL 2000, pages 352-360. Springer-Verlag, Berlin, August 2000. 6. O. F. Diessel, H. Elgindy, "On Dynamic Task Scheduling for FPGA-based Systems", International Journal of Foundations of Computer Science,IJFCS'01, Vol. 12, No. 5, pp. 645-669, 2001 7. K. Bazargan, R. Kastner, M. Sarrafzadeh, “Fast Template Placement for Reconfigurable Computing Systems”, IEEE Design and Test of Computers, volume 17, pages 68–83, 2000. 8. H. Walder, M. Platzner, “Non-preemptive Multitasking on FPGAs: Task Placement and Footprint Transform”, ERSA’02, June 2002. 9. K. Compton, J. Cooley, S. Knol, S. Hauck, "Configuration Relocation and Defragmentation for Reconfigurable Computing", Trans. on VLSI Systems, Vol. 10, No. 3., pp. 209-220. June 2002. 10. H. Walder, M. Platzner, “Online Scheduling for Block-partitioned Reconfigurable Devices”, DATE’03, 2003. 11. E.Coffman, J. Csirik, G. Woeginger, “Approximate Solutions to Bin-Packing Problems", in Handbook of Applied Optimization, P. Pardalos and M Resende, editors, Oxford University Press, 2002