2012-02-16 12 views
6

L'utilizzo di flussi diversi per i kernel CUDA rende possibile l'esecuzione concomitante del kernel. Pertanto i kernel n sugli stream n potrebbero teoricamente essere eseguiti contemporaneamente se si inseriscono nell'hardware, giusto?Esecuzione concomitante del kernel CUDA con più kernel per flusso

Ora sto affrontando il seguente problema: non ci sono n kernel distinte ma n*m in cui devono essere eseguite in modo m kernel. Per esempio n=2 e m=3 porterebbe il seguente schema di esecuzione con flussi:

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

mia ipotesi naive è che il kernel x.0 e Y.1 devono eseguire contemporaneamente (da un punto di vista teorico) o almeno non consecutivamente (da un punto di vista pratico). Ma le mie misurazioni mi stanno dimostrando che non è questo il caso e sembra che venga eseguita un'esecuzione consecutiva (cioè K0.0, K1.0, K2.0, K0.1, K1.1, K2.1). I kernel stessi sono molto piccoli, quindi l'esecuzione simultanea non dovrebbe essere un problema.

Ora il mio approccio sarebbe quello di realizzare una sorta di dispatching per assicurarsi che i kernel siano en-Queued in uno stile interlacciato nello scheduler sulla GPU. Ma quando si ha a che fare con un gran numero di stream/kernel, questo potrebbe fare più male che bene.

Va bene, venendo dritto al punto: quale sarebbe un approccio appropriato (o almeno diverso) per risolvere questa situazione?

Edit: Le misurazioni vengono effettuate utilizzando eventi CUDA. Ho misurato il tempo necessario per risolvere completamente il calcolo, i. e. la GPU deve calcolare tutti i kernel n * m. L'ipotesi è: in caso di esecuzione del kernel completamente concomitante, il tempo di esecuzione è approssimativamente (idealmente) 1/n volte del tempo necessario per eseguire tutti i kernel in ordine, per cui è possibile che due o più kernel possano essere eseguiti contemporaneamente. Lo sto assicurando utilizzando solo due stream distinti al momento.

Posso misurare una chiara differenza per quanto riguarda i tempi di esecuzione tra l'utilizzo dei flussi come descritto e la spedizione dei kernel interlacciati, i. E .:

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

contro

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

Il secondo porta ad un tempo di esecuzione più lungo.

Modifica n. 2: Modificato i numeri del flusso iniziale da 1 (anziché 0, vedere i commenti di seguito).

Modifica # 3: dell'hardware è un NVIDIA Tesla M2090 (cioè Fermi, calcolare la capacità 2.0)

+0

Probabilmente è necessario utilizzare alcune primitive di sincronizzazione dello stream per far rispettare l'ordine di esecuzione necessario. Potresti forse ampliare un po 'il modo in cui hai effettuato le tue misurazioni nella tua domanda, e potresti anche confermare che quando scrivi "Stream 0", non intendi letteralmente CUDA stream 0? – talonmies

+0

Ho chiarito la misura (almeno lo spero). Con stream sto intendendo istanze di 'cudaStream_t' come descritto in [CUDA C Programming Guide] (http://developer.download.nvidia.com/compute/DevZone/docs/html/C/doc/CUDA_C_Programming_Guide.pdf), sezione 3.2.5 (Esecuzione simultanea asincrona). –

+2

Forse hai frainteso quello che stavo chiedendo - voglio dire è uno dei tuoi stream CUDA stream 0, perché lo stream 0 (il flusso predefinito) è sincrono. – talonmies

risposta

5

On Fermi (aka Compute Capability 2.0) hardware è meglio interleave kernel lancia ai flussi multipli, piuttosto che a lancia tutti i kernel in un flusso, poi nel flusso successivo, ecc. Questo perché l'hardware può lanciare immediatamente i kernel su flussi diversi se ci sono risorse sufficienti, mentre se i lanci successivi sono nello stesso flusso, spesso viene introdotto un ritardo, riducendo la concorrenza. Questo è il motivo per cui il tuo primo approccio si comporta meglio e questo approccio è quello che dovresti scegliere.

Abilitare il profilo può anche disabilitare la concorrenza su Fermi, quindi fai attenzione.Inoltre, fai attenzione nell'usare gli eventi CUDA durante il tuo ciclo di lancio, in quanto questi possono interferire, ad esempio, preferibilmente per cronometrare l'intero ciclo utilizzando eventi come stai facendo.

+0

Puoi darmi una fonte da cui proviene questa conoscenza (entro il primo paragrafo, non la seconda)? –

+0

Ci sono informazioni nella Sezione 3 della Guida alla Programmazione CUDA 4.1. Tuttavia, dopo averlo letto, vedo che non dice esplicitamente "lanci di kernel interleave". Ho ricevuto le informazioni dai miei colleghi nel team del software NVIDIA CUDA. – harrism

+0

Grazie per l'aggiornamento. Ho intenzione di rivisitare il mio codice e fornire ulteriori informazioni/aggiornamenti, se possibile. –

Problemi correlati