Introducción a GPGPU y CUDA Doctorado en Tecnologías de la Información y las Telecomunicaciones

Documentos relacionados
Primeros pasos con CUDA. Clase 1

INTRODUCCIÓN A LA PROGRAMACIÓN EN CUDA. Francisco Javier Hernández López

SUMA de Vectores: Hands-on

CUDA Overview and Programming model

GPU-Ejemplo CUDA. Carlos García Sánchez

Arquitecturas GPU v. 2015

CÓMPUTO DE ALTO RENDIMIENTO EN MEMORIA COMPARTIDA Y PROCESADORES GRÁFICOS

PROGRAMACIÓN AVANZADA DE GPUs PARA APLICACIONES CIENTÍFICAS

Computación de Propósito General en Unidades de Procesamiento Gráfico GPGPU

Arquitecturas GPU v. 2013

GPGPU Avanzado. Sistemas Complejos en Máquinas Paralelas. Esteban E. Mocskos 5/6/2012

Computación en procesadores gráficos

Modelo de aplicaciones CUDA

48 ContactoS 84, (2012)

UNIVERSIDAD DE BURGOS Área de Tecnología Electrónica INTRODUCCIÓN A LA PROGRAMACIÓN EN CUDA

Inside Kepler. I. Presentación de la arquitectura. Índice de contenidos [25 diapositivas] Kepler, Johannes ( )

Librería Thrust. Clase 4.

DESARROLLO DE APLICACIONES EN CUDA

Introducción a OpenGL Shading Language (GLSL)

Computación en procesadores gráficos

Segunda Parte: TECNOLOGÍA CUDA

Francisco Javier Hernández López

Seminario II: Introducción a la Computación GPU

Paralelización de algoritmos para el procesado de imágenes de teledetección

INTRODUCCIÓN A LA COMPUTACIÓN PARALELA CON GPUS

NVIDIA CUDA RESEARCH CENTER

Computación de Propósito General en Unidades de Procesamiento Gráfico GPGPU

Computación Heterogénea con OpenCL. Flores, Facundo UNSA Fac. Cs. Exactas

Kepler. 1. Presentación de la arquitectura. Índice de contenidos [25 diapositivas] Kepler, Johannes ( )

Memorias, opciones del compilador y otras yerbas. Clase 3

cuevogenet Paralelización en CUDA de la Dinámica Evolutiva de Redes Génicas Dirigido por: Fernando Díaz del Río José Luis Guisado Lizar

Arquitecturas y programación de procesadores gráficos. Nicolás Guil Mata Dpto. de Arquitectura de Computadores Universidad de Málaga

Computación de Propósito General en Unidades de Procesamiento Gráfico GPGPU. Clase 5 Programación Avanzada y Optimización

Arquitectura de aceleradores. Carlos Bederián IFEG CONICET GPGPU Computing Group FaMAF UNC

PAP - Programación y Arquitecturas Paralelas

Sistemas Complejos en Máquinas Paralelas

Programación de altas prestaciones utilizando GPUs

Bloque IV. Prácticas de programación en CUDA. David Miraut Marcos García Ricardo Suárez

Procesamiento Paralelo

Introducción a la programación de códigos paralelos con CUDA y su ejecución en un GPU multi-hilos

Analista Universitario en Sistemas. Taller de Programación II. Instituto Politécnico Superior MEMORIA DINAMICA

Computación de Propósito General en Unidades de Procesamiento Gráfico GPGPU

Sistemas Operativos. Procesos

Computación de Propósito General en Unidades de Procesamiento Gráfico GPGPU. Clase 1 Introducción

FLAG/C. Una API para computación matricial sobre GPUs. M. Jesús Zafont Alberto Martín Francisco Igual Enrique S. Quintana-Ortí

Tile64 Many-Core. vs. Intel Xeon Multi-Core

CDI Arquitecturas que soportan la concurrencia. granularidad

FUNDAMENTOS DE COMPUTACIÓN PARA CIENTÍFICOS. CNCA Abril 2013

Utilización de la programación paralela en procesadores gráficos para el cálculo científico.

Funciones y paso de parámetros

MAGMA. Matrix Algebra on GPU and Multicore Architecture. Ginés David Guerrero Hernández

GPU - Procesadores de vértices

