Durante el proceso de compilación, es posible aplicar diversas directivas u opciones (flags) para reestructurar el código binario resultante. Estas optimizaciones permiten incrementar la velocidad de ejecución, reducir el uso de memoria o explotar instrucciones específicas del hardware de destino. Se clasifican fundamentalmente en dos bloques: optimizaciones generales (independientes de la plataforma) y optimizaciones específicas de la arquitectura.
Optimizaciones Generales
Estas opciones modifican la lógica interna del código (unrolling de bucles, eliminación de código muerto, enlineado de funciones) sin restringir el ejecutable a un modelo de procesador concreto. La práctica totalidad de los compiladores disponibles (gcc, clang, intel, aocc) implementan los siguientes niveles estándar:
-
-O0(Sin optimización): Nivel por defecto. Minimiza el tiempo de compilación y mantiene una correspondencia directa entre el código fuente y el binario. Se debería utilizar solamente durante las fases de preparación y depuración, ya que el rendimiento resultante no es eficiente. -
-O1(Optimización moderada): Aplica optimizaciones básicas que incrementan el rendimiento de la CPU sin penalizar significativamente el tiempo de compilación ni el tamaño del archivo binario. -
-O2(Optimización recomendada): Activa la gran mayoría de optimizaciones globales que no implican un compromiso entre espacio y velocidad. Es el modo más usado, ya que maximiza el rendimiento manteniendo una estricta estabilidad y fidelidad en los cálculos numéricos. -
-O3(Optimización agresiva / Vectorización): Habilita transformaciones avanzadas, incluyendo la vectorización automática de bucles independientes. Altamente recomendado para códigos numéricos y simulaciones físicas con arrays pesados. Nota: Excepcionalmente, puede aumentar de forma notable el tamaño del binario o inducir sutiles variaciones en la precisión por reordenamiento de operaciones. Se aconseja verificar la validez científica de los resultados. -
-Ofast(Optimización extrema no estándar): Incorpora todas las optimizaciones de-O3junto con opciones que relajan la conformidad estricta de los estándares de coma flotante (equivalente a activar-ffast-math).⚠️ Advertencia: El uso de
-Ofastpuede comprometer la precisión matemática (p.e., ignorando valoresNaNoInf, o alterando el redondeo IEEE-754). No se recomienda su uso en simulaciones que requieran de gran exactitud de los resultados.
Optimizaciones específicas de la arquitectura
Cada generación de procesadores introduce mejoras microarquitectónicas y extensiones de su repertorio de instrucciones (ISA). Las extensiones vectoriales (SSE, AVX, AVX2, AVX-512) implementan el paradigma SIMD (Single Instruction Multiple Data), el cual permite ejecutar una misma operación aritmética de manera simultánea sobre múltiples operandos integrados en registros de gran tamaño (de 128, 256 o 512 bits).
Para que el compilador genere estas instrucciones específicas, es necesario indicárselo explícitamente a través de parámetros de arquitectura. No obstante, tenga en cuenta que un binario compilado para una arquitectura avanzada fallará inmediatamente con un error de tipo Illegal Instruction si se ejecuta en un nodo más antiguo que carezca de dicho soporte.
Directivas principales de arquitectura:
-
-march=native: Detecta automáticamente la microarquitectura de la CPU del nodo donde se está compilando y aplica todas sus extensiones vectoriales nativas. Importante: Solo debe utilizarse si la compilación y la ejecución posterior se realizan en la misma familia de nodos del clúster (p.e., compilando mediante una tarea interactiva en el nodo de destino). -
-march=[nombre_arquitectura]: Fuerza la compilación para una generación específica (ej.-march=haswell,-march=znver4), garantizando que el binario aproveche las instrucciones de dicha familia con independencia del nodo donde se compile.
Familias de procesadores en PROTEUS y soporte vectorial
A fin de seleccionar los flags de arquitectura idóneos, a continuación se detallan las familias de procesadores que integran los nodos de cómputo de PROTEUS, clasificadas por su soporte de instrucciones vectoriales SIMD:
| Apodo (Nodo) | Microarquitectura | Fabricante | Extensiones Vectoriales | Tamaño Registro | Flag Recomendado (-march=) |
| Kratos | Westmere | Intel | SSE4.2 | 128 bits | westmere |
| Hermes v1 / v2 | Haswell / Broadwell | Intel | SSE, AVX, AVX2, FMA3 | 256 bits | haswell / broadwell |
| Metis v1 / v2 | Skylake / Cascade Lake | Intel | SSE, AVX, AVX2, AVX-512 | 512 bits | skylake-avx512 / cascadelake |
| Nix / Orion / Perseo / Quimera | Genoa / Bergamo (Zen 4) | AMD | SSE, AVX, AVX2, AVX-512 | 512 bits | znver4 (Requiere GCC 13+ o LLVM 16+) |
| Rodas | Turin (Zen 5) | AMD | SSE, AVX, AVX2, AVX-512 | 512 bits | znver5 (Requiere GCC 14.1+ o LLVM 19+) |
Recomendación para la sumisión de trabajos (Slurm)
Si compila su código utilizando optimizaciones específicas de última generación (como AVX-512 mediante los parámetros znver4, znver5 o cascadelake), asegúrese de utilizar las restricciones de Slurm (--constraints o seleccionando la partición adecuada) para dirigir su tarea a nodos compatibles. Compilar con directivas para Rodas o Nix e intentar ejecutar la simulación en nodos Hermes o Kratos provocará el aborto inmediato del programa. Puede consultar las características (Features) de cada nodo que se pueden usar como restricciones con scontrol show node nombredelnodo.