Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
Reducción
Clase 3
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,
Integración numérica por el método de trapecios
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
yi = f(xi) � b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�yi = f(xi)
f(x)
x
y
2
Hay varias maneras de paralelizar
Dos pasos:
1. Cada thread calcula
2. Suma en CPU
Integración numérica por el método de trapecios
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�yi = f(xi)
f(x)
x
y
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
__global__voidtrapz_simple(float*x,float*data,float*integral,intN){intindex=threadIdx.x+blockIdx.x*blockDim.x;floattmp;floath;floatxi,xim,yi,yim;
//computetheaverageofthisthread'sneighbors 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;}
Método de trapecios
Este código tiene varios problemas....
prom2.cu
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
__global__voidtrapz_simple(float*x,float*data,float*integral,intN){intindex=threadIdx.x+blockIdx.x*blockDim.x;floattmp;floath;floatxi,xim,yi,yim;
//computetheaverageofthisthread'sneighbors 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;}
Método de trapecios
Qué pasa si index=0
prom2.cu
¿Porqué no funciona?
y index0 1 2 4 5 6 8 9
El thread con index=0 es un caso particular
index-1-1 0 1 3 4 5 7 8
6
__global__voidtrapz_simple(float*x,float*data,float*integral,intN){intindex=threadIdx.x+blockIdx.x*blockDim.x;floattmp;floath;floatxi,xim,yi,yim;
//computetheaverageofthisthread'sneighbors if(index>0){xi=x[index];//x_ixim=x[index-1];//x_{i-1} yi=data[index];//y_iyim=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;}}
Método de trapecios
index=0 es un caso particular
prom2.cu
__global__voidtrapz_simple(float*x,float*data,float*integral,intN){intindex=threadIdx.x+blockIdx.x*blockDim.x;floattmp;floath;floatxi,xim,yi,yim;
//computetheaverageofthisthread'sneighbors 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;}
Método de trapecios
Otra forma de hacerlo
prom.cu
Pasando opciones al mainint main( int argc, const char** argv ) { ....
if(argc==1){ // Help si no hay argumentosprintf("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;
}if(argc==3){
N = atoi(argv[1]);numthreads = atoi(argv[2]);
}
argv[0] es el nombre del exe
argc cuenta el número de argumentos
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);
Midiendo el tiempo de ejecución en GPU
En kernels cortos (como los de estas clases) puede ser necesario correrlos varias veces usando un for/while
#include <stdlib.h>#include <stdio.h>
#include "../common/curso.h"
__global__ void trapz_simple(float* x, float *data, float *integral, int N)
Manejo de errores
copiar curso.h y modificar el include de acuerdo a la organización de c/u.
Pasando opciones al main[flavioc@gpgpu-fisica ~]$ cp -a /share/apps/codigos/alumnos_icnpg2016/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
Hay varias maneras de paralelizar
Dos pasos:
1. Cada thread calcula
2. Suma en GPU
Reducción en GPU
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�yi = f(xi)
f(x)
x
y
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
Integración numérica por el método de trapecios
Reducción
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) Es un caso particular de scan, que es una transformación de una secuencia de
valores en otra prefix sum: scan donde cada elemento de la secuencia es suma de todos los
anteriores reducción: el primer elemento de prefix sum
Sequence4055055131031135PrefixSum44914141924252829293233343742Reduction42
Reducción
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) Es un caso particular de scan, que es una transformación de una secuencia de
valores en otra prefix sum: scan donde cada elemento de la secuencia es suma de todos los
anteriores reducción: el primer elemento de prefix sum
Sequence4055055131031135PrefixSum44914141924252829293233343742Reduction42
Prefix Sum: Contiguo
Values (in shared memory)
Values
Values
Values
2 0 11 0 7 2 -3 -2 5 3 -2 0 -1 8 1 10
0 1 2 3 4 5 6 7
2 2 11 11 7 9 -3 -5 5 8 -2 -2 -1 7 1 11
0 1 2 3
2 2 11 13 7 9 -3 4 5 8 -2 6 -1 7 1 18
0 1
2 2 11 13 7 9 -3 17 5 8 -2 6 -1 7 1 24
0
2 2 11 13 7 9 -3 17 5 8 -2 6 -1 7 1 41 Values
Thread IDs
Step 1 Stride 1
Step 2 Stride 2
Step 3 Stride 4
Step 4 Stride 8
Thread IDs
Thread IDs
Thread IDs
Thanks to: Stanford, CS193G
Prefix Sum: Entrelazado2 0 11 0 7 2 -3 -2 5 3 -2 0 -1 8 1 10 Values (in shared memory)
0 1 2 3 4 5 6 7
2 0 11 0 7 2 -3 -2 7 3 9 0 6 10 -2 8 Values
0 1 2 3
2 0 11 0 7 2 -3 -2 7 3 9 0 13 13 7 8 Values
0 1
2 0 11 0 7 2 -3 -2 7 3 9 0 13 13 20 21 Values
0
2 0 11 0 7 2 -3 -2 7 3 9 0 13 13 20 41 Values
Thread IDs
Step 1 Stride 8
Step 2 Stride 4
Step 3 Stride 2
Step 4 Stride 1
Thread IDs
Thread IDs
Thread IDs
Thanks to: Stanford, CS193G
Reduction/Prefix sum: integral
si sequence son los valores de mi función, prefix sum es la integral ‘indefinida’ la reducción de la secuencia es la integral que buscamos
Sequence4055055131031135PrefixSum44914141924252829293233343742
¿Cómo se hace en la GPU?
19
1. Cada thread calcula
2. Se hace la suma parcial en cada bloque
3. Cada bloque devuelve un valor a CPU
4. Se hace una última reducción en CPU
Reducción en GPU
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�yi = f(xi)
f(x)
x
y
� b
af(x)dx =
12
N�
i=1
(xi � xi�1)�yi + yi�1
�
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
4 4 0 1 3 4 5 6 7 1 2 0 7 6 5 4 3 2 0 5 1 0 1 6 3 5 1 1 1 4 5 3
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=8
4 4 0 1 3 4 5 6 7 1 2 0 7 6 5 4 3 2 0 5 1 0 1 6 3 5 1 1 1 4 5 3
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
4 4 0 1 3 4 5 6 7 1 2 0 7 6 5 4 3 2 0 5 1 0 1 6 3 5 1 1 1 4 5 3
integral
i=8
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=8
13 5 2 1 10 11 10 10 7 1 2 0 7 6 5 4 6 7 1 6 2 4 6 6 3 5 1 1 1 4 5 3
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=4
13 5 2 1 10 11 10 10 7 1 2 0 7 6 5 4 6 7 1 6 2 4 6 6 3 5 1 1 1 4 5 3
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=4
13 5 2 1 10 11 10 10 7 1 2 0 7 6 5 4 6 7 1 6 2 4 6 6 3 5 1 1 1 4 5 313 5 2 1 10 11 10 10 7 1 2 0 7 6 5 4 6 7 1 6 2 4 6 6 3 5 1 1 1 4 5 3
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=4
23 16 12 11 10 11 10 10 7 1 2 0 7 6 5 4 8 11 7 12 2 4 6 6 3 5 1 1 1 4 5 3
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=2
23 16 12 11 10 11 10 10 7 1 2 0 7 6 5 4 8 11 7 12 2 4 6 6 3 5 1 1 1 4 5 323 16 12 11 10 11 10 10 7 1 2 0 7 6 5 4 8 11 7 12 2 4 6 6 3 5 1 1 1 4 5 3
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=2
23 16 12 11 10 11 10 10 7 1 2 0 7 6 5 4 8 11 7 12 2 4 6 6 3 5 1 1 1 4 5 3
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=2
35 27 12 11 10 11 10 10 7 1 2 0 7 6 5 4 15 23 7 12 2 4 6 6 3 5 1 1 1 4 5 3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=1
35 27 12 11 10 11 10 10 7 1 2 0 7 6 5 4 15 23 7 12 2 4 6 6 3 5 1 1 1 4 5 3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=1
35 27 12 11 10 11 10 10 7 1 2 0 7 6 5 4 15 23 7 12 2 4 6 6 3 5 1 1 1 4 5 3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
intindex=threadIdx.x+blockIdx.x*blockDim.x;inttid=threadIdx.x;.....
inti=blockDim.x/2;while(i!=0){if(tid<i)integral[index]+=integral[index+i];__syncthreads();i/=2;}
Suma global en la integral por trapecios
BlockDim.x=16 GridDim=2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31index
tid
integral
i=1
62 27 12 11 10 11 10 10 7 1 2 0 7 6 5 4 38 23 7 12 2 4 6 6 3 5 1 1 1 4 5 3
Suma final en CPU
62 27 12 11 10 11 10 10 7 1 2 0 7 6 5 4 38 23 7 12 2 4 6 6 3 5 1 1 1 4 5 3
Se devuelve integral a CPU
integral
HANDLE_ERROR(cudaMemcpy(integ,d_integ,N*sizeof(float),cudaMemcpyDeviceToHost));
floatsum=0;for(inti=0;i<numblocks;i++){intj=i*numthreads;sum=sum+integ[j];}printf(“Laintegrales:%f\n”,sum);
Laintegrales:100.0
Modificar prom2.cu
1. Agregar el bloque de código que calcula la reducción en cada bloque.
2. Corregir el kernel para que el thread 0 escriba el resultado de la integral en ese bloque.
3. Corregir el main para que integral[] tenga las dimensiones correctas.
4. Corregir el main para que la reducción en cpu sea la correcta.
¡Hands On!
Modificar prom2.cu
1. Agregar el bloque de código que calcula la reducción en cada bloque.
2. Corregir el kernel para que el thread 0 escriba el resultado de la integral en ese bloque.
3. Corregir el main para que integral[] tenga las dimensiones correctas.
4. Corregir el main para que la reducción en CPU sea la correcta.
¿ Dudas ?
Su turno....