Upload
joel-frank-huarayo-quispe
View
223
Download
0
Embed Size (px)
Citation preview
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 1/34
Manuel UjaldonNvidia CUDA FellowProfesor del Dpto. de Arquitectura de Computadores. Universidad de M‡laga (Espa–a).
Conjoint Senior Lecturer. University of Newcastle (Australia)
RIO 2014R’o Cuarto (Argentina), 17 y 18 de Febrero, 2014
2
Agradecimientos
Al personal de Nvidia, por compartir conmigo ideas,material, diagramas, presentaciones, ... AlfabŽticamente:
Bill Dally [2010-2011: Consumo energŽtico, Echelon y dise–os futuros].
Simon Green [2007-2009: Los pilares de CUDA].
Sumit Gupta [2008-2009: El hardware de Tesla].Mark Harris [2008, 2012: CUDA, OpenACC, Lenguajes de Programaci—n, Librer’as].
Wen-Mei Hwu [2009: Programaci—n y trucos para mejorar el rendimiento].
Stephen Jones [2012: Kepler].
David B. Kirk [2008-2009: Hardware de Nvidia].
Timothy Lanfear [2012: Kepler y OpenACC].
David Luebke [2007-2008: Hardware de Nvidia].
Lars Nyland [2012: Kepler].
Edmondo Orlotti [2012: CUDA 5.0, OpenACC].
Cyril Zeller [2008-2009: Fundamentos de CUDA].
... por mencionar s—lo unos pocos del equipo que contribuy— a estapresentaci—n.
Contenidos del tutorial
1. Introducci—n. [18 diapositivas]
2. Arquitectura. [15]
1. El modelo hardware de CUDA. [3]
2. La primera generaci—n: Tesla (2006-2009). [3]
3. La segunda generaci—n: Fermi (2010-2011). [4]
4. La tercera generaci—n: Kepler (2012-2014). [5]
3. Programaci—n. [15]
4. Sintaxis. [16]
1. Elementos b‡sicos. [10]
2. Un par de ejemplos preliminares. [6]
5. Compilaci—n. [9]
6. Ejemplos: VectorAdd, Stencil, MxM. [25]
7. Bibliograf’a y herramientas. [6] 3
Prerrequisitos para este tutorial
Se requiere estar familiarizado con el lenguaje C.
No es necesaria experiencia en programaci—n paralela(aunque si se tiene, ayuda bastante).
No se necesitan conocimientos sobre la arquitectura de la
GPU: Empezaremos describiendo sus pilares b‡sicos.No es necesario tener experiencia en programaci—n
gr‡fica. Eso era antes cuando GPGPU se basaba en losshaders y Cg. Con CUDA, no hace falta desenvolverse convŽrtices, p’xeles o texturas porque es transparente a todosestos recursos.
4
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 2/34
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 3/34
Las 3 cualidades que han hechode la GPU un procesador œnico
Control simplificado.El control de un hilo se amortiza en otros 31 (warp size = 32).
Escalabilidad.
Aprovech‡ndose del gran volumen de datos que manejan lasaplicaciones, se define un modelo de paralelizaci—n sostenible.
Productividad.Se habilitan multitud de mecanismos para que cuando un hilo pase
a realizar operaciones que no permitan su ejecuci—n veloz, otrooculte su latencia tomando el procesador de forma inmediata.
Palabras clave esenciales para CUDA:Warp, SIMD, ocultaci—n de latencia, conmutaci—n de contexto
gratis. 9
ÀQuŽ es CUDA? ÒCompute Unified Device ArchitectureÓ
Una plataforma dise–ada conjuntamente a nivel software yhardware para aprovechar la potencia de una GPU enaplicaciones de prop—sito general a tres niveles:
Software: Permite programar la GPU en C con m’nimaspero potentes extensiones SIMD para lograr una ejecuci—neficiente y escalable.
Firmware: Ofrece un driver para la programaci—n GPGPUque es compatible con el que utiliza para renderizar. Sencillos APIs manejan los dispositivos, la memoria, etc.
Hardware: Habilita el paralelismo de la GPU paraprogramaci—n de prop—sito general a travŽs de un nœmero demultiprocesadores dotados de un conjunto de nœcleoscomputacionales arropados por una jerarqu’a de memoria.
10
Lo esencial de CUDA
En general, es lenguaje C con m’nimas extensiones:El programador escribe el programa para un solo hilo (thread), y el
c—digo se instancia de forma autom‡tica sobre miles de hilos.
CUDA define:Un modelo de arquitectura:
Con multitud de unidades de proceso (cores), agrupadas en multiprocesadores quecomparten una misma unidad de control (ejecuci—n SIMD).
Un modelo de programaci—n:Basado en el paralelismo masivo de datos y en el paralelismo de grano fino.
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, con control expl’cito de la memoria cachŽ.
Objetivos:Construir c—digo escalable a cientos de cores, declarando miles de hilos.
Permitir computaci—n heterogŽnea en CPU y GPU.11
Terminolog’a:Host (el anfitri—n): La CPU y la memoria de la placa base [DDR3].
Device (el dispositivo): La tarjeta gr‡fica [GPU + memoria de v’deo]: GPU: Nvidia GeForce/Tesla.
Memoria de v’deo: GDDR5 en 2013.
Computaci—n heterogŽnea (1/4)
Host Device12
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 4/34
CUDA ejecuta un programa sobre un dispositivo (la GPU), que actœa comocoprocesador de un anfitri—n o host (la CPU).
CUDA puede verse como una librer’a de funciones que contienen 3 tipos decomponentes:
Host: Control y acceso a los dispositivos.
Dispositivos: Funciones espec’ficas para ellos.
Todos: Tipos de datos vectoriales y un conjunto de rutinas soportadas por ambas partes.
Computaci—n heterogŽnea (2/4)
13
CPU (host)
GPU(device)
Memoria principal
(DDR3)
Memoria dev’deo
(GDDR5)
Cores Caches50 GB/s.
3 canales (192 bits = 24 bytes)
@ 1.333 GHz 32 GB/s.
PCI-e 3.0: 8 GB/s.
384 bits @ 3 GHz 144 GB/s.
Computaci—n heterogŽnea (3/4)
El c—digo reescrito en CUDA puede ser inferior al 5%, peroconsumir m‡s del 50% del tiempo si no migra a la GPU. 14
#include<iostream>#include<algorithm>
usingnamespace std;
#define N 1024#define RADIUS 3#define BLOCK_SIZE16
__global__void stencil_1d(int *in, int *out) { __shared__int temp[BLOCK_SIZE+ 2 * RADIUS]; int gindex = threadIdx.x+ blockIdx.x* blockDim.x; int lindex = threadIdx.x+ RADIUS;
//Read input elementsinto shared memory temp[lindex]= in[gindex]; if (threadIdx.x< RADIUS) { temp[lindex- RADIUS] = in[gindex- RADIUS]; temp[lindex+ BLOCK_SIZE] = in[gindex+ BLOCK_SIZE]; }
//Synchronize(ensure all thedata isavailable) __syncthreads();
//Apply thestencil int result= 0;
for (int offset= -RADIUS; offset<= RADIUS; offset++) result+= temp[lindex+ offset];
//Store theresult out[gindex] = result;}
void fill_ints(int *x, int n){ fill_n(x, n, 1);}
int main(void){ int *in, *out; //host copiesof a, b, c int *d_in, *d_out; //device copiesof a, b, c int size= (N+ 2*RADIUS) * sizeof (int);
//Alloc spacefor hostcopies and setup values in = (int *)malloc(size); fill_ints(in, N+ 2*RADIUS); out= (int *)malloc(size); fill_ints(out, N+ 2*RADIUS);
//Alloc spacefor devicecopies cudaMalloc((void **)&d_in, size); cudaMalloc((void **)&d_out, size);
//Copy to device cudaMemcpy(d_in, in, size, cudaMemcpyHostToDevice); cudaMemcpy(d_out, out, size, cudaMemcpyHostToDevice);
//Launch stencil_1d() kernel on GPU stencil_1d<<<N/BLOCK_SIZE,BLOCK_SIZE>>>(d_in + RADIUS, d_out+ RADIUS);
//Copy resultback to host cudaMemcpy(out, d_out, size, cudaMemcpyDeviceToHost);
//Cleanup free(in); free(out); cudaFree(d_in); cudaFree(d_out); return 0;}
Computaci—n heterogŽnea (4/4)
CODIGO DEL HOST:
- C—digo serie.- C—digo paralelo.- C—digo serie.
CODIGO DEL DISPOSITIVO:Funci—n paralela
15
Un sencillo flujo de procesamiento (1/3)
Bus PCI
16
1.Copiar los datos de entrada de lamemoria de la CPU a la memoriade la GPU.
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 5/34
Un sencillo flujo de procesamiento (2/3)
PCI Bus
17
1.Copiar los datos de entrada de lamemoria de la CPU a la memoriade la GPU.
2.Cargar el programa en la GPU yejecutarlo, ubicando datos encachŽ para mejorar elrendimiento.
Un sencillo flujo de procesamiento (3/3)
1.Copiar los datos de entrada de lamemoria de la CPU a la memoriade la GPU.
2.Cargar el programa en la GPU yejecutarlo, ubicando datos encachŽ para mejorar elrendimiento.
3.Transferir los resultados de lamemoria de la GPU a la memoriade la CPU.
PCI Bus
18
El cl‡sico ejemplo
Es c—digo C est‡ndar que se ejecuta en el host.
El compilador nvcc de Nvidia puede utilizarse paracompilar programas que no contengan c—digo para la GPU.
19
Salida:
$ nvcc hello.cu$ a.outÁHola mundo!
$
int main(void) {
printf("ÁHola mundo!\n");
return 0;
}
ÁHola mundo! con c—digo para la GPU (1/2)
Dos nuevos elementossint‡cticos:
La palabra clave de CUDA __global__ indica una funci—n que se ejecuta en laGPU y se lanza desde la CPU. Por
ejemplo, mikernel<<<1,1>>>.Eso es todo lo que se requiere
para ejecutar una funci—n en GPU.
20
__global__ void mikernel(void)
{
}
int main(void)
{
mikernel<<<1,1>>>();
printf("ÁHola mundo!\n");
return 0;
}
nvcc separa el c—digo fuente para la CPU y la GPU.
Las funciones que corresponden a la GPU (como mikernel())son procesadas por el compilador de Nvidia.
Las funciones de la CPU (como main()) son procesadas porsu compilador (como gcc para Unix o cl.exe para Windows).
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 6/34
ÁHola mundo! con c—digo para la GPU (2/2)
mikernel() no hace nada esta vez.
Los s’mbolos "<<<" y ">>>" delimitan la llamada desde el c—digode la CPU al c—digo de la GPU, tambiŽn denominado Òlanzamiento deun kernelÓ.
Los par‡metros 1,1 describen el paralelismo (bloques e hilos CUDA).21
__global__ void mikernel(void)
{
}
int main(void) {
mikernel<<<1,1>>>();
printf("ÁHola mundo!\n");
return 0;
}
Salida:
$ nvcc hello.cu$ a.out
ÁHola mundo!$
Computaci—n en GPU
NVIDIA GPU con la arquitectura
de computaci—n paralela CUDA
C OpenCL
tm DirectCompute
Fortran Java yPython
C++
Si tenemos una arquitectura CUDA, podemosprogramarla de muy diversas formas...
... aunque este tutorial se focaliza sobre CUDA C.22
La evoluci—n de CUDA
En los œltimos 5 a–os, Nvidia ha vendido m‡s de 450 millones deGPUs que aceptan CUDA para su programaci—n.
Pero CUDA ha evolucionado en la direcci—n opuesta a la que estamosacostumbrados: Partiendo de los investigadores para poco a poco llegara los usuarios m‡s genŽricos.
23
Versi—n deCUDA [a–o]
Usuarios
1.0 [2007]
2.0 [2008]
3.0 [2009]
4.0 [2011]
5.0 [2012]
Muchos investigadores y algunos usuarios madrugadores.
Cient’ficos y aplicaciones para computaci—n de altas prestaciones.
L’deres en la innovaci—n de aplicaciones.
Adopci—n mucho m‡s extensa de desarrolladores.
Optimizada para Kepler e inaugurada en el tercer trimestre de 2012.
2013 finaliza con CUDA 5.5, en transici—n hacia CUDA 6.0.
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 7/34
Las generaciones hardware de CUDA
26
El modelo hardware de CUDA:Un conjunto de procesadores SIMD
La GPU consta de:N multiprocesadores, cada uno dotado
de M cores (o procesadores streaming).
Paralelismo masivo: Aplicado sobre miles de hilos.
Compartiendo datos a diferentesniveles de una jerarqu’a de memoria.
Computaci—n heterogŽnea:GPU:
Intensiva en datos.
Paralelismo de grano fino.
CPU:Gesti—n y control.
Paralelismo de grano grueso.
27
GPU
Multiprocesador N
Multiprocesador 2
Multiprocesador 1
Unidad deControl SIMDCore 1
É
Core 2 Core M
G80(Tesla)
GT200(Tesla)
GF100(Fermi)
GK110(Kepler)
Marco temporal
N (multiprocs.)
M (cores/multip.)
Nœmero de cores
2006-07 2008-09 2010-11 2012-13
16 30 14-16 13-15
8 8 32 192
128 240 448-512 2496-2880
Jerarqu’a de memoria
Cada multiprocesador tiene:Su banco de registros.
Memoria compartida.
Una cachŽ de constantes y otrade texturas, ambas de s—lolectura y uso marginal.
La memoria global es lamemoria de v’deo (GDDR5):
Tres veces m‡s r‡pida que lamemoria principal de la CPU,pero... Á500 veces m‡s lenta quela memoria compartida! (que esSRAM en realidad).
2813
GPU
Multiprocesador N
Multiprocesador 2
Multiprocesador 1
Memoria global
Memoria compartida
Unidadde
ControlSIMD
Procesador 1
Registros
ÉProcesador 2
Registros
Procesador M
Registros
CachŽ paraconstantes
CachŽ paratexturas
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 8/34
29
Latencia y ancho de bandade la memoria en CUDA
Memoria de la CPU (o memoria principal - DDR3): Ancho de banda con mem. v’deo: 3.2 GB/s.(PCIe) y 5.2 GB/s(PCIe2).
Memoria de v’deo (o memoria global):Gran ancho de banda (80-100 GB/s) y latencia, no pasa por cachŽ.
Memoria compartidaBaja latencia, ancho de banda muy elevado, tama–o reducido. Actœa como una cachŽ gestionada por el usuario (scratchpad).
Memoria de texturas/constantesDe s—lo lectura, alta/baja latencia, pasa por cachŽ.
Host
CPU
Chipset
DRAM
Device
DRAM
Global
Constantes
Texturas
Local
GPU
Multiprocesador
Registros y
memoria compartida
CachŽs para constantesy texturas
La primera generaci—n: G80 (GeForce 8800)
31
GPU G80 (en torno a 600 MHz, frecuencia muy inferior a la de sus cores)
Multiprocesador 16
Multiprocesador 2
Multiprocesador 1
Memoria global (hasta 1.5 GB) (GDDR3 @ 2x 800MHz)
Memoria compartida (16 KB)
Unidad decontrol
(emiteinstrucciones
SIMD)
Core 1 (1.35 GHz)
Registros
ÉCore 2
Registros
Core 8
Registros
CachŽ de texturas(los kernels se mapean
sobre los cores)
(los bloques de c—digo CUDA se mapean sobre los multipr.)
La primera generaci—n: GT200 (GTX 200)
32
GPU GTX 200 (en torno a 600 MHz)
Multiprocesador 30
Multiprocesador 2
Multiprocesador 1
Memoria global (hasta 4 GB) (GDDR3, 512 bits @ 2x 1.1GHz = 141.7 GB/s)
Memoria compartida (16 KB)
Unidad decontrol
(emiteinstrucciones
SIMD)
Core 1 (1.30 GHz)
Registros
ÉCore 2
Registros
Core 8
Registros
CachŽ de texturas(los kernels se mapean
sobre los cores)
(los bloques de c—digo CUDA se mapean sobre los multipr.)
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 9/34
Escalabilidad para futuras generaciones: Alternativas para su crecimiento futuro
Aumentar el nœmero demultiprocesadores por pares(nodo b‡sico), esto es, creceren la dimensi—n Z. Es lo quehizo la 1» gener. (de 16 a 30).
Aumentar el nœmero deprocesadores de cadamultiprocesador, o crecer en ladimensi—n X. Es el caminotrazado por la 2» y 3» geners.
Aumentar el tama–o de lamemoria compartida, esto es,crecer en la dimensi—n Y. 33
GPUMultiprocesador 30
Multiprocesador 2
Multiprocesador 1
Memoria global
Memoria compartida
Core 1
Registros
ÉCore 2
Registros
Core 8
Registros
CachŽ de texturas
(escalabilidad en 1» gener.)
(escalabilidad en 2» y 3» gener.)
35
El HW de Fermi comparado con los modelosrepresentativos de la generaci—n anterior
Arquitectura GPU
Nombre comercial
A–o de lanzamiento
G80 GT200 GF100 (Fermi)
GeForce 8800 GTX 200 GTX 580
2006 2008 2010
Nœmero de transistores
Nœmero de cores (int y fp32)
Nœmero de cores (fp64) Velocidad de c‡lculo en fp64
Planificadores de warps
Memoria compartida
CachŽ L1
CachŽ L2
Correcci—n de errores(DRAM)
Anchura del busde direcciones
681 mil lones 1400 mil lones 3000 mi llones
128 240 512
0 30 256Ninguna 30 madds/ciclo 256 madds/ciclo
1 1 2
16 KB 16 KB 16 KB + 48 KB
Ninguna Ninguna
(o viceversa)
Ninguna Ninguna 768 KB
No No S’
32 bits 32 bits 64 bits
Arquitectura global de Fermi
36
Hasta 512 cores (16 SMs dotados de 32 cores cada uno).Los SPs crecen de 240 a 512, los DPs de 30 a 256 y los SFUs de 60 a 64.
Doble planificador de procesos (scheduler) para los hilos que entran a cada SM.
64 KB de SRAM, repartidos entre la cachŽ L1 y la memoria compartida.
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 10/34
Mejoras en la aritmŽtica
Unidades aritmŽtico-l—gicas (ALUs):Redise–ada para optimizar operaciones
sobre enteros de 64 bits.
Admite operaciones de precisi—nextendida.
La instrucci—n ÒmaddÓ (sumay producto simult‡neos):
Est‡ disponible tanto para simplecomo para doble precisi—n.
La FPU (Floating-Point Unit):Implementa el formato IEEE-754 en su
versi—n de 2008, aventajando incluso a lasCPUs m‡s avezadas.
37
Load/Store Units x 16
Special Func Units x 4
FP Unit INT Unit
La jerarqu’a de memoria
3813
Fermi es la primera GPUque ofrece una cachŽ L1 t’picaon-chip, que combina con la
shared memory de CUDA enproporci—n 3:1 o 1:3 para untotal de 64 Kbytes por cadamultiprocesador (32 cores).
TambiŽn incluye una cachŽunificada de 768 Kbytes concoherencia de datos para elconjunto total de cores.
Diagrama de bloques: Kepler GK110
7.100 Mt.
15 SMX multiprocs.
> 1 TFLOP FP64.
1.5 MB L2 Cache.
384-bit GDDR5.PCI Express Gen3.
40
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 11/34
Evoluci—n de los multiprocesadores:Del SM de Femi al SMX de Kepler
41
Mejora de recursos en los SMX
42
RecursoKepler GK110
frente a Fermi GF100
Ritmo de c‡lculo con opers. punto flotante
M‡ximo nœmero de bloques por SMX
M‡ximo nœmero de hilos por SMX
Ancho de banda del banco de registros
Capacidad del banco de registros
Ancho de banda de la memoria compartida
Capacidad de la memoria compartida
Ancho de banda de la cachŽ L2
Capacidad de la cachŽ L2
2-3x
2x
1.3x
2x
2x
2x
1x
2x
2x
Innovaciones de Kepler:Paralelismo din‡mico
43
CPU GPU CPU GPU
La GPU es un procesador aut—nomoLa GPU es un co-procesador
Innovaciones de Kepler:Paralelismo din‡mico (2)
El paralelismo puede depender de los datos, o incluso de lapotencia computacional asociada a las regiones de interŽs.
44
CUDA en 2012 CUDA sobre Kepler
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 12/34
46
El modelo de programaci—n CUDA
La GPU (device) ofrece a la CPU (host) la visi—n de uncoprocesador altamente ramificado en hilos.
Que tiene su propia memoria DRAM.
Donde los hilos se ejecutan en paralelo sobre los nœcleos (coreso stream processors) de un multiprocesador.
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, quela GPU necesita para lograr rendimiento y escalabilidad.
GPU
Multiprocesador 1 Multiprocesador 2 Multiprocesador N
Cada modelo se diferencia en pocos par‡-metros para generar el cat‡logo comercial
Debemos esperar que estas diferencias crezcan entremodelos asociados a diferentes generaciones.
Las diferencias tambiŽn crecer‡n cuando dos tarjetaspertenezcan a gamas diferentes:
300-500 ! para la gama alta.150-250 ! para la gama media.
60-120 ! para la gama baja.
La memoria de v’deo puede diferir tambiŽn cuandoemerge una nueva tecnolog’a, como el caso de la GDDR5.
Los modelos difieren tambiŽn en sus prestacionesgr‡ficas, aunque este tutorial no cubre las mismas.
47 48
Modelo comercial
Generaci—n
A–o
GTX 285 GTX 480 GTX 465 GTX 460
GT200 GF100 GF100 GF104
2009 2010 2010 2011
Precio de lanzamiento
Nœmero de transistores
Proceso de fabricaci—n
Nœmero de SMs
Cores en cada SM
Nœmero total de cores
Reloj de los cores (MHz)
Tecnolog’a de memoria
Reloj de memoria (MHz)
Ancho del bus de mem.
Tama–o de la memoria
! 300 ! 500 ! 250 ! 230/200
1400 mill. 3000 mill. 3000 mill. 1950 mill.
TSMC 55 nm. TSMC 40 nm. TSMC 40 nm TSMC 40 nm.
30 15 11 7
8 32 32 48
240 480 352 336
1476 1401 1215 1350
GDDR3 GDDR5 GDDR5 GDDR5
2x 1242 4x 924 4x 802 4x 900
512 bits 384 bits 256 bits 256 bits
1 GB. 1.5 GB. 1 GB. 1 GB. / 768 MB.
Ejemplo de cat‡logo comercial
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 13/34
49
Modelo comercial
Generaci—n
A–o
GTX 285 GTX 480 GTX 465 GTX 460
GT200 GF100 GF100 GF104
2009 2010 2010 2011
fp64 vs. fp32
Frecuencia GPU (MHz)
Direccionam. a texturas
Filtrado de texturas
Rasterizadores
1 vs. 16 1 vs. 8 1 vs. 8 1 vs. 6
648 700 607 675
80 60 44 56
80 60 44 56
32 48 32 32
Ejemplo de cat‡logo comercial (cont.)
50
Estructura de un programa CUDA
Cada multiprocesador procesa lotes de bloques, unodetr‡s de otro
Bloques activos = los bloques procesados por un multiprocesadoren un lote.
Hilos activos = todos los que provienen de los bloques que seencuentren activos.
Los registros y la memoria compartida de un multi-procesador se reparten entre sus hilos activos. Para unkernel 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.
51
Conceptos b‡sicos
Los programadores se enfrentan al reto de exponer el paralelismo paramœltiples cores y mœltiples hilos por core. Para ello, deben usar lossiguientes elementos:
Dispositivo = GPU = Conjunto de multiprocesadores.
Multiprocesador = Conjunto de procesadores y memoria compartida.
Kernel = Programa listo para ser ejecutado en la GPU. Malla (grid) = Conjunto de bloques cuya compleci—n ejecuta un kernel.
Bloque [de hilos] = Grupo de hilos SIMD que:
Ejecutan un kernel delimitando su dominio de datos segœn su threadIDy blockID.
Pueden comunicarse a travŽs de la memoria compartida delmultiprocesador.
Tama–o del warp = 32. Esta es la resoluci—n del planificador para emitirhilos por grupos a las unidades de ejecuci—n.
Correspondencia entre los conceptoshardware y software de CUDA
52
GPU
Multiprocesador N
Multiprocesador 2
Multiprocesador 1
Memoria global
Memoria compartida
Unidadde
ControlSIMD
Procesador 1
Registros
ÉProcesador 2
Registros
Procesador M
Registros
CachŽ paraconstantes
CachŽ paratexturas
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 14/34
53
Recursos y limitaciones segœn la GPU queutilicemos para programar (CCC)
CUDA C mpute apability (CCC)
1.0, 1.1 1.2, 1.3 2.0, 2.1 3.0, 3.5
Multiprocesadores / GPU
Cores / Multiprocesador
Hilos / Warp
Bloques / Multiprocesador
Hilos / Bloque
Hilos / Multiprocesador
Registros de 32 bits / Multiprocesador
Memoria compartida / Multiprocesador
16 30 14-16 14-16 HardwareEscala-
ili8 8 32 192 Hardware
l
bilidad
32 32 32 32 Software Ritmo deli
8 8 8 16 Softwarelidatos
512 512 1024 1024 Softwarel li
768 1 024 1 536 2048 Softwarel li
8K 16K 32K 64K Hardware Conjunto
16K 16K 16K 48K
16K,32K, 48K
Hardware trabajo
! ! ! !
54
Bloques e hilos en GPU
Los bloques se asignan a los
multiprocesadores
[L’mite en Kepler:16 bloques
concurrentes porcada
multiprocesador]
Bloque 0 Bloque 1 Bloque 2
Malla 0 [L’mite en Kepler: 4G bloques por malla]
L’mite en Kepler: 1024 hilos por bloque, 2048 hilos por multiprocesador
Los hilos se asignan a los multiprocesadores en bloques, queconstituyen la unidad para asignar hilos a cores via warps.Los hilos de un bloque pueden compartir informaci—n a travŽsde la memoria compartida, sincroniz‡ndose impl’citamente (alacabar el bloque) o expl’citamente (con synchthreads()).
Ejemplos de restricciones de paralelismo enKepler al tratar de maximizar concurrencia
L’mites para un multiprocesador: [1] 16 bloques concu-rrentes, [2] 1024 hilos/bloque y [3] 2048 hilos en total.
1 bloque de 2048 hilos. No lo permite [2].
2 bloques de 1024 hilos. Posible en el mismo multiproc.
4 bloques de 512 hilos. Posible en el mismo multiproc. 4 bloques de 1024 hilos. No lo permite [3] en el mismo
multiprocesador, pero posible usando dos multiprocs.
8 bloques de 256 hilos. Posible en el mismo multiproc.
256 bloques de 8 hilos. No lo permite [1] en el mismomultiprocesador, posible usando 16 multiprocesadores.
55
Estos bloquespueden
ejecutarse enun mismo
multiprocesadorsi se cumplen
ciertas
limitaciones deespacio
Local memory: Off-chip
56
La memoria en la GPU: çmbito y ubicaci—n
! ! ! !
T a m b i Ž n e x i s t e
u
n a m e m o r i a d e
c o n s t a n t e s y
t e x t u r a s
Bloque 0 Bloque 1 Bloque 2
Malla 0
Memoria global: GDDR5 (DRAM)
Memoria compartida
Los hilos pueden usar la memoria compartida para comunicarse entreellos dentro del bloque o realizar tareas de manera cooperativa y veloz.
La memoria global es la œnica visible a todas las entidades definidas
para un programa CUDA (hilos, bloques, kernels).
BRBRBRBRBRBRBRBR
ML ML ML ML ML ML ML ML
Significado: BR: Banco de registros. ML = Memoria local
Memoria GPU: On- ch ip Off -c hip
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 15/34
Jugando con las restricciones de memoria enKepler para maximizar el uso de los recursos
L’mites dentro de un multiprocesador (SMX): 64 Kregs. y48 KB. de memoria compartida. As’:
Para permitir que un segundo bloque se ejecute en el mismomultiprocesador, cada bloque debe usar a lo sumo 32 Kregs. y 24 KB.
de memoria compartida.
Para permitir que un tercer bloque se ejecute en el mismo multi-procesador, cada bloque debe usar a lo sumo 21.3 Kregs. y 16 KB. dememoria compartida.
...y as’ sucesivamente. Cuanto menor cantidad dememoria usemos, mayor concurrencia para la ejecuci—n debloques.
El programador debe establecer el compromiso adecuadoentre apostar por memoria o paralelismo en cada c—digo. 57
Recordar: Mejor paralelismo de grano fino (asignar un datoa cada hilo). Despliegue de bloques e hilos:
8 bloques de 8 hilos cada uno. Riesgo en bloques
peque–os: Desperdiciar paralelismo si se alcanza el m‡ximo de8/16 bloques en cada multiprocesador con pocos hilos entotal.
4 bloques de 16 hilos cada uno. Riesgo en bloques grandes:Estrangular el espacio de cada hilo (la memoria compartida yel banco de registros se comparte entre todos los hilos).
Pensando en peque–o: Particionamiento 1Dde un vector de 64 elementos
58
Pensando a lo grande: Particionamiento 1Dde un vector de 64 millones de elementos
M‡ximo nœmero de hilos por bloque: 1K.
Maximo nœmero de bloques:64K en Fermi y 4G en Kepler.
Tama–os m‡s grandes para las estructuras de datos s—lo
pueden implementarse mediante un nœmero ingente debloques (si queremos preservar el paralelismo fino).
Posibilidades a elegir:64K bloques de 1K hilos cada uno.
128K bloques de 512 hilos cada uno (s—lo factible en Kepler).
256K bloques de 256 hilos cada uno (s—lo factible en Kepler).
... y as’ sucesivamente.
59 60
Recopilando sobre kernels,bloques y paralelismo
Los kernels se lanzan en grids.Un bloque se ejecuta en un
multiprocesador (SMX).El bloque no migra.
Varios bloques pueden residirconcurrentemente en un SMX.
Con las limitaciones de Kepler:Hasta 16 bloques concurrentes.Hasta 1024 hilos en cada bloque.Hasta 2048 hilos en cada SMX.
Otras limitaciones entran en juegodebido al uso conjunto de lamemoria compartida y el banco deregistros segœn hemos visto hace 3diapositivas.
Malla
Bloque (0, 0)
Memoria compartida
Hilo (0, 0)
Regs Regs
Bloque (1, 0)
Memoria compartida
Hilo (0, 0)
Regs
Hilo (1, 0)
Regs
Memoria global
Hilo (1, 0)
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 16/34
61
Escalabilidad transparente
Dado que los bloques no se pueden sincronizar: El hardware tiene libertad para planificar la ejecuci—n de un bloque
en cualquier multiprocesador.
Los bloques pueden ejecutarse secuencialmente o
concurrentemente segœn la disponibilidad de recursos.GPU con 2 SMX
SMX 0 SMX 1
B lo ck 0 B lo ck 1
B lo ck 2 B lo ck 3
B lo ck 4 B lo ck 5
B lo ck 6 B lo ck 7
Malla para el kernel
Block 0 Block 1
Block 2 Block 3
Block 4 Block 5
Block 6 Block 7
GPU con 4 SMX
SMX 0 SMX 1 SMX 2 SMX 3
Block 0 Block 1 Block 2 Block 3
Block 4 Block 5 Block 6 Block 7
! Un kernel se puede expandir a lo largo de cualquiernœmero de procesadores (siempre que hayamosdeclarado un nœmero suficiente de bloques).
Espacios de memoria
La CPU y la GPU tiene espacios de memoria separados:Para comunicar ambos procesadores, se utiliza el bus PCI-express.
En la GPU se utilizan funciones para alojar memoria y copiar datosde la CPU de forma similar a como la CPU procede en lenguaje C
(malloc para alojar y free para liberar).
Los punteros son s—lo direcciones:No se puede conocer a travŽs del valor de un puntero si la direcci—n
pertenece al espacio de la CPU o al de la GPU.
Hay que ir con mucha cautela a la hora de acceder a los datos atravŽs de punteros, ya que si un dato de la CPU trata de accedersedesde la GPU o viceversa, el programa se colgar‡.
62
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 17/34
CUDA es C con algunas palabras clave m‡s.Un ejemplo preliminar
65
void saxpy_secuencial(int n, float a, float *x, float *y){ for (int i = 0; i < n; ++i) y[i] = a*x[i] + y[i];}// Invocar al kernel SAXPY secuencialsaxpy_secuencial(n, 2.0, x, y);
__global__ void saxpy_paralelo(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/bloqueint numero_de_bloques = (n + 255) / 256;saxpy_paralelo<<<numero_de_bloques, 256>>>(n, 2.0, x, y);
C—digo C est‡ndar
C—digo CUDA equivalente de ejecuci—n paralela en GPU:
Lista de extensiones sobre el lenguaje C
Modificadores para las variables(type qualifiers):
global, device, shared, local,constant.
Palabras clave (keywords):threadIdx, blockIdx.
Funciones intr’nsecas (intrinsics): __syncthreads
API en tiempo de ejecuci—n:Memoria, s’mbolos, gesti—n de la
ejecuci—n.
Funciones kernel para lanzar66
__device__ float vector[N];
__global__ void filtro (float *image) {
__shared__ float region[M]; ...
region[threadIdx.x] = image[i];
__syncthreads()...
imagen[j] = result;}
// Alojar memoria en la GPUvoid *myimage;
cudaMalloc(&myimage, bytes);
// 100 bloques de hilos, 10 hilos por bloqueconvolucion <<<100, 10>>> (myimage);
67
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 deforma convencional.
De esta manera, el t’pico main() de C combina la ejecuci—nsecuencial en CPU y paralela en GPU de kernels CUDA.
Un kernel se lanza siempre de forma as’ncrona, esto es, elcontrol 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 lesvamos intercalando c—digo con similar carga computacional.
68
La interacci—n entre la CPU y la GPU (cont.)
__global__ kernelA(){ááá} __global__ kernelB(){ááá}int main()ááákernelA <<< dimGridA, dimBlockA >>> (params.);ááákernelB <<< dimGridB, dimBlockB >>> (params.);
ááá
GPU
CPU
GPU
E j
e c u c
i —
n
CPU
CPU
Un kernel no comienza hasta que terminan los anteriores.Podemos emplear streams para definir kernels concurrentes.
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 18/34
Partici—n de datos para una matriz 2D [paraun patr—n de acceso paralelo, ver ejemplo 2]
69
Anchura de la matriz
A l t u r a d e l a m a t r i z
Malla (0, 0)
Bloque (0,0) Bloque (1,0) (blockDim.x,0)
(0,blockDim.y) (1,blockDim.y) (blockDim.x, blockDim.y)
Malla (gridDim.x, 0)
B lo ck (0,0) B lo ck (1,0) (blockD im.x,0 )
(0,blockDim.y) (1,blockDim.y) (blockDim.x, blockDim.y)
Malla (0, gridDim.y)
Bloque (0,0) Bloque (1,0) (blockDim.x,0)
(0,blockDim.y) (1,blockDim.y)(blockDim.x, blockDim.y)
Malla (gridDim.x, gridDim.y)
Bloque (0,0) Bloque (1,0) (blockDim.x,0)
(0,blockDim.y) (1,blockDim.y)(blockDim.x, blockDim.y)
Dado que queremosparalelismo de grano fino,asignaremos un elemento acada hilo, que puedeconocer sus coordenadasdurante la ejecuci—n as’:
- La posici—n (hor,ver) parael bloque dentro de la mallaes (blockIdx.x, blockIdx.y).- La posici—n (hor,ver) parael hilo dentro del bloque es(threadIdx.x, threadIdx.y)
Para este hilo:- blockIdx.x es 1.- blockIdx.y es 0.- threadIdx.x es 11.- threadIdx.y es 2.
70
Modificadores para las funciones ylanzamiento de ejecuciones en GPU
Modificadores para las funciones ejecutadas en la GPU: __global__ void MyKernel() { } // Invocado por la CPU
__device__ ßoat MyFunc() { } // Invocado por la GPU
Modificadores para las variables que residen en la GPU: __shared__ ßoat MySharedArray[32]; // Mem. compartida
__constant__ ßoat 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 hilos por bloque
MyKernel <<< gridDim,blockDim >>> (pars.); // Lanzam.
Nota: Opcionalmente, puede haber un tercer par‡metrotras blockDim para indicar la cantidad de memoriacompartida que ser‡ alojada din‡micamente por cadakernel durante su ejecuci—n.
71
dim3 gridDim; // Dimension(es) de la malla
dim3 blockDim; // Dimension(es) del bloque
uint3 blockIdx; // Indice del bloque dentro de la malla
uint3 threadIdx; // Indice del hilo dentro del bloque
void __syncthreads(); // Sincronizaci—n entre hilos
Variables y funciones intr’nsecas
El programador debe elegir el tama–o del bloquey el nœmero de bloques para explotar al m‡ximoel paralelismo del c—digo durante su ejecuci—n.
Funciones para conocer en tiempo deejecuci—n con quŽ recursos contamos
Cada GPU disponible en la capa hardware recibe unnœmero entero consecutivo que la identifica, comenzando porel 0.
Para conocer el nœmero de GPUs disponibles:cudaGetDeviceCount(int* count);
Para conocer los recursos disponibles en la GPU dev (cachŽ, registros, frecuencia de reloj, ...):
cudaGetDeviceProperties(struct cudaDeviceProp* prop, int dev);
Para conocer la mejor GPU que reœne ciertos requisitos:cudaChooseDevice(int* dev, const struct cudaDeviceProp* prop);
Para seleccionar una GPU concreta:cudaSetDevice(int dev);
Para conocer en quŽ GPU estamos ejecutando el c—digo:cudaGetDevice(int* dev);
72
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 19/34
Ejemplo: Salida de la funci—ncudaGetDeviceProperties
El programa se encuentra dentro del SDK de nVidia.
73
Para gestionar la memoria de v’deo
Para reservar y liberar memoria en la GPU:cudaMalloc(puntero, tama–o)
cudaFree(puntero)
Para mover ‡reas de memoria entre CPU y GPU:En la CPU, declaramos malloc(h_A).
En la GPU, declaramos cudaMalloc(d_A).
Y una vez hecho esto:Para pasar los datos desde la CPU a la GPU:
cudaMemcpy(d_A, h_A, numBytes, cudaMemcpyHostToDevice);
Para pasar los datos desde la GPU a la CPU:
cudaMemcpy(h_A, d_A, numBytes, cudaMemcpyDeviceToHost);
El prefijo Òh_Ó suele usarse para punteros en memoriaprincipal. Idem Òd_Ó para punteros en mem. de v’deo.
74
Ejemplo 1: Descripci—ndel c—digo a programar
Alojar N enteros en la memoria de la CPU.
Alojar N enteros en la memoria de la GPU.
Inicializar la memoria de la GPU a cero.
Copiar los valores desde la GPU a la CPU.
Imprimir los valores.
76
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 20/34
Ejemplo 1: Implementaci—n[c—digo C en rojo, extensiones CUDA en azul]
77
int main(){ int N = 16; int num_bytes = N*sizeof(int); int *d_a=0, *h_a=0; // Punteros en dispos. (GPU) y host (CPU)
h_a = (int*) malloc(num_bytes); cudaMalloc( (void**)&d_a, num_bytes);
if( 0==h_a || 0==d_a ) printf("No pude alojar memoria\n");
cudaMemset( d_a, 0, num_bytes); cudaMemcpy( h_a, d_a, num_bytes, cudaMemcpyDeviceToHost);
for (int i=0; i<N; i++) printf("%d ", h_a[i]);
free(h_a); cudaFree(d_a);}
Transferencias de memoria as’ncronas
Las llamadas a cudaMemcpy() son s’ncronas, esto es:No comienzan hasta que no hayan finalizado todas las llamadas
CUDA que le preceden.
El retorno a la CPU no tiene lugar hasta que no se haya realizado la
copia en memoria.
A partir de CUDA Compute Capabilities 1.2 es posibleutilizar la variante cudaMemcpyAsync(), cuyas diferenciasson las siguientes:
El retorno a la CPU tiene lugar de forma inmediata.
Podemos solapar comunicaci—n y computaci—n.
78
7962
Programa C en CPU
(compilado con gcc)
El kernel CUDA que se ejecuta en la GPU
(parte superior), seguido del c—digo host
en CPU. Este archivo se compila con
nvcc (ver m‡s adelante).
void incremento_en_cpu(float *a, float b, int N)
{
for (int idx = 0; idx<N; idx++)
a[idx] = a[idx] + b;
}
void main()
{
.....
incremento_en_cpu(a, b, N);
}
__global__ void incremento_en_gpu(float *a, float b, int N)
{ int idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx < N) a[idx] = a[idx] + b;}
void main()
{
É..
dim3 dimBlock (blocksize);
dim3 dimGrid( ceil( N / (float)blocksize) );
incremento_en_gpu<<<dimGrid, dimBlock>>>(a, b, N);
}
Ejemplo 2: Incrementar un valor ÒbÓa los N elementos de un vector
8063
Con N = 16 y blockDim = 4, tenemos 4 bloques de hilos,encarg‡ndose cada hilo de computar un elemento del vector.
blockIdx.x = 0blockDim.x = 4threadIdx.x = 0,1,2,3idx = 0,1,2,3
blockIdx.x = 1blockDim.x = 4threadIdx.x = 0,1,2,3idx = 4,5,6,7
blockIdx.x = 2blockDim.x = 4threadIdx.x = 0,1,2,3idx = 8,9,10,11
blockIdx.x = 3blockDim.x = 4threadIdx.x = 0,1,2,3idx = 12,13,14,15
int idx = (blockIdx.x * blockDim.x) + threadIdx.x;Se mapear‡ del ’ndice local threadIdx al ’ndice global
Nota: blockDim deber’a ser >= 32 (warp size) en c—digo real, esto es s—lo un ejemplo
Patr—n de accesocomœn a todoslos hilos
E x t e n s i o n e s
a l l e n g u a j e
Ejemplo 2: Incrementar un valor ÒbÓa los N elementos de un vector
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 21/34
8164
// Aloja memoria en la CPU
unsigned int numBytes = N * sizeof(float);
float* h_A = (float*) malloc(numBytes);
// Aloja memoria en la GPU
float* d_A = 0; cudaMalloc((void**)&d_A , numbytes);
// Copia los datos de la CPU a la GPU
cudaMemcpy(d_A, h_A, numBytes, cudaMemcpyHostToDevice);
// Ejecuta el kernel con un nœmero de bloques y tama–o de bloque
incremento_en_gpu <<< N/blockSize, blockSize >>> (d_A, b);
// Copia los resultados de la GPU a la CPU
cudaMemcpy(h_A, d_A, numBytes, cudaMemcpyDeviceToHost);
// Libera la memoria de v’deo
cudaFree(d_A );
C—digo en CPU para el ejemplo 2[rojo es C, verde son vars., azul es CUDA]
El proceso global de compilaci—n
83
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(..); ...}
NVCC(Open64)
Compiladorde la CPU
KernelsCUDA
Ficheros objetoCUDA
Resto delc—digo C
Ficheros objetode la CPUEnlazador
EjecutableCPU-GPU
Identificarlos kernels
CUDA y rees-cribirlos paraaprovecharparalelismo
en GPU
84
Los diferentes m—dulos de compilaci—n
NVCC
C/C++ CUDAApplication
PTX to TargetCompiler
G80 É GPU
PTX Code
C—digo CPU
C—digoobjeto
El c—digo fuente CUDA secompila con NVCC.
NVCC separa el c—digo quese ejecuta en CPU del que lohace en GPU.
La compilaci—n se realizaen dos etapas:
Virtual: Genera c—digo PTX(Parallel Thread eXecution).
F’sica: Genera el binario parauna GPU espec’fica (o inclusopara una CPU multicore).
C—digofuente
Virtual
F’sico
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 22/34
85
Compilador NVCC y m‡quina virtual PTX
EDGSepara c—digo GPU y CPU.
Open64Genera ensamblador PTX.
Parallel Thread eXecution(PTX)
M‡quina virtual e ISA.
Modelo de programaci—n.
Recursos y estado de ejecuci—n.
EDG
C/C++ CUDAApplication
CPU Code
Open64
PTX Code
ld.global.v4.f32 {$f1,$f3,$f5,$f7}, [$r9+0];mad.f32 $f1, $f5, $f3, $f1;
float4 me = gx[gtid];me.x += me.y * me.z;
NVCC (NVidia CUDA Compiler)
NVCC es un driver del compilador.Invoca a los compiladores y herramientas, como cudacc, g++,
cl, ...
NVCC produce como salida:C—digo C para la CPU, que debe luego
compilarse con el resto de la aplicaci—nutilizando otra herramienta.
C—digo objeto PTX para la GPU.
86
Proceso de compilaci—n Linux:
Proceso decompilaci—nen Windows:
87
Para conocer la utilizaci—n de los recursos
Compilar el c—digo del kernel con el flag -cubin paraconocer c—mo se est‡n usando los registros.
Alternativa on-line: nvcc --ptxas-options=-v
Abrir el archivo de texto .cubin y mirar la secci—n ÒcodeÓ.
architecture {sm_10}abiversion {0}modname {cubin}code { name = myGPUcode lmem = 0 smem = 68
reg = 20 bar = 0 bincode { 0xa0004205 0x04200780 0x40024c09 0x00200780
É
Memoria local para cada hilo(usada por el compilador para
volcar contenidos de los registrosen memoria)
Memoria compartida usadapor cada bloque de hilos
Registros usadospor cada hilo
88
CUDA Occupancy Calculator
Asesora en la selecci—n de los par‡metros de configuraci—nhttp://developer.download.nvidia.com/compute/cuda/CUDA_Occupancy_calculator.xls
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 23/34
Para alcanzar el mayor grado de paralelismo,fijarse en el ‡rea naranja del CUDA Occup.(1)
El primer dato es el nœmero de hilos por bloque:El l’mite es 1024 en las generaciones Fermi y Kepler.
Las potencias de dos son las mejores elecciones.
Lista de candidatos: 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024.
Pondremos 256 como primera estimaci—n, y el ciclo de desarrollo nosconducir‡ al valor —ptimo aqu’, aunque normalmente:
Valores peque–os [2, 4, 8, 16] no explotan el tama–o del warp ni los bancos dememoria compartida.
Valores intermedios [32, 64] comprometen la cooperaci—n entre hilos y laescalabilidad en Kepler, Maxwell y futuras generaciones de GPUs.
Valores grandes [512, 1024] nos impiden tener suficiente nœmero de bloquesconcurrentes en cada multiprocesador, ya que el m‡ximo de hilos por bloque y SMXson dos valores muy pr—ximos. Adem‡s, la cantidad de registros disponibles paracada hilo es baja.
89
Para alcanzar el mayor grado de paralelismo,fijarse en el ‡rea naranja del CUDA Occup.(2)
El segundo dato es el n¼ de registros que usa cada hilo.Esto lo obtendremos del archivo .cubin.
El l’mite es 8K (G80), 16K (GT200), 32K (Fermi), o 64K (Kepler),as’ que consumiendo 10 registros/hilo es posible ejecutar:
En G80: 768 hilos/SM, o sea, 3 bloques de 256 hilos [3*256*10=7680] (< 8192).
En Kepler: Alcanzamos el m‡ximo de 8 bloques por SMX (2048 threads/SMX):8 bloques * 256 hilos/bloque * 10 registros/hilo = 22480 regs. (< 65536 m‡x.).
En el caso de la G80, si hubiŽramos consumido 11 registros/hilo, yano podr’amos acomodar 3 bloques en el SMX, sino s—lo 2, por lo queperder’amos 1/3 del paralelismo => Habr’a que esforzarse en reducirde 11 a 10 el nœmero de registros.
90
Para alcanzar el mayor grado de paralelismo,fijarse en el ‡rea naranja del CUDA Occup.(3)
El tercer dato es el gasto de memoria compartida en cadabloque de hilos:
Esto tambiŽn lo obtenemos del archivo .cubin, aunque podemosllevar una contabilidad manual, ya que todo depende de la declaraci—nde variables __shared__ que elegimos como programador.
L’mites: 16 KB (CCC 1.x), 16/48 KB (CCC 2.x), 16/32/48 KB (CCC3.x).
Para el caso anterior sobre la G80, no gastaremos m‡s de 5 KB dememoria compartida por cada bloque para que podamos ejecutar elm‡ximo de 3 bloques en paralelo en cada multiprocesador:
3 bloques x 5 KB./bloque = 15 KB (< 16 KB.)
A partir de 5.33 KB. de memoria compartida usada por cada bloque,estamos sacrificando un 33% del paralelismo, igual que suced’a antessi no Žramos capaces de bajar a 10 registros/kernel. 91
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 24/34
93
Pasos para la construcci—ndel c—digo fuente CUDA
1. Identificar las partes del c—digo con mayor potencial parabeneficiarse del paralelismo de datos SIMD de la GPU.
2. Acotar el volumen de datos necesario para realizar dichas
computaciones.3. Transferir los datos a la GPU.
4. Hacer la llamada al kernel.
5. Establecer las sincronizaciones entre la CPU y la GPU.
6. Transferir los resultados desde la GPU a la CPU.
7. Integrarlos en las estructuras de datos de la CPU.
Se requiere cierta coordinaci—nen las tareas paralelas
El paralelismo viene expresado por los bloques e hilos.
Los hilos de un bloque pueden requerir sincronizaci—n siaparecen dependencias, ya que s—lo dentro del warp se
garantiza su progresi—n conjunta (SIMD). Ejemplo:
94
a[i] = b[i] + 7;syncthreads();x[i] = a[i-1]; // El warp 1 lee aqu’ el valor a[31],
// que debe haber sido escrito ANTES por el warp 0
En las fronteras entre kernels hay barreras impl’citas:
Kernel1 <<<nblocks,nthreads>>> (a,b,c);
Kernel2 <<<nblocks,nthreads>>> (a,b);
Bloques pueden coordinarse usando operaciones at—micas:
C—digo para GPU y su invocaci—n desde CPU
El prefijo __global__ indica que vecAdd() se ejecuta enla GPU (device) y ser‡ llamado desde la CPU (host).
A , B y C son punteros a la memoria de v’deo de la GPU, porlo que necesitamos:
Alojar/liberar memoria en GPU, usando cudaMalloc /cudaFree.
Estos punteros no pueden ser utilizados desde el c—digo de la CPU. 96
// Suma de dos vectores de tama–o N: C[1..N] = A[1..N] + B[1..N]
// Cada hilo computa un solo componente del vector resultado C __global__ void vecAdd(ßoat* A, ßoat* B, ßoat* C) { int tid = threadIdx.x + (blockDim.x* blockIdx.x); C[tid] = A[tid] + B[tid];}
C—digo GPU
int main() { // Lanza N/256 bloques de 256 hilos cada uno
vecAdd<<< N/256, 256>>>(d_A, d_B, d_C);}
C—digo CPU
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 25/34
9764
unsigned int numBytes = N * sizeof(float);
// Aloja memoria en la CPU
float* h_A = (float*) malloc(numBytes);
float* h_B = (float*) malloc(numBytes);
... inicializa h_A y h_B ...
// Aloja memoria en la GPU
float* d_A = 0; cudaMalloc((void **)&d_A, numBytes);
float* d_B = 0; cudaMalloc((void **)&d_B, numBytes);
float* d_C = 0; cudaMalloc((void **)&d_C, numBytes);
// Copiar los datos de entrada desde la CPU a la GPU
cudaMemcpy(d_A, h_A, numBytes, cudaMemcpyHostToDevice);
cudaMemcpy(d_B, h_B, numBytes, cudaMemcpyHostToDevice);
(aqu’ colocamos la llamada al kernel VecAdd de la p‡g. anterior)
// Copiar los resultados desde la GPU a la CPU
float* h_C = (float*) malloc(numBytes);
cudaMemcpy(h_C, d_C, numBytes, cudaMemcpyDeviceToHost);
// Liberar la memoria de v’deo
cudaFree(d_A); cudaFree(d_B); cudaFree(d_C);
C—digo CPU para manejar la memoria yrecoger los resultados de GPU
Ejecutando en paralelo(independientemente de la generaci—n HW)
vecAdd<<< 1, 1 >>>():Ejecuta 1 bloque de 1 hilo. Nohay paralelismo.
vecAdd<<< B, 1 >>>():Ejecuta B bloques de 1 hilo. Hayparalelismo entremultiprocesadores.
vecAdd<<< B, M >>>():Ejecuta B bloques compuestos deM hilos. Hay paralelismo entremultiprocesadores y entre loscores del multiprocesador.
98
GPUMultiprocesador 30
Multiprocesador 2
Multiprocesador 1
Memoria global
Memoria compartida
Core 1
Registros
ÉCore 2
Registros
Core 8
Registros
CachŽ de texturas
(escalabilidad en 1» gener.)
(escalabilidad en 2» y 3» gener.)
Con M hilos por bloque, un ’ndice un’voco viene dado por:
tid = threadIdx.x+ blockDim.x* blockIdx.x;
Para acceder a un vector en el que cada hilo computa unsolo elemento (queremos paralelismo de grano fino), B=4
bloques de M=8 hilos cada uno:
ÀQuŽ hilo computar‡ el vigŽsimo segundo elemento delvector?
gridDim.x es 4. blockDim.x es 8. blockIdx.x = 2. threadIdx.x = 5.
tid = 5 + (8 * 2) = 21 (al comenzar en 0, Žste es el elemento 22).
Calculando el ’ndice de acceso a un vectorsegœn el bloque y el hilo dentro del mismo
99
0
threadIdx.x threadIdx.x threadIdx.x threadIdx.x
blockIdx.x = 0 blockIdx.x = 1 blockIdx.x = 2 blockIdx.x = 3
Manejando vectores de tama–o genŽrico
Los algoritmos reales no suelen tener dimensiones quesean mœltiplos exactos de blockDim.x, as’ que debemosdesactivar los hilos que computan fuera de rango:
Y ahora, hay que incluir el bloque "incompleto" de hilosen el lanzamiento del kernel (redondeo al alza en la div.):
100
// Suma dos vectores de tama–o N: C[1..N] = A[1..N] + B[1..N] __global__ void vecAdd(ßoat* A, ßoat* B, ßoat* C, N) {
int tid = threadIdx.x + (blockDim.x * blockIdx.x);if (tid < N)
C[tid] = A[tid] + B[tid];}
vecAdd<<< (N + M-1)/256, 256>>>(d_A, d_B, d_C, N);
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 26/34
Por quŽ hemos seleccionado este c—digo
En el ejemplo anterior, los hilos a–aden complejidad sinrealizar contribuciones rese–ables.
Sin embargo, los hilos pueden hacer cosas que no est‡n al
alcance de los bloques paralelos:Comunicarse (a travŽs de la memoria compartida).
Sincronizarse (por ejemplo, para salvar los conflictos pordependencias de datos).
Para ilustrarlo, necesitamos un ejemplo m‡s sofisticado ...
102
Patr—n unidimensional (1D)
Apliquemos un patr—n 1D a un vector 1D. Al finalizar el algoritmo, cada elemento contendr‡ la suma de todos
los elementos dentro de un radio pr—ximo al elemento dado.
Por ejemplo, si el radio es 3, cada elemento agrupar‡ lasuma de 7:
De nuevo aplicamos paralelismo de grano fino, por lo quecada hilo se encargar‡ de obtener el resultado de un soloelemento del vector resultado.
Los valores del vector de entrada deben leerse varias veces:Por ejemplo, para un radio de 3, cada elemento se leer‡ 7 veces. 103
radio radio
Compartiendo datos entre hilos. Ventajas
Los hilos de un mismo bloque pueden compartir datos atravŽs de memoria compartida.
La memoria compartida es gestionada de forma expl’citapor el programador insertando el prefijo __shared__ en ladeclaraci—n de la variable.
Los datos se alojan para cada uno de los bloques.
La memoria compartida es extremadamente r‡pida:500 veces m‡s r‡pida que la memoria global (que es memoria de video GDDR5).
La diferencia es tecnol—gica: est‡tica (construida con transistores) frente a din‡mica(construida con mini-condensadores).
El programador puede ver la memoria compartida como una extensi—n del bancode registros.
Pero la memoria compartida es m‡s vers‡til que los registros, yaque Žstos son privados para cada hilo. 104
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 27/34
Compartiendo datos entre hilos. Limitaciones
El uso de los registros y la memoria compartida limita elparalelismo.
Si dejamos espacio para un segundo bloque en cada multiprocesador,el banco de registros y la memoria compartida se particionan (aunque
la ejecuci—n no es simult‡nea, el cambio de contexto es inmediato).
Ya mostramos ejemplos para Kepler anteriormente. Con unm‡ximo de 64K registros y 48 Kbytes de memoria compartidapor cada multiprocesador SMX, tenemos:
Para 2 bl. /SMX: No superar 32 Kregs. ni 24 KB. de memoria comp.
Para 3 bl. /SMX: No superar 21.33 Kregs. ni 16 KB. de memoria comp.
Para 4 bl. /SMX: No superar 16 Kregs. ni 12 KB. de memoria comp.
... y as’ sucesivamente. Usar el CUDA Occupancy Calculator paraasesorarse en la selecci—n de la configuraci—n m‡s adecuada. 105
Utilizando la memoria compartida
Pasos para cachear los datos en memoria compartida:Leer (blockDim.x + 2 * radio) elementos de entrada desde la
memoria global a la memoria compartida.
Computar blockDim.x elementos de salida.
Escribir blockDim.x elementos de salida a memoria global.
Cada bloque necesita una extensi—n de radio elementosen los extremos del vector.
106
blockDim.x elementos de salida
extensi—n porla izquierda
extensi—n porla derecha
Kernel patr—n
107
__global__ void stencil_1d(int *d_in, int *d_out,
int RADIO)
{
__shared__ int temp[BLOCK_SIZE + 2 * RADIO];
int gindex = threadIdx.x
+ blockIdx.x * blockDim.x;
int lindex = threadIdx.x + RADIO;
// Pasar los elementos a memoria compartida
temp[lindex] = d_in[gindex]; if (threadIdx.x < RADIO) {
temp[lindex-RADIO] = d_in[gindex-RADIO];
temp[lindex+BLOCK_SIZE] = d_in[gindex
+BLOCK_SIZE];
}
// Aplicar el patr—n
int result = 0;
for (int offset=-RADIO; offset<=RADIO; offset++)
result += temp[lindex + offset];
// Almacenar el resultado
d_out[gindex] = result;
}
Pero hay que prevenircondiciones de carrera. Porejemplo, el œltimo hilo lee laextensi—n antes del que elprimer hilo haya cargadoesos valores (en otro warp).Es necesaria unasincronizaci—n entre hilos.
Sincronizaci—n entre hilos
Usar __synchthreads(); para sincronizar todos los hilos deun bloque:
La barrera tiene que ser alcanzadapor todos los hilos antes de que Žstospuedan continuar.
Puede utilizarse para prevenirriesgos del tipo RAW / WAR / WAW.
En sentencias condicionales, lacodici—n debe ser uniforme a lo largode todo el bloque.
108
__global__ void stencil_1d(...) {
< Declarar variables e ’ndices>
< Pasar el vector a mem. compartida >
__synchthreads();
< Aplicar el patr—n >
< Almacenar el resultado >
}
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 28/34
Recopilando los conceptos puestosen pr‡ctica en este ejemplo
Lanzar N bloques con M hilos por bloque para ejecutar los hilosen paralelo. Emplear:
kernel<<<N,M>>>();
Acceder al ’ndice del bloque dentro de la malla y al ’ndice del hilo
dentro del bloque. Emplear:blockIdx.x y threadIdx.x;
Calcular los ’ndices globales donde cada hilo tenga que trabajaren un ‡rea de datos diferente segœn la partici—n. Emplear:
int index = threadIdx.x + blockIdx.x * blockDim.x;
Declarar el vector en memoria compartida. Emplear: __shared__ (como prefijo antecediendo al tipo de dato en la declaraci—n).
Sincronizar los hilos para prevenir los riesgos de datos. Emplear: __synchthreads();
109
C—digo en GPU para el kernel ReverseArray(1) utilizando un œnico bloque
111
__global__ void reverseArray(int *in, int *out) {
int index_in = threadIdx.x;
int index_out = blockDim.x Ð 1 Ð threadIdx.x;
// Invertir los contenidos del vector con un solo bloque
out[index_out] = in[index_in];
}
Es una soluci—n demasiado simplista: No aspira a aplicarparalelismo masivo porque el m‡ximo tama–o de bloquees 1024 hilos, con lo que Žse ser’a el mayor vector queeste c—digo podr’a aceptar como entrada.
C—digo en GPU para el kernel ReverseArray(2) con mœltiples bloques
112
__global__ void reverseArray(int *in, int *out) {
int in_offset = blockIdx.x * blockDim.x;
int out_offset = (gridDim.x Ð 1 Ð blockIdx.x) * blockDim.x;
int index_in = in_offset + threadIdx.x;
int index_out = out_offset + (blockDim.x Ð 1 Ð threadIdx.x);
// Invertir los contenidos en fragmentos de bloques enteros
out[index_out] = in[index_in];
}
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 29/34
Versi—n utilizando la memoria compartida
113
C—digo en GPU para el kernel ReverseArray(3) con mœltiples bloques y mem. compartida
114
__global__ void reverseArray(int *in, int *out) {
__shared__ int temp[BLOCK_SIZE];
int gindex = threadIdx.x + blockIdx.x * blockDim.x;
int lindex = threadIdx.x;
// Colocar los elementos de entrada en memoria compartida
temp[lindex] = in[gindex];
synchthreads();
// Invertir los elementos del vector local a cada bloque
temp[lindex] = temp[blockDim.x-lindex-1];
synchthreads();
// Invertir los contenidos en fragmentos de bloques enteros
out[threadIdx.x + ((N/blockDim.x)-blockIdx.x-1) * blockDim.x] = temp[lindex];
}
Versi—n de c—digo CPU escrita en lenguaje C
C = A * B.
Matrices cuadradas de tama–o N * N.
Linearizadas en vectores para simplificarel alojamiento de memoria din‡mica.
116
void MxMonCPU(float* A, float* B, float* C, int N);{ for (int i=0; i<N; i++) for (int j=0; j<N; j++) { float sum=0; for (int k=0; k<N; k++)
{ float a = A[i*N + k]; float b = B[k*N + j]; sum += a*b; } C[i*N + j] = sum; }}
A
B
C
N
N N
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 30/34
Versi—n CUDA para el producto de matrices:Un primer borrador para el c—digo paralelo
117
__global__ MxMonGPU(float* A, float* B, float* C, int N);{ float sum=0; int i, j; i = threadIdx.x + blockIdx.x * blockDim.x; j = threadIdx.y + blockIdx.y * blockDim.y; for (int k=0; k<N; k++){
float a = A[i*N + k]; float b = B[k*N + j]; sum += a*b; } C[i*N + j] = sum;}
A
B
C
N
N N
118
Versi—n CUDA para el producto de matrices:Descripci—n de la paralelizaci—n
Cada hilo computa un elemento de la matriz resultado C.Las matrices A y B se cargan N veces desde memoria de v’deo.
Los bloques acomodan los hilos en grupos de 1024(limitaci—n interna en arquitecturas Fermi y Kepler). As’podemos usar bloques 2D de 32x32 hilos cada uno.
N
N
N N
X=C(x, y)
Anchura A
A l t u r a A
Anchura B
AlturaA
Anchura B
C A B! ! ! ! ! ! ! ! ! ! ! ! ! ! !
! ! ! ! ! ! !! ! ! !
! ! ! !! ! ! ! ! !
! ! ! !
! ! ! !! ! ! ! ! !
! ! ! ! ! ! !! ! ! !
! ! ! !! ! ! ! ! !
! ! ! !
! ! ! !! ! ! ! ! !
MallaBloque
Hilo(x,y) dim2 dimBlock(BLOCKSIZE, BLOCKSIZE);dim2 dimGrid(AnchuraB/BLOCKSIZE, AlturaA/BLOCKSIZE);...MxMonGPU <<<dimGrid,dimBlock>>> (A, B, C, N);
A l t u r a B
Versi—n CUDA para el producto de matrices: An‡lisis
Cada hilo utiliza 10 registros, lo que nos permite alcanzarel mayor grado de paralelismo en Kepler:
2 bloques de 1024 hilos (32x32) en cada SMX. [2x1024x10 =20480 registros, que es inferior a la cota de 65536 registrosdisponibles].
Problemas:Baja intensidad aritmŽtica.
Exigente en el ancho de banda a memoria, que termina erigiŽndosecomo el cuello de botella para el rendimiento.
Soluci—n:Utilizar la memoria compartida de cada multiprocesador.
119 120
La submatriz de Csub de 32x32 datos
computada por cada bloque de hilosutiliza mosaicos de 32x32 elementos de Ay B que se alojan de forma reiterativa enmemoria compartida.
A y B se cargan s—lo (N/32) vecesdesde memoria global.
Logros:Menos exigente en el
ancho de banda a memoria.
M‡s intensidad aritmŽtica.
A
B
C
Csub
MM M M
M
M
M
M
N
N
N N
Utilizando la memoria compartida: Versi—n con mosaicos (tiling)
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 31/34
Tiling: Detalles de la implementaci—n
Tenemos que gestionar todos los mosaicos pertenecientes acada bloque de hilos:
Cargar en paralelo (contribuyen todos los hilos) los mosaicos de entrada(A y B) desde memoria global a memoria compartida. Estos mosaicos
reutilizan el espacio de memoria compartida. __syncthreads() (para asegurarnos que hemos cargado las matrices
completamente antes de comenzar la computaci—n).
Computar todos los productos y sumas para C utilizando los mosaicos dememoria compartida.
Cada hilo puede ahora iterar eficientemente sobre los elementos del mosaico.
__syncthreads() (para asegurarnos que la computaci—n con elmosaico ha acabado antes de cargar dos nuevos mosaicos para A y B en lasiguiente iteraci—n).
Transferir los resultados de C alojamos en memoria global.121
Un truco para evitar conflictos en el accesoa los bancos de memoria compartida
Recordemos algunos rasgos de CUDA:La memoria compartida consta de 16 (pre-Fermi) — 32 bancos.
Los hilos de un bloque se enumeran en orden "column major", estoes, la dimensi—n x es la que m‡s r‡pidamente var’a.
Si accedemos de la forma habitual a los vectores enmemoria compartida: shData[threadIdx.x][threadIdx.y], loshilos de un mismo warp leer‡n de la misma columna, estoes, del mismo banco en memoria compartida.
En cambio, utilizando shData[threadIdx.y][threadIdx.x],leer‡n de la misma fila, accediendo a un banco diferente.
Por tanto, los mosaicos se almacenan y acceden enmemoria compartida de forma invertida o traspuesta.
122
Tiling: El c—digo CUDA para el kernel en GPU
123
__global__ void MxMonGPU(float *A, float *B, float *C, int N){ int sum=0, tx, ty, i, j; tx = threadIdx.x; ty = threadIdx.y; i = tx + blockIdx.x * blockDim.x; j = ty + blockIdx.y * blockDim.y; __shared__ float As[32][32], float Bs[32][32];
// Recorre los mosaicos de A y B necesarios para computar la submatriz de C for (int tile=0; tile<(N/32); tile++)
{ // Carga los mosaicos (32x32) de A y B en paralelo (y de forma traspuesta)
As[ty][tx]= A[(i*N) + (ty+(tile*32))];Bs[ty][tx]= B[((tx+(tile*32))*N) + j];
__syncthreads(); // Computa los resultados para la submatriz de C
for (int k=0; k<32; k++) // Los datos tambiŽn se leer‡n de forma traspuesta sum += As[k][tx] * Bs[ty][k]; __syncthreads(); } // Escribe en paralelo todos los resultados obtenidos por el bloque C[i*N+j] = sum;}
124
Una optimizaci—n gracias al compilador:Desenrrollado de bucles (loop unrolling)
Sin desenrrollar el bucle: Desenrrollando el bucle:
... __syncthreads();
// Computar la parte de ese mosaico
for (k=0; k<32; k++) sum += As[tx][k]*Bs[k][ty];
__syncthreads();}C[indexC] = sum;
... __syncthreads();
// Computar la parte de ese mosaico
sum += As[tx][0]*Bs[0][ty]; sum += As[tx][1]*Bs[1][ty];
sum += As[tx][2]*Bs[2][ty]; sum += As[tx][3]*Bs[3][ty]; sum += As[tx][4]*Bs[4][ty]; sum += As[tx][5]*Bs[5][ty]; sum += As[tx][6]*Bs[6][ty]; sum += As[tx][7]*Bs[7][ty]; sum += As[tx][8]*Bs[8][ty];
!!!!
sum += As[tx][31]*Bs[31][ty]; __syncthreads();}C[indexC] = sum;
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 32/34
125
Rendimiento con tiling & unrolling en la G80
0
25
50
75
100
GF L OP S
4x4 8x8 12x12 16x16
Tama–o del mosaico (32x32 no es factible en la G80)
S—lo tilingTiling & Unrolling
CUDA Zone:La web b‡sica del programador CUDA
[http://developer.nvidia.com/category/zone/cuda-zone]:127
- Lenguajes (C/C++, Python).- Librer’as (cuBLAS, cuFFT).- Directivas (OpenACC).- Templates (thrust).
- Compilador (NVCC).
- Depurador (GDB).- Profiler (cudaprof y Visual).- Entorno de desarrollo (Nsight).- C—digos de ejemplo.
- Eclipse.- Matlab.- CUDA Fortran.- GPUDirect.- SDK para el compilador LLVM.
CUDA 5.5 Toolkit de descarga gratuita paratodas las plataformas y sistemas operativos
128
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 33/34
Libros sobre CUDA: Desde 2007 hasta 2013
La serie GPU Gems [http://developer.vidia.com/content/GPUGems3/gpugems3_part01.html]
Una lista de libros de CUDA en [http://www.nvidia.com/object/cuda_books.html]
129
Sep'07 Feb'10 Jul'10 Abr'11 Oct'11
Nov'11 Dic'12 Jun'13 Oct'13
Gu’as de desarrollo y otros documentos
Para iniciarse con CUDA C: La gu’a del programador.
http://docs.nvidia.com/cuda/cuda-c-programming-guide
Para optimizadores de c—digo: La gu’a con los mejores trucos.
http://docs.nvidia.com/cuda/cuda-c-best-practices-guide
La web ra’z que aglutina todos los documentos ligados a CUDA:http://docs.nvidia.com/cuda
donde encontramos, adem‡s de las gu’as anteriores, otras para:Instalar CUDA en Linux, MacOS y Windows.
Optimizar y mejorar los programas CUDA sobre plataformas Kepler.
Consultar la sintaxis del API de CUDA (runtime, driver y math).
Aprender a usar librer’as como cuBLAS, cuFFT, cuRAND, cuSPARSE, ...
Manejarse con las herramientas b‡sicas (compilador, depurador, optimizador).
130
Cursos on-line, tutoriales y webinarios
Cursos on-line de acceso gratuito:Introducci—n a la programaci—n paralela: [www.udacity.com]
Programaci—n paralela heterogŽnea: [www.coursera.org]
Los han realizado m‡s de 50.000 programadores de 127 pa’ses en losœltimos seis meses. Impartidos por reputados pedagogos:
Prof. Wen-mei W. Hwu (Univ. of Illinois). Prof. John Owens (Univ. of California at Davis).
Dr. David Luebke (Nvidia Research).
Webinarios sobre computaci—n en GPU:Listado hist—rico de charlas en v’deo (mp4/wmv) y diapositivas (PDF).
Listado de pr—ximas charlas on-line a las que poder apuntarse.[http://developer.nvidia.com/gpu-computing-webinars]
383 charlas de la GTC'13 (Graphics Technology Conference).[http://www.gputechconf.com/gtcnew/on-demand-gtc.php]
131
Desarrolladores
Para firmar como desarrollador registrado:http://developer.nvidia.com/user/register
Sitio de encuentro con otros muchos desarrolladores: http://www.gpucomputing.net
Noticias y eventos de GPGPU: http://www.gpgpu.org
Lista oficial de GPUs que soportan CUDA: http://developer.nvidia.com/cuda-gpus
Y una œltima herramienta: El CUDA Occupancy Calculatorhttp://developer.download.nvidia.com/compute/cuda/
CUDA_Occupancy_calculator.xls
132
7/24/2019 Teoria acerca de CUDA
http://slidepdf.com/reader/full/teoria-acerca-de-cuda 34/34
Muchas gracias por vuestra atenci—n
Siempre a vuestra disposici—n en elDepartamento de Arquitectura deComputadores de la Universidad de M‡laga
e-mail: [email protected]
TelŽfono: +34 952 13 28 24.
P‡gina Web: http://manuel.ujaldon.es(versiones en castellano e inglŽs).
O de forma m‡s espec’fica sobre GPUs,visita mi p‡gina Web como CUDA Fellow:
http://research.nvidia.com/users/manuel-ujaldon
133