Cuda... episode 2
By Hugo on Sunday, October 5 2008, 15:16 - GPU - Permalink
Le premier programme en cuda, c'est fait, maintenant il serait bon de ne pas avoir a se prendre la tete avec les allocations memoires, ou tout du moins les simplifier un peu...
Ha aufait je vais ecrire en francais a partir de cet article, apres tout il n'y a pas d'articles en francais sur cuda (en tout cas pas la derniere fois que j'ai regarde :p) et puis ca me permettra surement d'etre plus clair.
Donc, personnellement les cudaMemcpy, cudaFree etc, ca va 5minutes, mais ca va me gonfler de devoir taper cudaMemcpyHostToDevice a longueur de temps, donc je me suis code une petite classe pour faire officer de "container" cuda. Il n'y aura rien d'extraordinaire la dedans, juste une petite classe fonctionnelle :)
Un rapide "cahier des charges", la classe doit pouvoir :
- Envoyer des donnees vers la carte graphique
- S'occuper seule comme une grande d'allouer la memoire dans la memoire de la carte graphique
- liberer cet espace
- Permettre de recuperer le pointeur vers le device pour pouvoir appeler les kernels
- Pouvoir fonctionner avec n'importe quel type
- Recuperer les donnees traitees par la CG
Ce qui nous donne la declaration de classe suivante :
template <typename T> class CudaContainer { public: CudaContainer(T* var, size_t size); CudaContainer(T& var); CudaContainer(size_t size); ~CudaContainer(); void sendToDevice(); void getFromDevice(); T* getHost() T* getDevice() private: //probably more stuff here };
ce qui une fois implemente, donne le fichier fourni en piece jointe de ce billet :)
Je n'ai pas commente abusivement, je pense que les noms de methodes et des fonctions de l'API cuda sont assez clairs ;)
Et voila le main du billet precedent, retouche pour fonctionner avec ce "container" :
int main() { const int NbElems = 100; float *toSquare = new float[NbElems]; for (int i = 0; i < NbElems; ++i) toSquare[i] = (float)i; CudaContainer<float> c(toSquare, sizeof(float) * NbElems); c.sendToDevice(); //Cuda Kernel execution { dim3 blockSize(5, 5); const int nbThreads = blockSize.x * blockSize.y; int nbBlocks = NbElems / nbThreads + (NbElems % nbThreads == 0 ? 0 : 1); SquareArray<<<nbBlocks, blockSize>>>(c.getDevice(), NbElems); } c.getFromDevice(); for (int i = 0; i < NbElems; ++i) std::cout << i << " => " << toSquare[i] << "\n"; std::cout.flush(); }
Ce qui, a mes yeux, est toujours un peu plus agreable a lire/utiliser, qu'avec les fonctions initiales :)