Der wahrscheinlich beste Weg, um nach Fehlern im Laufzeit-API-Code zu suchen, besteht darin, eine Assert-Style-Handler-Funktion und ein Wrapper-Makro wie folgt zu definieren:
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
Anschließend können Sie jeden API-Aufruf mit dem gpuErrchk
Makro umschließen, das den Rückgabestatus des umschlossenen API-Aufrufs verarbeitet. Beispiel:
gpuErrchk( cudaMalloc(&a_d, size*sizeof(int)) );
Wenn bei einem Aufruf ein Fehler auftritt, wird eine Textnachricht ausgegeben, die den Fehler sowie die Datei und Zeile in Ihrem Code beschreibt, in der der Fehler aufgetreten ist, stderr
und die Anwendung wird beendet. Sie können möglicherweise Änderungen vornehmen gpuAssert
, um eine Ausnahme auszulösen , anstatt exit()
eine komplexere Anwendung aufzurufen, wenn dies erforderlich ist.
Eine zweite verwandte Frage ist, wie beim Starten von Kerneln nach Fehlern gesucht werden kann, die nicht direkt in einen Makroaufruf wie Standard-Laufzeit-API-Aufrufe eingeschlossen werden können. Für Kernel ungefähr so:
kernel<<<1,1>>>(a);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaDeviceSynchronize() );
prüft zunächst, ob ein ungültiges Startargument vorliegt, und zwingt den Host dann, zu warten, bis der Kernel stoppt, und nach einem Ausführungsfehler zu suchen. Die Synchronisation kann beseitigt werden, wenn Sie einen nachfolgenden blockierenden API-Aufruf wie folgt haben:
kernel<<<1,1>>>(a_d);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaMemcpy(a_h, a_d, size * sizeof(int), cudaMemcpyDeviceToHost) );
In diesem Fall kann der cudaMemcpy
Aufruf entweder Fehler zurückgeben, die während der Kernelausführung aufgetreten sind, oder solche aus der Speicherkopie selbst. Dies kann für Anfänger verwirrend sein, und ich würde empfehlen, nach dem Start des Kernels während des Debuggens eine explizite Synchronisierung zu verwenden, um leichter zu verstehen, wo Probleme auftreten können.
Beachten Sie, dass bei Verwendung von CUDA Dynamic Parallelism eine sehr ähnliche Methode auf jede Verwendung der CUDA-Laufzeit-API in Gerätekerneln sowie nach dem Start eines Gerätekerns angewendet werden kann und sollte:
#include <assert.h>
#define cdpErrchk(ans) { cdpAssert((ans), __FILE__, __LINE__); }
__device__ void cdpAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
printf("GPU kernel assert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) assert(0);
}
}
getLastCudaError
undcheckCudaErrors
der so ziemlich das tut, was in der akzeptierten Antwort beschrieben ist . Demonstrationen finden Sie in den Beispielen. Installieren Sie einfach die Beispiele zusammen mit dem Toolkit und Sie werden es haben.