2012-03-30 12 views
2

Ich muss berechnen wie: A [x] [y] = Summe {von z = 0 bis z = n} {B [x] [y] [z] + C [x] [ y] [z]}, wobei Matrix A Abmessungen [Höhe] [Breite] und Matrix B hat, C Abmessungen [Höhe] [Breite] [n] hat.Summe 3D-Matrix cuda

Werte in dem Speicher mit so etwas wie abgebildet werden:

index = 0; 
for (z = 0; z<n; ++z) 
    for(y = 0; y<width; ++y) 
     for(x = 0; x<height; ++x) { 
      matrix[index] = value; 
      index++; 
     } 

Q1: Ist das Cuda Kernel ok?

idx = blockIdx.x*blockDim.x + threadIdx.x; 
idy = blockIdx.y*blockDim.y + threadIdx.y; 

for(z=0; z<n; z++){ 
    A[idx*width+idy] += B[idx*width+idy+z*width*height] + C[idx*width+idy+z*width*height]; 
} 

Q2: Ist dies der schnellere Weg, um die Berechnung durchzuführen?

idx = blockIdx.x*blockDim.x + threadIdx.x; 
idy = blockIdx.y*blockDim.y + threadIdx.y; 
idz = blockIdx.z*blockDim.z + threadIdx.z; 

int stride_x = blockDim.x * gridDim.x; 
int stride_y = blockDim.y * gridDim.y; 
int stride_z = blockDim.z * gridDim.z; 

while (idx < height && idy < width && idz < n) { 
    atomicAdd(&(A[idx*width+idy]), B[idx*width+idy+idz*width*height] + C[idx*width+idy+idz*width*height]); 
    idx += stride_x; 
    idy += stride_y; 
    idz += stride_z; 
} 

Antwort

1

Q1: Test mit Matrizen, wo Sie die Antwort wissen

Anmerkung: Sie könnten Probleme haben, wenn sehr große Matrizen. Verwenden Sie eine While-Schleife mit geeigneten Schritten. Cuda by Example ist wie immer das Nachschlagewerk.

Ein Beispiel für die Implementierung einer verschachtelten Schleife finden Sie hier: For nested loops with CUDA. Dort ist eine while-Schleife implementiert.

marina.k hat Recht bezüglich der Race Condition. Das würde Ansatz 1 bevorzugen, da atomare Operationen den Code tendenziell verlangsamen.

+0

Maximum Dimensionalität des Gewindesatzes = 3, Maximum Dimensionalität des Gitters von Gewindesätzen = 2 (für CC <2) = 3 (für CC> = 2). also denke ich, dass es kein Problem gibt. Ich habe große Matrizen, sehe aber das Problem nicht. – user1281071

+0

Okay gut zu wissen. Ich habe meine Antwort aktualisiert. – Azrael3000

+0

Sie sagen: 'if (idx> = Höhe || idy> = Breite || idz> = n) zurück;'? – user1281071

2

Der erste Kernel ist in Ordnung. Aber wir haben keinen Zugriff auf die Matrix B und C.

Wie für die zweite Kernel-Funktion. Sie haben Datenrennen, weil nicht nur ein Thread eine Fähigkeit hat, in A[idx*width+idy] Adressen zu schreiben. Sie benötigen zusätzliche Synchronisation wie AttomicAdd

Wie für allgemeine Frage: Ich denke, dass Experimente zeigen, dass es besser ist. Es hängt von typischen Matrixgrößen ab, die Sie haben. Denken Sie daran, dass die maximale Thread-Blockgröße auf Fermi < 1024 und wenn Matrizen groß sind, Sie viele Thread-Blöcke gem. Normalerweise ist es langsamer (um viele Thread-Blöcke zu haben).

+0

guter Punkt mit Daten racing, thx :) wenn ich atomare Funktion hinzufügen der Code Form Q2 wird genau das gleiche wie Code in Q1? Mein Hauptziel ist die Geschwindigkeit, also suche ich nach der schnellsten Lösung. – user1281071

+0

Ich habe meine Antwort bearbeitet. – geek

+0

"Experimente zeigen, dass es besser ist", ist es besser atomare Funktionen zu verwenden? oder nicht benutzen? – user1281071

2

wirklich einfach in ArrayFire:

array A = randu(nx,ny,nz); 
array B = sum(A,2); // sum along 3rd dimension 
print(B);