Lenguaje C. República Bolivariana de Venezuela Fundación Misión Sucre Aldea Fray Pedro de Agreda Introducción a la Programación III

FUNDAMENTOS DE COMPUTACION INVESTIGACION PROCESADORES DIANA CARRIÓN DEL VALLE DOCENTE: JOHANNA NAVARRO ESPINOSA TRIMESTRE II

Programación de GPUs con CUDA

1 Primitivas básicas de OpenMP

Tema 6: Memoria dinámica

SISTEMAS PARALELOS Y DISTRIBUIDOS. 3º GIC. PRÁCTICA 9 Departamento de Arquitectura y Tecnología de Computadores Universidad de Sevilla

Múltiples GPU (y otras chauchas)

Programando la GPU con CUDA RIO 2014 Río Cuarto (Argentina), 17 y 18 de Febrero, Agradecimientos. Prerrequisitos para este tutorial

HPC y GPUs. GPGPU y software libre. Emilio J. Padrón González DE UNIVERSIDADE DA CORUNA GAC.UDC.ES

J. Nicolás Bustos Pieper. Microprocesadores en. Microprocesadores para Comunicaciones Curso 2009/2010 5º E.T.S.I.T. - ULPGC

Programación en Intel Xeon Phi

Tema 12: El sistema operativo y los procesos

Descubriendo Kepler. 1. Presentación de la arquitectura. Agradecimientos. Indice de contenidos [46 diapositivas]

TEMA 1: EJECUCIÓN PARALELA: FUNDAMENTOS(I)

TEMA 2. LENGUAJE C. CONCEPTOS BÁSICOS Y PROGRAMACIÓN ELEMENTAL.

Examen Teórico (1/3 de la nota final)

Taller: Introducción a GPU's y Programación CUDA para HPC

Programación. Test Autoevaluación Tema 3

CLUSTER FING: ARQUITECTURA Y APLICACIONES

PARTE II PROGRAMACION CON THREADS EN C

CAPACIDAD COMPUTACIONAL: Tabla 1: Resumen de algunas características de GPUs CUDA.

Programando con memoria unificada. Contenidos [15 diapositivas] Aportaciones de la memoria unificada. I. Descripción

Programación I Teoría II.

MPP. MIMD Computador Masivamente Paralelo

Elementos de un programa en C

GENERACIÓN DE IMÁGENES VOLUMÉTRICAS DE DATOS BIOMÉDICOS EN TIEMPO REAL

Programando la GPU con CUDA

ENTRADA-SALIDA. 2. Dispositivos de Carácter: Envía o recibe un flujo de caracteres No es direccionable, no tiene operación de búsqueda

Programación Híbrida e Introducción a la Programación de GPUs

Universidad Complutense de Madrid FACULTAD DE INFORMÁTICA

Ejemplos de optimización para Kepler. 1. Balanceo dinámico de la carga. Contenidos de la charla [18 diapositivas]

Ejercicios de jerarquía de memoria

Cómputo paralelo con openmp y C

USO DE TECNOLOGÍAS GPU PARA EL DESARROLLO DE ALGORITMOS CRIPTOGRÁFICOS

TIPOS DE DATOS BASICOS EN LENGUAJE C

Arquitectura de Computadores Problemas (hoja 4). Curso

Memoria Dinámica. Jornadas de Marzo 2010 Grupo de Usuarios de Linux Tania Pérez

Memoria Dinámica en C++

Introducción a la Programación en C Funciones

Técnicas de paralelización de código para robots basados en emociones

ESTRUCTURA DE DATOS. Memoria estática Memoria dinámica Tipo puntero Declaración de punteros Gestión de memoria dinámica Resumen ejemplo

Velocidades Típicas de transferencia en Dispositivos I/O

Tema 05: Elementos de un programa en C

Kepler. Contenidos de la charla. Kepler, Johannes ( ) 1. Presentación de la arquitectura

Nociones básicas de computación paralela

Es un lenguaje estructurado, tiene una abundante cantidad de operadores y tipos de datos.

Punteros. Índice. 1. Qué es un puntero y por que son importantes.

Introducción a C++ Índice

Transcripción:

