@misc{10902/37109, year = {2025}, month = {6}, url = {https://hdl.handle.net/10902/37109}, abstract = {En este trabajo se aborda el diseño y la implementación de kernels de convolución Gaussiana que combinan CUDA Cores y Tensor Cores en GPUs modernas, con especial atención a los desafíos de organización de datos y gestión de memoria. Desarrollamos una transformación manual del vecindario de cada píxel en una matriz intermedia, garantizando que los 32 threads de cada warp lean posiciones contiguas en memoria global. Se declarará un espacio fijo de memoria shared para que distintos fragmentos (entrada, filtro y acumulador) compartan el mismo bloque de shared sin interferencias. La obligación de declarar un tamaño fijo de memoria compartida llevó a diseñar un esquema en el que, aunque el buffer se reserva una sola vez por bloque, cada warp calcula su propio offset de lectura y escritura, salvaguardando espacio para otros warps que cubran la latencia. Además, reescribimos comprobaciones de límites y bucles de carga con operaciones aritméticas y máscaras, lo que unificó el flujo de ejecución dentro de cada warp y limitó al mínimo las sincronizaciones necesarias. En paralelo, investigamos distintas estrategias de paralelismo: kernels dedicados por completo a CUDA Cores, otros al 100 % a Tensor Cores y versiones híbridas que alternan dinámicamente entre ambos. Esta variedad de aproximaciones permitió identificar los cuellos de botella reales (tanto en cómputo como en memoria) y probar técnicas para optimizar la coalescencia en caches L1/L2. El resultado es un conjunto de prácticas para maximizar el rendimiento en operaciones matriciales de gran tamaño, que serán evaluadas en detalle en las secciones siguientes.}, abstract = {In this work, we explore the design and implementation of Gaussian convolution kernels that combine CUDA Cores and Tensor Cores on modern GPUs, paying particular attention to data-layout challenges and memory management. We manually transformed each pixel’s neighborhood into an intermediate matrix, ensuring that all 32 threads of a warp read contiguous global-memory addresses. We create a fixed space in shared memory to coexist different segments (input, filter and accumulator) in the same shared block without interference. Because shared memory requires a fixed size declaration, we devised a scheme in which the buffer is reserved just once per block, while each warp computes its own read/write offset. Furthermore, to eliminate costly branch divergences, we replaced boundary checks and load loops with purely arithmetic operations and bitmasking, unifying the execution path within each warp and minimizing necessary synchronizations. Simultaneously, we evaluated several parallelization strategies: kernels fully dedicated to CUDA Cores, others exclusively using Tensor Cores, and hybrid versions that dynamically switch between the two. This range of approaches let us identify the real bottlenecks—both compute- and memory-bound—and experiment with techniques to improve coalescing in L1/L2 caches. The end result is a collection of practices for squeezing out maximum performance in large-scale matrix operations, which we will examine in detail in the sections that follow.}, title = {Paralelización eficiente en GPUs mediante Tensor Cores y CUDA Cores}, author = {Saura Sánchez, Pablo}, }