x
1

CUDA



CUDA son las siglas de Compute Unified Device Architecture (Arquitectura Unificada de Dispositivos de Cómputo) que hace referencia a una plataforma de computación en paralelo incluyendo un compilador y un conjunto de herramientas de desarrollo creadas por Nvidia que permiten a los programadores usar una variación del lenguaje de programación C (CUDA C) para codificar algoritmos en GPU de Nvidia.

Por medio de wrappers se puede usar Python, Fortran, Julia y Java en vez de C/C++.

Funciona en todas las GPU Nvidia de la serie G8X en adelante, incluyendo GeForce, Quadro, ION y la línea Tesla.[1]Nvidia afirma que los programas desarrollados para la serie GeForce 8 también funcionarán sin modificaciones en todas las futuras tarjetas Nvidia, gracias a la compatibilidad binaria provista por el conjunto de instrucciones PTX (Parallel Thread Execution).[2]

CUDA intenta explotar las ventajas de las GPU frente a las CPU de propósito general utilizando el paralelismo que ofrecen sus múltiples núcleos, que permiten el lanzamiento de un altísimo número de hilos simultáneos. Por ello, si una aplicación está diseñada utilizando numerosos hilos que realizan tareas independientes (que es lo que hacen las GPU al procesar gráficos, su tarea natural), una GPU podrá ofrecer un gran rendimiento en campos que podrían ir desde la biología computacional a la criptografía, por ejemplo.

El primer SDK se publicó en febrero de 2007 en un principio para Windows, Linux, y más adelante en su versión 2.0 para macOS. Actualmente se ofrece para Windows XP/Vista/7/8/10,[3]​ para Linux 32/64 bits[4]​ y para macOS.[5]

CUDA presenta ciertas ventajas sobre otros tipos de computación sobre GPU utilizando APIs gráficas.

CUDA intenta aprovechar el gran paralelismo, y el alto ancho de banda de la memoria en las GPU en aplicaciones con un gran coste aritmético frente a realizar numerosos accesos a memoria principal, lo que podría actuar de cuello de botella.

El modelo de programación de CUDA está diseñado para que se creen aplicaciones que de forma transparente escalen su paralelismo para poder incrementar el número de núcleos computacionales. Este diseño contiene tres puntos claves, que son la jerarquía de grupos de hilos, las memorias compartidas y las barreras de sincronización.

La estructura que se utiliza en este modelo está definido por un grid, dentro del cual hay bloques de hilos que están formados por como máximo 1024 hilos distintos.

Cada hilo en un bloque está identificado con un identificador único, que se accede con la variable threadIdx. Esta variable es muy útil para repartir el trabajo entre distintos hilos. threadIdx tiene 3 componentes (x, y, z), coincidiendo con las dimensiones de bloques de hilos. Así, cada elemento de una matriz, por ejemplo, lo podría tratar su homólogo en un bloque de hilos de dos dimensiones.

Al igual que los hilos, los bloques se identifican mediante blockIdx (en sus componentes x, y, z). Algunas otras funciones útiles son blockDim, para acceder al tamaño de bloque y gridDim, para acceder a la forma de la grid.

Un kernel en “C for CUDA”, es una función la cual al ejecutarse lo hará en N distintos hilos en lugar de en secuencial. Se define incluyendo __global__ en la declaración. Por ejemplo:

Si nuestra función f queremos que calcule la diferencia entre dos vectores A y B y lo almacene en un tercero C:

Esta función se ejecutaría una vez en cada hilo, reduciendo el tiempo total de ejecución en gran medida, y dividiendo su complejidad, O(n), por una constante directamente relacionada con el número de procesadores disponibles.

El mismo ejemplo con matrices sería:

En una llamada a un kernel, se le ha de pasar el tamaño de grid y de bloque, por ejemplo, en el main del ejemplo anterior podríamos añadir:

En el momento que se invoque esta función, los bloques de un grid se enumerarán y distribuirán por los distintos multiprocesadores libres.

Como los distintos hilos colaboran entre ellos y pueden compartir datos, se requieren unas directivas de sincronización. En un kernel, se puede explicitar una barrera incluyendo una llamada a __syncthreads(), en la que todos los hilos se esperarán a que los demás lleguen a ese mismo punto.

Los hilos en CUDA pueden acceder a distintas memorias, unas compartidas y otras no.

Además, existen otros dos espacios de memoria más, que son de solo lectura y accesibles por todos los hilos. Son la memoria constante y la de texturas. Todas las memorias de acceso global persisten mientras esté el kernel en ejecución.

Un multiprocesador contiene ocho procesadores escalares, dos unidades especiales para funciones trascendentales, una unidad multihilo de instrucciones y una memoria compartida. El multiprocesador crea y maneja los hilos sin ningún tipo de overhead por la planificación, lo cual unido a una rápida sincronización por barreras y una creación de hilos muy ligera, consigue que se pueda utilizar CUDA en problemas de muy baja granularidad, incluso asignando un hilo a un elemento por ejemplo de una imagen (un píxel).

Lista completa, con la versión soportada de CUDA: https://developer.nvidia.com/cuda-gpus



Escribe un comentario o lo que quieras sobre CUDA (directo, no tienes que registrarte)


Comentarios
(de más nuevos a más antiguos)


Aún no hay comentarios, ¡deja el primero!