it-swarm.dev

Transmisión multiprocesadores, bloques e hilos (CUDA)

¿Cuál es la relación entre un núcleo de CUDA, un multiprocesador de transmisión y el modelo de bloques y subprocesos de CUDA?

¿Qué se asigna a qué y qué se paraliza y cómo? y, ¿qué es más eficiente, maximizar el número de bloques o el número de subprocesos?


Mi entendimiento actual es que hay 8 cuda cores por multiprocesador. y que cada núcleo cuda podrá ejecutar un bloque cuda a la vez. y todos los hilos en ese bloque se ejecutan en serie en ese núcleo en particular.

¿Es esto correcto?

62
ExtremeCoder

El diseño del hilo/bloque se describe en detalle en la guía de programación CUDA . En particular, el capítulo 4 establece:

La arquitectura CUDA se basa en una matriz escalable de multiprocesadores de transmisión (SM) multiproceso. Cuando un programa CUDA en la CPU host invoca una cuadrícula de kernel, los bloques de la cuadrícula se enumeran y distribuyen a multiprocesadores con capacidad de ejecución disponible. Los subprocesos de un bloque de subprocesos se ejecutan simultáneamente en un multiprocesador, y varios bloques de subprocesos pueden ejecutarse simultáneamente en un multiprocesador. A medida que terminan los bloques de hilos, se inician nuevos bloques en los multiprocesadores desocupados.

Cada SM contiene 8 núcleos CUDA, y en cualquier momento están ejecutando un solo warp de 32 hilos, por lo que se requieren 4 ciclos de reloj para emitir una única instrucción para todo el warp. Puede suponer que los subprocesos en cualquier deformación dada se ejecutan en el paso de bloqueo, pero para sincronizar entre las deformaciones, debe usar __syncthreads().

60
Edric

Para la GTX 970 hay 13 multiprocesadores de transmisión (SM) con 128 núcleos Cuda cada uno. Los núcleos Cuda también se denominan Stream Processors (SP).

Puede definir cuadrículas que mapean bloques a la GPU.

Puede definir los bloques que asignan hilos a los procesadores Stream (los 128 Cuda Cores por SM).

Una urdimbre siempre está formada por 32 hilos y todos los hilos de una urdimbre se ejecutan de forma simultánea.

Para utilizar toda la potencia posible de una GPU, se necesitan muchos más subprocesos por SM que el SM tiene SP. Para cada capacidad de cálculo, hay un cierto número de subprocesos que pueden residir en un SM a la vez. Todos los bloques que defina están en cola y esperan que un SM tenga los recursos (número de SP libres), luego se carga. El SM comienza a ejecutar Warps. Dado que un Warp solo tiene 32 subprocesos y un SM tiene, por ejemplo, 128 SP, un SM puede ejecutar 4 Warps en un momento dado. El problema es si los subprocesos acceden a la memoria, el subproceso se bloqueará hasta que se satisfaga su solicitud de memoria. En números: un cálculo aritmético en el SP tiene una latencia de 18-22 ciclos, mientras que el acceso a una memoria global no almacenada en caché puede llevar hasta 300-400 ciclos. Esto significa que si los subprocesos de una deformación esperan datos, solo funcionará un subconjunto de los 128 SP. Por lo tanto, el programador cambia para ejecutar otra deformación si está disponible. Y si esta deformación bloquea, ejecuta la siguiente y así sucesivamente. Este concepto se llama ocultación de latencia. La cantidad de deformaciones y el tamaño del bloque determinan la ocupación (de cuántas deformaciones puede elegir ejecutar el SM). Si la ocupación es alta, es más improbable que no haya trabajo para los SP.

Su declaración de que cada núcleo cuda ejecutará un bloque a la vez es incorrecta. Si habla de multiprocesadores de transmisión, pueden ejecutar deformaciones desde todos los hilos que residen en el SM. Si un bloque tiene un tamaño de 256 subprocesos y su GPU permite que haya 2048 subprocesos por cada SM, cada uno de los SM tendrá 8 bloques de los cuales el SM puede elegir que se ejecuten las deformaciones. Todos los hilos de las deformaciones ejecutadas se ejecutan en paralelo.

Encontrará los números de las diferentes capacidades de computación y arquitecturas de GPU aquí: https://en.wikipedia.org/wiki/CUDA#Limitations

Puede descargar una hoja de cálculo de ocupación de Nvidia Hoja de cálculo de ocupación (por Nvidia) .

32
JoeFox

