it-swarm.dev

CUDA determinando hilos por bloque, bloques por cuadrícula

Soy nuevo en el paradigma de CUDA. Mi pregunta es para determinar el número de subprocesos por bloque y bloques por cuadrícula. ¿Un poco de arte y prueba juegan en esto? Lo que he encontrado es que muchos ejemplos tienen un número aparentemente arbitrario elegido para estas cosas.

Estoy considerando un problema en el que podría pasar matrices, de cualquier tamaño, a un método de multiplicación. De modo que, cada elemento de C (como en C = A * B) se calcularía por un solo hilo. ¿Cómo determinarías los hilos/bloques, bloques/cuadrículas en este caso?

51
dnbwise

En general, desea dimensionar sus bloques/cuadrícula para que coincidan con sus datos y al mismo tiempo maximizar la ocupación, es decir, cuántos subprocesos están activos al mismo tiempo. Los principales factores que influyen en la ocupación son el uso de la memoria compartida, el uso del registro y el tamaño del bloque de hilos.

Una GPU habilitada para CUDA tiene su capacidad de procesamiento dividida en SM (multiprocesadores de transmisión) y la cantidad de SM depende de la tarjeta real, pero aquí nos centraremos en un solo SM para simplificar (todos se comportan igual). Cada SM tiene un número finito de registros de 32 bits, memoria compartida, un número máximo de bloques activos Y un número máximo de subprocesos activos. Estos números dependen de la CC (capacidad de cómputo) de su GPU y se pueden encontrar en medio del artículo de Wikipedia http://en.wikipedia.org/wiki/CUDA .

En primer lugar, el tamaño de su bloque de subprocesos siempre debe ser un múltiplo de 32, porque los kernels emiten instrucciones en deformaciones (32 subprocesos). Por ejemplo, si tiene un tamaño de bloque de 50 subprocesos, la GPU seguirá emitiendo comandos a 64 subprocesos y los estaría desperdiciando.

En segundo lugar, antes de preocuparse por la memoria compartida y los registros, intente dimensionar sus bloques en función del número máximo de hilos y bloques que correspondan a la capacidad de cálculo de su tarjeta. A veces hay varias formas de hacer esto ... por ejemplo, una tarjeta CC 3.0 de cada SM puede tener 16 bloques activos y 2048 hilos activos. Esto significa que si tiene 128 subprocesos por bloque, podría colocar 16 bloques en su SM antes de alcanzar el límite de 2048 subprocesos. Si usa 256 subprocesos, solo puede ajustar 8, pero sigue usando todos los subprocesos disponibles y seguirá teniendo ocupación completa. Sin embargo, el uso de 64 subprocesos por bloque solo usará 1024 subprocesos cuando se alcanza el límite de 16 bloqueos, por lo que solo el 50% de ocupación. Si la memoria compartida y el uso del registro no son un cuello de botella, esta debe ser su principal preocupación (aparte de las dimensiones de sus datos).

Sobre el tema de su cuadrícula ... los bloques en su cuadrícula se extienden sobre los SM para comenzar, y luego los bloques restantes se colocan en una tubería. Los bloques se mueven a los SM para su procesamiento tan pronto como haya suficientes recursos en ese SM para tomar el bloque. En otras palabras, a medida que se completan los bloques en un SM, se mueven nuevos. Se podría argumentar que tener bloques más pequeños (128 en lugar de 256 en el ejemplo anterior) puede completarse más rápido, ya que un bloque particularmente lento consumirá menos recursos, Esto depende mucho del código.

Con respecto a los registros y la memoria compartida, mire eso a continuación, ya que puede estar limitando su ocupación. La memoria compartida es finita para todo un SM, así que intente usarla en una cantidad que permita que tantos bloques como sea posible aún puedan caber en un SM. Lo mismo ocurre con el uso del registro. Nuevamente, estos números dependen de la capacidad de cómputo y se pueden encontrar tabulados en la página de wikipedia. ¡Buena suerte!

83
underpickled

http://developer.download.nvidia.com/compute/cuda/CUDA_Occupancy_calculator.xls

La Calculadora de ocupación CUDA le permite calcular el multiprocesador ocupación de una GPU por un kernel CUDA determinado. La ocupación del multiprocesador es la relación de deformaciones activas al número máximo de deformaciones admitidas en un multiprocesador de la GPU. Cada multiprocesador en el dispositivo tiene un conjunto de N registros disponibles para ser utilizados por los subprocesos del programa CUDA. Estos registros son un recurso compartido que se asignan entre los bloques de subprocesos que se ejecutan en un multiprocesador. El compilador CUDA intenta minimizar el uso del registro para maximizar la cantidad de bloques de hilos que pueden estar activos en la máquina simultáneamente. Si un programa intenta lanzar un kernel para el cual los registros utilizados por hilo multiplicados por el tamaño del bloque de hilos es mayor que N, el inicio fallará ...

18
jmilloy

Con raras excepciones, debe usar un número constante de subprocesos por bloque. El número de bloques por cuadrícula se determina entonces por el tamaño del problema, como las dimensiones de la matriz en el caso de la multiplicación de la matriz.

Elegir el número de hilos por bloque es muy complicado. La mayoría de los algoritmos CUDA admiten una gran variedad de posibilidades, y la elección se basa en lo que hace que el kernel funcione de manera más eficiente. Casi siempre es un múltiplo de 32, y al menos 64, debido a cómo funciona el hardware de programación de subprocesos. Una buena opción para un primer intento es 128 o 256.

15
Heatsink

También debe considerar la memoria compartida porque los hilos en el mismo bloque pueden acceder a la misma memoria compartida. Si está diseñando algo que requiere una gran cantidad de memoria compartida, entonces podría ser ventajoso tener más hilos por bloque.

Por ejemplo, en términos de cambio de contexto, cualquier múltiplo de 32 funciona igual. Entonces, para el caso 1D, el lanzamiento de 1 bloque con 64 hilos o 2 bloques con 32 hilos cada uno no hace ninguna diferencia para los accesos de memoria global. Sin embargo, si el problema en cuestión se descompone naturalmente en 1 vector longitud-64, entonces la primera opción será mejor (menos sobrecarga de memoria, cada hilo puede acceder a la misma memoria compartida) que el segundo.

3
ely