Introducción a GPGPU y CUDA Doctorado en Tecnologías de la Información y las Telecomunicaciones ETSI Telecomunicación Universidad de Valladolid Mario Martínez-Zarzuela Febrero de 2015 Introducción CONTENIDO Diferencias entre CPU y GPU Desarrollo de aplicaciones para GPU Ejemplo: suma de vectores Ejercicios: suma de vectores, suma de matrices Conclusiones 1

INTRODUCCIÓN CPU vs GPU by Mythbusters Cazadores de mitos en el NVISION08 Adam & Jaime contratados por NVIDIA 2

GPGPU & CUDA GPU - Graphics Processing Unit Unidad de Procesamiento Gráfico Procesador gráfico Coprocesador de la CPU tareas gráficas GPGPU - General-Purpose computing on GPU GPU de Propósito General 2004 Inicios de GPGPU Primeros desarrolladores Compleja programación gráfica API OpenGL Shaders Cg Brook (Universidad de Standford), Lib Sh GPGPU & CUDA Pipeline gráfica programable Vértices X,Y,Z,W Rasterizador Interpolación Fragmentos R,G,B,A Pre-cuda Shaders Operaciones vectores de 4 componentes 3

GPGPU & CUDA 2007 NVIDIA CUDA Toolkit Supercomputación para las masas CUDA - Compute Unified Device Architecture Plataforma de cálculo en paralelo y modelo de programación Inicialmente extensiones de lenguaje C Compilador nvcc Librería en tiempo de ejecución La primera GPU habilitada por NVIDIA fue la GeForce G80 (2006) Cada vez más herramientas y lenguajes Entornos de desarrollo integrados Visual Studio Nsight y Eclipse Nsight Edition Herramientas de depurado y profiling Librerías y plugins 3 rd party GPGPU y hardware Tegra GeForce/Quadro Tesla Tegra (GPU + ARM) (GPU + ARM) 4

DIFERENCIAS ENTRE CPU Y GPU Rendimiento computacional y ancho de banda GPU vs. СPU 5

Características CPU Intel Core i7 Varios núcleos independientes de alto rendimiento 2,4,6,8 núcleos 2,66 3,6GHz cada uno Hyper-Threading : cada núcleo es visto por el SO como dos núcleos lógicos, que pueden ejecutar dos hilos de forma simultánea. 3 niveles de caché, gran caché L3 Cada núcleo: L1=32KB (datos) + 32KB (instrucciones), L2=256KB L3 compartida, hasta 15 MB Peticiones a memoria gestionadas de forma independiente por cada hilo/proceso Core I7-3960x, 6 núcleos, 15MB L3 Características GPU GeForce 780 Ti (Kepler GK110) 15 Multiprocesadores SMX 2880 núcleos en total < 1 GHz 2 niveles de caché Cada núcleo: L1=64KB (datos) L2 compartida=1492 KB Las peticiones a memoria son realizadas por grupos de hilos Ancho de banda 384- bit GDDR5 3072 MB 6

GK1xx GPU Kepler Streaming Multiprocessor (SMX) Formados por: 192 núcleos CUDA @ ~ 1 GHz cada uno Disposición en grupos de 48 64 unidades FP 32 unidades de Funciones Especiales 32 unidades de Carga/Almacenamiento dedicadas al acceso a memoria Las peticiones a memoria son realizadas por grupos de hilos 65536 registros x 32 bit (256KB) 64KB memoria compartida/ L1 caché Configurable por el usuario 48KB caché de solo lectura 48KB caché 2D para texturas Evolución de arquitecturas 7

