kernel CUDA per il gioco di Conway della vita
-
09-10-2019 - |
Domanda
Sto cercando di calcolare il numero di transizioni che sarebbero realizzati in un percorso di GOL Conway per una matrice pxq per n iterazioni. Ad esempio, in 1 iterazione con lo stato iniziale essendo 1 lampeggiante (come sotto). ci sarebbero 5 transizioni (2 nascite, 1 sopravvivenza, 2 morti da sottopopolamento). Ho già ottenuto questo lavoro, ma vorrei convertire questa logica da eseguire utilizzando CUDA. Qui di seguito è quello che voglio a porta per CUDA.
codice:
static void gol() // call this iterations x's
{
int[] tempGrid = new int[rows * cols]; // grid holds init conditions
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
tempGrid[i * cols + j] = grid[i * cols + j];
}
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
int numNeighbors = neighbors(i, j); // finds # of neighbors
if (grid[i * cols + j] == 1 && numNeighbors > 3)
{
tempGrid[i * cols + j] = 0;
overcrowding++;
}
else if (grid[i * cols + j] == 1 && numNeighbors < 2)
{
tempGrid[i * cols + j] = 0;
underpopulation++;
}
else if (grid[i * cols + j] == 1 && numNeighbors > 1)
{
tempGrid[i * cols + j] = 1;
survival++;
}
else if (grid[i * cols + j] == 0 && numNeighbors == 3)
{
tempGrid[i * cols + j] = 1;
birth++;
}
}
}
grid = tempGrid;
}
Soluzione
Il rallentamento principale sarà l'accesso alla memoria principale. Quindi io suggerirei che si sceglie una dimensione di blocco filo abbastanza grande basata su hardware che avete a disposizione. 256 (16x16) è una buona scelta per la compatibilità cross-hardware. Ognuno di questi blocchi di filettatura sta per calcolare i risultati per una sezione leggermente più piccolo del consiglio - se è stato utilizzato 16x16, faranno calcolano i risultati per una sezione 14x14 del consiglio di amministrazione, in quanto non v'è un bordo un elemento. (La ragione per usare un blocco 16x16 a 14x14 calcolare un pezzo piuttosto che un pezzo 16x16 è per la memoria leggere coalescenza.)
Dividere il bordo fino in (diciamo) 14x14 pezzi; questa è la vostra griglia (organizzato tuttavia si vede in forma, ma molto probabilmente qualcosa di simile board_width / 14
, board_height / 14
.
Nei kernel, hanno ogni carico filo suo elemento nella memoria condivisa. syncthreads allora. Poi hanno gli intermedi 14x14 elementi calcolare il nuovo valore (utilizzando i valori memorizzati nella memoria condivisa) e scrivere di nuovo nella memoria globale. L'uso di memoria condivisa aiuta a minimizzare letture e le scritture globale. Questo è anche il motivo per avere la dimensione del blocco di filettatura più grande possibile -. I bordi e gli angoli sono "sprecati" accessi di memoria globale, dal momento che i valori recuperati ci si abitua solo 1 o 3 volte, non 9 volte
Altri suggerimenti
Ecco un modo si potrebbe procedere:
- Ogni thread rende il calcolo per 1 elemento della rete
- Ogni thread primi carichi fino un elemento dalla griglia principale nella memoria condivisa
- Filati sul bordo della necessità blocco di filettatura anche per caricare elementi di contorno
- Ogni thread può quindi fare la loro sopravvivenza calcolo in base al contenuto della memoria condivisa
- Ogni thread quindi scrive il risultato di nuovo alla memoria principale