introducción a cudadada una señal discreta x[n] y un flitro h[n], la convolución se define como:...

70
Introducción a CUDA

Upload: others

Post on 28-Mar-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Introducción a CUDA

Page 2: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Ejemplo: convolución 1D

● Dada una señal discreta x[n] y un flitro h[n], la convolución

se define como:

– Considerar un array x de números reales de tamaño N que representa la señal en un dominio discreto y un array h de tamaño M que describe el filtro h, M << N.

La convolución es un operador matemático que transforma dos funciones f y g en una tercera función que en cierto sentido representa la magnitud en la que se superponen f y una versión trasladada e invertida de g

Page 3: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

h0 h1 hM-1…

…x1 x2xN-1

Page 4: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

…x1 x2xN-1

* * * * *

Page 5: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

…x1 x2xN-1

* * * * *

Page 6: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

…x1 x2xN-1

* * * * *

y

y0

Page 7: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

…x1 x2xN-1

* * * * *

y

y0

Page 8: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

…x1 x2xN-1

* * * * *

y

y0 y1

Page 9: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

…x1 x2xN-1

* * * * *

y

y0 y1

Page 10: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

…x1 x2xN-1

* * * * *

y

y0 y1 y2

Page 11: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo se calcula la convolución?

x

x0

h

…x1 x2xN-1

* * * * *

y

y0 …y1 y2yN-1

Page 12: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Correlación (o convolución) 1D

/* convolucion en la cpu: requiere dos loops … */void conv_cpu(float *input, float *output, float *filter) {

float temp;for(int j = 0; j < N; j++){

temp=0.0;for(int i = 0; i < M; i++){

temp += filter[i]*input[i+j];}output[j] = temp;

}}

Versión secuencial simple

Ojo...

Page 13: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Correlación (o convolución) 1D

/* convolucion en la cpu: requiere dos loops … */void conv_cpu(float *input, float *output, float *filter) {

float temp;for(int j = 0; j < N; j++){

temp=0.0;for(int i = 0;i < M; i++){

temp += filter[i]*input[i+j];}output[j] = temp;

}}

Versión secuencial simple

Ojo...

Complejidad computacional cuadrática: O(NxM)

Page 14: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

Tiene orden de complejidad cuadrático, al aumentar el número de elementos aumenta cuadráticamente la cantidad de operaciones.

Page 15: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

void conv_gpu(const FLOAT* d_input, FLOAT* d_output, const FLOAT* d_filter) {

}

Convolución 1D

/* convolucion en la cpu: requiere dos loops … */void conv_cpu(const FLOAT* input, FLOAT* output, const FLOAT* filter) {

FLOAT temp;for(int j = 0; j < N;j++){

temp=0.0;for(int i = 0; i < M; i++){

temp += filter[i]*input[i+j];}output[j] = temp;

}}

Versión simple serial

¿ Versión paralela ?

¿....?

Ojo...

Page 16: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo sería una solución paralela?

Se puede paralelizar convolución→ el cálculo de cada elemento de la señal resultante es independiente de los demás elementos de la señal:

x

x0

h

…x1 x2xN-1

* * * * *

y

y0 …y1 y2yN-1

Cada sumatoria se puede realizaren paralelo!!

Page 17: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

● ¿Cómo sería una solución paralela?

Se puede paralelizar convolución→ el cálculo de cada elemento de la señal resultante es independiente de los demás elementos de la señal:

x

h

* * * * *

y…

Cada sumatoria se puede realizar

en paralelo!!

Si en vez de un único procesador disponemos P procesadores, dividimos los cálculos entre los P procesadores.

Si contamos con N procesadores, realizamos todos los cálculos al mismo tiempo.

De orden lineal a orden constante

Y se resuelve en paralelo todos losresultados del vector.

Page 18: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Entonces...

Tengo una PC re linda...

Tengo una GPU que me dicen que es re linda...

Tengo una convolución...

¿¿Cómo utilizo estas arquitecturas para solucionar

mi problema??

x

h…

Page 19: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

CUDA (Compute Unified Device Architecture)

