OpenCL

35
OpenCL Programmation de cartes graphiques

description

OpenCL. Programmation de cartes graphiques. 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 - PowerPoint PPT Presentation

Transcript of OpenCL

OpenCL

OpenCLProgrammation de cartes graphiquesOpenCLAPI + langage bas sur le C99Conu pour programmer des systmes parallles htrognes: CPU multi-coeur, GPU, etc.

On distingue le processeur hte des priphriquesUn conteneur spcial (context) sert dinterface entre le processeur hte et les priphriquesLes donnes et les tches (kernels) sont transfrs laide dune file dattente (command queue)Un priphrique vu par OpenCL

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]; }}Comparaison: Programmation multithreadvoid vecadd(int *C, int* A, int *B, int N, int NP, int tid) { int ept = N/NP; // nbre dlments par thread for(int i = tid*ept; i < (tid+1)*ept; i++) { C[i] = A[i] + B[i]; }}Comparaison: OpenCL__kernelvoid vecadd(__global int *C, __global int* A, __global int *B) { int tid = get_global_id(0); // fonction OpenCL C[tid] = A[tid] + B[tid];}Espace des indicesEn OpenCL, lespace des indices des processeurs peut avoir 1, 2 ou 3 dimensions.Il y a deux niveaux dindices:Un indice global unique pour chaque work-item du priphrique (NDRange)Un indice local unique pour chaque work-item lintrieur dun mme workgroup.

NDRange et Workgroups

Connatre son indiceget_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.

Relation entre global et localget_global_id(dim) = get_local_size(dim)*get_group_id(dim) + get_local_id(dim)PlateformesUne plateforme est une implmentation de OpenCL spcifique un manufacturier donnPour obtenir la liste des plateformes:

cl_int clGetPlatformIDs(cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms)clGetPlatformInfo pour obtenir de linformation sur une plateforme donnExemple 1cl_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);PriphriquesPour chacune des plateformes (ex. NVIDIA), on peut obtenir la liste des priphriques associs:

cl_int clGetDeviceIDs(cl_platform_id platform, cl_device_type device_type, cl_uint num_entries, cl_device_id *devices, cl_uint *num_devices)Exemple 2cl_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));

status = clGetDeviceIDs( platforms[0], CL_DEVICE_TYPE_ALL, numDevices, devices, NULL);ContextesUn contexte est un type de conteneur permettant de communiquer des donnes et des instructions des priphriquesOn utilise la fonction: clCreateContextLe premier paramtre sert limit la port du contexte, par exemple en spcifiant une plateforme particulire.Le callback sert a fournir une fonction qui pourra fournir davantage dinformation sur les erreurs se produisant tout au long de lutilisation du contexte.

Contextescl_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)Exemple 3cl_context context = NULL;

context = clCreateContext( NULL, numDevices, devices, NULL, NULL, &status);File de commandesOn a dj dit quun contexte est un conteneur permettant de communiquer avec un priphrique.

On ajoute et retire linformation dun contexte laide dune file dattente appele file de commande (command queue).

Toutes les commandes indiquant une communication hte-priphrique commencent par clEnqueue.Cration dune file de commandescl_command_queueclCreateCommandQueue( cl_context context, cl_device_id device, cl_command_queue_properties properties, cl_int* errcode_ret)

Note: Le paramtre properties sert, entre autres, indiquer si les lments seront pris dans lordre.Exemple 4cl_command_queue cmdQueue;cmdQueue = clCreateCommandQueue( context, devices[0], 0, &status);Objets mmoireAvant dtre transfrs, les donnes doivent tre converties dans un format particulier.Il y a deux formats:Les tampons (buffers)Les imagesLes tampons sont lquivalent des tableaux en C et sont stocks de faon contigu en mmoire.Les images sont des objets opaques et sont places en mmoire de faon optimiser les performances.Cration dun tamponcl_mem clCreateBuffer( cl_context context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret)

Note: Le paramtre flags sert indiquer si le tampon est en lecture, en criture ou les deux.crire dans un tamponcl_intclEnqueueWriteBuffer ( 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)Lire dans un tamponcl_int clEnqueueReadBuffer( cl_command_queuecommand_queue, cl_membuffer, cl_boolblocking_read, size_toffset, size_tsize, void*ptr, cl_uintnum_events_in_wait_list, const cl_event*event_wait_list, cl_event*event)

Exemple 5cl_mem bufferA, bufferB, bufferC;

bufferA = clCreateBuffer( context, CL_MEM_READ_ONLY, datasize, NULL, &status); bufferB = clCreateBuffer( context, CL_MEM_READ_ONLY, datasize, NULL, &status); bufferC = clCreateBuffer( context, CL_MEM_WRITE_ONLY, datasize, NULL, &status);

status = clEnqueueWriteBuffer( cmdQueue, bufferA, CL_FALSE, 0, datasize, A, 0, NULL, NULL);

status = clEnqueueWriteBuffer( cmdQueue, bufferB, CL_FALSE, 0, datasize, B, 0, NULL, NULL);

KernelsIl faut distinguer le programme C de lordinateur hte du programme C OpenCL qui sera excut sur un priphrique.

Un programme C OpenCL est une collection de fonctions appeles kernels

Le type de retour de ces fonctions doit tre void

Les kernels reprsentent les tches que lon peut ordonnancer de faon dynamique sur les priphriques.

Cration et excution dun kernelLe code source est stock sous la forme dune chane de caractresLa chaine est convertie en objet programmes laide de la commande clCreateProgramWithSource()Un objet programme est compil laide de la commande clBuildProgram() Un kernel est obtenu laide de la fonction clCreateKernelLes paramtres du kernel sont affects laide de la commande clSetKernelArg()Le kernel est finalement excut laide de la commande clEnqueueNDRangeKernel()

Cration dun objet programmecl_program clCreateProgramWithSource ( cl_contextcontext, cl_uintcount, const char**strings, const size_t*lengths, cl_int*errcode_ret)

Compiler un objet programmecl_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)Obtenir un kernelcl_kernel clCreateKernel ( cl_program program, const char*kernel_name, cl_int*errcode_ret)

Note 1: *kernel_name contient le nom dune fonction dans le programme source .

Note 2: Voir clGetProgramBuildInfo pour les erreurs de compilationAffecter les paramtrescl_int clSetKernelArg ( cl_kernelkernel, cl_uintarg_index, size_targ_size, const void*arg_value)

Note: Les paramtres demeurent affects au kernel tant quil ny a pas de modification explicite laide de clSetKernelArg()Excuter un kernelcl_intclEnqueueNDRangeKernel( cl_command_queuecommand_queue, cl_kernelkernel, cl_uintwork_dim, const size_t*global_work_offset, const size_t*global_work_size, const size_t*local_work_size, cl_uintnum_events_in_wait_list, const cl_event*event_wait_list, cl_event*event)Organisation de la mmoire

Espaces dadressageLes qualificatifs:__global: Mmoire partage par tous les work-items du kernel.

__constant: Mmoire en lecture seule partage par tous les work-items du kernel.

__local: Mmoire partage par tous les work-items dun mme work-group.

__private: Mmoire prive pour chaque work-item.Espace dadressage par dfautPour amliorer la performance, on utilise autant que possible la mmoire __local ou __private.Sil ny a pas de qualificatif, les paramtres des fonctions et les variables locales sont __private Le qualificatif des paramtres qui sont des pointeurs doit tre spcifi et ne peut pas tre __private.Les mmoires __private et __local ne sont pas prserves la fin de lexcution dun work-item.La seule faon de retourner une valeur lhte est via la mmoire __global.