Propiedades del Device. Tipos de funciones en CUDA

Anuncio
CUDA C
Clase 2
module load cuda
• Obteniendo las propiedades del Device desde CUDA C
• Funciones en CUDA C
• Operaciones fundamentales en paralelo
Copiando los códigos
[flavioc@gpgpu-­‐fisica ~]$ ls /share/apps/codigos/alumnos_icnpg2015/ common ejemplos_thrust SUMA-­‐Vectores Get_device [flavioc@gpgpu-­‐fisica ~]$ cd icnpg2015/ [flavioc@gpgpu-­‐fisica icnpg2015]$ cp -­‐R /share/apps/codigos/alumnos_icnpg2015/Get_device/ . [flavioc@gpgpu-­‐fisica icnpg2015]$ cd Get_device [flavioc@gpgpu-­‐fisica Get_device]$ ls devicequery.cu devicequery.h main.cu Makefile submit_gpuh.sh vector_io.cu vector_io.h vector_ops.cu vector_ops.h Get device
devicequery.cu
int device_count; int driverVersion = 0, runtimeVersion = 0; cudaGetDeviceCount( &device_count ); // printf("Number of GPUs available : %d\n",device_count); cudaGetDevice(&card); cudaDeviceProp deviceProp; cudaGetDeviceProperties(&deviceProp, card); Cuenta el número de devices
cuda_runtime_api.h
cudaDeviceProp struct definido en cuda_runtime_api.h
Get/Set device
devicequery.cu
int device_count; int driverVersion = 0, runtimeVersion = 0; cudaGetDeviceCount( &device_count ); // printf("Number of GPUs available : %d\n",device_count); cudaGetDevice(&card); cudaDeviceProp deviceProp; cudaGetDeviceProperties(&deviceProp, card); Cuenta el número de devices
cuda_runtime_api.h
cudaSetDevice(int) Selecciona el Device para correr cudaGetDevice(*int) Obtiene el Device en el que se está corriendo
Generaciones de GPU
GeForce GTX 780
GeForce GTX Titan
CUDA Driver Version
CUDA Capability Major/Minor version number
Total amount of global memory
Multiprocessors x Cores/MP = Cores
Maximum number of threads per block
Maximum sizes of each dimension of a block
Maximum sizes of each dimension of a grid
7
¡Hands On!
Funciones en el device
__device__ int addem( int a, int b ) { return a + b; } __global__ void add(int a, int b, int *dc ) { *dc = addem(a,b); }
__global__ declara a add como una función que se ejecuta en el device
__device__ declara a addem como una función que se ejecuta en el device, y se llama desde el device
Los argumentos pasan por valor como en Lenguaje C
9
Funciones en CUDA C
Sólo acceden a variables en la GPU
No pueden tener número variable de argumentos
No pueden ser recursivas (__device__ functions support recursion in device code compute capability > 2.x)
No pueden contener variables estáticas
Deben declararse con un calificador: __global__, __host__ o __device__
Funciones en CUDA C
Calificador
Se ejecuta en
Se llama desde
__device__
device
device
__global__
device
host
__host__
host
host
__global__ designa una función como kernel
funciones __global__ son void
funciones __global__ necesitan una configuración de lanzamiento <<<xx,yy>>>
Las llamadas a funciones __global__ son asincrónicas, es decir que retornan antes que el device haya
completado su ejecución
CUDA Programming Guide, Appendix E
Integrales, reducción y convolución
Integración numérica por el método de trapecios
b
a
1
f(x)dx =
2
N
N
b
1
f(x)dx =
(x i
(xa i xi 1 ) yi2+ yi 1
xi
y
1)
yi + y i
y i = f( xi )
1
i=1
i=1
f(x)
La integral se calcula sumando las areas de los trapecios
La función está definida por dos arrays, x e y de tamaño N,
y i = f( xi )
b
a
b N
N
1
1
x
f(x)dx = f(x)(dx
xi = xi 1 ) (yxi i+ yxi i 11 ) yi + yi
2
a2
i=1
1
i=1
13
Integración numérica por el método de trapecios
b
a
1
f(x)dx =
2
N
N
b
1
f(x)dx =
(x i
(xa i xi 1 ) yi2+ yi 1
xi
y
1)
yi + y i
y i = f( xi )
1
i=1
i=1
f(x)
Hay varias maneras de paralelizar
Dos pasos:
1. Cada thread calcula
1
x)dx =
2
N
(x i
xi
1)
yi + y i
1
b
i=1
2. Suma en CPU
a
b N
N
1
1
x
f(x)dx = f(x)(dx
xi = xi 1 ) (yxi i+ yxi i 11 ) yi + yi
2
a2
i=1
i=1
1
Método de trapecios
prom2.cu
__global__ void trapz_simple(float* x, float *data, float *integral, int N) { int index = threadIdx.x + blockIdx.x * blockDim.x ; float tmp; float h; float xi,xim,yi,yim; // compute the average of this thread's neighbors xi = x[index]; // x_i xim = x[index-­‐1]; // x_{i-­‐1} b
yi = data[index]; // y_i yim = data[index-­‐1]; // y_{i-­‐1} a
h = xi-­‐xim; // h = x_{i}-­‐x_{i-­‐1} tmp = (yi+yim)*0.5f; // tmp = (y_i+x_{i-­‐1})/2 integral[index] = h* tmp; } 1
f(x)dx =
2
Este código tiene
varios problemas....
N
(x i
i=1
xi
1)
yi + y i
1
Método de trapecios
prom2.cu
__global__ void trapz_simple(float* x, float *data, float *integral, int N) { int index = threadIdx.x + blockIdx.x * blockDim.x ; float tmp; float h; float xi,xim,yi,yim; // compute the average of this thread's neighbors xi = x[index]; // x_i xim = x[index-­‐1]; // x_{i-­‐1} yi = data[index]; // y_i yim = data[index-­‐1]; // y_{i-­‐1} h = xi-­‐xim; // h = x_{i}-­‐x_{i-­‐1} tmp = (yi+yim)*0.5f; // tmp = (y_i+x_{i-­‐1})/2 integral[index] = h* tmp; } Qué pasa si index=0
¿Porqué no funciona?
y
-1
0
1
0
1
2
3
4
5
4
5
6
8
7
8
9
index
index-1
El thread con index=0 es un caso particular
17
Método de trapecios
prom2.cu
__global__ void trapz_simple(float* x, float *data, float *integral, int N) { int index = threadIdx.x + blockIdx.x * blockDim.x ; float tmp; float h; float xi,xim,yi,yim; // compute the average of this thread's neighbors if(index>0){ xi = x[index]; // x_i xim = x[index-­‐1]; // x_{i-­‐1} yi = data[index]; // y_i yim = data[index-­‐1]; // y_{i-­‐1} h = xi-­‐xim; // h = x_{i}-­‐x_{i-­‐1} tmp = (yi+yim)*0.5f; // tmp = (y_i+x_{i-­‐1})/2 integral[index] = h* tmp; }else{ integral[0]=0.0; } index=0 es un caso particular
Método de trapecios
prom.cu
__global__ void trapz_simple(float* x, float *data, float *integral, int N) { int index = threadIdx.x + blockIdx.x * blockDim.x ; float tmp; float h; float xi,xim,yi,yim; // compute the average of this thread's neighbors xi = x[index]; // x_i xim = x[index>0?index-­‐1:0]; // x_{i-­‐1} yi = data[index]; // y_i yim = data[index>0?index-­‐1:0]; // y_{i-­‐1} h = xi-­‐xim; // h = x_{i}-­‐x_{i-­‐1} tmp = (yi+yim)*0.5f; // tmp = (y_i+x_{i-­‐1})/2 integral[index] = h* tmp; } Otra forma de hacerlo
Pasando opciones al main
int main( int argc, const char** argv ) {
....
if(argc==1){ // Help si no hay argumentos
printf("Usage %s [array size] [number of threads per block]\n",argv[0]);
exit(1);
}
if(argc==2){ // un solo argumento implica numthreads=32
printf("Assuming number of threads per block=32\n");
N = atoi(argv[1]);
numthreads = 32;
}
argc cuenta el número de argumentos
if(argc==3){
N = atoi(argv[1]);
numthreads = atoi(argv[2]);
}
argv[0] es el nombre del exe
Pasando opciones al main
[flavioc@gpgpu-fisica ~]$ cp -a /share/apps/codigos/Trapecios .
[flavioc@gpgpu-fisica ~]$ cd Trapecios
[flavioc@gpgpu-fisica ~]$ nvcc prom2.cu -o trap
[flavioc@gpgpu-fisica ~]$ ./trap
Usage ./trap [array size] [number of threads per block]
[flavioc@gpgpu-fisica ~]$ qsub submit_gpuh.sh 1024 32
Se pueden hacer varias corridas sin compilar
Su turno....
22
Reducción en GPU
b
a
1
f(x)dx =
2
N
N
b
1
f(x)dx =
(x i
(xa i xi 1 ) yi2+ yi 1
xi
y
1)
yi + y i
y i = f( xi )
1
i=1
i=1
f(x)
Hay varias maneras de paralelizar
Dos pasos:
1. Cada thread calcula
1
x)dx =
2
N
(x i
xi
1)
yi + y i
1
b
i=1
2. Suma en GPU
a
b N
N
1
1
x
f(x)dx = f(x)(dx
xi = xi 1 ) (yxi i+ yxi i 11 ) yi + yi
2
a2
i=1
i=1
1
Reduction/Scan
Scan: una transformación de una secuencia de valores en otra
Es una de las operaciones más importantes en gpgpu
Es una operación ‘horizontal’ (ej: producto escalar) a diferencia de una operación ‘vertical’ o
componente a componente (ej: suma de vectores)
prefix sum: cada elemento de la secuencia es suma de todos los anteriores
Sequence 4 0 5 5 0 5 5 1 3 1 0 3 1 1 3 5 Scan 4 4 9 14 14 19 24 25 28 29 29 32 33 34 37 42 24
Reduction/Scan
Scan: una transformación de una secuencia de valores en otra
Es una de las operaciones más importantes en gpgpu
Es una operación ‘horizontal’ (ej: producto escalar) a diferencia de una operación ‘vertical’ o
componente a componente (ej: suma de vectores)
prefix sum: cada elemento de la secuencia es suma de todos los anteriores
Sequence 4 0 5 5 0 5 5 1 3 1 0 3 1 1 3 5 Scan 4 4 9 14 14 19 24 25 28 29 29 32 33 34 37 42 25
Prefix Sum
Algoritmo
offset = 1 4 0 5 5 0 5 5 1 3 1 0 3 1 1 3 5 offset = 2 4 4 5 10 5 5 10 6 4 4 1 3 4 2 4 8 offset = 4 4 4 9 14 10 15 15 11 14 10 5 7 5 5 8 10 offset = 8 4 4 9 14 14 19 24 25 24 25 20 18 19 15 13 17 offset = 16 4 4 9 14 14 19 24 25 28 29 29 32 33 34 37 42 26
Suma global: Entrelazada
Values (in shared memory) 10
Step 1
Stride 1
Step 2
Stride 2
Thread
IDs
0
Values
11
Thread
IDs
0
Values 18
Step 3
Stride 4
Thread
IDs
Thread
IDs
8
-1
1
1
7
0
-2
2
-1
-2
3
5
3
-2
8
5
1
1
7
-1
6
-2
-3
4
-5
2
7
5
-3
9
-2
8
5
4
0
11
6
7
2
11
0
2
7
11
2
2
3
-3
9
7
13
11
2
2
1
0
Values 24
Step 4
Stride 8
1
1
7
-1
6
-2
8
5
17
-3
9
7
13
11
2
2
1
7
-1
6
-2
8
5
17
-3
9
7
13
11
2
2
0
Values 41
Thanks to: Stanford, CS193G
Suma global: Contigua
Values (in shared memory) 10
Step 1
Stride 8
Step 2
Stride 4
Step 3
Stride 2
Step 4
Stride 1
1
8
-1
0
-2
3
5
0
1
2
3
4
5
6
7
Values
8
-2
10
6
0
9
3
Thread
IDs
0
1
2
3
Values
8
7
13
13
0
9
Thread
IDs
0
1
Values 21 20 13 13
0
0
Thread
IDs
Thread
IDs
-2
-3
2
7
0
11
0
2
7
-2
-3
2
7
0
11
0
2
3
7
-2
-3
2
7
0
11
0
2
9
3
7
-2
-3
2
7
0
11
0
2
9
3
7
-2
-3
2
7
0
11
0
2
0
Values 41 20 13 13
Thanks to: Stanford, CS193G
Reduction/Scan: integral
Si la secuencia es el vector integral[] del ejemplo prom
prefix sum es la integral ‘indefinida’ y el último elemento de la secuencia es la integral que buscamos
Sequence 4 0 5 5 0 5 5 1 3 1 0 3 1 1 3 5 Prefix Sum 4 4 9 14 14 19 24 25 28 29 29 32 33 34 37 42
¿Cómo se hace en la GPU?
29
Midiendo el tiempo de ejecución en GPU
cudaEvent_t start,stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord( start, 0 );
// llamado a Kernel/s
cudaEventRecord( stop, 0 );
cudaEventSynchronize( stop ); //Necesario
float
elapsedTime;
cudaEventElapsedTime( &elapsedTime,start, stop )); // en milisec.
printf( "Time in Kernel: %3.1f ms\n", elapsedTime);
En kernels cortos (como los de estas clases) puede ser
necesario correrlos varias veces usando un for/while
Trabajo Práctico 1
[flavioc@gpgpu-­‐fisica ~]$ ls /share/apps/codigos/TPs TP1 [flavioc@gpgpu-­‐fisica ~]$ ls /share/apps/codigos/TPs/TP1 g1ej1 g1ej2 g1ej3 g1ej4 g1ej5 [flavioc@gpgpu-­‐fisica TP1]$ cp -­‐R /share/apps/codigos/TPs/TP1 icnpg2013/ ¡Hands On!
¿ Dudas ?
Trabajo Práctico 1
http://fisica.cab.cnea.gov.ar/gpgpu/index.php/en/icnpg
Descargar