El Distribuidor de trabajo de cálculo programará un bloque de hilos (CTA) en un SM solo si el SM tiene recursos suficientes para el bloque de hilos (memoria compartida, deformaciones, registros, barreras, ...). Se asignan recursos a nivel de bloque de subprocesos como memoria compartida. La asignación crea suficientes deformaciones para todos los subprocesos en el bloque de subprocesos. El administrador de recursos asigna warps usando round robin a las subparticiones SM. Cada subpartición SM contiene un programador de deformación, un archivo de registro y unidades de ejecución. Una vez que una urdimbre se asigna a una subparte, permanecerá en la subparte hasta que se complete o sea precedida por un cambio de contexto (arquitectura de Pascal). En la restauración del cambio de contexto, la deformación se restaurará en el mismo SM mismo ID de warp.

Cuando todos los subprocesos en warp han completado, el programador de warp espera a que se completen todas las instrucciones pendientes emitidas por warp y, a continuación, el administrador de recursos libera los recursos de nivel de warp que incluyen el archivo warp-id y register.

Cuando se completan todas las deformaciones en un bloque de hilos, se liberan los recursos a nivel de bloque y el SM notifica al Distribuidor de trabajo de cálculo que el bloque se ha completado.

Una vez que se asigna una deformación a una subparte y se asignan todos los recursos, la deformación se considera activa, lo que significa que el programador de la deformación realiza un seguimiento activo del estado de la deformación. En cada ciclo, el programador de deformación determina qué deformaciones activas están bloqueadas y cuáles son elegibles para emitir una instrucción. El programador de warp elige la warp elegible de mayor prioridad y emite 1-2 instrucciones consecutivas de la warp. Las reglas para el problema dual son específicas para cada arquitectura. Si una deformación emite una carga de memoria, puede continuar ejecutando instrucciones independientes hasta que llegue a una instrucción dependiente. La deformación se reportará estancada hasta que se complete la carga. Lo mismo es cierto para las instrucciones de matemáticas dependientes. La arquitectura SM está diseñada para ocultar tanto la ALU como la latencia de la memoria cambiando por ciclo entre las deformaciones.

Esta respuesta no usa el término CUDA core ya que introduce un modelo mental incorrecto. Los núcleos CUDA son unidades de ejecución de enteros/puntos flotantes de precisión simple segmentados. La tasa de problemas y la latencia de dependencia son específicas de cada arquitectura. Cada subpartición SM y SM tienen otras unidades de ejecución, incluidas unidades de carga/almacenamiento, unidades de punto flotante de doble precisión, unidades de punto flotante de media precisión, unidades de derivación, etc.

Para maximizar el rendimiento, el desarrollador debe comprender el intercambio de bloques frente a deformaciones frente a registros/subprocesos.

El término ocupación es la relación entre las deformaciones activas y las deformaciones máximas en un SM. Kepler: la arquitectura Pascal (excepto GP100) tiene 4 programadores de deformación por SM. El número mínimo de deformaciones por SM debe ser al menos igual al número de programadores de deformación. Si la arquitectura tiene una latencia de ejecución dependiente de 6 ciclos (Maxwell y Pascal), entonces necesitará al menos 6 distorsiones por programador, que es 24 por SM (24/64 = 37.5% de ocupación) para cubrir la latencia. Si los hilos tienen un paralelismo de nivel de instrucción, esto podría reducirse. Casi todos los kernels emiten instrucciones de latencia variable, como cargas de memoria que pueden durar entre 80 y 1000 ciclos. Esto requiere más deformaciones activas por el programador de deformación para ocultar la latencia. Para cada núcleo hay un punto de intercambio entre la cantidad de urdimbres y otros recursos, como la memoria compartida o los registros, por lo que no se recomienda la optimización del 100% de ocupación, ya que es probable que se realicen otros sacrificios. El generador de perfiles de CUDA puede ayudar a identificar la tasa de problemas de instrucción, la ocupación y los motivos de bloqueo para ayudar al desarrollador a determinar ese balance.

El tamaño de un bloque de hilos puede afectar el rendimiento. Si el kernel tiene bloques grandes y usa barreras de sincronización, entonces los bloqueos de barrera pueden ser una razón para detenerse. Esto se puede aliviar reduciendo las deformaciones por bloque de hilos.

4
Greg Smith

Hay múltiples multiprocesadores de transmisión en un dispositivo.
Un SM puede contener múltiples bloques. Cada bloque puede contener varios hilos.
Un SM tiene múltiples núcleos CUDA (como desarrollador, no debes preocuparte por esto porque está deformado por warp), que funcionará en el hilo. SM siempre trabajando en urdimbre de hilos (siempre 32). Una deformación solo funcionará en el hilo del mismo bloque.
SM y el bloque tienen límites en el número de subprocesos, el número de registros y la memoria compartida.

0
liu km