¿Cómo se asignan los bloques / urdimbres / hilos CUDA en los núcleos CUDA?

142

He estado usando CUDA durante algunas semanas, pero tengo algunas dudas sobre la asignación de bloques / warps / thread. Estoy estudiando la arquitectura desde un punto de vista didáctico (proyecto universitario), por lo que alcanzar mi máximo rendimiento no es mi preocupación.

En primer lugar, me gustaría entender si entendí bien estos hechos:

  1. El programador escribe un núcleo y organiza su ejecución en una cuadrícula de bloques de hilos.

  2. Cada bloque se asigna a un Multiprocesador de transmisión (SM). Una vez asignado, no puede migrar a otro SM.

  3. Cada SM divide sus propios bloques en Warps (actualmente con un tamaño máximo de 32 hilos). Todos los hilos de una urdimbre se ejecutan simultáneamente en los recursos del SM.

  4. La ejecución real de un hilo es realizada por los núcleos CUDA contenidos en el SM. No existe un mapeo específico entre hilos y núcleos.

  5. Si un warp contiene 20 hilos, pero actualmente solo hay 16 núcleos disponibles, el warp no se ejecutará.

  6. Por otro lado, si un bloque contiene 48 hilos, se dividirá en 2 urdimbres y se ejecutarán en paralelo siempre que haya suficiente memoria disponible.

  7. Si un subproceso se inicia en un núcleo, se detiene para el acceso a la memoria o para una operación de coma flotante larga, su ejecución podría reanudarse en un núcleo diferente.

¿Son correctas?

Ahora, tengo una GeForce 560 Ti, de acuerdo con las especificaciones, está equipada con 8 SM, cada una con 48 núcleos CUDA (384 núcleos en total).

Mi objetivo es asegurarme de que cada núcleo de la arquitectura ejecute las MISMAS instrucciones. Suponiendo que mi código no requerirá más registros que los disponibles en cada SM, imaginé diferentes enfoques:

  1. Creo 8 bloques de 48 hilos cada uno, para que cada SM tenga 1 bloque para ejecutar. En este caso, ¿se ejecutarán los 48 hilos en paralelo en el SM (explotando todos los 48 núcleos disponibles para ellos)?

  2. ¿Hay alguna diferencia si ejecuto 64 bloques de 6 hilos? (Suponiendo que se asignarán de manera uniforme entre los SM)

  3. Si "sumerjo" la GPU en el trabajo programado (creando 1024 bloques de 1024 hilos cada uno, por ejemplo), es razonable suponer que todos los núcleos se usarán en un cierto punto y realizarán los mismos cálculos (suponiendo que los hilos nunca pararse)?

  4. ¿Hay alguna forma de verificar estas situaciones con el generador de perfiles?

  5. ¿Hay alguna referencia para estas cosas? Leí la guía de programación CUDA y los capítulos dedicados a la arquitectura de hardware en "Programación de procesadores paralelos masivos" y "Diseño y desarrollo de aplicaciones CUDA"; pero no pude obtener una respuesta precisa.

Dédalo
fuente
Me gustaría agregar como comentario lo que es "núcleo de CUDA". "Núcleo CUDA" o "Unidad de ejecución" es una ALU y una FPU enteras totalmente canalizadas que ejecuta una instrucción de instrucción aritmética por ciclo de reloj en un hilo de Cuda.
bruziuz

Respuestas:

123

Dos de las mejores referencias son

  1. Informe técnico de NVIDIA Fermi Compute Architecture
  2. Comentarios sobre el GF104

Trataré de responder cada una de tus preguntas.