Características GPU GeForce 980 (Maxwell GK204) 16 Multiprocesadores SMM 2048 núcleos en total Mayor cache L2 2048 KB frente a: 1492KB (GK110) 512KB (GK104) Reducción interfaz con memoria 256-bit Ancho de banda: 224 GB/sec GM204 GPU Maxwell Multiprocessor (SMM) Septiembre 2014 Novedades: 2da generación chip Maxwell, tras GM107 Menos núcleos por SM 128 núcleos CUDA @ ~ 1 GHz cada uno +40% eficiencia para cada CUDA core Planificador mejorado Nuevo damino de datos Mayor eficiencia energética 2x perf/watt vs GK104 Diseño en cuadrantes de 32 núcleos 1 warp scheduler por cuadrante 2 instrucciones por ciclo reloj Mayor memoria compartida / L1 cache 96 KB frente a 64KB (GK110) / 48KB (GK104) Máximo 48KB por thread block Hasta 32 block threads activos por SM ( frente a 16 en Kepler. 8

Maxwell Desmitificando la conspiración de la llegada del hombre a la luna Montaje? Buzz Aldrin en zona de sombra porque el Sol está detrás del módulo lunar Iluminación de estudio en L.A.? Parece que está iluminado por múltiples fuentes de luz! No se ven estrellas y los astronautas no recuerdan haberlas visto Se omitieron debido a la dificultad de crearlas? Maxwell Desmitificando la conspiración de la llegada del hombre a la luna Maxwell: renderizado luz tiempo real por primera vez Unreal Engine Voxelized Global Illumination (VGI) 9

X1 NVIDIA drive Enero de 2015 (CES Las Vegas) Potencia superior a la del mayor supercomputador de hace 15 años GPU Maxwell de 256 núcleos 8 núcleos de CPU ARM Procesamiento de 12 cámaras 60 fps NVIDIA DRIVE PX: Autonomous drive Deep Neural Network Computer Vision GPU vs. CPU Cientos de núcleos de cálculo simplificados Bajas frecuencias ~1 GHz (en lugar de 2-12 en CPU) Cachés pequeñas (valores Kepler) 192 núcleos comparten la caché L1 (16-48 KB) L2 compartida entre todos los núcleos, 1.5 MB, no L3 Cambios de contexto rápidos en GPU Sin sobrecarga por cambiar entre hilos (en hardware) Soporte para millones de hilos virtuales 10

Latencia en los accesos a Memoria Objetivo: cargar todos los núcleos Problema: latencia en los accesos a memoria Solución: CPU: compleja jerarquía de cachés GPU: miles de hilos listos para ser ejecutados Ocultar la latencia realizando cálculos LENGUAJES Y LIBRERÍAS DESARROLLO DE APLICACIONES 11

DRAM I/F Giga Thread HOST I/F DRAM I/F 03/02/2015 Ecosistema de Desarrollo GPGPU Librerías Aplicaciones Directivas OpenACC Lenguajes de Programación (CUDA) Aceleración Drop-in Aceleración rápida de aplicaciones existentes Máximo Rendimiento Directivas OpenACC void saxpy(int n, float a, float *x, float *restrict y){ #pragma acc parallel loop for (int i = 0; i < n; ++i) y[i] = a*x[i] + y[i]; } L2 DRAM I/F DRAM I/F DRAM I/F DRAM I/F... // Perform SAXPY on 1M elements saxpy(1<<20, 2.0, x, y);... 12

Librería Thrust #include <thrust/device_vector.h> #include <thrust/transform.h> #include <thrust/functional.h> #include <iostream> int main(void) { thrust::device_vector<float> X(3); thrust::device_vector<float> Y(3); thrust::device_vector<float> Z(3); X[0] = 10; X[1] = 20; X[2] = 30; Y[0] = 15; Y[1] = 35; Y[2] = 10; thrust::transform(x.begin(), X.end(), Y.begin(), Z.begin(),\ thrust::plus<float>()); } for (size_t i = 0; i < Z.size(); i++) std::cout << "Z[" << i << "] =" << Z[i] << "\n"; return 0; Cálculos utilizando la GPU GPU (device) es controlado por la CPU (host) Co-procesador GPU es «pasiva», i.e. no puede llamarse a si misma Excepción Paralelismo dinámico (CUDA 5.X) Cálculos en paralelo en el device Invocados normalmente por el host Desde cualquier parte del programa Oportunidad para una optimización incremental del código Memorias GPU y CPU separadas Excepción Tarjetas integradas Opción de Unified Virtual Address 13

Cálculos utilizando la GPU Cálculos utilizando la GPU Un programa que utiliza GPU está formado por: Código para la GPU (código del device), que contiene: Instrucciones de cálculo en paralelo un CUDA Kernel Accesos a la memoria de la GPU Código para la CPU (código del host), maneja: Gestión de memoria GPU reserva/liberación Intercambio de datos entre GPU y CPU Invocar ejecución de CUDA Kernel en GPU Interpretación de resultados y otras etapas de procesamiento en serie 14

CUDA: Código del device CUDA usa C++ con algunas extensiones: Atributos para funciones, variables y estructuras Funciones integradas (built-in) Funciones matemáticas propias de la GPU Funciones de sincronización, operaciones colectivas entre hilos Vectores de datos de varias dimensiones Variables integradas threadidx, blockidx, blockdim, griddim Plantillas (templates) para trabajar con texturas Compilado con un compilador especial: nvcc Basado en el compilador de código abierto LLVM Puede ampliar los lenguajes de programación para que soporten dispositivos compatibles con CUDA CUDA: Código del host Existe una sintaxis especial para lanzar los kernels de CUDA desde el código del host En su forma más simple se invocan: kernel_routine<<<griddim, blockdim>>>(args, ); Código de CPU se compila con un compilador normal gcc, icc, llvm Excepto invocación del kernel <<<... >>> Funciones enlazadas mediante librerías dinámicas 15

CUDA Kernel Función especial, punto de entrada para el código ejecutado en GPU No devuelve nada (void) Se declara con el calificador global Solo puede accede a la memoria GPU Excepción: memoria host mapeada Sin variables estáticas Declaración de parámetros y mismo uso que para funciones normales global void kernel (int * ptr) { ptr = ptr + 1; ptr[0] = 100;.; //other code for GPU } Host lanza «kernels», device los ejecuta CUDA grid, bloques e hilos Invocación de kernel crea una jerarquía de hilos de procesamiento Bloque: agrupación de hilos. Hilos y bloques representan diferentes niveles de paralelismo Grid: conjunto de bloques de hilos invocados Warp: hilos planificados en grupos de 32 hilos Grid Múltiples bloques del mismo tamaño Habitualmente definido por nuestro dominio de cálculo 16

CUDA grid, bloques e hilos Hilos dentro de un bloque, y bloque dentro de un grid, indexados de forma especial Posición de un hilo en un bloque, y un bloque en el grid, indexada en tres dimensiones (x,y,z) Tamaño de grid/bloque especificado por el número de bloques/hilos en cada dimensión Si el grid y el bloque tienen dimension z=1, estamos ante un grid de hilos bidimensional o lineal (si además y=1) CUDA grid, bloques e hilos typedef struct{ } dim3; Tipo predefinido en CUDA con 3 miembros x, y, z. Usada para variables built-in : dim3 threadidx índice del hilo en cada bloque dim3 blockidx índice del bloque en el grid dim3 blockdim tamaño de bloque en cada dimensión dim3 griddim tamaño de grid en cada dimensión Cálculo del índice absoluto de un hilo de ejecución a partir de índices relativos. Para un grid de hilos lineal: unsigned int tidx = threadidx.x + blockdim.x*blockidx.x; 17

CUDA Escalabilidad Automática Diferentes GPUs con el mismo chip tienen diferente número de SMs GeForce GTX 980 2048 cores 16xSM GM204 Maxwell X1 256 cores 2xSM GM204 EJEMPLO SUMA DE VECTORES 18

Suma de vectores en una dimensión Hilos Vector A ld ld ld ld ld ld ld ld ld ld Vector B ld ld ld ld ld ld ld ld ld ld Vector C st st st st st st st st st st Código en el device global void sum_kernel(int *A, int *B, int *C) { int tidx = threadidx.x + blockidx.x * blockdim.x; //calcular índice int elema = A[tidx]; //leer elemento de A int elemb = B[tidx]; //leer elemento de B C[tidx] = elema + elemb; //calcular y escribir elemento en C } Cada hilo de CUDA: Recibe una copia de los parámetros En este ejemplo recibe punteros a vectores en GPU Determina su posición en el grid con el índice tidx Lee los elementos de dos vectores de entrada usando el índice tidx Calcula la suma y escribe los resultados en un vector de salida con el mismo índice tidx 19

Código en el host 1. 2. 3. 4. Especificar el tamaño del grid y de cada bloque 5. Lanzar el kernel 6. Código en el host 4. Especificar el tamaño del grid y de cada bloque Depende el tamaño del problema 5. Lanzar el kernel Supondremos vectores de longitud 1024 elementos Tamaño de bloque: 256 (múltiplo de tamaño de warp) Tamaño de grid = 1024 / 256 = 4 bloques //d_a, d_b y d_c son punteros a vectores en el device dim3 blockdim(256,1,1); //Bloques típicos de 128, 256, 512 dim3 griddim(4,1,1); sum_kernel<<<griddim,blockdim>>>(d_a,d_b,d_c); 20

Código en el host 1. 2. Reservar memoria en la GPU 3. Copiar datos de entrada a la GPU 4. Especificar el tamaño del grid y de cada bloque 5. Lanzar el kernel 6. Copiar los datos de salida de vuelta al host Reserva de memoria en el device cudaerror_t cudamalloc (void** devptr, size_t size) Reserva size bytes de memoria lineal en la GPU, y devuelve un puntero a la memoria ubicada en *devptr. Los elementos de memoria no son puestos a cero. Las direcciones de memoria están alineadas a 512 bytes cudaerror_t cudafree (void* devptr) Libera la memoria apuntada por devptr En donde cudaerror_t es una enumeración para control de errores 21

Transferencia de datos cudaerror_t cudamemcpy ( void* dst, const void* src, size_t count, cudamemcpykind kind) Copia count bytes de la memoria apuntada por src a la memoria apuntada por dst kind especifica la dirección de la transferencia cudamemcpyhosttohost transferencia de datos entre host cudamemcpyhosttodevice transferencia de datos de host a device cudamemcpydevicetohost transferencia de datos de device a host cudamemcpydevicetodevice transferencia de datos entre devices Una llamada a cudamemcpy() con kind inconsistente con punteros dst y src, puede provocar resultados impredecibles GPU no sabe si los punteros pertenecen a la CPU o la GPU (excepción: UVA) Comprobación de Errores En donde cudaerror_t es una enumeración para control de errores En caso de error el código de error recogido por el sistema no está necesariamente asociado a la última llamada de biblioteca de CUDA Funciones útiles para conocer el último error ocurrido cudaerror_t cudapeekatlasterror() devuelve el último error ocurrido en cualquiera de las llamadas cudaerror_t cudagetlasterror() devuelve el último error ocurrido y resetea el estado de error a cudasuccess const char* cudageterrorstring (cudaerror_t error) devuelve la cadena del mensaje del código de error La lista de posibles errores puede consultarse en la documentación de CUDA 22

Control de errores La mayoría de funciones de biblioteca devuelven en caso de error una variable de tipo enumeración enum cudaerror_t cudaerror_t err = cudasuccess; err = /* Llamada a función de CUDA */ if (err!= cudasuccess){ fprintf(stderr, Error (error code %s)!\n", cudageterrorstring(err)); exit(exit_failure); } Control de errores Una macro muy útil para gestión de errores es la siguiente Traduce el código de error devuelto a un mensaje de texto #define CUDA_CALL(x) do{ \ cudaerror_t err = (x); \ if (err!= cudasuccess) { \ printf ("Error \"%s\"\n", \ cudageterrorstring(err)); \ exit(-1); \ }} while (0) 23

Código en el host #include <stdio.h> #include <cuda_runtime.h> #define CUDA_CALL(x) do{ \ // }} while (0) int main(void) { int N = 1024; size_t size = N * sizeof(float); // Allocate the host input vectors and initialize float *h_a = (float *)malloc(size); float *h_b = (float *)malloc(size); float *h_c = (float *)malloc(size); //... float *d_a,*d_b = NULL; //Reservar memoria E/S en el dispositivo CUDA_CALL(cudaMalloc((void **)&d_a, size)); CUDA_CALL(cudaMalloc((void **)&d_b, size)); float *d_c = NULL; CUDA_CALL(cudaMalloc((void **)&d_c, size)); Código en el host //Copiar los vectores de entrada h_a y h_b al dispositivo CUDA_CALL(cudaMemcpy(d_A, h_a, size, cudamemcpyhosttodevice)); CUDA_CALL(cudaMemcpy(d_B, h_b, size, cudamemcpyhosttodevice)); //Configurar parámetros y lanzar el kernel int blockdim = 256; int griddim = 4; printf("cuda kernel launch with %d blocks of %d threads\n", griddim, blockdim); vectoradd<<<griddim, blockdim>>>(d_a, d_b, d_c, N); cudaerror_t err = cudagetlasterror(); if (err!= cudasuccess) { fprintf(stderr, "Failed to launch vectoradd kernel (error code %s)!\n", cudageterrorstring(err)); exit(exit_failure); } //Copiar resultado al host CUDA_CALL(cudaMemcpy(h_C, d_c, size, cudamemcpydevicetohost)); 24

Código en el host //Comprobar cálculos realizados for (int i = 0; i < N; ++i) { if (fabs(h_a[i] + h_b[i] - h_c[i]) > 1e-5) { fprintf(stderr, "Result verification failed at element %d!\n", i); exit(exit_failure); } } printf("test PASSED\n"); CUDA_CALL(cudaFree(d_A)); // Liberar memoria del dispositivo CUDA_CALL(cudaFree(d_B)); CUDA_CALL(cudaFree(d_C)); free(h_a); // Free host memory free(h_b); free(h_c); // Resetear el dispositivo y salir CUDA_CALL(cudaDeviceReset()); return 0; } Compilación rápida con nvcc CUDA amplía C++ de distintas formas: Llamadas a los kernels <<<. >>> Variables integradas threadidx, blockidx Calificadores global device etc. Estas extensiones sólo pueden ser procesadas por archivos *.cu No por archivos *.cpp Es posible ubicar todo nuestro código en archivos *.cu Recomendado para códigos pequeños Se evita utilizar *.c ó *.cpp Compilación y enlazado utilizando nvcc nvcc test.cu o test Ejecutar desde línea de comandos./test 25

EJERCICIO Y si la longitud de los vectores no es múltiplo de el tamaño de bloque? Por ejemplo, bloques de tamaño 512 y vectores de longitud 10E6. Cambia el código del host: - Para asegurarte que lanzas exactamente los bloques que son necesarios Cambia el código del device: - Para asegurarte de que hay hilos en el último bloque que permanecen en estado idle. SUMA DE VECTORES Código en el host Qué ocurre si longitud vectores es N, no necesariamente múltiplo de 256? Parámetros de invocación del kernel genéricos Necesario restringir cálculo al dominio de cómputo Algunos threads deberán estar en estado de reposo (idle) //d_a, d_b y d_c son punteros a vectores en el device dim3 blockdim(256,1,1); //Bloques típicos de 128, 256, 512 dim3 griddim((n-1)/blockdim.x+1,1,1); sum_kernel<<<griddim,blockdim>>>(d_a,d_b,d_c,n); 26

Código en el device Qué ocurre si longitud vectores es N, no necesariamente múltiplo de 256? Necesario restringir cálculo al dominio de cómputo Algunos threads deberán estar en estado de reposo (idle) global void sum_kernel(int *A, int *B, int *C, int N) { int tidx = blockidx.x * blockdim.x + threadidx.x; //calcular índice if(tid<n){ int elema = A[tidx]; //leer elemento de A int elemb = B[tidx]; //leer elemento de B C[tidx] = elema + elemb; //calcular y escribir elemento en C } } EJERCICIO Extiende el ejemplo anterior a suma de matrices indexando los threads dentro del bloque y los bloques dentro del grid usando dos dimensiones SUMA MATRICES 27

Conclusiones Arquitectura GPU muy distinta de CPU Arquitecturas masivamente paralelas Incremento ámbitos de aplicación de GPUs Aumentar rendimiento aplicaciones paralelas Directivas OpenACC / OpenMP Librerías drop in Programación CUDA Curva más elevada de aprendizaje Asequible con conocimientos previos C/C++, Fortran, Programa en CUDA Código en el device CUDA Kernel Código en el host Invoca el CUDA Kernel Información adicional Página web de NVIDIA www.nvidia.es/cud a Controladores SDK IDE Nsight Visual Studio Eclipse Tutoriales y documentación 28

Libros CUDA by Example by Jason Sanders and Edward Kandrot Programming Massively Parallel Processors: A Hands-on Approach by David Kirk, Wen-mei Hwu (2nd ed.) The CUDA Handbook by Nicholas Wilt CUDA Application Design and Development by Rob Farber CUDA Programming: A Developer's Guide to Parallel Computing with GPUs by Shane Cook Gracias por su atención marmar@tel.uva.es Mario Martínez-Zarzuela Febrero 2015 29