2012-05-05 9 views
104

Utilizzo CUDA da alcune settimane, ma ho qualche dubbio sull'assegnazione di blocchi/fili/filo. Sto studiando l'architettura da un punto di vista didattico (progetto universitario), quindi raggiungere il massimo delle prestazioni non è la mia preoccupazione.In che modo CUDA blocca/deforma/filtra la mappa sui core CUDA?

Prima di tutto, vorrei capire se ho ottenuto questi fatti dritto:

  1. Il programmatore scrive un kernel, e organizzare la sua esecuzione in una griglia di blocchi di filettatura.

  2. Ogni blocco è assegnato a un multiprocessore di flusso (SM). Una volta assegnato, non può migrare a un altro SM.

  3. Ogni SM divide i propri blocchi in Warps (attualmente con una dimensione massima di 32 thread). Tutti i thread in un warp vengono eseguiti simultaneamente sulle risorse dell'SM.

  4. L'esecuzione effettiva di un thread viene eseguita dai core CUDA contenuti nell'SM. Non esiste una mappatura specifica tra thread e core.

  5. Se un warp contiene 20 thread, ma attualmente sono disponibili solo 16 core, il warp non verrà eseguito.

  6. D'altra parte se un blocco contiene 48 thread, sarà diviso in 2 warps e verrà eseguito in parallelo a condizione che sia disponibile memoria sufficiente.

  7. Se un thread inizia su un core, quindi viene bloccato per l'accesso alla memoria o per un'operazione a virgola mobile lunga, la sua esecuzione potrebbe riprendere su un core differente.

Sono corretti?

Ora, ho una GeForce 560 Ti quindi secondo le specifiche è dotata di 8 SM, ciascuna contenente 48 core CUDA (384 core in totale).

Il mio obiettivo è assicurarsi che ogni nucleo dell'architettura esegua le istruzioni SAME. Supponendo che il mio codice non richiederà più il registro di quelli disponibili in ogni SM, ho immaginato diversi approcci:

  1. ho creare 8 blocchi di 48 thread ciascuno, in modo che ogni SM ha 1 blocco da eseguire. In questo caso i 48 thread verranno eseguiti in parallelo nell'SM (sfruttando tutti i 48 core disponibili per loro)?

  2. C'è qualche differenza se lancio 64 blocchi di 6 thread? (Supponendo che verranno mappati in modo uniforme tra gli SM)

  3. Se "immergo" la GPU in lavoro pianificato (creando 1024 blocchi di 1024 thread ciascuno, ad esempio) è ragionevole presumere che tutti i core saranno usato ad un certo punto e eseguirà gli stessi calcoli (supponendo che i fili non si fermino mai)?

  4. C'è un modo per verificare queste situazioni utilizzando il profiler?

  5. C'è qualche riferimento per questa roba?Ho letto la guida alla programmazione CUDA e i capitoli dedicati all'architettura hardware in "Programmazione di processori paralleli in parallelo" e "Progettazione e sviluppo di applicazioni CUDA"; ma non ho potuto ottenere una risposta precisa.

risposta

94

Due dei migliori riferimenti sono

  1. NVIDIA Fermi Compute Architecture Whitepaper
  2. GF104 Reviews

Cercherò di rispondere a ciascuna delle vostre domande.

Il programmatore divide il lavoro in thread, thread in blocchi di thread e blocchi di thread in griglie. Il distributore di lavoro di calcolo assegna i blocchi di thread a Streaming Multiprocessor (SM). Una volta che un blocco di thread viene distribuito a un SM, vengono allocate le risorse per il blocco di thread (warps e memoria condivisa) ei thread sono divisi in gruppi di 32 thread chiamati warps. Una volta assegnato un ordito, viene chiamato curvatura attiva. I due schedulatori di ordito scelgono due orditi attivi per ciclo e orditi di spedizione in unità di esecuzione. Per ulteriori dettagli sulle unità di esecuzione e sulla spedizione delle istruzioni, vedere 1 p.7-10 e 2.

4 '. Esiste una mappatura tra laneid (indice dei fili in un ordito) e un nucleo.

5 '. Se un warp contiene meno di 32 thread, nella maggior parte dei casi verrà eseguito come se avesse 32 thread. Warps può avere meno di 32 thread attivi per diversi motivi: il numero di thread per blocco non è divisibile per 32, il programma esegue un blocco divergente in modo che i thread che non hanno preso il percorso corrente siano contrassegnati inattivi o che un thread nel warp sia terminato.

6 '. Un blocco di thread sarà suddiviso in WarpsPerBlock = (ThreadsPerBlock + WarpSize - 1)/WarpSize Non vi è alcun obbligo per gli schedulatori di warp di selezionare due warp dallo stesso blocco di thread.

7 '. Un'unità di esecuzione non si fermerà su un'operazione di memoria. Se una risorsa non è disponibile quando un'istruzione è pronta per essere spedita, l'istruzione verrà nuovamente inviata in futuro quando la risorsa sarà disponibile. I Warp possono bloccarsi alle barriere, sulle operazioni di memoria, sulle operazioni di trama, sulle dipendenze dei dati, ... Un ordito in stallo non è idoneo per essere selezionato dallo schedulatore di warp. Su Fermi è utile avere almeno 2 warps idonei per ciclo in modo che lo scheduler di warp possa emettere un'istruzione.

