2012-02-16 32 views
6

El uso de diferentes flujos para kernels CUDA posibilita la ejecución simultánea del kernel. Por lo tanto, n núcleos en n corrientes teóricamente podrían ejecutarse al mismo tiempo si se ajustan al hardware, ¿no?Ejecución simultánea del kernel CUDA con múltiples núcleos por secuencia

Ahora me enfrenta el siguiente problema: No hay n kernels distintos pero n*m donde los kernels m deben ejecutarse en orden. Por ejemplo n=2 y m=3 conduciría a la siguiente esquema de ejecución con corrientes:

Stream 1: <<<Kernel 0.1>>> <<<Kernel 1.1>>> <<<Kernel 2.1>>> 
Stream 2: <<<Kernel 0.2>>> <<<Kernel 1.2>>> <<<Kernel 2.2>>> 

Mi ingenua suposición es que los granos x.0 y Y.1 deben ejecutarse concurrentemente (desde un punto de vista teórico) o al menos no consecutivamente (desde un punto de vista práctico). Pero mis mediciones me muestran que este no es el caso y parece que se ejecuta de forma consecutiva (es decir, K0.0, K1.0, K2.0, K0.1, K1.1, K2.1). Los kernels en sí son muy pequeños, por lo que la ejecución simultánea no debería ser un problema.

Ahora mi enfoque sería realizar un tipo de envío para asegurarme de que los núcleos estén en cola en un estilo intercalado en el programador de la GPU. Pero cuando se trata de una gran cantidad de flujos/núcleos, esto podría causar más daño que beneficio.

Bien, yendo directo al grano: ¿Cuál sería un enfoque apropiado (o al menos diferente) para resolver esta situación?

Editar: Las mediciones se realizan mediante el uso de eventos CUDA. He medido el tiempo que se necesita para resolver completamente el cálculo, i. mi. la GPU tiene que calcular todos los núcleos n * m. La suposición es: en la ejecución completamente simultánea del núcleo, el tiempo de ejecución es aproximadamente (idealmente) 1/n veces el tiempo necesario para ejecutar todos los núcleos en orden, por lo que debe ser posible que dos o más núcleos se puedan ejecutar simultáneamente. Estoy asegurándome de esto usando solo dos corrientes distintas en este momento.

Puedo medir una clara diferencia con respecto a los tiempos de ejecución entre el uso de las secuencias como se describe y el envío de los núcleos intercalados, i. E .:

Loop: i = 0 to m 
    EnqueueKernel(Kernel i.1, Stream 1) 
    EnqueueKernel(Kernel i.2, Stream 2) 

frente

Loop: i = 1 to n 
    Loop: j = 0 to m 
     EnqueueKernel(Kernel j.i, Stream i) 

Este último conduce a un tiempo de ejecución más largo.

Edit # 2: Cambié los números de secuencia para comenzar por 1 (en lugar de 0, consulte los comentarios a continuación).

Edición # 3: hardware es una NVIDIA Tesla M2090 (es decir, de Fermi, la capacidad de cómputo 2.0)

+0

Probablemente necesite utilizar algunas primitivas de sincronización de flujo para imponer el orden de ejecución que necesita. ¿Pero podrías ampliar un poco sobre cómo hiciste tus mediciones en tu pregunta, y también podrías confirmar que cuando escribes "Stream 0", no te refieres literalmente a CUDA stream 0? – talonmies

+0

Aclaré la medida (al menos eso espero). Con streams quiero decir instancias de 'cudaStream_t' como se describe en [CUDA C Programming Guide] (http://developer.download.nvidia.com/compute/DevZone/docs/html/C/doc/CUDA_C_Programming_Guide.pdf), sección 3.2.5 (Ejecución concurrente asincrónica). –

+2

Quizás entendiste mal lo que estaba preguntando, quiero decir, es uno de tus streams de la transmisión CUDA 0, porque la transmisión 0 (la transmisión predeterminada) es sincrónica. – talonmies

Respuesta

5

En Fermi (aka Calcular Capacidad de 2.0) de hardware que lo mejor es intercalar kernel lanza a múltiples flujos en lugar de lanzar todos los kernels a una secuencia, luego a la siguiente secuencia, etc. Esto se debe a que el hardware puede iniciar núcleos a diferentes flujos si hay recursos suficientes, mientras que si los lanzamientos posteriores son a la misma secuencia, a menudo se introduce demora, lo que reduce la concurrencia. Esta es la razón por la que su primer enfoque tiene un mejor rendimiento, y este enfoque es el que debe elegir.

La habilitación de perfiles también puede deshabilitar la concurrencia en Fermi, así que tenga cuidado con eso.Además, tenga cuidado con el uso de los eventos CUDA durante su ciclo de inicio, ya que pueden interferir; es mejor temporizar todo el ciclo utilizando eventos como lo hace, por ejemplo.

+0

¿Puede darme una fuente de dónde proviene este conocimiento (en el primer párrafo, no en el segundo)? –

+0

Hay información en la Sección 3 de la Guía de programación de CUDA 4.1. Sin embargo, después de leerlo veo que no dice explícitamente "se lanza el kernel intercalado". Obtuve la información de mis colegas en el equipo de software NVIDIA CUDA. – harrism

+0

Gracias por la actualización. Voy a volver a visitar mi código y proporcionar más información/actualizaciones si es posible. –

Cuestiones relacionadas