2012-05-05 42 views
104

He estado usando CUDA durante algunas semanas, pero tengo algunas dudas sobre la asignación de bloques/warps/hilo. Estoy estudiando la arquitectura desde el punto de vista didáctico (proyecto de la universidad), por lo que no es mi preocupación alcanzar el máximo rendimiento.¿Cómo se mapean/deforman/hilos CUDA en núcleos CUDA?

En primer lugar, me gustaría entender si tengo estas cosas claras:

  1. El programador escribe un núcleo, y organizar su ejecución en una rejilla de hilo se bloquea.

  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 en una urdimbre se ejecutan simultáneamente en los recursos de la SM.

  4. La ejecución real de un hilo es realizada por los núcleos CUDA contenidos en el SM. No hay una asignación específica entre hilos y núcleos.

  5. Si una urdimbre contiene 20 hilos, pero actualmente solo hay 16 núcleos disponibles, la urdimbre no se ejecutará.

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

  7. Si un subproceso se inicia en un núcleo, luego se detiene para 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 correctos?

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

Mi objetivo es asegurarse de que cada núcleo de la arquitectura ejecuta las instrucciones MISMAS. Suponiendo que mi código no requerirá más registro de los que están disponibles en cada SM, que imaginaron diferentes enfoques:

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

  2. ¿Hay alguna diferencia si pongo en marcha 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 subprocesos cada uno, por ejemplo) es razonable suponer que todos los núcleos serán utilizado en un cierto punto, y realizará los mismos cálculos (suponiendo que los hilos nunca se detengan)?

  4. ¿Hay alguna manera de comprobar estas situaciones utilizando el generador de perfiles?

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

Respuesta

94

Dos de las mejores referencias son

  1. NVIDIA Fermi Compute Architecture Whitepaper
  2. GF104 Reviews

voy a tratar de responder a cada una de sus preguntas.

El programador divide el trabajo en hilos, hilos en bloques de hilos y rosca bloques en cuadrículas. El distribuidor de trabajo de cómputo asigna bloques de hilos a los multiprocesadores de transmisión (SM). Una vez que se distribuye un bloque de subprocesos a un SM, se asignan los recursos para el bloque de subprocesos (warps y memoria compartida) y los subprocesos se dividen en grupos de 32 subprocesos llamados warps. Una vez que se asigna un warp, se llama warp activo. Los dos planificadores de warp eligen dos warps activos por ciclo y envían warps a las unidades de ejecución. Para obtener más información sobre las unidades de ejecución y el despacho de instrucciones, consulte 1 p.7-10 y 2.

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

5 '. Si un warp contiene menos de 32 hilos, en la mayoría de los casos se ejecutará de la misma manera que si tuviera 32 hilos. Warps puede 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 se salga un subproceso de la distorsión.

6 '. Un bloque de subprocesos se dividirá en WarpsPerBlock = (ThreadsPerBlock + WarpSize - 1)/WarpSize No es necesario que los planificadores de warp seleccionen dos warps del mismo bloque de subprocesos.

7 '. Una unidad de ejecución no se parará en una operación de memoria. Si un recurso no está disponible cuando una instrucción está lista para ser despachada, la instrucción se enviará de nuevo en el futuro cuando el recurso esté disponible. Los Warps pueden estancarse en barreras, en operaciones de memoria, operaciones de textura, dependencias de datos, ... Un warp estancado no es elegible para ser seleccionado por el planificador warp. En Fermi es útil tener al menos 2 urdimbres elegibles por ciclo para que el planificador de warp pueda emitir una instrucción.

Consulte la referencia 2 para ver las diferencias entre una GTX480 y una GTX560.

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

1 '. Si inicia kernel < < < 8, 48 >>> obtendrá 8 bloques cada uno con 2 warps de 32 y 16 hilos. No hay garantía de que estos 8 bloques se asignarán a SM diferentes. Si se asignan 2 bloques a un SM, es posible que cada planificador de warp pueda seleccionar un warp y ejecutar el warp. Solo usarás 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 cada hilo ejecuta 10 instrucciones.

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

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

3 '. Un GTX560 puede tener 8 bloques SM * 8 = 64 bloques a la vez u 8 SM * 48 warps = 512 warps si el núcleo no alcanza el máximo de registros o memoria compartida. En cualquier momento dado, una parte del trabajo estará activo en SM. Cada SM tiene múltiples unidades de ejecución (más que núcleos CUDA). Qué recursos están en uso en un momento dado depende 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 punto flotante, las unidades SUFU estarán inactivas.

4 '. Parallel Nsight y Visual Profiler muestran

a. ejecutado IPC

b. emitido IPC

c. urdimbres activas por ciclo activo

d. urdimbres elegibles por ciclo activo (Nsight solamente)

e. razones de warp stall (Nsight solamente)

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, una estimación aproximada sería IssuedIPC/MaxIPC. Para maxIPC suponga GF100 (GTX480) es 2 GF10x (GTX560) es 4 pero el objetivo es 3 es un objetivo mejor.

+0

Gracias por su respuesta. Leí las referencias, pero hay algunas cosas que no entiendo en su respuesta.En las siguientes preguntas, supongo que estamos utilizando una arquitectura de Fermi con 48 núcleos (16 núcleos * 3 "grupos principales"): 1. Usted mencionó un mapeo entre los núcleos y laneid. ¿Qué tipo de mapeo es? 2. De las referencias que obtuve, cada "grupo núcleo" ejecuta a lo sumo un medio warp (16 hilos) por ciclo de reloj. Entonces, en teoría, si tenemos 48 hilos en el mismo bloque, se organizarán en 3 medias urdimbres y se ejecutarán en paralelo en los 48 núcleos. ¿Estoy en lo cierto? – Daedalus

+0

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 planificadores de warp necesita seleccionar un warp que cumpla con el requisito de un par superescalar y ambas instrucciones deben ser de un tipo ejecutado por núcleos CUDA. Además, el otro planificador de warp tiene que elegir un warp cuya siguiente instrucción será ejecutada por núcleos CUDA. –

+0

No es necesario que las urdimbres estén en el mismo bloque o que las urdimbres en un bloque tengan el mismo contador de programa. –

5

"E. Si una urdimbre contiene 20 hilos, pero actualmente solo hay 16 núcleos disponibles, la urdimbre no se ejecutará".

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

Una deformación en sí misma solo se puede programar en un único núcleo (= multiprocesador), y puede ejecutar hasta 32 subprocesos al mismo tiempo; no puede usar más de un solo núcleo.

El número "48 warps" es el número máximo de warps activos (warps que pueden elegirse para programarse para trabajar en el ciclo siguiente, en cualquier ciclo dado) por multiprocesador, en nVIDIA GPU con Compute Capability 2.x ; y este número corresponde a 1536 = 48 x 32 hilos.

respuesta basada en this webinar

+0

@GregSmith: Editado la respuesta para abordar esto. Está bien que fueras paciente con eso, pero - han pasado cinco años ... – einpoklum

+0

núcleo único (= multiprocesador)? Creo que la pregunta asume la terminología núcleo único = procesador y no multiprocesador. Con tu terminología tu respuesta es correcta. – Adarsh