Vedere il riferimento 2 per le differenze tra una GTX480 e una GTX560.

Se leggi il materiale di riferimento (pochi minuti) penso che troverai che il tuo obiettivo non ha senso. Proverò a rispondere ai tuoi punti.

1 '. Se lanci il kernel < < < 8, 48 >>> otterrai 8 blocchi ciascuno con 2 fili di 32 e 16 fili. Non è garantito che questi 8 blocchi saranno assegnati a SM diversi. Se 2 blocchi sono assegnati ad un SM, allora è possibile che ogni schedulatore di warp possa selezionare un warp ed eseguire il warp. Utilizzerai solo 32 dei 48 core.

2 '.C'è una grande differenza tra 8 blocchi di 48 thread e 64 blocchi di 6 thread. Supponiamo che il tuo kernel non abbia divergenze e che ogni thread esegua 10 istruzioni.

  • 8 blocchi con 48 fili = 16 orditi * 10 istruzioni = 160 Avviso
  • 64 blocchi con 6 fili = 64 fili di ordito * 10 Avviso = 640 Avviso

Al fine di ottenere un rendimento ottimale del la divisione del lavoro dovrebbe essere in multipli di 32 thread. L'hardware non collegherà i fili da diversi orditi.

3 '. Una GTX560 può avere 8 blocchi SM * 8 = 64 blocchi alla volta o 8 SM * 48 warps = 512 warps se il kernel non raggiunge il massimo dei registri o della memoria condivisa. In qualsiasi momento su una parte del lavoro sarà attivo su SM. Ogni SM ha più unità di esecuzione (più che core CUDA). Quali risorse sono in uso in un dato momento dipende dagli schedulatori di warp e dal mix di istruzioni dell'applicazione. Se non esegui operazioni TEX, le unità TEX saranno inattive. Se non si esegue una speciale operazione in virgola mobile, le unità SUFU saranno inattive.

4 '. Parallel Nsight e Visual Profiler mostrano

a. eseguito IPC

b. emesso IPC

c. orditi attivi per ciclo attivo

d. orditi idonei per ciclo attivo (solo Nsight)

e. motivi di stasi warp (solo Nsight)

f. thread attivi per istruzione eseguita

Il profiler non mostra la percentuale di utilizzo di nessuna delle unità di esecuzione. Per GTX560 una stima approssimativa sarebbe IssuedIPC/MaxIPC. Per MaxIPC assumere GF100 (GTX480) è 2 GF10x (GTX560) è 4 ma l'obiettivo 3 è un obiettivo migliore.

+0

Grazie per la tua risposta. Leggo i riferimenti, ma ci sono alcune cose che non capisco nella tua risposta.Nelle seguenti domande presumo che stiamo usando un'architettura Fermi con 48 core (16 core * 3 "core group"): 1. Hai menzionato una mappatura tra core e laneid. Che tipo di mappatura è? 2. Dai riferimenti che ho ottenuto, ciascun "core group" esegue al massimo un half-warp (16 thread) per ciclo di clock. Quindi, in teoria, se abbiamo 48 thread nello stesso blocco, saranno organizzati in 3 mezzi mezzi warps e eseguiti in parallelo sui 48 core. Ho ragione? – Daedalus

+0

I core CUDA sono il numero di unità FP di precisione singola. Pensare all'esecuzione in termini di core CUDA non è corretto. Ogni ordito ha 32 fili. Questi thread saranno rilasciati a un gruppo di unità di esecuzione (ad esempio 16 cuda core). Per emettere su tutti i 48 core in un singolo clock, uno dei due schedulatori di warp deve selezionare una distorsione che soddisfi il req di una coppia superscalare ed entrambe le istruzioni devono essere di un tipo eseguito dai core CUDA. Inoltre l'altro schedulatore di warp deve scegliere un ordito la cui prossima istruzione sarà eseguita dai core CUDA. –

+0

Non è richiesto che gli orditi siano nello stesso blocco o che gli orditi in un blocco abbiano lo stesso contatore di programma. –

5

"E. Se un ordito contiene 20 thread, ma attualmente sono disponibili solo 16 core, l'ordito non verrà eseguito."

non è corretto. Si stanno confondendo nuclei nel loro senso comune (usato anche nelle CPU) - il numero di "multiprocessori" in una GPU, con i nuclei nel marketing nVIDIA ("la nostra carta ha migliaia di core CUDA").

Un ordito stesso può essere pianificato solo su un singolo core (= multiprocessore) e può eseguire fino a 32 thread contemporaneamente; non può usare più di un singolo core.

Il numero "48 orditi" è il numero massimo di orditi attivi (orditi che possono essere scelti per essere programmati per il lavoro nel ciclo successivo, in qualsiasi ciclo) per multiprocessore, su GPU nVIDIA con capacità di calcolo 2.x ; e questo numero corrisponde a 1536 = 48 x 32 thread.

risposta sulla base di this webinar

+0

@GregSmith: Modificato la risposta per risolvere questo problema. Va bene che tu fossi paziente con esso, ma - sono passati cinque anni ... – einpoklum

+0

single core (= multiprocessore)? Penso che la domanda presupponga la terminologia single core = processore e non multiprocessore. Con la tua terminologia la tua risposta è corretta. – Adarsh