El programador divide el trabajo en hilos, hilos en bloques de hilos y bloques de hilos en cuadrículas. El distribuidor de trabajo de cálculo asigna bloques de subprocesos a multiprocesadores de transmisión (SM). Una vez que se distribuye un bloque de subprocesos a un SM, los recursos para el bloque de subprocesos se asignan (deformaciones y memoria compartida) y los subprocesos se dividen en grupos de 32 subprocesos llamados deformaciones. Una vez que se asigna una deformación, se denomina deformación activa. Los dos programadores warp seleccionan dos warps activos por ciclo y envían warps a las unidades de ejecución. Para obtener más detalles sobre las unidades de ejecución y el envío de instrucciones, consulte 1 p.7-10 y 2 .

4 ' . Hay un mapeo entre laneid (índice de hilos en una urdimbre) y un núcleo.

5 ' . Si una urdimbre contiene menos de 32 hilos, en la mayoría de los casos se ejecutará igual que si tuviera 32 hilos. Las deformaciones pueden tener menos de 32 subprocesos activos por varias razones: el número de subprocesos por bloque no es divisible por 32, el programa ejecuta un bloque divergente para que los subprocesos que no tomaron la ruta actual se marquen como inactivos o salga un subproceso en la distorsión.

6 ' . Un bloque de subprocesos se dividirá en WarpsPerBlock = (ThreadsPerBlock + WarpSize - 1) / WarpSize No hay ningún requisito para que los programadores de warp seleccionen dos warps del mismo bloque de subprocesos.

7 ' . Una unidad de ejecución no se detendrá en una operación de memoria. Si un recurso no está disponible cuando una instrucción está lista para ser enviada, la instrucción se enviará nuevamente en el futuro cuando el recurso esté disponible. Las deformaciones pueden detenerse en barreras, operaciones de memoria, operaciones de textura, dependencias de datos, ... Una deformación estancada no es elegible para ser seleccionada por el programador de deformaciones. En Fermi es útil tener al menos 2 warps elegibles por ciclo para que el programador warp pueda emitir una instrucción.

Consulte la referencia 2 para conocer las diferencias entre un GTX480 y GTX560.

Si lees el material de referencia (unos minutos) creo que encontrarás que tu objetivo no tiene sentido. Intentaré responder a tus puntos.

1 ' . Si inicia el núcleo <<< 8, 48 >>> obtendrá 8 bloques cada uno con 2 urdimbres de 32 y 16 hilos. No hay garantía de que estos 8 bloques se asignen a diferentes SM. Si se asignan 2 bloques a un SM, entonces es posible que cada planificador de warp pueda seleccionar un warp y ejecutar el warp. Solo usará 32 de los 48 núcleos.

2 ' . Hay una gran diferencia entre 8 bloques de 48 hilos y 64 bloques de 6 hilos. Supongamos que su núcleo no tiene divergencia y que cada hilo ejecuta 10 instrucciones.

  • 8 bloques con 48 hilos = 16 urdimbres * 10 instrucciones = 160 instrucciones
  • 64 bloques con 6 hilos = 64 urdimbres * 10 instrucciones = 640 instrucciones

Para obtener una eficiencia óptima, la división del trabajo debe estar en múltiplos de 32 hilos. El hardware no fusionará hilos de diferentes urdimbres.

3 ' . Un GTX560 puede tener 8 SM * 8 bloques = 64 bloques a la vez u 8 SM * 48 warps = 512 warps si el núcleo no maximiza los registros o la memoria compartida. En cualquier momento dado, una parte del trabajo estará activa en SM. Cada SM tiene múltiples unidades de ejecución (más que núcleos CUDA). Los recursos que se usan en un momento dado dependen de los programadores warp y la combinación de instrucciones de la aplicación. Si no realiza operaciones TEX, las unidades TEX estarán inactivas. Si no realiza una operación especial de coma flotante, las unidades SUFU estarán inactivas.

4 ' . Parallel Nsight y el programa Visual Profiler

a. IPC ejecutado

si. IPC emitido

C. deformaciones activas por ciclo activo

re. deformaciones elegibles por ciclo activo (solo Nsight)

mi. razones de pérdida de deformación (solo Nsight)

F. hilos activos por instrucción ejecutada

