La creciente complejidad de las arquitecturas de hardware en HPC y AI/ML, caracterizadas por jerarquías de memoria intrincadas, heterogeneidad de procesadores (CPUs, GPUs, aceleradores) y la necesidad de gestionar concurrencia y sincronización a gran escala, presenta un desafío fundamental en la optimización del rendimiento. Los sistemas distribuidos modernos requieren un modelo de programación y ejecución que pueda abstraer y gestionar eficientemente las dependencias de datos y la orquestación de tareas a través de múltiples nodos y dispositivos.
CARTS aborda este problema introduciendo un enfoque de compilación centrado en tareas y datos, inspirado en el modelo Codelet. Al transformar el código fuente en una representación intermedia que expone explícitamente Event-Driven Tasks (EDTs), DataBlocks, Events y Epochs, CARTS permite optimizaciones a nivel de compilador que son conscientes de la distribución y las dependencias. Esto contrasta con los enfoques tradicionales que a menudo delegan gran parte de la gestión de la concurrencia y la localidad de datos al runtime, con menos información estática disponible para la optimización.
La relevancia de este enfoque radica en la capacidad de pre-planificar y optimizar la ejecución de tareas y el movimiento de datos en tiempo de compilación, reduciendo la sobrecarga de runtime y mejorando la eficiencia en entornos donde la latencia de comunicación y el acceso a memoria son críticos. La utilización de MLIR como infraestructura de compilación proporciona la flexibilidad necesaria para definir dialectos específicos de dominio que capturan estas abstracciones de HPC, mientras que LLVM asegura la generación de código de máquina de alto rendimiento.
Arquitectura del Sistema
La arquitectura de CARTS se construye sobre la infraestructura de compilación de MLIR y LLVM, adoptando un pipeline de múltiples etapas. El proceso comienza con la ingesta de código fuente C/OpenMP, que es traducido a MLIR utilizando la infraestructura Polygeist. Esta etapa inicial convierte construcciones de alto nivel, incluyendo OpenMP Tasks, en dialectos MLIR como OpenMP, SCF (Structured Control Flow), Affine y Arith.
Posteriormente, el componente central de CARTS introduce el 'ARTS Dialect'. Este dialecto personalizado es responsable de transformar las tareas de OpenMP de alto nivel en las abstracciones fundamentales de ARTS: Event-Driven Tasks (EDTs), DataBlocks, Events y Epochs. Los EDTs son las unidades atómicas de trabajo, los DataBlocks representan regiones de memoria con datos, los Events son señales de sincronización para la disponibilidad de DataBlocks o la finalización de tareas, y los Epochs definen límites de sincronización para grupos de tareas. Esta representación explícita facilita un análisis más profundo y optimizaciones específicas para sistemas distribuidos.
El pipeline continúa con una serie de 'Optimization and Transformation Passes'. Estas pasadas operan sobre el ARTS Dialect para realizar optimizaciones como la eliminación de tareas redundantes, la reestructuración de tareas (ej. convertir una tarea paralela con una subtarea en una tarea síncrona), y la gestión de DataBlocks mediante el análisis de patrones de acceso a memoria. También se realizan optimizaciones clásicas como dead code elimination y common subexpression elimination. Finalmente, el MLIR enriquecido con ARTS se convierte a LLVM IR, donde las regiones EDT se delinean en funciones y se insertan llamadas a la API de ARTS para la gestión de tareas, DataBlocks, epochs y events. El binario resultante se ejecuta sobre el runtime de ARTS, que se encarga de la planificación dinámica de tareas basada en la disponibilidad de datos.
Pipeline de Compilación CARTS
- 1 C/OpenMP Source Código fuente de la aplicación HPC.
- 2 Clang/Polygeist Traducción de C/OpenMP a MLIR con múltiples dialectos.
- 3 ARTS Dialect Conversión de tareas OpenMP a EDTs, DataBlocks, Events, Epochs.
- 4 Optimization Passes Optimización de EDTs, gestión de DataBlocks, eliminación de código muerto.
- 5 Lowering to LLVM IR Conversión a LLVM IR, delineación de EDTs, inserción de llamadas a API de ARTS.
- 6 ARTS Runtime Ejecución dinámica de tareas basada en la disponibilidad de datos.
| Capa | Tecnología | Justificación |
|---|---|---|
| data-processing | MLIR | Infraestructura de compilación para representar y transformar código en múltiples dialectos, permitiendo optimizaciones específicas de dominio para HPC. |
| data-processing | LLVM | Backend de compilación para la generación de código de máquina de alto rendimiento a partir de la representación intermedia optimizada por CARTS. |
| data-processing | Polygeist | Frontend para la traducción de código C/OpenMP a MLIR, sirviendo como punto de entrada al pipeline de compilación de CARTS. |
| orchestration | ARTS Runtime | Sistema de ejecución en tiempo real que programa dinámicamente las Event-Driven Tasks (EDTs) basándose en la disponibilidad de datos y eventos. |
Fundamentos Teóricos
El modelo subyacente a ARTS, y por extensión a CARTS, está profundamente arraigado en el concepto de 'Codelet Model'. Este modelo, desarrollado por el grupo de investigación CAPSL de la Universidad de Delaware, propone la descomposición de la computación en pequeñas tareas independientes (codelets) que se ejecutan tan pronto como sus dependencias de datos se satisfacen. Esta filosofía de ejecución event-driven y data-driven tiene paralelismos con los grafos de tareas dirigidos acíclicos (DAGs) y los modelos de programación basados en futures o promises, que han sido objeto de estudio en la investigación de sistemas distribuidos y paralelismo desde hace décadas.
La gestión de dependencias de datos y la sincronización sin bloqueos pesados a través de eventos se alinea con principios de concurrencia no-bloqueante y modelos de actor, que buscan maximizar el paralelismo y minimizar la contención. Aunque el artículo no cita directamente papers fundacionales, el enfoque de descomposición de tareas y gestión explícita de dependencias de datos se puede rastrear a trabajos pioneros en programación paralela y sistemas operativos distribuidos que abordaron la granularidad de las tareas y la coordinación entre procesos, como los modelos de dataflow computing de los años 70 y 80.