2010-02-01 8 views
9

Sto tentando di scrivere un semplice sistema di particelle che si avvale di CUDA per eseguire l'aggiornamento delle posizioni delle particelle. In questo momento sto definendo una particella con un oggetto con una posizione definita con tre valori float e una velocità definita anche con tre valori float. Quando aggiorno le particelle, aggiungo un valore costante alla componente Y della velocità per simulare la gravità, quindi aggiungo la velocità alla posizione corrente per ottenere la nuova posizione. In termini di gestione della memoria è meglio mantenere due matrici separate di float per archiviare i dati o strutturarli in modo orientato agli oggetti. Qualcosa di simile:Come strutturare i dati per la velocità ottimale in un'app CUDA

struct Vector 
{ 
    float x, y, z; 
}; 

struct Particle 
{ 
    Vector position; 
    Vector velocity; 
}; 

Sembra che la dimensione dei dati è lo stesso con uno dei due metodi (4 byte per galleggiante, 3 galleggianti per Vector, 2 vettori per particella totale di 24 byte totale) Sembra che il OO l'approccio consentirebbe un trasferimento di dati più efficiente tra CPU e GPU perché potrei usare una singola istruzione di copia di memoria invece di 2 (e nel lungo termine di più, poiché ci sono alcune altre informazioni sulle particelle che diventeranno rilevanti, come Age , Vita, Peso/Massa, Temperatura, ecc.) E poi c'è anche solo la semplice leggibilità del codice e la facilità con cui ci si confronta che mi rende anche incline all'approccio OO. Ma gli esempi che ho visto non utilizzano dati strutturati, quindi mi chiedo se c'è un motivo.

Quindi la domanda è: meglio un singolo array di dati o oggetti strutturati?

+1

Err .. perché non provare e scoprire? –

+4

Lol. Perché sono interessato alla teoria, anche se trovo che uno funzioni meglio dell'altro, voglio ancora sapere perché. –

risposta

18

È comune nella programmazione parallela di dati parlare di "Struct of Arrays" (SOA) rispetto a "Array of Structs" (AOS), dove il primo dei due esempi è AOS e il secondo è SOA. Molti paradigmi di programmazione parallela, in particolare i paradigmi in stile SIMD, preferiranno SOA.

Nella programmazione GPU, il motivo per cui SOA è in genere preferito è ottimizzare gli accessi alla memoria globale. È possibile visualizzare la presentazione registrata su Advanced CUDA C da GTC l'anno scorso per una descrizione dettagliata di come la GPU accede alla memoria.

Il punto principale è che le transazioni di memoria hanno una dimensione minima di 32 byte e si desidera massimizzare l'efficienza di ciascuna transazione.

Con AOS:

position[base + tid].x = position[base + tid].x + velocity[base + tid].x * dt; 
//^write to every third address     ^read from every third address 
//       ^read from every third address 

Con SOA:

position.x[base + tid] = position.x[base + tid] + velocity.x[base + tid] * dt; 
//^write to consecutive addresses    ^read from consecutive addresses 
//       ^read from consecutive addresses 

Nel secondo caso, la lettura da indirizzi consecutivi significa avere efficienza 100% contro 33% nel primo caso. Si noti che su GPU precedenti (capacità di calcolo 1.0 e 1.1) la situazione è molto peggiore (efficienza del 13%).

C'è un'altra possibilità - se aveste due o quattro carri nel struct allora si potrebbe leggere l'AOS con un'efficienza del 100%:

float4 lpos; 
float4 lvel; 
lpos = position[base + tid]; 
lvel = velocity[base + tid]; 
lpos.x += lvel.x * dt; 
//... 
position[base + tid] = lpos; 

Ancora una volta, controlla la presentazione avanzata CUDA C per i dettagli .

+0

Tom, è possibile scaricare la presentazione che hai collegato? –

+0

John, è possibile utilizzare uno dei seguenti collegamenti: http://www.nvidia.com/content/GTC/videos/GTC09-1086.flv http://www.nvidia.com/content/GTC/videos/GTC09 -1086.mp4 – Tom

Problemi correlati