El generador de perfiles no muestra el porcentaje de utilización de ninguna de las unidades de ejecución. Para GTX560 se emitiría una estimación aproximada IPC / MaxIPC. Para MaxIPC, suponga que GF100 (GTX480) es 2 GF10x (GTX560) es 4 pero el objetivo es 3 es un mejor objetivo.

Greg Smith
fuente
1
Gracias por su respuesta. Leí las referencias, pero hay algunas cosas que no entiendo en su respuesta. En las siguientes preguntas, supongo que estamos usando una arquitectura Fermi con 48 núcleos (16 núcleos * 3 "grupos principales"): 1. Usted mencionó un mapeo entre núcleos y carril. ¿Qué tipo de mapeo es? 2. De las referencias obtuve que cada "grupo central" ejecuta a lo sumo una media urdimbre (16 hilos) por ciclo de reloj. Entonces, en teoría, si tenemos 48 hilos en el mismo bloque, se organizarán en 3 medias deformaciones y se ejecutarán en paralelo en los 48 núcleos. Estoy en lo cierto?
Dédalo
1
Los núcleos CUDA son el número de unidades FP de precisión simple. Pensar en la ejecución en términos de núcleos CUDA no es correcto. Cada urdimbre tiene 32 hilos. Estos hilos se emitirán a un grupo de unidades de ejecución (por ejemplo, 16 núcleos cuda). Para emitir a los 48 núcleos en un solo reloj, uno de los dos programadores warp necesita seleccionar un warp que cumpla con los requisitos de un par superescalar y ambas instrucciones deben ser del tipo ejecutado por los núcleos CUDA. Además, el otro planificador de deformación tiene que elegir una deformación cuya próxima instrucción será ejecutada por los núcleos CUDA.
Greg Smith
1
No hay ningún requisito de que las deformaciones estén en el mismo bloque o que las deformaciones en un bloque tengan el mismo contador de programa.
Greg Smith
2
En su ejemplo, cada planificador elige una deformación y emite 1 instrucción. En este caso solo se utilizarán 2 grupos de unidades de ejecución. Para utilizar más unidades de ejecución, 1 de los planificadores tiene que emitir dos veces. Como se indica en las referencias, existen múltiples tipos de unidades de ejecución (no solo lo que se conoce como núcleos cuda) y hay reglas de emparejamiento de instrucciones (no bien documentadas) que los programadores deben cumplir para emitir dos veces.
Greg Smith
1
@GregSmith Estoy buscando en toda la web para averiguar de dónde provienen estos 8 bloques activos por SM en la arquitectura Fermi. Ni siquiera se menciona en el documento técnico de fermi. ¿Tienes alguna referencia más sobre eso?
Greg K.
8

"E. Si un warp contiene 20 hilos, pero actualmente solo hay 16 núcleos disponibles, el warp no se ejecutará".

Es incorrecto. Está confundiendo los núcleos en su sentido habitual (también se usa en CPU): la cantidad de "multiprocesadores" en una GPU, con núcleos en el lenguaje de marketing nVIDIA ("nuestra tarjeta tiene miles de núcleos CUDA").

Un warp en sí solo puede programarse en un solo núcleo (= multiprocesador) y puede ejecutar hasta 32 hilos al mismo tiempo; No puede usar más de un núcleo.

El número "48 urdimbres" es el número máximo de urdimbres activos (urdimbres que pueden elegirse para ser programados para el trabajo en el próximo ciclo, en cualquier ciclo dado) por multiprocesador, en GPU nVIDIA con capacidad de cálculo 2.x; y este número corresponde a 1536 = 48 x 32 hilos.

Respuesta basada en este seminario web

Andrej
fuente
@GregSmith: editó la respuesta para abordar esto. Está bien que fue muy paciente con él, pero - que ha sido cinco años ...
einpoklum
núcleo único (= multiprocesador)? Creo que la pregunta asume la terminología de núcleo único = procesador y no multiprocesador. Con su terminología su respuesta es correcta.
Adarsh