Documente Academic
Documente Profesional
Documente Cultură
CUDA
Manuel Ujaldn Martnez
Departamento de Arquitectura de Computadores Universidad de Mlaga
1. Introduccin. [14 diapositivas] 2. Arquitectura. [25] 1. El modelo hardware de CUDA. [3] 2. Las dos primeras generaciones (2006-2009). [5] 3. La tercera generacin: Fermi (2010). [12] 4. La cuarta generacin: Kepler (2012). [5] 3. Programacin. [40] 4. Sintaxis. [23] 1. Elementos bsicos. [11] 2. Algunos ejemplos. [6] 3. La librera en tiempo de ejecucin. [5]
I. Introduccin
! Respuesta del ao 2007: Se unifican los sombreadores, y sobre ellos, surge el modelo de programacin CUDA.
5
Qu es CUDA?
! En esencia, es lenguaje C con mnimas extensiones:
! El programador escribe el programa para un solo hilo (thread), y el cdigo se instancia de forma automtica sobre cientos de threads.
! CUDA define:
! Un modelo de arquitectura:
! Con multitud de unidades de proceso (cores) y una sola unidad de control (SIMD).
! Un modelo de programacin:
! Basado en el paralelismo masivo de datos y en el paralelismo de grano fino. ! Escalable: El cdigo se ejecuta sobre cualquier nmero de cores sin recompilar.
HOST
CPU
! Objetivos:
! Construir cdigo escalable a cientos de cores de forma sencilla, permitiendo declarar miles de hilos. ! Permitir computacin heterognea en CPU y GPU.
Memoria principal
9
E/S (PCIe)
GPU
DEVICE
Memoria de vdeo
10
Objetivos de CUDA
! Habilitar paralelismo masivo en GPU ejecutando programas SIMD sin las limitaciones y sobrecargas del API grfico. GPGPU ya no es cdigo OpenGL:
! Dispone de driver independiente optimizado para computacin, no especializado en renderizacin. ! Su API no posee llamadas con vrtices, texturas, polgonos, .... aunque comparte informacin con algunos buffers OpenGL.
! Sincronizacin para los hilos y la memoria compartida (para cada bloque de hilos CUDA).
! Los hilos pueden cargar datos en memoria compartida de forma cooperativa dentro de un bloque.
11 12
! El tiempo de ejecucin del cdigo no sufre una penalizacin por la sobrecarga del API grfico (DirectX/ OpenGL).
! La depuracin y optimizacin de cdigo resultan mucho ms llevaderas.
13
14
Si instalamos una arquitectura CUDA, la programacin tampoco tiene que ser CUDA
! Se soporta Windows, Linux y MacOS, y sobre ellos, herramientas de desarrollo y lenguajes de programacin plenamente consolidados:
! A partir de 2010, el abanico de opciones es ms amplio con OpenCL, Ocelot y el compilador CUDA/C++ de PGI.
15
16
2008
Agosto 08 Julio 09
2009
Nov 09
CUDA C 1.0
CUDA C 1.1
CUDA C 2.0
CUDA C 2.3
CUDA HW debugger
Doble precisin
Optimizaciones del compilador Windows Vista de 32 y 64 bits Mac OSX Texturas 3D Interpolacin por hardware
FFT en doble
precisin
17 40
18
II. Arquitectura
19
20
! Paralelismo masivo:
! Aplicado sobre miles de hilos. ! Compartiendo datos a diferentes niveles.
Core 1
Core 2
Core M
! Computacin heterognea:
! GPU:
! Intensiva en datos. ! Paralelismo de grano fino.
GT200
Procesador M
! CPU:
Memoria global
13 22
! Memoria de texturas/constantes
GPU
Multiprocesador
Registros y memoria compartida
La arquitectura en general
! Se compone de multiprocesadores dotados de 8 cores, donde los GFLOPS escalan con el nmero de cores (stream processors), y el ancho de banda escala con el nmero de controladores de memoria segn el modelo comercial:
Thread manager
G80
G92
GT200 GF100
v1.0 8 2 16 8 128 0 0 2 32
v1.1 8 2 16 8 128 0 0 2 32
v1.3 10 3 30 8 240 1 30 2 60
GDDR3
TPC
30 240 624 8 256 141
25
Modelo GeForce GTS8600 GTX9800 GTX200 Multiprocesadores Cores GFLOPS Control. de mem. Anchura del bus A. banda (GB/s) 4 32 93 2 64 32 16 128 429 4 128 70
! CCC = CUDA Compute Capabilities (describe el ritmo evolutivo). ! TPC = Thread Processing Cluster. El hardware del prop. general. ! SFU = Special Function Unit. Operadores matemticos complejos.
26
Core 1
(1.35 GHz)
Core 2
Registros
Unidad de control
(emite instrucciones SIMD) (los kernels se mapean sobre los cores)
Registros
Registros
Core 8
Core 1
(1.30 GHz)
Core 2
Registros
Unidad de control
(emite instrucciones SIMD) (los kernels se mapean sobre los cores)
Core 8
Cach de texturas
Cach de texturas
Memoria global (hasta 4 GB) (GDDR3, 512 bits @ 2x 1.1GHz = 141.7 GB/s)
28
29
30
nVidia GT200
GeForce GTX285
nVidia Fermi
Tesla C2050
32
Principales rasgos de Fermi (GF 100) The soul of a Supercomputer in the body of a GPU
DRAM I/F DRAM I/F
! Principales
DRAM I/F
Rendimiento 8 veces superior en aritmtica de punto flotante de doble precisin: A 2 GHz, proporciona 1 TFLOPS. Correccin de errores (ECC). Cachs L1 y L2 transparentes.
!!!-
La disposicin fsica de los cores y la memoria apenas ha cambiado en GF100 respecto a su predecesora, la arquitectura GT200.
El doble de ancho de banda con memoria de vdeo (GDDR5). Hasta 1 TB. de memoria de vdeo. Kernels concurrentes, C++.
33 34
!!-
La jerarqua de memoria
! Fermi es la primera GPU que ofrece una cach L1 tpica on-chip, que combina con la shared memory de CUDA en proporcin 3:1 o 1:3 para un total de 64 Kbytes por cada multiprocesador (32 cores). ! Tambin incluye una cach unificada de 768 Kbytes con coherencia de datos para el conjunto total de cores.
35
! La instruccin madd (suma y producto simultneos) est disponible tanto para simple como para doble precisin. ! La FPU (Floating-Point Unit):
! Implementa el formato IEEE-754 en su versin de 2008, aventajando incluso a las CPUs ms avezadas.
FP Unit
INT Unit
Load/Store Units x 16 Special Func Units x 4
13
36
SDT
HTS
! Ejemplo de actividad:
Kernel 0 Kernel 1
!
SDT0 SDT0
Kernel 2 Kernel 3
37
El planificador de instruccin
Ms mejoras en el front-end del procesador: GeForce 100 vs. 104 (para cada multiproc.)
! Emite 2 instrucciones a la vez, ! Emite 4 instrucciones a la vez, selecciona entre 6 cauces de ejec. selecciona entre 7 cauces de ejec.
14
39
40
GeF 104: Planificador dual combinado con superescalaridad (por primera vez en GPU)
! Recursos desequilibrados con respecto al tamao de WARP:
! 48 cores vs 32 warp size.
7.100 Mt. 15 SMX multiprocs. > 1 TFLOP FP64. 1.5 MB L2 Cache. 384-bit GDDR5. PCI Express Gen3.
43
44
La GPU es un co-procesador
CUDA en 2012
III. Programacin
Lenguajes
C, C++ DirectX Fortran Java OpenCL Python
Compiladores
PGI Fortran CAPs HMPP MCUDA MPI NOAA Fortran2C OpenMP
Aplicaciones
Oil & Gas Finance CFD
Libreras
FFT BLAS LAPACK Proc. de imgenes Proc. de vdeo Proc. de seal Visin
Consultores
ANEO
Marcas
Numerics
49
DSP
EDA
GPU Tech
50
Terminologa
! Host: La CPU y la memoria de la placa base [DDR3 en 2012]. ! Device: La tarjeta grfica [GPU + memoria de vdeo]:
! GPU: Nvidia GeForce/Tesla. ! Memoria de vdeo: GDDR5 en 2012.
Computacin heterognea
Host
Device
51 52
DEVICE CODE: parallel function HOST CODE: - serial code - parallel code - serial code
Bus PCI
void fill_ints(int *x, int n) { fill_n(x, n, 1); } int main(void) { int *in, *out; // host copies of a, b, c int *d_in, *d_out; // device copies of a, b, c int size = (N + 2*RADIUS) * sizeof(int); // Alloc space for host copies and setup values in = (int *)malloc(size); fill_ints(in, N + 2*RADIUS); out = (int *)malloc(size); fill_ints(out, N + 2*RADIUS); // Alloc space for device copies 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 result back to host cudaMemcpy(out, d_out, size, cudaMemcpyDeviceToHost); // Cleanup free(in); free(out); cudaFree(d_in); cudaFree(d_out); return 0;
53
54
PCI Bus
PCI Bus
1. Copiar los datos de entrada desde la memoria de la CPU a la memoria de la GPU. 2. Cargar el programa de la GPU y ejecutar, utilizando la memoria compartida y/o la cach para mejorar el rendimiento.
1. Copiar los datos de entrada desde la memoria de la CPU a la memoria de la GPU. 2. Cargar el programa de la GPU y ejecutar, utilizando la memoria compartida y/o la cach para mejorar el rendimiento. 3. Copiar los resultados desde la memoria de la GPU a la memoria de la CPU.
55 56
El clsico ejemplo
int main(void) { printf("Hello World!\n"); return 0; }
Es C estndar que se ejecuta en el host (la CPU). El compilador de Nvidia (nvcc) puede utilizarse para compilar programas que no contengan cdigo para alojar en GPU.
nvcc separa el cdigo fuente en dos: Host y device. De las funciones del device (ej: mykernel()) se encarga nvcc. De las funciones del host (ej: main()) se encarga el compilador de C. gcc (for UNIX), cl.exe (for Windows).
57 58
GPU Computing
OpenCL
tm
Direct Compute
Fortran
! mykernel() no hace nada en esta ocasin. ! El triple signo "<" y ">" delimita una llamadas desde el host al device, cuyos parmetros determinan el paralelismo en forma de bloques e hilos.
59
60
La evolucin de CUDA
! En los ltimos 5 aos, Nvidia ha vendido ms de 350 millones de GPUs que aceptan CUDA para su programacin. ! Pero CUDA ha evolucionado en la direccin opuesta a la que estamos acostumbrados: Desde los investigadores hasta los usuarios ms genricos.
Versin de CUDA [ao] 1.0 [2007] 2.0 [2008] 3.0 [2009] 4.0 [2011] 5.0 [2012] Usuarios Muchos investigadores y algunos usuarios madrugadores. Cientficos y aplicaciones para computacin de altas prestaciones. Lderes en la innovacin de aplicaciones. Adopcin mucho ms extensa de desarrolladores. Optimizada para Kepler y disponible pblicamente en el tercer trimestre de 2012.
61
! Objetivo del programador: Declarar miles de hilos, que la GPU necesita para lograr rendimiento y escalabilidad.
62
! 500
TSMC 40 nm.
! 250
TSMC 40 nm
3000 mill. 3000 mill. 15 32 480 1401 GDDR5 4x 924 384 bits 1.5 GB. 11 32 352 1215 GDDR5 4x 802 256 bits 1 GB.
! La memoria de vdeo puede diferir tambin cuando emerge una nueva tecnologa, como en el caso de la GDDR5. ! Los modelos difieren tambin en sus prestaciones grficas, pero aqu no estamos interesados en ellas.
1 vs. 16 648 80 80 32
1 vs. 8 700 60 60 48
1 vs. 8 607 44 44 32
1 vs. 6 675 56 56 32
1 vs. 6 675 56 56 24
! Los registros y la memoria compartida de un multiprocesador se reparten entre sus hilos activos. Para un kernel dado, el nmero de bloques activos depende de:
! El nmero de registros requeridos por el kernel. ! La memoria compartida consumida por el kernel.
65 66
Conceptos bsicos
Los programadores se enfrentan al reto de exponer el paralelismo para mltiples cores y para mltiples hilos por core. Para ello, deben usar los siguientes elementos: Device = GPU = conjunto de multiprocesadores. Multiprocesador = conjunto de cores + memoria compartida. Kernel = programa ejecutndose 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 segn su threadID y blockID. ! Pueden comunicarse a travs de la memoria compartida del multiprocesador.
Impacto
! ! ! ! !
Escalabilidad Escalabilidad Throughput Throughput Paralelismo Paralelismo Working set Working set
68
WARPs. Concepto
Registros Memoria compartida
Asignacin a un multiproc.
! Los hilos se asignan a los multiprocesadores en bloques, que constituyen la unidad de asignacin de hilos. ! Cada multiprocesador puede tener hasta 8 bloques y cada bloque hasta 512, 512 o 1024 hilos. En total, caben un mximo de 768, 1024 o 1536 hilos en cada multiprocesador. ! Los hilos de un bloque comparten informacin a travs de memoria compartida, y se sincronizan mediante barreras.
! Cada bloque activo se descompone en WARPs o grupos de 32 hilos con ID correlativo que se ejecutan usando tiempo compartido en un multiprocesador. ! Los hilos de un WARP se ejecutan fsicamente en paralelo. ! Los WARPs y los bloques se ejecutan lgicamente en paralelo.
Bloque (0, 1)
Bloque (1, 1)
Bloque (2, 1)
Grid 2
...
32 hilos
Multiproc.
32 hilos 32 hilos
Hilo (0, 0)
Hilo (31, 0)
Hilo (32, 0)
Warp 1
Hilo (63, 0)
Bloque de hilos
Warps
16 16
Hilo (0, 1)
Warp 2
Hilo (31,
Hilo (32, 1)
Warp 3
Hilo (63,
DRAM
Hilo (0, 2)
69
Warp 4
Hilo (31, 2)
Hilo (32, 2)
Warp 5
Hilo (63, 2)
70
WARPs. Ejecucin
! Dado que el tamao del WARP es de 32 hilos:
! Si hay 8 procesadores en cada multiprocesador (como en las series 8, 9 y 10 de GeForce), cada WARP de una instruccin consume 4 ciclos de reloj en su ejecucin. ! Si hay 32 procesadores en cada multiprocesador (a partir de Fermi), cada WARP de una instruccin consume un solo ciclo.
Warp j (32 hilos) Instruccin x de warp j Bsqueda de instruccin L1 datos Registros
t0 t1 t2 t31
Multiprocesador streaming
Cach L1 de instrs. Cach L1 de datos
Bi
Memoria compartida Core Core Core Core SFU SFU Core Core Core Core
71
72
WARPs. Planificacin
Un ejemplo ideal sobre la G80 (en la prctica, la ejecucin del WARP no es tan uniforme como ilustramos aqu - esto se ver mejor dos diapositivas ms tarde):
Multiprocesador
Planificador de WARPS del multiprocesador tiempo warp 8 instruccin 11 warp 1 instruccin 42 warp 3 instruccin 95 . . . warp 8 instruccin 12 warp 3 instruccin 96
74
Warp 5 Instr. 10
Warp 23 Instr. 17
Warp 5 Instr. 11
Warp 12 Instr. 3
Warp 12 Instr. 4
Warp 11 Instr. 8
Warp 15 Instr. 1
ciclos
! Round-robin/aging para seleccionar el prximo WARP a planificar de entre aquellos con operandos ya ledos. ! Scoreboarding para evitar riesgos en el anlisis de dependencias.
! El cambio de contexto entre WARPs de un multiprocesador se lleva a cabo sin penalidad en ciclos de ejecucin.
Grid
Bloque (0, 0)
Memoria compartida
Bloque (1, 0)
Memoria compartida
Regs
Regs
Regs
Regs
Hilo (0, 0)
Hilo (1, 0)
Hilo (0, 0)
Hilo (1, 0)
Memoria global
76
Escalabilidad transparente
! Dado que los bloques de hilos no pueden sincronizarse:
! El hardware tiene libertad para acomodar su ejecucin en cualquier multiprocesador en cualquier instante. ! Pueden correr secuencial o concurrentemente, y cualquier permutacin en su ejecucin paralela debe ser vlida.
Device Kernel grid Bloque 0 Bloque 1 Bloque 2 Bloque 3 Bloque 0 Bloque 1 Bloque 4 Bloque 5 Bloque 6 Bloque 7 Bloque 2 Bloque 3 Bloque 4 Bloque 5 Bloque 6 Bloque 7 Bloque 0 Bloque 1 Bloque 2 Bloque 3 Device
6 7
threadID
Bloque 4
Bloque 5
! Un kernel puede ejecutarse sobre cualquier nmero de multiprocesadores. ! El lanzamiento de un kernel sirve como punto de sincronizacin para los bloques.
Bloque 6
Bloque 7
77
78
! El bloque garantiza rendimiento y escalabilidad, ya que permite replicar la ejecucin de un grupo de hilos tantas veces como sea necesario en funcin del volumen de datos:
! Permitiendo mantener el paralelismo de grano fino. ! Sin penalidad, ya que el cambio de contexto es gratis.
Bloque de hilos 0
threadID
0 1 2 3 4 5 6 7
Bloque de hilos 1
0 1 2 3 4 5 6 7
! Un kernel se ejecuta como una malla o grid 1D o 2D de bloques de hebras 1D, 2D o 3D. ! Los hilos y los bloques tienen IDs para que cada hilo pueda acotar sobre qu datos trabaja, y simplificar el dir. a memoria al procesar datos multidim.
79
Bloque (1, 1)
Hilo Hilo (0, 0) (1, 0) Hilo (2, 0) Hilo Hilo (3, 0) (4, 0)
Hilo Hilo Hilo Hilo Hilo (0, 1) (1, 1) (2, 1) (3, 1) (4, 1) Hilo Hilo Hilo Hilo Hilo (0, 2) (1, 2) (2, 2) (3, 2) (4, 2)
80
Manipulacin de datos
! Una de las diferencias ms importantes entre CPU y GPU (y una de las claves para que la GPU se acerque a su rendimiento pico). ! La cach es 1000 veces menor en la GPU, por lo que los programadores deben gestionar la localidad de acceso a los datos con mucho esmero: ! La memoria local aloja a las variables de la GPU declaradas sin prefijo. ! Los registros albergan a escalares y resultados parciales. ! La memoria de vdeo (global) aloja a los vectores de datos.
Memoria Ubicacin Cach Local Compartida Global Constantes De texturas Acceso mbito Prefijo Vigencia
Integrada en la GPU
! Los hilos pueden compartir el espacio de memoria compartida para comunicarse entre ellos.
!!! Grid 0 !!! !!! Grid 1 !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!!
Memoria Memoria para global (lectura y constantes (lectura) escritura) Memoria para texturas (lectura)
No No S S
Lect./escr.
Un hilo
Lect./escr. Hilos de un bloque Lect./escr. Los hilos y la CPU Lectura Lectura Los hilos y la CPU
! El nivel de memoria global es el nico visible a todos los entes definidos por el programador (hilos, bloques, kernels y grids).
82
83
84
Hilo (0, 0)
Hilo (1, 0)
Hilo (0, 0)
Hilo (1, 0)
Memoria local
Memoria local
Memoria local
Memoria local
! La CPU puede:
! Leer/escribir en memoria CPU (host) global, de constantes y de texturas (mapeadas sobre DRAM)
Memoria global
Memoria de constantes Memoria de texturas
85
! El ancho de banda entre memoria global (la de la tarjeta grfica) y los procesadores puede saturarse fcilmente. Las tareas que tienen un bajo ndice de reutilizacin de datos se quedan hambrientas. Ej: Suma vector-escalar, producto de vectores. ! Limitada capacidad del banco de registros y la memoria compartida que comparten todos los hilos de un multiprocesador. Utilizar el CUDA Occupancy Calculator para ayudarse en la toma de decisiones. ! Los saltos condicionales degradan notablemente el rendimiento si no se estructuran de forma sabia.
86
IV. Sintaxis
88
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]; Cdigo C estndar } // Invocar al kernel SAXPY secuencial saxpy_serial(n, 2.0, x, y);
// Alojar memoria en la GPU void *myimage; cudaMalloc(&myimage, bytes); // 100 bloques de hilos, 10 hilos por bloque convolve<<<100, 10>>> (myimage);
91
92
Ejecucin
! BlockIdx: vector (1D o 2D) que identifica el bloque dentro del grid.
blockDim.y
Grid de bloques
Un kernel no comienza su ejecucin en GPU hasta que no hayan finalizado todas las llamadas CUDA anteriores.
94
! uint3 blockIdx; // Indice del bloque dentro de la malla ! uint3 threadIdx; // Indice del hilo dentro del bloque ! void __syncthreads(); // Sincronizacin entre threads
! Para conocer los recursos disponibles en la GPU dev (cach, registros, frecuencia de reloj, ...):
! cudaGetDeviceProperties(struct cudaDeviceProp* prop, int dev);
El programador debe elegir el tamao del bloque y el nmero de bloques para explotar al mximo el paralelismo del cdigo durante su ejecucin.
97
99
! El prefijo h_ suele usarse para punteros en memoria principal. Idem d_ para punteros en mem. de vdeo.
100
! 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.
101
102
Ejemplo 1: Implementacin
int main() { int N = 16; int num_bytes = N*sizeof(int); int *d_a=0, *h_a=0; h_a = (int*) malloc(num_bytes); cudaMalloc( (void**)&d_a, num_bytes); if( 0==h_a || 0==d_a ) printf("No pude alojar la 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); }
! A partir de CUDA Compute Capabilities 1.2 es posible utilizar la variante cudaMemcpyAsync(), cuyas diferencias son las siguientes:
! El retorno a la CPU tiene lugar de forma inmediata. ! Podemos solapar comunicacin y computacin. ! En la seccin de optimizaciones pondremos un ejemplo basado en streams.
103 104
void increment_cpu(float *a, float b, int N) { for (int idx = 0; idx<N; idx++) a[idx] = a[idx] + b; }
void main() { .. dim3 dimBlock (blocksize); dim3 dimGrid( ceil( N / (float)blocksize) ); increment_gpu<<<dimGrid, dimBlock>>>(a, b, N); } 62
105
int idx = (blockId.x * blockDim.x) + threadIdx.x; Se mapear del ndice local threadIdx al ndice global
Nota: blockDim debera ser >= 32 (warp size) en cdigo real, esto es slo un ejemplo
63
106
Cdigo en CPU para el ejemplo 2 (azul es C, verde es CUDA, rojo son vars.)
// 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. B es es nmero de bloques increment_gpu <<< N/blockSize, blockSize >>> (d_A, b); // copia los datos de regreso a la CPU cudaMemcpy(h_A, d_A, numBytes, cudaMemcpyDeviceToHost); // libera la memoria de vdeo cudaFree(d_A);
64
107
108
! Tipos de datos basados en uint3 para especificar dimensiones: dim3 ! Un subconjunto de la librera runtime C soportada en los cdigos tanto de la CPU como de la GPU para los tipos de datos escalares:
! pow, sqrt, cbrt, hypot. ! exp, exp2, expm1, log, log2, log10, log1p. ! sin, asin, sinh, asinh, cos, acos, cosh, acosh, tan, atan, tanh, atanh. ! ceil, floor, trunc, round.
109
110
V. Compilacin
! Vertex Buffer Objects y Pixel Buffer Objects, tanto de OpenGL como de Direct3D, pueden mapearse sobre el espacio de direcciones de CUDA, y luego se manejan como memoria global en el cdigo de la GPU. ! Los datos de una imagen alojados en Pixel Buffer Objects pueden mostrarse con glDrawPixels/glTexImage2D.
113
114
El proceso global
V. 1. El proceso de compilacin
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
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
115 116
! EDG
NVCC Cdigo CPU EDG PTX Code CPU Code
! Open64
! Genera ensamblador PTX.
Virtual
Fsico
PTX to Target
Compiler
Cdigo objeto
ld.global.v4.f32 mad.f32
117
Compilation process in Linux: ! Cdigo C para la CPU, que debe luego compilarse con el resto de la aplicacin utilizando otra herramienta. ! Cdigo objeto PTX para la GPU.
119
120
Ocelot http://code.google.com/p/gpuocelot
! Entorno de compilacin dinmico para el cdigo PTX sobre sistemas heterogneos que aporta:
! Otras plataformas. ! Anlisis del PTX. !
! En su versin 2.0 de Febrero de 2011 permite que los programas CUDA puedan ejecutarse sobre:
121
122
Swan http://www.multiscalelab.org/swan
! Es un traductor fuente-a-fuente de cdigo CUDA a OpenCL:
! Proporciona un API comn que abstrae los soportes en tiempo de ejecucin de CUDA y OpenCL. ! Preserva la comodidad de los lanzamientos de los kernels en CUDA (<<<grid,block>>>) generando cdigo fuente C para las funciones de puntos de entrada a los kernels. ! ... pero el proceso de conversin no es automtico y requiere de intervencin humana.
MCUDA http://impact.crhc.illinois.edu/mcuda.php
! Desarrollado por el grupo de investigacin IMPACT de la Universidad de Illinois. ! Es un entorno de trabajo basado en Linux que trata de portar eficientemente cdigos CUDA a arquitecturas CPU. ! Est disponible para su descarga gratuita... ... pero no parece que la Web est actualizada de forma continua.
123 124
! Principales ventajas:
! Velocidad: El cdigo compilado es capaz de ejecutarse en una plataforma x86 que incluso no disponga de GPU. Esto otorga al compilador la facultad de vectorizar el cdigo para instrucciones SSE de 128 bits o sus sucesoras AVX de 256 bits. ! Transparencia: Incluso aquellas aplicaciones que utilizan recursos nativos de la GPU como las unidades de texturas tendrn un comportamiento idntico en CPU y GPU.
OpenACC (cont.)
! Las directivas proporcionan una base de cdigo comn
! Multi plataforma. ! Multi firma comercial.
! Objetivo: Orientado a un programador medio, el cdigo es portable a otros aceleradores, e incluso CPUs multicore. ! Primeros desarrollos y difusin comercial a cargo de:
! Portland Group (PGI). ! Cray.
! Esto abre un camino ideal para preservar la inversin en aplicaciones heredadas, permitiendo una fcil migracin hacia la computacin acelerada. ! La cuestin clave es Cunto rendimiento sacrificamos?
! Los primeros informes indican 5-10% respecto a CUDA en algunos casos. ! Otras aplicaciones han logrado una ganancia de 5x invirtiendo nicamente el tiempo de una semana o incluso un solo da.
El ltimo paso dado por nVidia para facilitar la interrelacin de CUDA: Abrir el compilador
! Al liberar el cdigo fuente (Dic11), resulta muy cmodo y eficiente conectar con otros lenguajes por encima y arquitecturas por debajo.
129
130
131
15
132
136
Cargas y almacenamientos locales Nmero total de bifurcaciones (branches) y bifurcaciones divergentes tomadas por los hilos
! Los valores se utilizan principalmente para cuantificar la mejora de rendimiento producida por una versin optimizada del cdigo.
! Se trata de reducir gld/gst_incoherent, divergent_branch y warp_serialize.
137 138
! instructions cuenta del nmero de instrucciones ejecutadas. ! warp_serialize warps de hilos que se han sido secuencializados por los conflictos de direccionamiento a la memoria compartida o a la memoria de constantes. ! cta_launched bloques de hilos que han sido ejecutados.
Vdeo ilustrativo del uso del CUDA Visual Profiler (4 min. 34 seg.)
! Se bloquean las instrucciones que presentan dependencias en el mismo hilo, pero no las que se encuentran en otros hilos. ! Para ocultar esta latencia, debemos ejecutar tantos hilos por multiprocesador como sea posible, eligiendo los parmetros de ejecucin que maximicen:
ocupacin = (n warps activos)/(mx. n warps activos)
139
Nota: El mximo n de warps activos en las series 8, 9 y 10 de GeForce es de 24, y en Fermi es de 48.
140
! Los recursos por bloque (registros y memoria compartida) deben ser al menos la mitad del total disponible.
! De lo contrario, resulta mejor fusionar bloques.
Para alcanzar el mayor grado de paralelismo, fijarse en el rea naranja del CUDA Occup.
! El primer dato es el nmero de hilos por bloque:
! Pondremos 256 como primer valor estimativo. ! El lmite oscila entre 512 y 1024 segn la arquitectura.
Para alcanzar el mayor grado de paralelismo, fijarse en el rea naranja del CUDA Occup.
! El tercer dato es el gasto de memoria compartida en cada bloque de hilos:
! Esto tambin lo obtenemos del archivo .cubin, aunque podemos llevar una contabilidad manual, ya que todo depende de la declaracin de variables __shared__ elegida por nosotros. ! El lmite es de 16 KB., y en Fermi, podemos escoger tambin 48 KB. ! Para el caso anterior sobre la G80, no gastaremos ms de 5 KB de memoria compartida por cada bloque para que podamos ejecutar el mximo de 3 bloques en paralelo en cada multiprocesador:
! 3 x 5 KB. = 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 suceda antes si no ramos capaces de bajar a 10 registros/kernel.
149 150
! Ejemplo 2 (el caso complejo). Notar que las dos ltimas sentencias no suponen solape adicional:
cudaStreamCreate(&stream1); cudaStreamCreate(&stream2); cudaMemcpyAsync(dst, src, size, dir, stream1); kernel<<<grid, block, 0, stream2>>>(); cudaMemcpyAsync(dst2, src2, size, stream2); cudaStreamQuery(stream2);
solape
solape
152
! Si se quiere aumentar el ancho de banda, usar memoria pinned (sin abusar), que aprovecha mejor PCI-express (3.2 GB/s. en v1.0 y 5.2 GB/s. en v2.0, hasta 4 y 8 GB/s. si usamos el chipset nForce 680i).
! Pasar algunas funciones de CPU a GPU aunque no puedan explotar mucho paralelismo
! Si eso evita un doble trasiego de datos de GPU a CPU y regreso.
153
154
! Ejemplo: ! Para ejecutar nuestro kernel bajo una config. Fermi de 16 KB de shared:
cudaFuncSetCacheCong (mykernel, cudaFuncCachePreferL1);
! Recordar que:
! Procesar datos es ms rpido que moverlos, ya que las GPUs dedican muchos ms transistores a las ALUs que a la memoria. ! Cuanto menos ahogado se encuentre un kernel por el acceso a memoria, mejor se comportar en las futuras arquitecturas GPU.
157 158
Bibliografa
! GPU Gems, Gems 2 y Gems 3. ! CUDA Programming Guide. Las bases de CUDA. ! CUDA Best Practices Guide. Para optimizar cdigo. ! CUDA Zone (http://www.nvidia.com/cuda).
! Los cdigos que se han desarrollado en CUDA junto a los factores de aceleracin logrados. ! Los artculos de investigacin que describen las aplicaciones y su implementacin. ! Tutoriales, forums, cursos de programacin paralela, ...
Herramientas software
! CUDA Toolkit, ya en su versin 3.0 para Fermi.
! Compilador nvcc, libreras y documentacin. ! Implementaciones disponibles para Linux, MacOS y Windows 7.
! CUDA SDK:
! Scripts de compilacin y algunas utilidades. ! Cdigos de ejemplo y whitepapers.
! GPGPU: El movimiento originario de la programacin de propsito general sobre la GPU que desde 2003 aglutina las novedades ms interesantes. http:///www.gpgpu.org
159
! CUDA Occupancy Calculator. ! CUDA Profiler: Analiza tiempos de ejecucin, accesos coalesced a memoria, warp divergentes, conflictos en el acceso a memoria compartida, ... ! nVidia Parallel Nsight: Entorno de desarrollo integrado en Visual Studio.
160
161