En Noviembre de 2006 NVIDIA introduce CUDA que hace referencia tanto a un compilador como a un conjunto de

herramientas de desarrollo creadas por NVIDIA.

CUDA es una arquitectura de software y hardware que permite a GPUs ejecutar programas escritos en C, C++,

Fortran, DirectCompute y otros lenguajes.

Page 20: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

CUDA (Compute Unified Device Architecture)

Un programa CUDA es un programa híbrido: – Código secuencial → se ejecuta en CPU

– Código paralelo → se ejecuta en GPU

Page 21: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

CUDA (Compute Unified Device Architecture)

Un programa CUDA es un programa híbrido: – Código secuencial → se ejecuta en CPU

– Código paralelo → se ejecuta en GPU

Código secuencialInicializaciones

Lectura de datos de entrada

Código paralelo

Código secuencialMuestra de resultados

Almacenamiento de resultados

….

….

Modelo SIMD - SIMT

Page 22: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

CUDA ● Cómo es la parte paralela de la aplicación?

● Un programa CUDA invoca a funciones paralelas

llamadas kernels. En CUDA: Kernel = función.● Un kernel se ejecuta en paralelo a

través threads paralelos.

Page 23: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

CUDA ● Cómo es la parte paralela de la aplicación?

El programador decide:

“el kernel A será ejecutado por n threads”

● Un programa CUDA invoca a funciones paralelas

llamadas kernels. En CUDA: Kernel = función.● Un kernel se ejecuta en paralelo a

través threads paralelos.

x

h

y…

=

Con n threads que cada uno calculeun elemento del vector resultante, consigo ejecutar la convolución muchomás rápido!!

Page 24: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

CUDA

● Un programa CUDA invoca a kernels paralelos. ● Un kernel se ejecuta en paralelo a través threads paralelos.

Múltiples threads ejecutandoel mismo kernel.

X

h

y…

* * *

=

Page 25: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

CUDA

● Tenemos programas CUDA híbridos, que se ejecutan en CPU y GPU.

● Tenemos dos arquitecturas que se conectan mediante un conector PCI-Express (no comparten espacio de direccionamiento)

Page 26: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolucion 1D

¿Cómo lo hacemos con CUDA? ● Este problema ahora implica:

– Inicialización de arreglos en CPU

– Transferencia de datos CPU → GPU

Page 27: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

¿Cómo lo hacemos con CUDA? ● Este problema ahora implica:

– Inicialización de arreglos en CPU

– Transferencia de datos CPU → GPU

– Cálculo de la convolución en paralelo.

Page 28: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

¿Cómo lo hacemos con CUDA? ● Este problema ahora implica:

– Inicialización de arreglos en CPU

– Transferencia de datos CPU → GPU

– Cálculo de la convolución en paralelo.

– Transferencia de datos GPU → CPU.

Page 29: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

¿Cómo lo hacemos con CUDA? ● Este problema ahora implica:

– Inicialización de arreglos en CPU

– Transferencia de datos CPU → GPU

– Cálculo en GPU.

– Transferencia de datos GPU → CPU.

Modelo de programación

CUDA

Page 30: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Modelo de programación CUDA

CUDA extiende al lenguaje C/C++ incluyendo dos característicasprincipales:

- Organización y manejo de threads concurrentes.

- Manejo de jerarquía de memorias instaladas en la GPU.

Page 31: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

● Jerarquía de threads:– thread,

CUDA extiende al lenguaje C/C++ incluyendo dos característicasprincipales:

- Organización y manejo de threads concurrentes.

thread

Page 32: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

● Jerarquía de threads:– thread,

– bloque,

CUDA extiende al lenguaje C/C++ incluyendo dos característicasprincipales:

- organización y manejo de threads concurrentes.

thread

bloque 1, 2 o 3 dimensiones

Page 33: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

● Jerarquía de threads:– thread,

– bloque

– grilla.

CUDA extiende al lenguaje C/C++ incluyendo dos característicasprincipales:

- organización y manejo de threads concurrentes.

thread

bloque

grilla

1, 2 o 3 dimensiones

1, 2 o 3 dimensiones

Grid 1

Block (0,0)

