[image]https://leganerd.com/wp-content/uploads/LEGANERD_046390.jpg[/image]

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.

[title]GPGPU[/title]
Il [b]GPGPU[/b] ([i]General-Purpose computing on Graphics Processing Units[/i]) 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 [b]CPU[/b] e [b]GPU[/b] è che mentre la prima deve essere in grado di eseguire in modo soddisfacente qualsiasi tipo di [i]workload[/i] con la seconda si può ottenere buoni risultati solo con carichi altamente paralleli.

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

Quindi l’idea di base per il [b]GPGPU[/b] non è far girare l’intero programma sulla [b]GPU[/b] ma utilizzare il mix [b]CPU/GPU[/b] 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 [b]CPU[/b] allo spazio proprio della [b]GPU[/b]. 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 [b]GPGPU[/b] 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 [b]ATI[/b], 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 ([b]CPU[/b]) e fargli fare tutti i conti oppure prendere tutti e 30 gli alunni ([b]GPU[/b]) 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.

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

[image]https://leganerd.com/wp-content/uploads/LEGANERD_046379.jpg[/image]

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

[image]https://leganerd.com/wp-content/uploads/LEGANERD_046391.jpg[/image]

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 [i]DRAM[/i] della [b]GPU[/b] stessa o utilizzare lo spazio per condividere dati tra [i]thread[/i] eseguiti sugli [i]Streaming Processor[/i]. Inoltre abbiamo una serie di registri e uno scheduler dei [i]warp[/i] (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 [b]ATI[/b], ha fatto prediligere [b]nVidia[/b] a quest’ultima, in questo campo.

[URL=http://www.nvidia.it/object/cuda_home_new_it.html]Via[/url]