tutorial programming cuda gpgpu

programming - cuda wikipedia



Modelo CUDA: ¿cuál es el tamaño de la urdimbre? (3)

El tamaño de warp es el número de subprocesos que un multiprocesador ejecuta al mismo tiempo. Un multiprocesador de NVIDIA puede ejecutar varios subprocesos desde el mismo bloque al mismo tiempo, utilizando hardware multihilo.

Es importante tener en cuenta el tamaño de la urdimbre, ya que todos los accesos a la memoria se combinan en múltiplos del tamaño de la urdimbre (32 bytes, 64 bytes, 128 bytes), y esto mejora el rendimiento.

La Guía de C mejores prácticas de CUDA contiene toda la información técnica sobre este tipo de optimizaciones.

¿Cuál es la relación entre el tamaño máximo de grupo de trabajo y el tamaño de urdimbre? Digamos que mi dispositivo tiene 240 procesadores de transmisión CUDA (SP) y devuelve la siguiente información:

CL_DEVICE_MAX_COMPUTE_UNITS: 30

CL_DEVICE_MAX_WORK_ITEM_SIZES: 512/512/64

CL_DEVICE_MAX_WORK_GROUP_SIZE: 512

CL_NV_DEVICE_WARP_SIZE: 32

Esto significa que tiene ocho SP por multiprocesador de transmisión (es decir, unidad de cálculo). Ahora, ¿cómo se relaciona el tamaño de la urdimbre = 32 con estos números?


La respuesta directa es breve: en Nvidia, los BLOQUES compuestos por HILOS son establecidos por el programador, y WARP es 32 (consta de 32 hilos), que es la unidad mínima que ejecuta la unidad de cálculo al mismo tiempo. En AMD, WARP se llama WAVEFRONT ("onda").

En OpenCL, WORKGROUPs significa BLOCK en CUDA, y lo que es más, WORKITEMs significa THREADs en CUDA.


Respuesta directa: el tamaño de la deformación es la cantidad de hilos en una urdimbre, que es una subdivisión utilizada en la implementación del hardware para combinar el acceso a la memoria y el despacho de instrucciones.

Lectura sugerida:

Como mencionó @Matias, iría a leer la Guía de C mejores prácticas de CUDA C (tendrá que desplazarse al final de la lista). Puede serle útil mirar fijamente la tabla del Apéndice G.1 en la página 164.

Explicación:

CUDA es el lenguaje que proporciona el paralelismo en dos niveles. Tienes hilos y tienes bloques de hilos. Esto es más evidente cuando ejecuta un kernel; debe especificar el tamaño de cada bloque de hilos y el número de bloques de hilos entre <<< >>> que preceden a los parámetros del núcleo.

Lo que CUDA no te dice es que las cosas están sucediendo realmente en cuatro niveles, no en dos. En el fondo, su bloque de hilos se divide en subbloques llamados "warps". Aquí hay una breve metáfora para ayudar a explicar lo que realmente está pasando:

Breve metáfora:

Haga de cuenta que es un educador / investigador / político que está interesado en la capacidad matemática actual de los estudiantes de último año de secundaria. Tu plan es dar una prueba a 10,240 estudiantes, pero no puedes simplemente ponerlos a todos en un estadio de fútbol o algo así y darles la prueba. Es más fácil subdividir (poner en paralelo) su colección de datos, por lo que debe ir a 20 escuelas secundarias diferentes y solicitar que 512 de sus estudiantes de cuarto año rindan la prueba de matemáticas.

Recoges tus datos y eso es todo lo que te importa. Lo que no sabía (y realmente no le importaba) es que cada escuela en realidad está subdividida en aulas. Entonces, sus 512 adultos mayores están divididos en 16 grupos de 32. Además, ninguna de estas escuelas tiene realmente los recursos necesarios: cada aula solo tiene dieciséis calculadoras. Por lo tanto, en cualquier momento, solo la mitad de cada aula puede tomar su examen de matemáticas.

Podría continuar para estirar las reglas tontas, ya que solo ocho aulas en una escuela pueden tomar el examen al mismo tiempo porque solo tienen ocho maestros. No puede muestrear más de 30 escuelas simultáneamente porque solo tiene 30 supervisores ...

De vuelta a tu pregunta:

Usando la metáfora, tu programa quiere calcular los resultados lo más rápido posible (deseas recolectar pruebas de matemáticas). Usted emite un kernel con un cierto número de bloques (escuelas) cada uno de los cuales tiene un cierto número de hilos (estudiantes). Solo puede tener tantos bloques ejecutándose al mismo tiempo (recopilar las respuestas de su encuesta requiere un supervisor por escuela). En CUDA, los bloques de subprocesos se ejecutan en un multiprocesador de transmisión (SM). La variable: CL_DEVICE_MAX_COMPUTE_UNITS le dice cuántos SMs, 30 , tiene una tarjeta específica. Esto varía drásticamente en función del hardware; consulte la tabla en el Apéndice A de la Guía de C mejores prácticas de CUDA . Tenga en cuenta que cada SM puede ejecutar solo ocho bloques simultáneamente independientemente de la capacidad de cómputo (1.X o 2.X).

Los bloques de subprocesos tienen dimensiones máximas: CL_DEVICE_MAX_WORK_ITEM_SIZES . Piensa en desplegar tus hilos en una grilla; no puedes tener una fila con más de 512 hilos. No puede tener una columna con más de 512 hilos. Y no puedes apilar más de 64 subprocesos. A continuación, hay un máximo: CL_DEVICE_MAX_WORK_GROUP_SIZE cantidad de subprocesos, 512 , que se pueden agrupar en un bloque. Entonces, las dimensiones de los bloques de hilos podrían ser:

512 x 1 x 1

1 x 512 x 1

4 x 2 x 64

64 x 8 x 1

etc ...

Tenga en cuenta que a partir de Compute Capability 2.X, sus bloques pueden tener como máximo 1024 hilos. Por último, la variable CL_NV_DEVICE_WARP_SIZE especifica el tamaño de warp, 32 (número de estudiantes por aula). En los dispositivos Compute Capability 1.X, las transferencias de memoria y el despacho de instrucciones ocurren en la granularidad de Half-Warp (solo tienes 16 calculadoras por aula). En Compute Capability 2.0, las transferencias de memoria se agrupan por Warp , por lo que se obtienen 32 simultáneamente, pero el despacho de instrucciones solo se agrupa por Half-Warp . Para Compute Capability 2.1, las transferencias de memoria y el despacho de instrucciones ocurren por Warp , 32 hilos. Estas cosas pueden cambiar y cambiarán en el hardware futuro.

Entonces, mi palabra! Vayamos al grano:

En resumen:

He descrito los matices del diseño de urdimbre / hilo y otros tales como shtuff, pero aquí hay un par de cosas para tener en cuenta. Primero, su acceso a la memoria debe ser "agrupable" en conjuntos de 16 o 32. Así que mantenga la dimensión X de sus bloques un múltiplo de 32. En segundo lugar, y lo más importante para obtener el máximo rendimiento de una GPU específica, necesita maximizar la ocupación. No tiene 5 bloques de 512 hilos. Y no tiene 1,000 bloques de 10 hilos. Recomiendo consultar la hoja de cálculo basada en Excel (¿funciona también en OpenOffice ? ¿Pienso?) Que le indicará cuál será la ocupación de la GPU para una llamada específica al kernel (disposición de la secuencia y requisitos de memoria compartida). ¡Espero que esta explicación ayude!