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)
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
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). –
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