2016-04-06 16 views
1

Ich benutze CUFFT für 2D FFT auf 128 Bildern. Jedes Bild hat die Größe 128 x 128. Auf MATLAB dauert die Durchführung einer 2D-FFT 0,3 ms, und die Durchführung einer FFT auf allen 128 Bildern dauert etwa 128 mal so viele Male. Verwendung CUFFT, die Ausführung des folgenden Coderechen FFT für ein BildStrategie - CUFFT computing 2D FFT auf vielen Bildern

cudaMalloc((void**)idata, sizeof(cufftDoubleReal) * 128 * 128); 
cudaMalloc((void**)odata, sizeof(cufftDoubleComplex) * 128 * 128); 
cudaMemcpy(*idata, in_real, 128 * 128 * sizeof(cufftDoubleReal), 
            cudaMemcpyHostToDevice); 
cudaMemcpy(*idata, in_complex, 128 * 128 * sizeof(cufftDoubleComples), 
            cudaMemcpyHostToDevice); 

cufftExecD2Z(plan, idata, odata); 
cudaMemcpy(out_complex, *odata, 128 * 128 * sizeof(cufftDoubleComplex), cudaMemcpyDeviceToHost); 

, die 0,4 ms auf meiner Maschine nimmt herum.

Ich habe versucht, den gleichen Code für mehr als ein Bild auszuführen, und die Ausführungszeit ist im Grunde die Anzahl der Bilder mehrere von 0,4ms. Die Art und Weise habe ich das im Grunde ist das Kopieren und die oben genannten Code viele Male einfügen, natürlich, mit den Variablen für die entsprechenden Bilder geändert, die

// For image1 
cudaMalloc((void**)idata, sizeof(cufftDoubleReal) * 128 * 128); 
cudaMalloc((void**)odata, sizeof(cufftDoubleComplex) * 128 * 128); 
cudaMemcpy(*idata, in_real, 128 * 128 * sizeof(cufftDoubleReal), 
            cudaMemcpyHostToDevice); 
cudaMemcpy(*idata, in_complex, 128 * 128 * sizeof(cufftDoubleComples), 
            cudaMemcpyHostToDevice); 
cufftExecD2Z(plan, idata, odata); 
cudaMemcpy(out_complex, *odata, 128 * 128 * sizeof(cufftDoubleComplex), cudaMemcpyDeviceToHost); 

// For image 2 
cudaMalloc((void**)idata2, sizeof(cufftDoubleReal) * 128 * 128); 
cudaMalloc((void**)odata2, sizeof(cufftDoubleComplex) * 128 * 128); 
cudaMemcpy(*idata2, in_real2, 128 * 128 * sizeof(cufftDoubleReal), 
            cudaMemcpyHostToDevice); 
cudaMemcpy(*idata2, in_complex2, 128 * 128 * sizeof(cufftDoubleComples), 
            cudaMemcpyHostToDevice); 
cufftExecD2Z(plan, idata2, odata2); 
cudaMemcpy(out_complex, *odata2, 128 * 128 * sizeof(cufftDoubleComplex), cudaMemcpyDeviceToHost); 
... 
// For image N 
... 

So bedeutet das kann ich erwarten, wenn ich 2D-FFT für alle 128 gelte Bilder, würde die Ausführungszeit ziemlich in der gleichen Reihenfolge wie die MATLAB sein.

Also meine Frage: ist die Art, wie ich die Ausführung richtig anwenden? Nutze ich die parallele Rechenleistung der GPU voll aus? Sollte ich die Art und Weise, wie ich den Code ausführe, ändern, zum Beispiel zuerst cudaMemcpy für alle 128 Bilder und führe sie dann aus, um einige CPU- und GPU-Ausführungen zu überlappen?

Antwort

2

Zuerst würde ich empfehlen, Ihren Code zu profilieren. Sie müssen nicht alle 100 Bilder profilieren, sondern vielleicht 2-5 Bilder.

Auf der Grundlage der Profildaten sollten Sie den Zeitaufwand für die Übertragung der Daten mit dem Zeitaufwand für die CUFFT-Operationen vergleichen. Wenn sie ungefähr gleich sind (oder wenn Sie visuell sehen können, dass die Überlappung von Vorteil wäre), dann versuchen Sie die Überlappung von Kopie und (CUFFT) berechnen, und Sie würden CUDA-Streams verwenden, um dies zu erreichen. Es gibt viele Tutorials zur CUDA-Stream-Verwendung sowie Beispielfragen hier zum CUDA-Tag (inkl. CUFFT-Tag), die die Verwendung von Streams und die Verwendung von Streams mit CUFFT behandeln.

Getrennt, aber im Zusammenhang mit oben, würde ich empfehlen, den CUFFT-Batch-Parameter zu verwenden, um 2-5 Bildtransformationen zusammenzufassen, um zu sehen, ob es zu einer Netto-Reduzierung der Gesamtverarbeitungszeit für die 100 Bilder führt.

Sie könnten die beiden Ideen kombinieren, was bedeutet, dass Sie die Transformationen in Stapeln durchführen und dann die Copy/Stream-Überlappung mit CUDA-Streams verwenden können, um die mit einem Stapel von Bildern verbundenen Kopiervorgänge mit den Rechenoperationen des vorherigen Stapels zu überlappen .

Getrennt von allem, cudaMalloc Operationen sind teuer. Es ist am besten, nicht, um sie in der Performance-Schleife (compute) zu haben, und das bedeutet, wenn möglich, führen Sie sie einmal, im Voraus, in Ihrem Code. Es ist besser, den gesamten benötigten Speicherplatz (z. B. für 2-3 Bilderstapel) zuzuweisen und dann den Speicherplatz erneut zu verwenden, anstatt jedem Bild neuen Speicherplatz zuzuweisen.