Block (2,0)

Block (1,0)

Block (0,0)

Block (1,0)

Grid 2

Block (0,1)

Block (1,1)

grilla

Page 34: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

CUDA extiende al lenguaje C/C++ incluyendo dos característicasprincipales:

- Manejo de memorias instaladas en la GPU

Grid 1

Block (0,0)

Block (2,0)

Block (1,0)

Block (0,0)

Block (1,0)

Grid 2

Block (0,1)

Block (1,1)

Memoria global

Page 35: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

conv.cu: Convolución 1D. Código que se ejecuta en host.

*/

conv.cu

int main(){ /* alocacion de memoria en host */ float *h_input = (float *) malloc((N+M) * sizeof(float)); float *h_filter = (float *) malloc(M * sizeof(float)); float *h_output = (float *) malloc(N * sizeof(float));

/* alocacion de memoria en device */ float *d_input, *d_filter, *d_output; cudaMalloc((void**)&d_input, sizeof(float) * (N+M)); cudaMalloc((void**)&d_filter, sizeof(float) * M); cudaMalloc((void**)&d_output, sizeof(float) * N);

/* chequeo de alocacion de memoria */ if (!h_input || !h_filter || !h_output || !d_input || !d_filter || !d_output) { printf("Error alocando arreglos \n"); exit(-1); }

Page 36: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

conv.cu: Convolución 1D. Código que se ejecuta en host.

*/

conv.cu

int main(){ /* alocacion de memoria en host */ float *h_input = (float *) malloc((N+M) * sizeof(float)); float *h_filter = (float *) malloc(M * sizeof(float)); float *h_output = (float *) malloc(N * sizeof(float));

/* alocacion de memoria en device */ float *d_input, *d_filter, *d_output; cudaMalloc((void**)&d_input, sizeof(float) * (N+M)); cudaMalloc((void**)&d_filter, sizeof(float) * M); cudaMalloc((void**)&d_output, sizeof(float) * N);

/* chequeo de alocacion de memoria */ if (!h_input || !h_filter || !h_output || !d_input || !d_filter || !d_output) { printf("Error alocando arreglos \n"); exit(-1); }

Alocación de memoria dinámica en host

Page 37: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

conv.cu: Convolución 1D. Código que se ejecuta en host.

*/

conv.cu

int main(){ /* alocacion de memoria en host */ float *h_input = (float *) malloc((N+M) * sizeof(float)); float *h_filter = (float *) malloc(M * sizeof(float)); float *h_output = (float *) malloc(N) * sizeof(float));

/* alocacion de memoria en device */ float *d_input, *d_filter, *d_output; cudaMalloc((void**)&d_input, sizeof(float) * (N+M)); cudaMalloc((void**)&d_filter, sizeof(float) * M); cudaMalloc((void**)&d_output, sizeof(float) * N);

/* chequeo de alocacion de memoria */ if (!h_input || !h_filter || !h_output || !d_input || !d_filter || !d_output) { printf("Error alocando arreglos \n"); exit(-1); }

Alocación de memoria dinámica en device

Alocación en memoria globaldel device. Arreglos apuntadospor d_input, d_output y d_filter (punteros en host).

Page 38: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

conv.cu: Convolución 1D. Código que se ejecuta en host.

*/

conv.cu

int main(){ /* alocacion de memoria en host */ float *h_input = (float *) malloc((N+M) * sizeof(float)); float *h_filter = (float *) malloc(M * sizeof(float)); float *h_output = (float *) malloc(N * sizeof(float));

/* alocacion de memoria en device */ float *d_input, *d_filter, *d_output; cudaMalloc((void**)&d_input, sizeof(float) * (N+M)); cudaMalloc((void**)&d_filter, sizeof(float) * M); cudaMalloc((void**)&d_output, sizeof(float) * N);

/* chequeo de alocacion de memoria */ if (!h_input || !h_filter || !h_output || !d_input || !d_filter || !d_output) { printf("Error alocando arreglos \n"); exit(-1); }

Page 39: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < N+M ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

Page 40: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

CPU

Memoriaprincipal

GPU

Memoriaglobal

I/O

Page 41: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

CPU

Memoriaprincipal

GPU

Memoriaglobal

I/O

Page 42: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

CPU

Memoriaprincipal

GPU

Memoriaglobal

I/O

Page 43: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

CPU

Memoriaprincipal

GPU

Memoriaglobal

I/O

Copia datos dehost a device

Page 44: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

Copia datos dehost a device

cudaMemcpy(destino, origen, size, DIRECCION_COPIA)

Copia size bytes desde la dirección origen a la direccióndestino en la memoria global. DIRECCION_COPIA indicael sentido de la copia: - cudaMemcpyHostToHost. - cudaMemcpyHostToDevice. - cudaMemcpyDeviceToHost. - cudaMemcpyDeviceToDevice.

Page 45: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

CPU

Memoriaprincipal

GPU

Memoriaglobal

I/O

Copia datos dehost a device

Tenemos los datos alocados en memoria principal de la CPU y en memoria global de GPU.

Estamos listos para operar en

device.

Page 46: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

Page 47: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

dim3 blockSize(512); dim3 gridSize((N / blockSize.x) + (N % blockSize.x ? 1 : 0));

conv_par<<<gridSize, blockSize>>>(d_input, d_output, d_filter);

cudaDeviceSynchronize();

Page 48: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

dim3 blockSize(512); dim3 gridSize((N / blockSize.x) + (N % blockSize.x ? 1 : 0));

conv_par<<<gridSize, blockSize>>>(d_input, d_output, d_filter);

cudaDeviceSynchronize();

Configuracióndel grid

Page 49: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device*/cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

dim3 blockSize(512); dim3 gridSize((N / blockSize.x) + (N % blockSize.x ? 1 : 0));

Configuracióndel grid

Variables de tipo dim3: vector de 3 enteros que se usa para especificar dimensiones. Componentes x, y, z. Si algún componente no se inicializa → 1.

blockSize → especificará cantidad de threads por bloque (bloques de 1, 2 o 3 dimensiones).gridSize → especificará cantidad de bloques en el grid (grids de 1, 2 o 3 dimensiones)

¿Cómo queda configurado el grid?

Page 50: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

● Kernel 1:– dim3 dimGrid(3,2)

– dim3 dimBlock(5,3)

● Kernel 2:– dim3 dimGrid(4,3)

– Dim3 dimBlock(?,?,?)

Page 51: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

dim3 blockSize(512); dim3 gridSize((N / blockSize.x) + (N % blockSize.x ? 1 : 0));

conv_par<<<gridSize, blockSize>>>(d_input, d_output, d_filter);

cudaDeviceSynchronize();

Page 52: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

dim3 blockSize(512); dim3 gridSize((N / blockSize.x) + (N % blockSize.x ? 1 : 0));

conv_par<<<gridSize, blockSize>>>(d_input, d_output, d_filter);

cudaDeviceSynchronize();

Lanzamientodel kernel

Page 53: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Inicializacíon del filtro */SetupFilter(h_filter, M, 0);

/* Inicilizacion (padded periodico) array de entrada con datos random */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copia senial al device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copia filtro al device */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

dim3 blockSize(512); dim3 gridSize((N / blockSize.x) + (N % blockSize.x ? 1 : 0));

conv_par<<<gridSize, blockSize>>>(d_input, d_output, d_filter);

cudaDeviceSynchronize();

Lanzamientodel kernel

nombre_Kernel<<<número de bloques, threads por bloque>>>(parámetros actuales);

Page 54: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Función Kernel

*/

conv.cu

/* convolucion usando indexado unidimensional de threads/blocks un thread por cada elemento del output todo en memoria global lanzamiento: la grilla se puede elegir independiente de N */

__global__ void conv_par(float *input, float *output, float *filter) { int j = blockIdx.x * blockDim.x + threadIdx.x;

float temp; while(j<N) { temp=0.0; for(int i=0;i<M;i++){ temp += filter[i]*input[i+j]; } output[j]=temp; j+=gridDim.x*blockDim.x; } }

Page 55: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Función Kernel

*/

conv.cu

/* convolucion usando indexado unidimensional de threads/blocks un thread por cada elemento del output todo en memoria global lanzamiento: la grilla se puede elegir independiente de N */

__global__ void conv_par(float *input, float *output, float *filter) { int j = blockIdx.x * blockDim.x + threadIdx.x;

float temp; while(j<N) { temp=0.0; for(int i=0;i<M;i++){ temp += filter[i]*input[i+j]; } output[j]=temp; j+=gridDim.x*blockDim.x; } }

Page 56: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Función Kernel

*/

conv.cu

/* convolucion usando indexado unidimensional de threads/blocks un thread por cada elemento del output todo en memoria global lanzamiento: la grilla se puede elegir independiente de N */

__global__ void conv_par(float *input, float *output, float *filter) { int j = blockIdx.x * blockDim.x + threadIdx.x;

float temp; while(j<N) { temp=0.0; for(int i=0;i<M;i++){ temp += filter[i]*input[i+j]; } output[j]=temp; j+=gridDim.x*blockDim.x; } }

__global__: calificador de función

Page 57: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Calificadores de funciones:

__global__: determina que es una función kernel, se ejecuta en el dispositivo y sólo puede ser invocada desde el host. Su invocación genera un grid de bloques con número fijo e igual de threads.

__device__ : es una función del dispositivo, se ejecuta en él y sólo puede ser invocada desde un kernel u otra función del dispositivo.

__host__ : determina que es una función del host, o simplemente una función de C tradicional a ejecutarse en host y que puede ser invocada desde host. Por omisión.

Page 58: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Función Kernel

*/

conv.cu

/* convolucion usando indexado unidimensional de threads/blocks un thread por cada elemento del output todo en memoria global lanzamiento: la grilla se puede elegir independiente de N */

__global__ void conv_par(float *input, float *output, float *filter) { int j = blockIdx.x * blockDim.x + threadIdx.x;

float temp; while(j<N) { temp=0.0; for(int i=0;i<M;i++){ temp += filter[i]*input[i+j]; } output[j]=temp; j+=gridDim.x*blockDim.x; } }

__global__: calificador de función

Page 59: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Variables reservadas:

gridDim: contiene las dimensiones del grid.

blockIdx : contiene el identificador del bloque en un grid.

blockDim: contiene las dimensiones del bloque.

threadIdx: contiene el identificador del thread dentro del bloque.

Todas tienen componentes x,y,z.

Grids y bloques de 1, 2 o 3 dimensiones.

Page 60: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Función Kernel

*/

conv.cu

/* convolucion usando indexado unidimensional de threads/blocks un thread por cada elemento del output todo en memoria global lanzamiento: la grilla se puede elegir independiente de N */

__global__ void conv_par(float *input, float *output, float *filter) { int j = blockIdx.x * blockDim.x + threadIdx.x;

float temp; while(j<N) { temp=0.0; for(int i=0;i<M;i++){ temp += filter[i]*input[i+j]; } output[j]=temp; j+=gridDim.x*blockDim.x; } }

Cada thread resuelve uno o varioselementos de la salida (si N > cantidad de threads en la grilla 1D(gridDim.x * blockDim.x)

Page 61: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Setup the filter */SetupFilter(h_filter, M, 0);

/* Fill (padded periodico) input array with random data */for(int i = 0 ; i < N ; i++) h_input[i] = (float)(rand() % 100); for(int i = N ; i < (N+M) ; i++) h_input[i] = h_input[i-N];

/* Copy input array to device */cudaMemcpy(d_input, h_input, (N+M) * sizeof(float), cudaMemcpyHostToDevice);

/* Copy the filter to the GPU */cudaMemcpy(d_filter, h_filter, M * sizeof(float), cudaMemcpyHostToDevice);

dim3 blockSize(512); dim3 gridSize((N / blockSize.x) + (N % blockSize.x ? 1 : 0));

conv_par<<<gridSize, blockSize>>>(d_input, d_output, d_filter);

cudaDeviceSynchronize(); Barrera hasta que terminande ejecutar todos los threads del kernel en GPU

Page 62: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

/* Copia resultado al host */ cudaMemcpy(h_output, d_output, N * sizeof(float), cudaMemcpyDeviceToHost);

/* Free memory on host */ free(h_input); free(h_output); free(h_filter);

/* Free memory on device */ cudaFree(d_input); cudaFree(d_output); cudaFree(d_filter);

}

Page 63: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

Copia de resultado GPU → CPU

/* Copia resultado al host */ cudaMemcpy(h_output, d_output, N * sizeof(FLOAT), cudaMemcpyDeviceToHost);

/* Free memory on host */ free(h_input); free(h_output); free(h_filter);

/* Free memory on device */ cudaFree(d_input); cudaFree(d_output); cudaFree(d_filter);

}

Page 64: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D/*

Continuación del código anterior

*/

conv.cu

Liberación de memoria en CPU y GPU

/* Copia resultado al host */ cudaMemcpy(h_output, d_output, N * sizeof(FLOAT), cudaMemcpyDeviceToHost);

/* Free memory on host */ free(h_input); free(h_output); free(h_filter);

/* Free memory on device */ cudaFree(d_input); cudaFree(d_output); cudaFree(d_filter);

}

Page 65: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Convolución 1D

De orden cuadrático a orden N/p (donde p es la cantidad de cores)

Y se resuelve en paralelo todos losresultados del vector.

th0 th1 th2 th3 thN-1…

x

h

* * * * *

y

Page 66: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Modelo de programación CUDA

No todos los problemas pueden ser resueltos usando placas de tipo GPU.

Los más adecuados son los que aplican la misma secuencia de código a los datos de entrada.

Page 67: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Modelo de programación CUDA

Ganaremos con GPU si:

El algoritmo tiene orden de ejecución cuadrático o superior: compensar el tiempo de transferencia de datos CPU – GPU.

Gran carga de cálculo en cada thread (por lo mismo que el itemanterior).

Poca dependencia de datos. Independencia de cómputo. Puede llevar aacceso a su memoria local o compartida y evita acceder a la global (costosa).

Mínima transferencia de datos CPU-GPU: óptimo: principio y final. Evitar tranferencias intermedias, ya sean para resultados parcialeso datos de entrada intermedios.

No existan secciones críticas: lecturas paralelas a datos, pero no escrituras: necesitamos mecanismos de acceso seguro → secuen-cialización de accesos.

Page 68: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Resumen

Hemos visto: - Alocación de memoria en device.- Transferencia de memoria host ↔ device.- Configuración de grid.- Lanzamiento de kernels.

Todas estas operaciones las ofrece CUDA como una libreríaque extiende al lenguaje C (en este caso).

Page 69: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Probando el código

1) Copiar la carpeta /share/apps/codigos/alumnos_icnpg2016/clase_01/convolucion a la carpeta personal:

