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
armv7yaarch64contienen versiones para procesadores de 32 y 64 bits. Enaarch64, los fihcerosMMult_4x4_*.cppaplican vectorización mediante NEON y bloques de 4×4 para aumentar el rendimiento. - CUDA: bajo el directorio
cudase ubican núcleos GPU comoMMult_cuda_12.cu, que combinan tiling 128×128×8 con memoria compartida para explotar el paralelismo masivo de NVIDIA. - Vulkan: en
vulkan, implementaciones comoMMult_vk_3.cppusan el framework Kompute para lanzar shaders de cómputo escritos en SPIR-V.
Cmoponentes clave del repositorio
- Referencia:
REF_MMult.cpp/.cproporciona 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_MMultcontienen las distintas variantes aceleradas para cada arquitectura. - Banco de pruebas:
test_MMult.cpp/.ccompara las distintas implementaciones, mide Gflops y verifica la exactitud de los resultados. - Configuración:
parameters.hcentraliza 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 queAesM×K,BesK×NyCesM×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
- Clonar el repositorio.
- Editar
parameters.hsegú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_gemmsiguiendo la interfaz común. - Nuevas estrategias de bloque: modificar las constantes
BLOCKySTRIDEen los ficheros CUDA, o probar distintos tamaños de tile en NEON. - Nuevos tipos de datos: partir de
cuda-bf16para añadir soporte de BF16, INT8 u otras precisiones mixtas.