La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Programmation de cartes graphiques

Présentations similaires


Présentation au sujet: "Programmation de cartes graphiques"— Transcription de la présentation:

1 Programmation de cartes graphiques
OpenCL Programmation de cartes graphiques

2 OpenCL API + langage basé sur le C99
Conçu pour programmer des systèmes parallèles hétérogènes: CPU multi-coeur, GPU, etc. On distingue le processeur hôte des périphériques Un conteneur spécial (context) sert d’interface entre le processeur hôte et les périphériques Les données et les tâches (kernels) sont transférés à l’aide d’une file d’attente (command queue)

3 Un périphérique vu par OpenCL

4 Comparaison: C standard
// Addition de 2 vecteurs de taille N // void vecadd(int *C, int* A, int *B, int N) { for(int i = 0; i < N; i++) { C[i] = A[i] + B[i]; }

5 Comparaison: Programmation multithread
void vecadd(int *C, int* A, int *B, int N, int NP, int tid) { int ept = N/NP; // nbre d’éléments par thread for(int i = tid*ept; i < (tid+1)*ept; i++) { C[i] = A[i] + B[i]; }

6 Comparaison: OpenCL __kernel void vecadd(__global int *C, __global int* A, __global int *B) { int tid = get_global_id(0); // fonction OpenCL C[tid] = A[tid] + B[tid]; }

7 Espace des indices En OpenCL, l’espace des indices des processeurs peut avoir 1, 2 ou 3 dimensions. Il y a deux niveaux d’indices: Un indice global unique pour chaque work-item du périphérique (NDRange) Un indice local unique pour chaque work-item à l’intérieur d’un même workgroup.

8 NDRange et Workgroups

9 Connaître son indice get_global_id(dim): indice globale du work-item appelant selon la dimension dim=0,1 ou 2 get_local_id(dim): indice local du work-item appelant get_group_id(dim): indice du workgroup auquel appartient le work-item appelant get_local_size(dim): taille de la dimension dim dans le workgroup du work-item appelant.

10 Relation entre global et local
get_global_id(dim) = get_local_size(dim)*get_group_id(dim) + get_local_id(dim)

11 Plateformes Une plateforme est une implémentation de OpenCL spécifique à un manufacturier donné Pour obtenir la liste des plateformes: cl_int clGetPlatformIDs(cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms) clGetPlatformInfo pour obtenir de l’information sur une plateforme donné

12 Exemple 1 cl_int status; cl_uint numPlatforms = 0;
cl_platform_id *platforms = NULL; status = clGetPlatformIDs(0, NULL, &numPlatforms); platforms = (cl_platform_id*)malloc( numPlatforms*sizeof(cl_platform_id)); status = clGetPlatformIDs(numPlatforms, platforms, NULL); char Name[1000]; clGetPlatformInfo(platforms[0], CL_PLATFORM_NAME, sizeof(Name), Name, NULL); printf("Name of platform : %s\n", Name);

13 Périphériques Pour chacune des plateformes (ex. NVIDIA), on peut obtenir la liste des périphériques associés: cl_int clGetDeviceIDs(cl_platform_id platform, cl_device_type device_type, cl_uint num_entries, cl_device_id *devices, cl_uint *num_devices)

14 Exemple 2 cl_uint numDevices = 0; cl_device_id *devices = NULL; status = clGetDeviceIDs( platforms[0], CL_DEVICE_TYPE_ALL, 0, NULL, &numDevices); devices = (cl_device_id*)malloc( numDevices*sizeof(cl_device_id)); CL_DEVICE_TYPE_ALL, numDevices, devices, NULL);

15 Contextes Un contexte est un type de conteneur permettant de communiquer des données et des instructions à des périphériques On utilise la fonction: clCreateContext Le premier paramètre sert à limité la porté du contexte, par exemple en spécifiant une plateforme particulière. Le « callback » sert a fournir une fonction qui pourra fournir d’avantage d’information sur les erreurs se produisant tout au long de l’utilisation du contexte.

16 Contextes cl_context clCreateContext ( const cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices, void (CL_CALLBACK *pfn_notify)( const char *errinfo, const void *private_info, size_t cb, void *user_data), void *user_data, cl_int *errcode_ret)

17 Exemple 3 cl_context context = NULL; context = clCreateContext( NULL, numDevices, devices, NULL, &status);

18 File de commandes On a déjà dit qu’un contexte est un conteneur permettant de communiquer avec un périphérique. On ajoute et retire l’information d’un contexte à l’aide d’une file d’attente appelée « file de commande » (command queue). Toutes les commandes indiquant une communication hôte-périphérique commencent par clEnqueue.

19 Création d’une file de commandes
cl_command_queue clCreateCommandQueue( cl_context context, cl_device_id device, cl_command_queue_properties properties, cl_int* errcode_ret) Note: Le paramètre « properties » sert, entre autres, à indiquer si les éléments seront pris dans l’ordre.

20 Exemple 4 cl_command_queue cmdQueue; cmdQueue = clCreateCommandQueue( context, devices[0], 0, &status);

21 Objets mémoire Avant d’être transférés, les données doivent être converties dans un format particulier. Il y a deux formats: Les tampons (buffers) Les images Les tampons sont l’équivalent des tableaux en C et sont stockés de façon contiguë en mémoire. Les images sont des objets opaques et sont placées en mémoire de façon optimiser les performances.

22 Création d’un tampon cl_mem clCreateBuffer( cl_context context,
cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret) Note: Le paramètre « flags » sert à indiquer si le tampon est en lecture, en écriture ou les deux.

23 Écrire dans un tampon cl_int clEnqueueWriteBuffer ( cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_write, // CL_TRUE pour appel bloquant size_t offset, size_t cb, const void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event)

24 Lire dans un tampon cl_int clEnqueueReadBuffer( cl_command_queue command_queue, cl_mem buffer, cl_bool blocking_read, size_t offset, size_t size, void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event)

25 Exemple 5 cl_mem bufferA, bufferB, bufferC; bufferA = clCreateBuffer( context, CL_MEM_READ_ONLY, datasize, NULL, &status); bufferB = clCreateBuffer( bufferC = clCreateBuffer( context, CL_MEM_WRITE_ONLY, datasize, NULL, &status); status = clEnqueueWriteBuffer( cmdQueue, bufferA, CL_FALSE, 0, datasize, A, 0, NULL, NULL); cmdQueue, bufferB, CL_FALSE, 0, datasize, B, 0, NULL, NULL);

26 Kernels Il faut distinguer le programme C de l’ordinateur hôte du programme C OpenCL qui sera exécuté sur un périphérique. Un programme C OpenCL est une collection de fonctions appelées « kernels » Le type de retour de ces fonctions doit être void Les kernels représentent les tâches que l’on peut ordonnancer de façon dynamique sur les périphériques.

27 Création et exécution d’un kernel
Le code source est stocké sous la forme d’une chaîne de caractères La chaine est convertie en objet programmes à l’aide de la commande clCreateProgramWithSource() Un objet programme est compilé à l’aide de la commande clBuildProgram() Un kernel est obtenu à l’aide de la fonction Les paramètres du kernel sont affectés à l’aide de la commande clSetKernelArg() Le kernel est finalement exécuté à l’aide de la commande clEnqueueNDRangeKernel()

28 Création d’un objet programme
cl_program clCreateProgramWithSource ( cl_context context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret)

29 Compiler un objet programme
cl_int clBuildProgram ( cl_program program, cl_uint num_devices, const cl_device_id *device_list, const char *options, void (CL_CALLBACK *pfn_notify)(cl_program program, void *user_data), void *user_data)

30 Obtenir un kernel cl_kernel clCreateKernel ( cl_program program,
const char *kernel_name,   cl_int *errcode_ret) Note: *kernel_name contient le nom d’une fonction dans le programme source .

31 Affecter les paramètres
cl_int clSetKernelArg ( cl_kernel kernel,   cl_uint arg_index,   size_t arg_size,   const void *arg_value) Note: Les paramètres demeurent affectés au kernel tant qu’il n’y a pas de modification explicite à l’aide de clSetKernelArg()

32 Exécuter un kernel cl_int clEnqueueNDRangeKernel( cl_command_queue command_queue, cl_kernel kernel, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event)

33 Organisation de la mémoire

34 Espaces d’adressage Les qualificat
__global: Mémoire partagée par tous les work-items du kernel. __constant: Mémoire en lecture seule partagée par tous les work-items du kernel. __local: Mémoire partagée par tous les work-items d’un même work-group. __private: Mémoire privée pour chaque work-item.

35 Espace d’adressage par défaut
Pour améliorer la performance, on utilise autant que possible la mémoire __local ou __private. S’il n’y a pas de qualificatif, les paramètres des fonctions et les variables locales sont __private Le qualificatif des paramètres qui sont des pointeurs doit être spécifié et ne peut pas être __private. Les mémoires __private et __local ne sont pas préservées à la fin de l’exécution d’un work-item. La seule façon de retourner une valeur à l’hôte est via la mémoire __global.


Télécharger ppt "Programmation de cartes graphiques"

Présentations similaires


Annonces Google