Ich bin neu bei CUDA und brauche Hilfe beim Verständnis einiger Dinge. Ich brauche Hilfe bei der Parallelisierung dieser beiden for-Schleifen. Insbesondere, wie man dimBlock und dimGrid einrichtet, damit dies schneller läuft. Ich weiß, dass dies wie das Beispiel zum Hinzufügen von Vektoren im SDK aussieht, aber dieses Beispiel gilt nur für quadratische Matrizen, und wenn ich versuche, diesen Code für meine 128 x 1024-Matrix zu ändern, funktioniert es nicht richtig.
__global__ void mAdd(float* A, float* B, float* C)
{
for(int i = 0; i < 128; i++)
{
for(int j = 0; j < 1024; j++)
{
C[i * 1024 + j] = A[i * 1024 + j] + B[i * 1024 + j];
}
}
}
Dieser Code ist Teil einer größeren Schleife und der einfachste Teil des Codes, also habe ich beschlossen, zu versuchen, ihn zu parallelisieren und gleichzeitig CUDA zu lernen. Ich habe die Anleitungen gelesen, verstehe aber immer noch nicht, wie ich die richtige Nr. bekomme. von Grids/Block/Threads gehen und sie effektiv nutzen.
Wie Sie es geschrieben haben, ist dieser Kernel vollständig seriell. Jeder Thread, der zu seiner Ausführung gestartet wird, wird dieselbe Arbeit ausführen.
Die Hauptidee hinter CUDA (und OpenCL und anderen ähnlichen Programmiermodellen vom Typ „Einzelprogramm, mehrere Daten“) besteht darin, dass Sie eine „datenparallele“ Operation verwenden – also eine, bei der die gleiche, weitgehend unabhängige Operation viele Male ausgeführt werden muss – und Schreiben Sie einen Kernel, der diese Operation ausführt. Eine große Anzahl von (semi)autonomen Threads wird dann gestartet, um diese Operation über den Eingabedatensatz hinweg auszuführen.
In Ihrem Array-Additionsbeispiel ist die Datenparalleloperation
C[k] = A[k] + B[k];
für alle k zwischen 0 und 128 * 1024. Jede Additionsoperation ist völlig unabhängig und hat keine Ordnungsanforderungen und kann daher von einem anderen Thread ausgeführt werden. Um dies in CUDA auszudrücken, könnte man den Kernel so schreiben:
__global__ void mAdd(float* A, float* B, float* C, int n)
{
int k = threadIdx.x + blockIdx.x * blockDim.x;
if (k < n)
C[k] = A[k] + B[k];
}
[disclaimer: code written in browser, not tested, use at own risk]
Hier werden die innere und äußere Schleife aus dem seriellen Code durch einen CUDA-Thread pro Operation ersetzt, und ich habe im Code eine Limitprüfung hinzugefügt, damit in Fällen, in denen mehr Threads als erforderliche Operationen gestartet werden, kein Pufferüberlauf auftreten kann. Wenn der Kernel dann so gestartet wird:
const int n = 128 * 1024;
int blocksize = 512; // value usually chosen by tuning and hardware constraints
int nblocks = n / blocksize; // value determine by block size and total work
madd<<<nblocks,blocksize>>>mAdd(A,B,C,n);
Dann werden 256 Blöcke mit jeweils 512 Threads auf der GPU-Hardware gestartet, um die Array-Hinzufügungsoperation parallel auszuführen. Beachten Sie, dass, wenn die Größe der Eingabedaten nicht als schönes rundes Vielfaches der Blockgröße ausgedrückt werden könnte, die Anzahl der Blöcke aufgerundet werden müsste, um den vollständigen Eingabedatensatz abzudecken.
All dies ist ein stark vereinfachter Überblick über das CUDA-Paradigma für eine sehr triviale Operation, aber vielleicht gibt es Ihnen genug Einblick, um selbst fortzufahren. CUDA ist heutzutage ziemlich ausgereift und es gibt eine Menge gutes, kostenloses Lehrmaterial im Internet, das Sie wahrscheinlich verwenden können, um viele der Aspekte des Programmiermodells, die ich in dieser Antwort beschönigt habe, weiter zu beleuchten.
.
In Pikuda es ist nur
C[i] = A[i] + B[i]
demo.py– jfs
13. April 11 um 2:06 Uhr