Modelo de aplicaciones CUDA
Utilización de GPGPUs: las placas gráficas se utilizan en el contexto de una CPU: host (CPU) + uno o varios device o GPUs Procesadores masivamente paralelos equipados con muchas (cientos o miles) de unidades de procesamiento aritmético.
En las GPUs, la mayor parte de la arquitectura está dedicada a cómputo. Lógica de control compleja para la ejecución paralela de código secuencial o incluir memorias cache más rápidas y más grandes para disminuir latencia de instrucciones. La mayor parte de la arquitectura estan dedicada a cómputo y no a técnicas para disminuir la latencia. CPU está compartido por todas las aplicaciones, operacions de E/S, funciones del SO coexistentes en el sistema, etc.
En aplicaciones modernas, es frecuente tener secciones de programas que tienen una gran cantidad de paralelismo de datos, que permitirían realizar diversas operaciones aritméticas simultáneas sobre dichos datos de forma correcta.
En aplicaciones modernas, es frecuente tener secciones de programas que tienen una gran cantidad de paralelismo de datos, que permitirían realizar diversas operaciones aritméticas simultáneas sobre dichos datos de forma correcta. Procesamiento de bases de datos con secuencias de ADN se emplea el mismo cálculo sobre cada una de las secuencias. Procesamiento de imágenes: se realiza el mismo cálculo sobre cada pixel de la imagen. Predicción de fenómenos naturales (clima, huracanes, incendios forestales, etc etc): una predicción precisa se basa en miles o millones de simulaciones.
Problema secuencial A a 0 a 1 a 2 a 3 a N-1 + + + + B b 0 b 1 b 2 b 3 b N-1 = c 0 c 1 c 2 c 3 c N-1 C
Suma de vectores solución I /* Suma de vectores secuencial */ /* Suma de vectores (inplace) */ int vector_ops_suma_sec(float *v1, float *v2, int dim) { for (int i = 0; i < dim; i++) { v1[i] = v1[i] + v2[i]; } } return 1;
Suma de vectores solución I /* Suma de vectores secuencial */ /* Suma de vectores (inplace) */ int vector_ops_suma_sec(float *v1, float *v2, int dim) { for (int i = 0; i < dim; i++) { v1[i] = v1[i] + v2[i]; } } return 1; Complejidad computacional lineal: O(N) donde N es la dimensión de los arreglos.
Suma de vectores solución I Tiene orden de complejidad lineal, al aumentar el número de elementos aumenta linealmente la cantidad de operaciones.
Suma de vectores solución I Tiene orden de complejidad lineal, al aumentar el número de elementos aumenta linealmente la cantidad de operaciones. Para vectores pequeños la solución es correcta.
Suma de vectores solución I Tiene orden de complejidad lineal, al aumentar el número de elementos aumenta linealmente la cantidad de operaciones. Para vectores pequeños la solución es correcta. Para vectores muy grandes este tipo de solución puede ocasionar penalizaciones en el tiempo de cómputo.
Suma de vectores Cómo sería una solución paralela? Se puede paralelizar la suma el cálculo de cada elemento del vector resultante es independiente de los demás elementos del vector: A B = C a 0 a 1 a 2 a 3 a N-1 + + + + + + + b 0 b 1 b 2 b 3 b N-1 c 0 c 1 c 2 c 3 c N-1 Si contamos con N procesadores, realizamos todos los cálculos al mismo tiempo. Y se resuelve en paralelo todos los resultados del vector. De orden lineal a orden constante
Entonces... Tengo una PC re linda... Tengo una GPU que me dicen que es re linda... Tengo dos vectores para sumar... A B Cómo utilizo estas arquitecturas para solucionar mi problema??
CUDA (Compute Unified Device Architecture) En Noviembre de 2006 NVIDIA introduce CUDA que hace referencia tanto a un compilador como a un conjunto de herramientas de desarrollo creadas por NVIDIA. CUDA es una arquitectura de software y hardware que permite a GPUs ejecutar programas escritos en C, C++, Fortran, DirectCompute y otros lenguajes.
CUDA (Compute Unified Device Architecture) Un programa CUDA es un programa híbrido: Código secuencial se ejecuta en CPU Código paralelo se ejecuta en GPU
CUDA (Compute Unified Device Architecture) Un programa CUDA es un programa híbrido: Código secuencial se ejecuta en CPU Código paralelo se ejecuta en GPU Código secuencial Inicializaciones Lectura de datos de entrada. Código paralelo Modelo SIMD - STMD Código secuencial Muestra de resultados Almacenamiento de resultados.
CUDA Cómo es la parte paralela de la aplicación? Un programa CUDA invoca a funciones paralelas llamadas kernels. En CUDA: Kernel = función. Un kernel se ejecuta en paralelo a través threads paralelos.
CUDA Cómo es la parte paralela de la aplicación? Un programa CUDA invoca a funciones paralelas llamadas kernels. En CUDA: Kernel = función. Un kernel se ejecuta en paralelo a través threads paralelos. El programador decide: el kernel A será ejecutado por n threads A B = C + + + + + + + Con n threads que cada uno sume un elemento del vector resultante, consigo ejecutar la suma de vectores en un único paso!!
CUDA Un programa CUDA invoca a kernels paralelos. Un kernel se ejecuta en paralelo a través threads paralelos. A B = C + + + + + + + Múltiples threads ejecutando el mismo kernel.
CUDA Tenemos programas CUDA híbridos, que se ejecutan en CPU y GPU. Tenemos dos arquitecturas que se conectan mediante un conector PCI-Express (no comparten espacio de direccionamiento)
Suma de vectores Cómo lo hacemos con CUDA? Este problema ahora implica: Inicialización de arreglos en CPU Transferencia de datos CPU GPU
Suma de vectores Cómo lo hacemos con CUDA? Este problema ahora implica: Inicialización de arreglos en CPU Transferencia de datos CPU GPU Cálculo de la suma en paralelo.
Suma de vectores Cómo lo hacemos con CUDA? Este problema ahora implica: Inicialización de arreglos en CPU Transferencia de datos CPU GPU Cálculo de la suma en paralelo. Transferencia de datos GPU CPU.
Suma de vectores Cómo lo hacemos con CUDA? Este problema ahora implica: Inicialización de arreglos en CPU Transferencia de datos CPU GPU Cálculo en GPU. Transferencia de datos GPU CPU. Modelo de programación CUDA
Modelo de programación CUDA CUDA extiende al lenguaje C/C++ incluyendo dos características principales: - Organización y manejo de threads concurrentes. - Manejo de jerarquía de memorias instaladas en la GPU.
CUDA extiende al lenguaje C/C++ incluyendo dos características principales: - Organización y manejo de threads concurrentes. thread Jerarquía de threads: thread,
CUDA extiende al lenguaje C/C++ incluyendo dos características principales: - organización y manejo de threads concurrentes. thread Jerarquía de threads: thread, bloque, bloque 1, 2 o 3 dimensiones
CUDA extiende al lenguaje C/C++ incluyendo dos características principales: - organización y manejo de threads concurrentes. thread Jerarquía de threads: bloque 1, 2 o 3 dimensiones thread, bloque Grid 1 grilla. grilla Block (0,0) Block (1,0) Block (2,0) Grid 2 grilla Block (0,0) Block (1,0) Block (0,1) Block (1,1) 1, 2 o 3 dimensiones
CUDA extiende al lenguaje C/C++ incluyendo dos características principales: - Manejo de jerarquía de memorias instaladas en la GPU Memoria local de thread Memorias: Privada de cada thread.
CUDA extiende al lenguaje C/C++ incluyendo dos características principales: - Manejo de jerarquía de memorias instaladas en la GPU Memoria local de thread Memoria compartida de bloque Memorias: Privada de cada thread. Compartida por bloque.
CUDA extiende al lenguaje C/C++ incluyendo dos características principales: - Manejo de jerarquía de memorias instaladas en la GPU Memoria local de thread Memoria compartida de bloque Grid 1 Block (0,0) Block (1,0) Block (2,0) Memorias: Privada de cada thread. Compartida por bloque. Grid 2 Memoria global Global de toda la aplicación Block (0,0) Block (0,1) Block (1,0) Block (1,1)
- Manejo de jerarquía de memorias instaladas en la GPU CUDA ofrece distintas memorias con distintas características: Registros Memoria compartida Memoria global Memoria constante. Algunas de ellas están en caché.
Memoria Global: es la más grande y la más lenta. Puede ser leída y escrita por la CPU y por los threads de GPU. Permite comunicar datos entre CPU y GPU. El patrón de acceso a memoria por los threads puede afectar el rendimiento. Memoria Constante: es parte de la memoria global. CPU puede leer y escribir, y es sólo de lectura para GPU threads. Ofrece mayor ancho de banda cuando grupos de threads acceden al mismo dato. Memoria compartida: es pequeña y muy rápida y es compartida por todos los threads de un bloque. Es de lectura/escritura por los threads. Puede comunicar datos entre threads del mismo bloque. Puede verse afectada por el patrón de acceso de los threads. Registros: cada thread utiliza su propio conjunto de registros. El programador no tiene control explícito de los registros, y son utilizados para la ejecución de programas de la misma forma que los registros de propósito general de CPU. Memoria local: es usada por el compilador automáticamente para alojar variables cuando hace falta. Memoria de textura: es controlada por el programador y puede beneficiar aplicaciones con localidad espacial donde el acceso a memoria global es un cuello de botella.
Modelo de programación CUDA No todos los problemas pueden ser resueltos usando placas de tipo GPU. Los más adecuados son los que aplican la misma secuencia de código a los datos de entrada.
Modelo de programación CUDA Ganaremos con GPU si: El algoritmo tiene orden de ejecución cuadrático o superior: compensar el tiempo de transferencia de datos CPU GPU. Gran carga de cálculo en cada thread (por lo mismo que el item anterior). Poca dependencia de datos. Independencia de cómputo. Puede llevar a acceso a su memoria local o compartida y evita acceder a la global (costosa). Mínima transferencia de datos CPU-GPU: óptimo: principio y final. Evitar tranferencias intermedias, ya sean para resultados parciales o datos de entrada intermedios. No existan secciones críticas: lecturas paralelas a datos, pero no escrituras: necesitamos mecanismos de acceso seguro secuencialización de accesos.