Guía técnica de how-to-optimize-gemm: arquitectura, API y uso

how-to-optimize-gemm es un repositorio centrado en la aceleración de la multiplicación de matrices en formato row-major. Ofrece implementaciones optimizadas para distintas arquitecturas y precisions numéricas, sirviendo como base para estudiar y aplicar técnicas de optimización de GEMM (General Matrix Multiplication).

La organización del código refleja su soporte multiplataforma:

  • ARM: los directorios armv7 y aarch64 contienen versiones para procesadores de 32 y 64 bits. En aarch64, los fihceros MMult_4x4_*.cpp aplican vectorización mediante NEON y bloques de 4×4 para aumentar el rendimiento.
  • CUDA: bajo el directorio cuda se ubican núcleos GPU como MMult_cuda_12.cu, que combinan tiling 128×128×8 con memoria compartida para explotar el paralelismo masivo de NVIDIA.
  • Vulkan: en vulkan, implementaciones como MMult_vk_3.cpp usan el framework Kompute para lanzar shaders de cómputo escritos en SPIR-V.

Cmoponentes clave del repositorio

  • Referencia: REF_MMult.cpp/.c proporciona una implementación basada en CBLAS que actúa como línea base de corrección y rendimiento.
  • Optimizaciones: los ficheros cuya función principal es MY_MMult contienen las distintas variantes aceleradas para cada arquitectura.
  • Banco de pruebas: test_MMult.cpp/.c compara las distintas implementaciones, mide Gflops y verifica la exactitud de los resultados.
  • Configuración: parameters.h centraliza las dimensiones de las matrices, los tamaños de bloque y otros parámetros de la evaluación.

API principal de multiplicación de matrices

La función central se puede representar con el siguiente prototipo, donde se han renombrado los argumentos para mayor claridad:

void optimizar_gemm(int M, int N, int K,
                    const float* A, int lda,
                    const float* B, int ldb,
                    float*       C, int ldc);

Los parámetros indican:

  • M, N, K: dimensiones de las matrices, de forma que A es M×K, B es K×N y C es M×N.
  • A, B, C: punteros a los datos en memoria, almacenados por filas.
  • lda, ldb, ldc: leading dimensions, es decir, el ancho de fila con el que se reservó cada matriz en memoria.

Estrategias de optimización por arquitectura

AArch64 con NEON

En aarch64/MMult_4x4_16.cpp se procesan bloques de 4×4 empleando registros vectoriales NEON, reduciendo las operaciones de carga y aprovechando el ancho de banda de la cache.

CUDA

El núcleo de cuda/MMult_cuda_12.cu utiliza tiling bidimensional de 128×128 y memoria compartida de 128×8 para minimizar accesos globales y mantener ocupación alta en la GPU.

Vulkan

La versión de Vulkan separa la inicialización del pipeline, la carga del shader SPIR-V y el dispatch de trabajo en colas de cómputo, lo que permite ejecutar GEMM en una amplia gama de GPUs sin depender exclusivamente de CUDA.

Evaluación de rendimiento

El banco de pruebas genera ficheros con sintaxis de Matlab, como output_MMult_4x4_16.m, que facilitan la representación gráfica de Gflops frente al tamaño de la matriz. De este modo se pueden comparar directamente las optimizaciones propias con CBLAS o cuBLAS.

Puesta en marcha rápida

  1. Clonar el repositorio.
  2. Editar parameters.h según el rango de matrices a evaluar:
#define FILAS_MIN   128
#define FILAS_MAX   2048
#define FILAS_PASO  128

Luego, compilar y ejecutar el test para la arquitectura deseada:

cd aarch64
make
./test_gemm

Extensiones y personalización

  • Nuevas arqiutecturas: crear un directorio propio e implementar la función optimizar_gemm siguiendo la interfaz común.
  • Nuevas estrategias de bloque: modificar las constantes BLOCK y STRIDE en los ficheros CUDA, o probar distintos tamaños de tile en NEON.
  • Nuevos tipos de datos: partir de cuda-bf16 para añadir soporte de BF16, INT8 u otras precisiones mixtas.

Etiquetas: GEMM BLAS NEON CUDA Vulkan

Publicado el 10-19 01:56