GPGPU - General Purpose computing on Graphics Processing Units #LegaNerd
5

Salve ragazzi, manco un po’ da LN ma adesso che ho un po’ di tempo ho proprio voglia di scrivere un articolo su l’argomento che mi ha tenuto compagnia in questi ultimi mesi.

GPGPU


Il GPGPU (General-Purpose computing on Graphics Processing Units) non è altro che l’elaborazione di dati, non prettamente inerenti alla grafica, attraverso una GPU. Questo tipo di elaborazione inizia a svilupparsi negli anni 06/07 quando ci si accorge che la potenza per far girare in modo decente alcuni videogiochi può essere utilizzata in altro modo.
La differenza sostanziale tra la computazione CPU e GPU è che mentre la prima deve essere in grado di eseguire in modo soddisfacente qualsiasi tipo di workload con la seconda si può ottenere buoni risultati solo con carichi altamente paralleli.

Questo in funzione del fatto che architetturalmente la CPU conta pochi processori (nell’ordine delle unità) ma complessi e “veloci”, mentre la GPU conta molti processori (nell’ordine delle centinaia) più semplici e “lenti”.

Quindi l’idea di base per il GPGPU non è far girare l’intero programma sulla GPU ma utilizzare il mix CPU/GPU per l’esecuzione, sfruttando il processore/i grafico/i solo nel caso in cui si possa ottenere reali vantaggi da una computazione parallela, come si fa con l’esecuzione dei nostri amati VG.

Per esempio l’applicazione più semplice dove si sfrutta il parallelismo è la somma di due vettori, dove la somma di ogni elemento con un altro può essere effettuata da ogni processore separato in modo parallelo e non in maniera sequenziale come avverrebbe su una CPU monoprocessore. Su un’applicazione del genere, senza usare tante finezze possiamo diminuire il tempo di esecuzione anche di 200 volte.

Ovviamente ci sono dei risvolti negativi, in particolare il fatto che ogni qualvolta si voglia elaborare dei dati questi vanno fisicamente spostati nello spazio di elaborazione della CPU allo spazio proprio della GPU. Questo comporta un surplus di tempo che non viene speso nell’elaborazione diretta, ma solo nello spostamento di dati, e spesso questo tempo è la componente predominante del tempo di esecuzione. Per risolvere questo problema ci sono diverse tecniche come l’uso della memoria condivisa ma rendono molto più complesso lo sviluppo dell’algoritmo.

Infatti un’altro problema del GPGPU e della computazione parallela in generale è proprio la difficoltà di programmazione, oltre alla non portabilità assoluta del codice prodotto in quanto abbastanza legato alla struttura hardware sottostante (un programma scritto con supporto nVidia non gira su una ATI, almeno per adesso). Per fare un esempio di quanto può essere difficile programmare il parallelo mi piace raccontare questo paradigma:

pensiamo a una classe di 30 alunni e un professore che vuol far fare dei calcoli aritmetici agli studenti, diciamo 30 addizioni numeriche. Può scegliere se prendere il più bravo degli alunni (CPU) e fargli fare tutti i conti oppure prendere tutti e 30 gli alunni (GPU) e fargli fare un calcolo ognuno. In questo caso la difficoltà del professore (il programmatore) è quella di distribuire a tutti gli alunni i dati, e riprendere i dati elaborati da tutti. Così è abbastanza semplice ma modificando di poco il comando diventa un inferno: pensiamo se le addizioni fossero mixate, ovvero un certo alunno deve sommare a il risultato dell’alunno 2,5,8 un certo valore e cosi via. Non si può sapere quale alunno ha terminato, se il valore che ha prodotto è quello attuale e cosi via, quindi il professore deve provvedere anche alla coordinazione tra gli alunni ed è decisamente problematico. Questo problema va sotto il nome di corenza della cache ed è uno dei problemi più rilevanti nella programmazione parallela e nella costruzione di hardware parallelo.

CUDA


CUDA(Compute Unified Device Architecture) è un’architettura hardware sviluppata da nVidia e applicata alle GPU a partire dalla serie 8. Anche ATI ha sviluppato la propria architettura adatta per il GPGPU ma dato che alla fine la programmazione di quest’ultima è più complessa e non la conosco parlerò della tecnologia sviluppata da nVidia. In particolare qui sotto vediamo il chip denominato Fermi montato sulla seria 400 in poi.

I rettangoli verde scuro rappresentano i processori elementari (Streaming Processor) e sono raggruppati in gruppi da 32 (Streaming Multiprocessor). Nell’architettura Fermi completa (quella utilizzata nella 580 per esempio) sono presenti un totale di 512 processori, mentre nelle schede di fascia inferiore uno o più Streaming Multiprocessor sono disabilitati. Al centro vediamo rappresentata una cache di livello 2 (il primo è interno a ogni SM).

Ogni Streaming Multiprocessor ha a disposizione 4 unità per il calcolo delle funzioni speciali (seno, coseno,radice quadrata) in modo efficiente, oltre che uno spazio di memoria di 64KB che può essere utilizzato per fare caching verso la DRAM della GPU stessa o utilizzare lo spazio per condividere dati tra thread eseguiti sugli Streaming Processor. Inoltre abbiamo una serie di registri e uno scheduler dei warp (non sono altro che blocchi di istruzioni per i 32 processori).

Per quanto riguarda la programmazione di questo tipo di architettura è praticamente C\C++ con aggiunta alcune funzioni particolari che magari spiegherò in un secondo articolo. Questa semplicità di programmazione ,che in realtà cosi semplice non è, che però risulta tale confrontato con il metodo di programmazione delle ATI, ha fatto prediligere nVidia a quest’ultima, in questo campo.

Via

Aree Tematiche
Hardware Tecnologie
Tag
mercoledì 22 febbraio 2012 - 12:43
Edit

Lega Nerd Podcast

Lega Nerd Live

LN Panic Mode - Premi "P" per tornare a Lega Nerd