CUDA (acronimo di Compute Unified Device Architecture) è un'architettura hardware per l'elaborazione parallela creata da NVIDIA. Tramite l'ambiente di sviluppo per CUDA, i programmatori di software possono scrivere applicazioni capaci di eseguire calcolo parallelo sulle GPU delle schede video NVIDIA.
I linguaggi di programmazione disponibili nell'ambiente di sviluppo CUDA sono estensioni dei linguaggi più diffusi per scrivere programmi. Il principale è 'CUDA-C' (C con estensioni NVIDIA), altri sono estensioni di Python, Fortran, Java e MATLAB.
Programmi che sfruttano l'architettura CUDA possono essere scritti anche utilizzando le librerie software OpenCL e DirectCompute.
CUDA dà accesso agli sviluppatori ad un set di istruzioni native per il calcolo parallelo di elementi delle GPU CUDA. Usando CUDA, le ultime GPU Nvidia diventano in effetti architetture aperte come le CPU. Diversamente dalle CPU, le GPU hanno un'architettura parallela con diversi core, ognuno capace di eseguire centinaia di processi simultaneamente: se un'applicazione è adatta per questo tipo di architettura, la GPU può offrire grandi prestazioni e benefici. Questo approccio alla risoluzione dei problemi è noto come GPGPU.
Vantaggi
CUDA ha parecchi vantaggi rispetto alle tradizionali tecniche di calcolo sulle GPU che usano le API grafiche.
- Il codice può essere letto da posizioni arbitrarie in memoria.
- Memoria condivisa: CUDA espone una regione di 16kB di grandezza che può essere condivisa velocemente fra i thread. Questa può essere usata come una cache gestita dall'utente, rendendo disponibili grandi larghezze di banda che è possibile usare per strutture texture.
- Letture e scritture veloci, verso e dalla GPU.
- Supporto completo per divisioni intere e operazioni bit-a-bit, tra cui l'accesso a texture intere.
Limitazioni
- CUDA era inizialmente un sottoinsieme del linguaggio C, privo di ricorsione e puntatori a funzione, più alcune semplici estensioni. Un singolo processo deve essere eseguito attraverso multiple disgiunzioni di spazi di memoria, diversamente da altri ambienti di runtime C. Le versioni più recenti tuttavia usano la sintassi C++. Il codice scritto per le versioni precedenti può non compilare, oppure può comportarsi in modo differente.
- Il rendering delle texture non è supportato.
- Per la doppia precisione, supportata a partire dalla serie GTX 2XX, ci sono diverse deviazioni dallo standard IEEE 754: l'arrotondamento al pari è l'unica approssimazione supportata per: reciproci, divisioni e radici quadrate. In singola precisione i NAN segnalati e denormalizzati non sono supportati; queste sono specifiche per istruzioni di base, rispetto ad una singola parola di controllo[non chiaro]; e la precisione delle cifre decimali di divisioni o radici n-esime è molto minore rispetto alla singola precisione.
- La larghezza di banda e la latenza tra CPU e GPU può essere un collo di bottiglia.
- I thread devono essere eseguiti in multipli di 32 per ottenere migliori prestazioni, con un numero totale di thread nell'ordine di migliaia. I rami dei codici non influiscono nelle prestazioni, a condizione che ciascuno dei 32 thread prenda lo stesso cammino di esecuzione. Il modello di esecuzione SIMD diviene una limitazione significativa per diversi compiti, per esempio l'attraversamento di uno spazio partizionato di strutture dati durante il raytracing.
- Diversamente da OpenCL, GPU dotate di CUDA sono disponibili solo da NVIDIA (GeForce 8 serie superiori, Quadro e Tesla)
- La gestione delle eccezioni non è supportata nel codice CUDA a causa del degrado delle prestazioni risultante con migliaia di thread in esecuzione.
- Nelle versioni più recenti non esistono emulatori software per l'esecuzione del codice CUDA.
Lista GPU supportate
Ecco una lista hardware che supporta ufficialmente CUDA. Notare che molte applicazioni richiedono almeno 256 MB di VRAM dedicata.
Nvidia GeForce
|
Geforce GTX 10xx
|
GeForce GTX 9xx
|
GeForce GTX 7xx
|
GeForce GT\GTX 6xx
|
GeForce GTX 580
|
GeForce GTX 570
|
GeForce GTX 560 Ti
|
GeForce GTX 480
|
GeForce GTX 470
|
GeForce GTX 465
|
GeForce GTX 460
|
GeForce GT 430
|
GeForce GTX 295
|
GeForce GTX 285
|
GeForce GTX 280
|
GeForce GTX 275
|
GeForce GTX 260
|
GeForce GTS 250
|
GeForce GTS 240
|
GeForce GT 240
|
GeForce GT 220
|
GeForce GT 330M
|
GeForce 210/G210
|
GeForce 9800 GX2
|
GeForce 9800 GTX+
|
GeForce 9800 GTX
|
GeForce 9800 GT
|
GeForce 9600 GSO
|
GeForce 9600 GT
|
GeForce 9500 GT
|
GeForce 9400 GT
|
GeForce 9400 mGPU
|
GeForce 9300 mGPU
|
GeForce 9100 mGPU
|
GeForce 8800 Ultra
|
GeForce 8800 GTX
|
GeForce 8800 GTS
|
GeForce 8800 GT
|
GeForce 8800 GS
|
GeForce 8600 GTS
|
GeForce 8600 GT
|
GeForce 8600 mGT
|
GeForce 8500 GT
|
GeForce 8400 GS
|
GeForce 8300 mGPU
|
GeForce 8200 mGPU
|
GeForce 8100 mGPU
|
|
Nvidia GeForce Mobile
|
GeForce GTX 880M
|
GeForce GTX 870M
|
GeForce GTX 860M
|
GeForce GTX 780M
|
GeForce GTX 770M
|
GeForce GTX 765M
|
GeForce GTX 760M
|
GeForce GT\GTX 6xx
|
GeForce GT\GTX 5xx
|
GeForce GT\GTX 4xx
|
GeForce GT\GTX 3xx
|
GeForce GTX 285M
|
GeForce GTX 280M
|
GeForce GTX 260M
|
GeForce GTS 260M
|
GeForce GTS 250M
|
GeForce GT 240M
|
GeForce GT 230M
|
GeForce GT 220M
|
GeForce G210M
|
GeForce GTS 160M
|
GeForce GTS 150M
|
GeForce GT 130M
|
GeForce GT 120M
|
GeForce G110M
|
GeForce G105M
|
GeForce G102M
|
GeForce G100
|
GeForce 9800M GTX
|
GeForce 9800M GTS
|
GeForce 9800M GT
|
GeForce 9800M GS
|
GeForce 9700M GTS
|
GeForce 9700M GT
|
GeForce 9650M GT
|
GeForce 9650M GS
|
GeForce 9600M GT
|
GeForce 9600M GS
|
GeForce 9500M GS
|
GeForce 9500M G
|
GeForce 9400M G
|
GeForce 9300M GS
|
GeForce 9300M G
|
GeForce 9200M GS
|
GeForce 9100M G
|
GeForce 8800M GTX
|
GeForce 8800M GTS
|
GeForce 8700M GT
|
GeForce 8600M GT
|
GeForce 8600M GS
|
GeForce 8400M GT
|
GeForce 8400M GS
|
GeForce 8400M G
|
GeForce 8200M G
|
|
Nvidia Quadro
|
Quadro FX 5800
|
Quadro FX 5600
|
Quadro FX 4800
|
Quadro FX 4700 X2
|
Quadro FX 4600
|
Quadro FX 3800
|
Quadro FX 3700
|
Quadro FX 1800
|
Quadro FX 1700
|
Quadro FX 580
|
Quadro FX 570
|
Quadro FX 380
|
Quadro FX 370
|
Quadro NVS 450
|
Quadro NVS 420
|
Quadro NVS 295
|
Quadro NVS 290
|
Quadro Plex 1000 Model IV
|
Quadro Plex 1000 Model S4
|
Nvidia Quadro Mobile
|
Quadro FX 3700M
|
Quadro FX 3600M
|
Quadro FX 2700M
|
Quadro FX 1700M
|
Quadro FX 1600M
|
Quadro FX 770M
|
Quadro FX 570M
|
Quadro FX 370M
|
Quadro FX 360M
|
Quadro NVS 320M
|
Quadro NVS 160M
|
Quadro NVS 150M
|
Quadro NVS 140M
|
Quadro NVS 135M
|
Quadro NVS 130M
|
Nvidia Tesla
|
Tesla S1070
|
Tesla C1060
|
Tesla C870
|
Tesla D870
|
Tesla S870
|
|
|
CUDA Nvidia e BOINC
La piattaforma BOINC (Berkeley Open Infrastructure for Network Computing) ha diversi progetti di calcolo distribuito che supportano e sfruttano a pieno le potenzialità e i benefici della tecnologia CUDA.
I progetti BOINC supportati dalla piattaforma Nvidia CUDA sono:[1]
- Collatz Conjecture: si pone come obiettivo la soluzione della celebre congettura di Collatz (o 3n + 1)
- DistrRTgen: è un progetto volto alla creazione di rainbow table distribuite gratuitamente
- Einstein@home: ha lo scopo di analizzare i dati prodotti da osservatori astronomici per rilevare delle onde gravitazionali da diverse fonti, come ad esempio i buchi neri
- GPUgrid.net: è un progetto nel campo della ricerca biomedica
- Milkyway@home: l'obiettivo di questo progetto è la creazione di un accurato modello tridimensionale della Via Lattea, utilizzando i dati forniti dallo Sloan Digital Sky Survey
- Moo!: permette di partecipare alla competizione RC5-72, è un wrapper di distributed.net
- PrimeGrid: esegue la ricerca dei numeri primi più elevati al mondo
- SETI@home: è il famosissimo progetto di calcolo distribuito, utilizza i dati del radiotelescopio di Arecibo per la ricerca di segnali correlati a intelligenze extraterrestri
Esempi
Questo esempio di codice in C++ carica una texture da un'immagine dentro un array della GPU:
* cudaArray* cu_array;
texture<float, 2> tex;
// Allocate array
cudaChannelFormatDesc description = cudaCreateChannelDesc<float>();
cudaMallocArray(&cu_array, &description, width, height);
// Copy image data to array
cudaMemcpy(cu_array, image, width*height*sizeof(float), cudaMemcpyHostToDevice);
// Bind the array to the texture
cudaBindTextureToArray(tex, cu_array);
// Run kernel
dim3 blockDim(16, 16, 1);
dim3 gridDim(width / blockDim.x, height / blockDim.y, 1);
kernel<<< gridDim, blockDim, 0 >>>(d_odata, height, width);
cudaUnbindTexture(tex);
__global__ void kernel(float* odata, int height, int width)
{
unsigned int x = blockIdx.x*blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y*blockDim.y + threadIdx.y;
float c = tex2D(tex, x, y);
odata[y*width+x] = c;
}
Sotto un esempio in Python che computa il prodotto di due array nella GPU. Il linguaggio non ufficiale Python può essere ottenuto da PyCUDA.
import pycuda.driver as drv
import numpy
import pycuda.autoinit
mod = drv.SourceModule("""
__global__ void multiply_them(float *dest, float *a, float *b)
{
const int i = threadIdx.x;
dest[i] = a[i] * b[i];
}
""")
multiply_them = mod.get_function("multiply_them")
a = numpy.random.randn(400).astype(numpy.float32)
b = numpy.random.randn(400).astype(numpy.float32)
dest = numpy.zeros_like(a)
multiply_them(
drv.Out(dest), drv.In(a), drv.In(b),
block=(400,1,1))
print(dest-a*b)
Altri Python bindings per semplificare i prodotti tra matrici possono essere trovati su pycublas.
import numpy
from pycublas import CUBLASMatrix
A = CUBLASMatrix( numpy.mat([[1,2,3],[4,5,6]],numpy.float32) )
B = CUBLASMatrix( numpy.mat([[2,3],[4,5],[6,7]],numpy.float32) )
C = A*B
print C.np_mat()
Note
Voci correlate
Altri progetti
Collegamenti esterni