XVII. Gestion des erreurs▲
Aucune fonction de CUDA ne renvoie directement ses erreurs. Il faut faire appel à une fonction spéciale, cudaGetLastError(), qui renvoie le code d'erreur, sous forme de cudaError_t.
Toutes les fonctions du runtime renvoient donc un code d'erreur, mais dans le cas d'appels asynchrones, comme le kernel retourne immédiatement, on ne peut pas savoir si une erreur a eu lieu. Vous devez donc utiliser une fonction de synchronisation afin de pouvoir récupérer l'erreur.
Chaque erreur est effacée par la suivante et une réussite renvoie aussi un code d'erreur. Récupérer une erreur remet le compteur à la réussite.
Un kernel ne peut pas retourner de code d'erreur, on doit donc vérifier s'il peut s'exécuter sans problème avant de le lancer.
Il existe une seconde fonction pour gérer les erreurs : cudaGetErrorString(), qui prend en paramètre un code d'erreur, tel que retourné par cudaGetLastError(). Elle retourne, sous la forme d'un const char *, la description de l'erreur.
Code d'erreur | Signification |
---|---|
cudaSuccess | Pas d'erreur. |
cudaErrorMissingConfiguration | Configuration manquante. |
cudaErrorMemoryAllocation | Erreur lors de l'allocation de la mémoire. |
cudaErrorInitializationError | Erreur lors de l'initialisation. |
cudaErrorLaunchFailure | Erreur au lancement. |
cudaErrorPriorLaunchFailure | Erreur lors d'un lancement précédent. |
cudaErrorLaunchTimeout | Temps d'exécution trop long. |
cudaErrorLaunchOutOfResources | Plus de ressources disponibles pour l'exécution. |
cudaErrorInvalidDeviceFunction | Fonction invalide pour le périphérique. |
cudaErrorInvalidConfiguration | Configuration invalide. |
cudaErrorInvalidDevice | Périphérique invalide. |
cudaErrorInvalidValue | Valeur invalide. |
cudaErrorInvalidPitchValue | Valeur de pas invalide. |
cudaErrorInvalidSymbol | Symbole invalide. |
cudaErrorMapBufferObjectFailed | Erreur lors de l'accès au buffer. |
cudaErrorUnmapBufferObjectFailed | Erreur lors de l'accès au buffer. |
cudaErrorInvalidHostPointer | Pointeur sur l'hôte invalide. |
cudaErrorInvalidDevicePointer | Pointeur sur le périphérique invalide. |
cudaErrorInvalidTexture | Texture invalide. |
cudaErrorInvalidTextureBinding | Binding de texture invalide. |
cudaErrorInvalidChannelDescriptor | Descripteur de chaîne invalide. |
cudaErrorInvalidMemcpyDirection | Direction invalide pour memcpy. |
cudaErrorAddressOfConstant | Erreur dans l'adresse d'une constante. |
cudaErrorTextureFetchFailed | Erreur lors de l'accès à une texture. |
cudaErrorTextureNotBound | Texture non liée. |
cudaErrorSynchronizationError | Erreur de synchronisation. |
cudaErrorInvalidFilterSetting | Paramètre de filtre invalide. |
cudaErrorInvalidNormSetting | Paramètre de norme invalide. |
cudaErrorMixedDeviceExecution | Exécution mixte sur le périphérique. |
cudaErrorCudartUnloading | CUDA runtime en cours de déchargement. |
cudaErrorUnknown | Erreur inconnue. |
cudaErrorNotYetImplemented | Fonction pas encore implémentée. |
cudaErrorMemoryValueTooLarge | Valeur mémoire trop grande. |
cudaErrorInvalidResourceHandle | Handle de ressource invalide. |
cudaErrorNotReady | Pas encore prêt. |
cudaErrorInsufficientDriver | CUDA runtime plus récent que le driver. |
cudaErrorSetOnActiveProcess | Set on active process error. |
cudaErrorNoDevice | Pas de périphérique disponible. |
cudaErrorStartupFailure | Échec du lancement. |
cudaErrorApiFailureBase | Erreur dans l'API. |
XVIII. Gestion des périphériques▲
cudaGetDeviceCount() et cudaGetDeviceProperties() permettent d'énumérer les périphériques, les cartes graphiques et leurs capacités.
int
deviceCount;
cudaGetDeviceCount
(&
deviceCount);
int
device;
for
(
device =
0
; device <
deviceCount ; ++
device)
{
cudaDeviceProp deviceProp;
cudaGetDeviceProperties
(&
deviceProp, device);
}
Seuls les périphériques avec un indice de capacité de calcul supérieur ou égal à 1.0 sont retournés, les autres ne pouvant pas être exploités par CUDA.
cudaSetDevice() sert à sélectionner le périphérique qui exécutera les calculs du thread CPU.
cudaSetDevice
(
device);
Un périphérique doit être choisi avant d'appeler le moindre kernel, soit explicitement avec cudaSetDevice(), soit implicitement (le périphérique 0 est alors choisi). Tout appel ultérieur à cudaSetDevice() échouera.
La fonction cudaGetDeviceProperties() renvoie une structure ainsi définie.
struct
cudaDeviceProp
{
char
name[256
];
size_t totalGlobalMem;
size_t sharedMemPerBlock;
int
regsPerBlock;
int
warpSize;
size_t memPitch;
int
maxThreadsPerBlock;
int
maxThreadsDim[3
];
int
maxGridSize[3
];
size_t totalConstMem;
int
major;
int
minor;
int
clockRate;
size_t textureAlignment;
int
deviceOverlap;
int
multiProcessorCount;
int
kernelExecTimeoutEnabled;
}
- name : chaîne ASCII identifiant le périphérique ;
- totalGlobalMem : mémoire globale totale disponible sur le périphérique en bytes ;
- sharedMemPerBlock : mémoire partagée disponible pour un bloc en bytes (cette mémoire est partagée par tous les blocs de threads résidant simultanément sur un multiprocesseur) ;
- regsPerBlock : nombre de registres 32 bits disponibles à un bloc de threads ;
- warpSize : taille d'un warp en threads ;
- memPitch : pas maximal en bytes permis par la copie de mémoire qui implique des régions de mémoire allouées par cudaMallocPitch(); ;
- maxThreadsPerBlock : nombre maximal de threads par bloc ;
- maxThreadsDim[3] : dimensions maximales d'un bloc ;
- maxGridSize[3] : dimensions maximales d'une grille ;
- totalConstMem : total de mémoire constante disponible sur le périphérique ;
- major : numéro de révision majeur de la capacité de calcul ;
- minor : numéro de révision mineur de la capacité de calcul ;
- clockRate : fréquence de l'horloge en kilohertz ;
- textureAlignment : alignement des textures requis, les adresses de base des textures qui sont alignées sur ceci n'ont pas besoin d'appliquer un offset lors des recherches ;
- deviceOverlap : 1 si le périphérique peut copier de la mémoire entre l'hôte et le périphérique en même temps qu'exécuter un kernel, 0 sinon ;
- multiProcessorCount : nombre de multiprocesseurs sur le périphérique ;
- kernelExecTimeoutEnabled : 1 s'il y a une limite de temps pour les kernels, 0 sinon.
Vous pouvez définir vous-même une structure de ce genre et demander à CUDA de choisir le périphérique qui y correspond le mieux, grâce à la fonction cudaChooseDevice( int * dev, const struct cudaDeviceProp * prop ) (elle retourne le périphérique dans dev).