Procesadores gráficos y supercomputación Manuel Ujaldón Martínez Departamento de Arquitectura de Computadores Universidad de Málaga Indice de contenidos 1. El nacimiento de GPGPU y su evolución [11]. 2. CUDA [22]. 3. La GPU en supercomputación [10]. I. El nacimiento de GPGPU y su evolución 3 2003. El punto de partida Se popularizan los shaders y su programación en Cg. Comienzan a verse los primeros códigos acelerados en la GPU… … pero la implementación es compleja y requiere un gran conocimiento del cauce de renderización gráfico: Tiempo de desarrollo elevado Perfil de usuario especializado. 4 2006. Emerge CUDA El rendimiento y la polivalencia del hardware gráfico son ya plenamente aceptados en la comunidad científica, pero a la GPU aún le quedan dos asignaturas pendientes: Precisión de los resultados: Ausencia de “floats” (FP32) Facilidad de programación. Excesivo tiempo de desarrollo Ambos aspectos se resuelven con la llegada de CUDA en la serie 8 de Nvidia (Noviembre de 2006). CUDA: Compute Unified Device Architecture. CUDA: Cómo Utilizar un Dispositivo Avanzado con eficiencia, versatilidad, precisión y sencillez. 5 2009. Prestaciones: Aplicaciones que vuelan sobre GPU 146X 36X 18X 50X Imágenes biomédicas Dinámica molecular Transcoding de vídeo Computación Matlab Univ. Utah Univ. Illinois, Urbana Elemental Tech AccelerEyes 100X Astrofísica RIKEN 149X 47X 20X 130X 30X Simulación financiera Oxford Algebra lineal Univ. Jaume I Ultrasonidos 3D Techniscan Química cuántica Univ. Illinois, Urbana Secuenciación genética Univ. Maryland 6 2009. Coste: Sistemas de múltiples GPUs construidos con hardware doméstico 16 GPUs MIT, Harvard 8 GPUs University of Antwerp Belgium 4 GPUs 3 GPUs TU Braunschweig, Germany University of Illinois 3 GPUs 3 GPUs 3 GPUs 2 GPUs Yonsei Univ., Korea Rice University Cambridge, UK Georgia Tech 7 A partir de aquí, la evolución es meteórica Octubre 2008 Febrero 2010 Junio 2011 > 100.000.000 > 120.000.000 > 150.000.000 # programadores CUDA en activo > 25.000 > 100.000 > 200.000 # herramientas SW descargadas de NV > 40.000 > 300.000 > 700.000 # descargas del compilador CUDA >18.000 > 100.000 > 200.000 # GPUs que admiten CUDA 8 Evolución a escala mundial Jun’11: 420 (13 españolas) Feb’10: 300 universidades (8 españolas) enseñan CUDA. enseñan CUDA en 50 países. Junio de 2010: 420 univs. enseñan CUDA (en 50 países). 9 Síntesis evolutiva de la GPU como procesador de propósito general 2001. Primeros chips many-core (en los sombreadores para vértices y píxeles), mostrando el camino evolutivo. 2003. Sombreadores programables. Polivalencia. 2006. Sombreadores unificados. Generalización. 2007. CUDA. Un paso hacia la convergencia entre los modelos de programación de la CPU y la GPU. 2008. Opers. punto flotante en doble precisión. Exactitud. 2010. ECC y normalización de operandos. Fiabilidad. Asignaturas pendientes: Robustez de la arquitectura a escala masiva (clusters). Conexión entre la memoria de vídeo y el disco (E/S). 10 Síntesis evolutiva por generaciones Marco temporal Principal baluarte del diseño Qué se persigue Objetivo último Primera generación Segunda generación Tercera generación 1990 - 1999 2000 - 2009 2010 - ? Segmentación y arquitectura Multi-cores homogéneos Multi-cores heterogéneos Frecuencia más elevada Velocidad en la emisión de instrucciones Identificar el hardware idóneo para cada tarea. Más rendimiento. Más rendimiento. Menos temperatura. Más rendimiento. Menos consumo. Especialización. La potencia de cálculo y el ancho de banda con memoria son las dos grandes ventajas Potencia de cálculo Ancho de banda con memoria Peak Performance Gflops/sec 1200 1000 120 Tesla T10 NVIDIA GPU 100 x86 CPU NVIDIA GPU x86 CPU 80 800 Tesla G80 600 40 Nehalem 3 GHz Harpertown 3 GHz 200 Tesla T10 Tesla G80 60 400 Harpertown 3 GHz 20 Nehalem 3 GHz 0 0 2003 Peak Memory Bandwidth GB/sec 2004 2005 2006 2007 2008 2009 2003 2004 2005 2006 2007 2008 2009 12 Dónde estamos ahora en rendimiento: Producto de matrices en doble precisión 13 Convergencia de CUDA hacia computación heterogénea: Ocelot 14 II. CUDA 15 ¿Qué es CUDA? “Compute Unified Device Arquitecture” CUDA es una plataforma diseñada conjuntamente a nivel hardware y software para aprovechar la potencia de la GPU en aplicaciones de propósito general. Define: Un modelo de arquitectura: Con multitud de unidades de proceso (cores) y una sola unidad de control (SIMD). Un modelo de programación: Paralela: Basado en el paralelismo masivo de datos y de grano fino. Es código C con extensiones para instanciarlo de forma automática a cientos de hilos. Escalable: El código se ejecuta sobre cualquier número de cores sin recompilar. Un modelo de gestión de la memoria: Más explícita al programador. Objetivos: Construir código escalable a cientos de cores de forma sencilla, permitiendo declarar miles de hilos. Permitir computación heterogénea entre CPU y GPU. 16 El modelo hardware de CUDA: Un conjunto de procesadores SIMD La GPU consta de: N multiprocesadores, cada uno dotado de M cores. Paralelismo masivo: GPU Multiprocesador N Multiprocesador 2 Multiprocesador 1 Core 1 Aplicado sobre miles de hilos. Compartiendo datos a diferentes niveles. Computación heterogénea, complementa CPU y GPU: GPU: Intensiva en datos. Paralelismo de grano fino. CPU: Gestión y control. Paralelismo de grano grueso. Core 2 … G80 Período de vigencia N (multiprocs.) M (cores) Número total de cores Core M Unidad de Control GT200 GF100 2006-07 2008-09 2010-11 16 30 16 8 8 32 128 240 512 17 La primera generación: G80 (GeForce 8800) GPU G80 (en torno a 600 MHz, frecuencia muy inferior a la de sus cores) Multiprocesador 16 Multiprocesador 2 Multiprocesador 1 (los bloques de código CUDA se mapean sobre los multipr.) Memoria compartida (16 KB) Registros Core 1 (1.35 GHz) Registros Core 2 … Caché de texturas Registros Core 8 Unidad de control (emite instrucciones SIMD) (los kernels se mapean sobre los cores) Memoria global (hasta 1.5 GB) (GDDR3 @ 2x 800MHz) 18 La segunda generación: GT200 (GTX 200) GPU GTX 200 (en torno a 600 MHz) Multiprocesador 30 Multiprocesador 2 Multiprocesador 1 (los bloques de código CUDA se mapean sobre los multipr.) Memoria compartida (16 KB) Registros Core 1 (1.30 GHz) Registros Core 2 … Caché de texturas Registros Core 8 Unidad de control (emite instrucciones SIMD) (los kernels se mapean sobre los cores) Memoria global (hasta 4 GB) (GDDR3, 512 bits @ 2x 1.1GHz = 141.7 GB/s) 19 Escalabilidad para futuras generaciones: Alternativas para su crecimiento futuro GPU Aumentar el número de Multiprocesador 30 multiprocesadores por pares (escalabilidad en 2ª gener.) (nodo básico), esto es, crecer Multiprocesador 2 en la dimensión Z. Es lo que Multiprocesador 1 hizo la 2ª gener. (de 16 a 30). Memoria compartida Aumentar el número de Registros Registros Registros procesadores de cada Core 2 … Core 8 Core 1 multiprocesador, o crecer en la (escalabilidad en 3ª gener.) dimensión X. Es lo que hizo la Caché de texturas 3ª gener. (de 8 a 32). Aumentar el tamaño de la memoria compartida, esto es, Memoria global crecer en la dimensión Y. 20 La tercera generación: GF100 (Fermi) 21 Arquitectura del sistema de memoria Cada multiprocesador tiene: Su banco de registros. Memoria compartida. Una caché de constantes y otra de texturas, ambas de sólo lectura y uso marginal. La memoria global es la memoria de vídeo (DRAM): Tres veces más rápida que la de la CPU, pero... ... ¡500 veces más lenta que la memoria compartida! (que es SRAM en realidad). GPU Multiprocesador N Multiprocesador 2 Multiprocesador 1 Memoria compartida Registros Registros Procesador 1 Procesador 2 Registros … Procesador M Unidad de Control Caché para constantes Caché para texturas Memoria global 13 22 La nueva jerarquía de memoria en Fermi La primera GPU que ofrece una caché L1 típica on-chip, que combina con la shared memory de CUDA para un total de 64 KB por cada multiprocesador (32 cores). También incluye una caché unificada de 768 KB con coherencia de datos para el conjunto de cores. 13 23 El modelo de programación CUDA La GPU (device) ofrece a la CPU (host) la visión de un coprocesador altamente ramificado en hilos. Que tiene su propia memoria DRAM. Donde los hilos se ejecutan en paralelo sobre los núcleos (cores o stream processors) de un multiprocesador. GPU Multiprocesador 1 Multiprocesador 2 Multiprocesador N Los hilos de CUDA son extremadamente ligeros. Se crean en un tiempo muy efímero. La conmutación de contexto es inmediata. Objetivo del programador: Declarar miles de hilos, que la GPU necesita para lograr rendimiento y escalabilidad. 24 Estructura de un programa CUDA Cada multiprocesador procesa lotes de bloques, uno detrás de otro Bloques activos = los bloques procesados por un multiprocesador en un lote. Hilos activos = todos los que provienen de los bloques que se encuentren activos. Los registros y la memoria compartida de un multiprocesador se reparten entre sus hilos activos. Para un kernel dado, el número de bloques activos depende de: El número de registros requeridos por el kernel. La memoria compartida consumida por el kernel. 25 Conceptos básicos Los programadores se enfrentan al reto de exponer el paralelismo para múltiples cores y para múltiples hilos por core. Para ello, deben usar los siguientes elementos: Device = GPU = conjunto de multiprocesadores. Multiprocesador = conjunto de procesadores y memoria compartida. Kernel = programa ejecutándose en GPU. Grid = matriz de bloques de hilos que ejecutan un kernel. Bloque de hilos (thread block) = grupo de hilos SIMD que ejecutan un kernel delimitando su dominio computacional según su threadID y blockID, y que pueden comunicarse a través de la memoria compartida del multiprocesador. 26 Recursos y limitaciones según la GPU que utilicemos para programar CUDA Parámetro CUDA Compute Capabilities Valor según gener. GPU 1.0 y 1.1 1.2 y 1.3 Fermi Limitación Impacto Multiprocesadores / GPU 16 30 14 HW. Escalabilidad Cores / Multiprocesador 8 8 32 HW. Escalabilidad 32 32 32 SW. Throughput 8 8 8 SW. Throughput Hilos / Bloque 512 512 1024 SW. Paralelismo Hilos / Multiprocesador 768 1 024 1 536 SW. Paralelismo Hilos / Warp Bloques de hilos / Multiprocesador Registros de 32 bits / Multiprocesador 8K 16K 32K HW. Working set Memoria compartida / Multiprocesador 16K 16K 16K 48K HW. Working set 27 Recopilando sobre kernels, bloques y paralelismo Los kernels se lanzan en grids. Sólo se ejecuta un kernel a la vez. Un bloque se ejecuta en un multiprocesador. Grid Bloque (0, 0) Bloque (1, 0) El bloque no migra. Varios bloques pueden residir concurrentemente en un multiprocesador. Con las consabidas limitaciones: 8 bloques concurrentes. 512 hilos en cada multiprocesador. 768/1024/1536 hilos en total. Memoria compartida Memoria compartida Regs Regs Regs Regs Hilo (0, 0) Hilo (1, 0) Hilo (0, 0) Hilo (1, 0) Y otras limitaciones entran en juego debido al uso conjunto de la memoria: El banco de registros se particiona entre todos los hilos existentes. La memoria compartida se particiona entre todos los bloques de hilos. Memoria global 28 Hilos, bloques, kernels: Su relación con los tipos de memoria Registros Hilo Bloque ··· Integrada en la GPU Memoria compartida Los hilos pueden compartir el espacio de memoria compartida para comunicarse entre ellos. Grid 0 Grid 1 ··· ··· ··· ··· ··· ··· ··· ··· ··· ··· ··· ··· ··· ··· ··· Memoria Memoria para global constantes (lectura y (lectura) escritura) Memoria para texturas (lectura) Externa a la GPU (pero dentro de la tarjeta gráfica) El nivel de memoria global es el único visible a todos los entes definidos por el programador (hilos, bloques, kernels y grids). 29 La interacción entre la CPU y la GPU CUDA extiende el lenguaje C con un nuevo tipo de función, kernel, que ejecutan en paralelo los hilos activos en GPU. El resto del código es C nativo que se ejecuta sobre la CPU de forma convencional. De esta manera, el típico main() de C combina la ejecución secuencial en CPU y paralela en GPU de kernels CUDA. Un kernel se lanza siempre de forma asíncrona, esto es, el control regresa de forma inmediata a la CPU. Cada kernel GPU tiene una barrera implícita a su conclusión, esto es, no finaliza hasta que no lo hagan todos sus hilos. Aprovecharemos al máximo el biprocesador CPU-GPU si les vamos intercalando código con similar carga computacional. 30 Ejecución La interacción entre la CPU y la GPU (cont.) __global__ kernelA(){···} __global__ kernelB(){···} int main() ··· kernelA <<< dimGridA, dimBlockA >>> (params.); ··· kernelB <<< dimGridB, dimBlockB >>> (params.); ··· CPU GPU CPU GPU CPU Un kernel no comienza su ejecución en GPU hasta que no hayan finalizado todas las llamadas CUDA anteriores. 31 Modificadores para las funciones y lanzamiento de ejecuciones en GPU Modificadores para las funciones ejecutadas en la GPU: __global__ void MyKernel() { } // Invocado por la CPU __device__ float MyFunc() { } // Invocado por la GPU Modificadores para las variables que residen en la GPU: __shared__ float MySharedArray[32]; // En mem. caché __constant__ float MyConstantArray[32]; Configuración de la ejecución para lanzar kernels: dim2 gridDim(100,50); // 5000 bloques de hilos dim3 blockDim(4,8,8); // 256 bloques de hilos MyKernel <<< gridDim,blockDim >>> (pars.); // Lanzam. 32 Variables y funciones intrínsecas dim3 gridDim; dim3 blockDim; // Dimensión del grid // Dimensión del bloque uint3 blockIdx; // Indice del bloque dentro de la malla uint3 threadIdx; // Indice del hilo dentro del bloque void __syncthreads(); // Sincronización entre threads El programador debe elegir el tamaño del bloque y el número de bloques para explotar al máximo el paralelismo del código durante su ejecución. 33 Para gestionar la memoria de vídeo Para reservar y liberar memoria en la GPU: cudaMalloc(void* p, size_t numBytes) y cudaFree(p) Para mover áreas de memoria entre CPU y GPU, tras declarar malloc(h_A) en la CPU y cudaMalloc(d_A) en la GPU: Desde la CPU a la GPU: cudaMemcpy(d_A, h_A, numBytes, cudaMemcpyHostToDevice); Desde la GPU a la CPU: cudaMemcpy(h_A, d_A, numBytes, cudaMemcpyDeviceToHost); 34 Un ejemplo preliminar: CUDA es C con algunas palabras clave más void saxpy_serial(int n, float a, float *x, float *y) { for (int i = 0; i < n; ++i) y[i] = a*x[i] + y[i]; Código C estándar } // Invocar al kernel SAXPY secuencial saxpy_serial(n, 2.0, x, y); Código CUDA equivalente de ejecución paralela en GPU: __global__ void saxpy_parallel(int n, float a, float *x, float *y) { int i = blockIdx.x*blockDim.x + threadIdx.x; if (i < n) y[i] = a*x[i] + y[i]; } // Invocar al kernel SAXPY paralelo con 256 hilos/bloque int nblocks = (n + 255) / 256; saxpy_parallel<<<nblocks, 256>>>(n, 2.0, x, y); 35 El proceso de compilación void funcion_en_CPU(… ) { ... } void otras_funcs_CPU(int ...) { ... } void saxpy_serial(float ... ) { for (int i = 0; i < n; ++i) y[i] = a*x[i] + y[i]; } void main( ) { float x; saxpy_serial(..); ... } Kernels CUDA Resto del código C NVCC (Open64) Compilador de la CPU Identificar los kernels Ficheros objeto CUDA y rees- Ficheros objeto de la CPU CUDA Enlazador cribirlos para aprovechar paralelismo en GPU Ejecutable CPU-GPU 36 Los diferentes módulos de compilación El código fuente CUDA se compila con NVCC. NVCC separa el código que se ejecuta en CPU del que lo hace en GPU. La compilación se realiza en dos etapas: Virtual: Genera código PTX (Parallel Thread eXecution). Física: Genera el binario para una GPU específica (o incluso para una CPU multicore - ver un poco más adelante). C/C++ CUDA Application Código fuente NVCC Código CPU Virtual PTX Code Físico PTX to Target Compiler G80 … GPU Código objeto 37 III. Supercomputación con GPUs 38 3 de los 5 supercomputadores más potentes del planeta aparecen en el TOP500 (Jun’11) 39 Hechos más relevantes del último TOP500 (Jun’11) relacionados con GPUs 19 supercomputadores incluyen aceleradores gráficos (dos más que hace seis meses - Nov’11). De ellos: 12 se basan en la arquitectura Tesla de Nvidia. 5 se basan en la arquitectura Cell de IBM. 2 se basan en la arquitectura Radeon de AMD. Sin embargo, ninguno de los 3 nuevos en el TOP10: #1: K Computer de Fujitsu en Kobe (Japón), con más de 500.000 cores SPARC64 de Sun. #6: Cielo, un Cray XE6 en Los Alamos Natl. Lab. (EEUU). #7: Pleiades, un SGI Altix en NASA Ames Research Center (EEUU). 40 Nuevo perfil de usuario en Nvidia GeForce® Jugones: Ocio y entretenimiento Quadro® Gráficos profesionales: Diseño y creación Tesla Computación de altas prestaciones Todos ellos basados en una misma microarquitectura 41 ¿Qué es una arquitectura TESLA? Una GPU de gama alta orientada a propósito general. La arquitectura de la GPU se comparte con la gama GeForce, aunque su memoria de vídeo es muy superior (clara analogía con los procesadores Xeon de Intel). Tiene definidas una serie de configuraciones cerradas: Tarjeta gráfica sobre PCI-express. Servidor que aglutina 4 tarjetas, ocupando 1U de un rack. Supercomputador gráfico con múltiples servidores interconectados. Cada servidor consume 800 W. y emite hasta 70 dB. Necesita un host (CPU) que le suministre los kernels de computación y el sistema de ficheros (interfaz a disco). 42 Conexión del servidor TESLA al armario (rack) de supercomputación (2) 43 Prestaciones a diferentes niveles 44 Existe una plataforma hardware para cada perfil de usuario... Cientos de investigadores Miles de investigadores Millones de investigadores Cluster a gran escala Más de un millón de dólares Cluster preconfigurado de servidores Tesla Entre 50.000 y 1.000.000 de dólares Tarjeta gráficaTesla Menos de 5000 dólares 45 La relación rendimiento/coste es muy favorable ... Rendimiento 10000x Cluster de nodos Tesla para coprocesamiento 100 veces más económico 100x Supercomputador personal Tesla 100 veces más potente Cluster tradicional de CPUs 100 veces más potente Estación de trabajo CPU 1x < 10000 € Coste 100000 - 1M € 46 ... y el consumo es más eficiente 20 15 10 18X mejor ratio en rendimiento/vatio respecto a la CPU 5 0 x86 Server Tesla S1070 47 Consumo dentro del TOP500 (Nov’10) 48 ¡Muchas gracias! Siempre a vuestra disposición en: Dpto. Arquitectura de Computadores. ETSI Informática. Campus de Teatinos. Universidad de Málaga. 29071 Málaga. e-mail: [email protected] http://manuel.ujaldon.es 49