[mdenham@gpgpu-fisica ~]$ cp -a /share/apps/codigos/alumnos_icnpg2016/Clase_01/convolucion/ .

2) Para compilar: los paquetes de compiladores/ bibliotecas se usan via el comando module. Para compilar con CUDA debemos cargar el módulo:

[mdenham@gpgpu-fisica ~]$ module load cuda

Entrar a la carpeta local Convolucion y compilar:

[mdenham@gpgpu-fisica ~]$ cd Convolucion[mdenham@gpgpu-fisica Convolucion]$ nvcc convolucion.cu -o convolucion

Page 70: Introducción a CUDADada una señal discreta x[n] y un flitro h[n], la convolución se define como: – Considerar un array x de números reales de tamaño N que representa la señal

Probando el código

3) Ejecutar la aplicación: encolamos el ejecutable convolucion usandoel script submit_gpuh.sh:

[mdenham@gpgpu-fisica Convolucion]$ qsub submit_gpu.sh

4) Para consultar el estado de los trabajos lanzados:

[mdenham@gpgpu-fisica Convolucion]$ qstat -f [mdenham@gpgpu-fisica Convolucion]$ qstat -u '*'

5) Verificar resultados: ver los resultados en submit_gpu.sh.o*****

[mdenham@gpgpu-fisica Convolucion]$ cat submit_gpu.sh.o***