CUDA cómo obtener cuadrícula, bloque, tamaño de hilo y parallalizar cálculo de matriz no cuadrada

Soy nuevo en CUDA y necesito ayuda para entender algunas cosas. Necesito ayuda para paralelizar estos dos bucles. Específicamente, cómo configurar el dimBlock y dimGrid para hacer que esta ejecución sea más rápida. Sé que esto parece el ejemplo de agregar vectores en el SDK, pero ese ejemplo es solo para matrices cuadradas y cuando bash modificar ese código para mi matriz de 128 x 1024, no funciona correctamente.

__global__ void mAdd(float* A, float* B, float* C) { for(int i = 0; i < 128; i++) { for(int i = 0; i < 1024; i++) { C[i * 1024 + j] = A[i * 1024 + j] + B[i * 1024 + j]; } } } 

Este código es parte de un bucle más grande y es la parte más simple del código, así que decidí tratar de hacer paralelo a thia y aprender CUDA al mismo tiempo. He leído las guías pero todavía no entiendo cómo obtener el no apropiado. de grids / block / threads en marcha y usarlos de manera efectiva.

Como lo has escrito, ese kernel es completamente serial. Cada hilo lanzado para ejecutarlo va a realizar el mismo trabajo.

La idea principal detrás de CUDA (y OpenCL y otros modelos de progtwigción similares de “progtwig único, datos múltiples”) es que se realiza una operación “paralela a los datos”, por lo que se debe realizar la misma operación, en gran parte independiente, muchas veces, y escribe un núcleo que realiza esa operación. A continuación, se inicia una gran cantidad de subprocesos (semi) autónomos para realizar esa operación en el conjunto de datos de entrada.

En su ejemplo de adición de matriz, la operación paralela de datos es

 C[k] = A[k] + B[k]; 

para todo k entre 0 y 128 * 1024. Cada operación de adición es completamente independiente y no tiene requisitos de pedido, y por lo tanto puede realizarse por un hilo diferente. Para express esto en CUDA, uno podría escribir el kernel así:

 __global__ void mAdd(float* A, float* B, float* C, int n) { int k = threadIdx.x + blockIdx.x * blockDim.x; if (k < n) C[k] = A[k] + B[k]; } 

[descargo de responsabilidad: código escrito en el navegador, no probado, usar bajo su propio riesgo]

Aquí, el bucle interno y externo del código de serie se reemplaza por un hilo CUDA por operación, y he agregado una verificación de límite en el código para que en los casos en que se inicien más hilos que las operaciones requeridas, no se produzca desbordamiento de búfer. Si el núcleo se inicia así:

 const int n = 128 * 1024; int blocksize = 512; // value usually chosen by tuning and hardware constraints int nblocks = n / nthreads; // value determine by block size and total work madd< <>>mAdd(A,B,C,n); 

Luego, se lanzarán 256 bloques, cada uno con 512 hilos, en el hardware de la GPU para realizar la operación de adición de matriz en paralelo. Tenga en cuenta que si el tamaño de los datos de entrada no se podía express como un bonito redondeo múltiple del tamaño del bloque, la cantidad de bloques debería redondearse hacia arriba para cubrir el conjunto completo de datos de entrada.

Todo lo anterior es una visión general muy simplificada del paradigma de CUDA para una operación muy trivial, pero tal vez le da suficiente información para que usted pueda continuar. CUDA es bastante maduro en estos días y hay una gran cantidad de material educativo bueno y gratuito flotando en la web que probablemente pueda utilizar para iluminar aún más muchos de los aspectos del modelo de progtwigción que he pasado por alto en esta respuesta.