Le Calcul Scientifique à l’IMATH

L’émergence des processeurs graphiques (GPU) dans le monde du calcul intensif permet de repenser un certain nombre d’algorithmes dès lors qu’ils sont massivement parallélisables.

C’est pourquoi, en 2010 puis en 2011, le laboratoire IMATH s’est équipé d’une machine hybride (2 noeuds CPU + 8 processeurs GPU), et ce, en partie grâce au soutien financier de l’organisme Toulon Provence Méditerranée (TPM) mais également de l’Université du Sud, de Toulon et du Var (USTV).

L’intérêt scientifique et pédagogique du projet se traduit, ici, par la mise en place d’un portail web d’informations sur les applications du GPU en Cryptographie et en CFD et au sein duquel sera mis à la disposition de la communauté recherche, un ensemble de programmes et de fonctionnalités, en libre accès. Les développements en cours apportent, au sein du laboratoire, des compétences sur les algorithmes GCPU (calculs utilisant CPU classique et GPU). En s’appuyant sur cette dynamique, les différentes thématiques du laboratoire, telles que la cryptographie, l’infographie et la mécanique des fluides numériques, bénéficieront bientôt de ces compétences afin d’optimiser les codes existants et développer de nouvelles applications.

Cryptographie :

De nombreux algorithmes en cryptographie peuvent tirer profit de la puissance des processeurs GPU. A titre d’exemple, l’algorithme de chiffrement à clé publique de Mc Eliece (l’une des rares alternatives au RSA) peut naturellement se paralléliser ce qui n’est pas le cas du système RSA classique. Il existe à l’heure actuelle très peu d’implémentations de primitives cryptographiques pour les GPU. Les données manipulées en cryptographie étant la plupart des entiers et les GPU des co-processeurs dédiés à la gestion des flottants, le portage des primitives cryptographiques dans cet environnement soulève certains problèmes. Parallèlement à cela, une grande partie des algorithmes développés pour attaquer des systèmes existants peuvent être repensés et modifiés afin de tirer partie de la puissance des GPU ce qui permettrait de fixer de nouvelles limites en terme de taille de clés à utiliser. Dans le domaine des fonctions booléennes les membres de l’IMATH ont mené en 2006 une campagne de calcul étalée sur 6 mois monopolisant 64 machines. La bibliothèque de programmes développée lors de ce calcul intensif pourrait bénéficier du contexte attractif des GPU.

Infographie 3D :

Le laboratoire IMATH développe des outils de rendu réaliste de résultats issus de simulation 3D de problème de la physique, principalement en mécanique des fluides. Les données à traiter devenant de plus en plus importantes, il devient nécessaire de paralléliser le traitement d’image. Par exemple, le « lancé de rayon » (Ray Tracing) est une opération élémentaire adaptée au calcul sur plusieurs GPU. D’autre part, le suivi d’interface qui est un outil essentiel en imagerie et en mécanique des fluides multiphasiques amène à résoudre une équation Eikonale approchée par « Fast Marching Method ». Une parallélisation GPU de cet algorithme améliorerait grandement les temps de simulation de nos codes.

Dynamique des fluides :

Nous développons des codes de recherche en mécanique des fluides parallélisés en MPI. Un serveur hybride permet d’accéder à un parallélisme « grain fin». Dans le domaine de la mécanique des fluides visqueux, le temps de calcul est principalement consommé par la résolution de systèmes linéaires creux de grande taille. Le développement d’un solveur sur GPU nous permettrait d’envisager des gains en temps de calcul. Dans le domaine de la mécanique des fluides non visqueux, une multitude de résolution de « problèmes locaux » (problème de Riemann) serait hautement parallélisable sur GPU permettant, là encore, une réduction du temps de calcul.

 

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/11/245/

gDEBuggerCL

http://www.gremedy.com/gDEBuggerCL.php

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/gdebuggercl/

Ressources matérielles de l’IMATH

En construction.

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/nos-ressources-materielles/

OpenCL : addition de deux vecteurs

#include <stdio.h>
#include <stdlib.h>

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif

#define MAX_SOURCE_SIZE (0x100000)

int main(void) {
// Create the two input vectors
int i;
const int LIST_SIZE = 1024;
int *A = (int*)malloc(sizeof(int)*LIST_SIZE);
int *B = (int*)malloc(sizeof(int)*LIST_SIZE);
for(i = 0; i < LIST_SIZE; i++) {
A[i] = i;
B[i] = LIST_SIZE – i;
}

// Compute on Host
int *C = (int*)malloc(sizeof(int)*LIST_SIZE);
for(i = 0; i < LIST_SIZE; i++) {
C[i] = A[i] + B[i];
}

// Load the kernel source code into the array source_str
FILE *fp;
char *source_str;
size_t source_size;

fp = fopen(« vector_add_kernel.cl », « r »);
if (!fp) {
fprintf(stderr, « Failed to load kernel.\n »);
exit(1);
}
source_str = (char*)malloc(MAX_SOURCE_SIZE);
source_size = fread( source_str, 1, MAX_SOURCE_SIZE, fp);
fclose( fp );

// Get platform and device information
cl_platform_id platform_id = NULL;
cl_device_id device_id = NULL;
cl_uint ret_num_devices;
cl_uint ret_num_platforms;
cl_int ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_DEFAULT, 1,
&device_id, &ret_num_devices);
//     ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_GPU, 1,
//            &device_id, &ret_num_devices);

//     char *infos ;
//     size_t taille_infos ;
//     clGetDeviceInfo(device_id,CL_DEVICE_NAME,0,NULL,&taille_infos);
//     infos = (char *)malloc(taille_infos*sizeof(char));
//     clGetDeviceInfo(device_id,CL_DEVICE_NAME,taille_infos,infos,NULL);
//     printf(« DEVICE NAME :%s\n »,infos);
//     free(infos);
//    return 0 ;

// Create an OpenCL context
cl_context context = clCreateContext( NULL, 1, &device_id, NULL, NULL, &ret);

// Create a command queue
cl_command_queue command_queue = clCreateCommandQueue(context, device_id, 0, &ret);

// Create memory buffers on the device for each vector
cl_mem a_mem_obj = clCreateBuffer(context, CL_MEM_READ_ONLY,
LIST_SIZE * sizeof(int), NULL, &ret);
cl_mem b_mem_obj = clCreateBuffer(context, CL_MEM_READ_ONLY,
LIST_SIZE * sizeof(int), NULL, &ret);
cl_mem c_mem_obj = clCreateBuffer(context, CL_MEM_WRITE_ONLY,
LIST_SIZE * sizeof(int), NULL, &ret);

// Copy the lists A and B to their respective memory buffers
ret = clEnqueueWriteBuffer(command_queue, a_mem_obj, CL_TRUE, 0,
LIST_SIZE * sizeof(int), A, 0, NULL, NULL);
ret = clEnqueueWriteBuffer(command_queue, b_mem_obj, CL_TRUE, 0,
LIST_SIZE * sizeof(int), B, 0, NULL, NULL);

// Create a program from the kernel source
cl_program program = clCreateProgramWithSource(context, 1,
(const char **)&source_str, (const size_t *)&source_size, &ret);

// Build the program
ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);

// Create the OpenCL kernel
cl_kernel kernel = clCreateKernel(program, « vector_add », &ret);

// Set the arguments of the kernel
ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&a_mem_obj);
ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&b_mem_obj);
ret = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&c_mem_obj);

// Execute the OpenCL kernel on the list
size_t global_item_size = LIST_SIZE; // Process the entire lists
//size_t local_item_size = 1; // Process one item at a time
size_t local_item_size = 32; // Process one warp at a time
ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL,
&global_item_size, &local_item_size, 0, NULL, NULL);

// Read the memory buffer C on the device to the local variable C
int *C = (int*)malloc(sizeof(int)*LIST_SIZE);
ret = clEnqueueReadBuffer(command_queue, c_mem_obj, CL_TRUE, 0,
LIST_SIZE * sizeof(int), C, 0, NULL, NULL);

// Display the result to the screen
for(i = 0; i < LIST_SIZE; i++)
printf(« %d + %d = %d\n », A[i], B[i], C[i]);

// Clean up
ret = clFlush(command_queue);
ret = clFinish(command_queue);
ret = clReleaseKernel(kernel);
ret = clReleaseProgram(program);
ret = clReleaseMemObject(a_mem_obj);
ret = clReleaseMemObject(b_mem_obj);
ret = clReleaseMemObject(c_mem_obj);
ret = clReleaseCommandQueue(command_queue);
ret = clReleaseContext(context);
free(A);
free(B);
free(C);
return 0;

}

Le kernel, associé au programme source du host, est donné ci-dessous :

__kernel void vector_add(__global const int *A, __global const int *B, __global int *C) {

// Get the index of the current element to be processed
int i = get_global_id(0);

// Do the operation
C[i] = A[i] + B[i];
}

 



Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/tutoriel-n%c2%b02/

OpenCL : algorithme Data Encryption Standard (DES)

En construction

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/tutoriels-cuda/

OpenCL: interroger ses plateformes de calcul

 

#include<stdio.h>
#include<CL/cl.h>

int main()
{
unsigned char j;

// Declarations propres a OpenCL

cl_platform_id id_plateforme;
cl_uint nb_plateformes, nb_devices ;
cl_uint compute_units, max_dimensions, global_mem_cacheline_size, address_bits ;
cl_ulong global_mem_size, local_mem_size, max_object_alloc_size, buffer_constant_mem_size, global_mem_cache_size ;
char *infos ;
size_t taille_infos, taille_par_groupe, global_memory, local_memory, nb_compute_units, nb_dimensions ;
size_t taille_par_dimension, max_work_group_size, max_alloc_size, buffer_memory, global_mem_cache_type_size, local_mem_type_size ;
size_t global_memory_cache, global_memory_cacheline, address_bits_size ;
cl_device_id liste_devices[2];
cl_device_type type_device;
cl_device_mem_cache_type global_mem_cache_type ;
cl_device_local_mem_type local_mem_type ;
size_t *tableau_dimension;

// Plateformes

if (clGetPlatformIDs(2,&id_plateforme,&nb_plateformes) == CL_SUCCESS)
{
printf(« Nb plateformes : %d\n »,nb_plateformes);

clGetPlatformInfo(id_plateforme,CL_PLATFORM_PROFILE,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetPlatformInfo(id_plateforme,CL_PLATFORM_PROFILE,taille_infos,infos,NULL);
printf(« PLATFORM_PROFILE : %s\n »,infos);
free(infos);

clGetPlatformInfo(id_plateforme,CL_PLATFORM_VERSION,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetPlatformInfo(id_plateforme,CL_PLATFORM_VERSION,taille_infos,infos,NULL);
printf(« PLATFORM_VERSION : %s\n »,infos);
free(infos);

clGetPlatformInfo(id_plateforme,CL_PLATFORM_NAME,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetPlatformInfo(id_plateforme,CL_PLATFORM_NAME,taille_infos,infos,NULL);
printf(« PLATFORM_NAME : %s\n »,infos);
free(infos);

clGetPlatformInfo(id_plateforme,CL_PLATFORM_VENDOR,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetPlatformInfo(id_plateforme,CL_PLATFORM_VENDOR,taille_infos,infos,NULL);
printf(« PLATFORM_VENDOR : %s\n »,infos);
free(infos);

clGetPlatformInfo(id_plateforme,CL_PLATFORM_EXTENSIONS,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetPlatformInfo(id_plateforme,CL_PLATFORM_EXTENSIONS,taille_infos,infos,NULL);
printf(« PLATFORM_EXTENSIONS : %s\n »,infos);
free(infos);

printf(« \n »);

// Devices

clGetDeviceIDs(id_plateforme,CL_DEVICE_TYPE_ALL,0,NULL,&nb_devices);
printf(« NOMBRE DEVICE :%d\n »,nb_devices);

if (clGetDeviceIDs(id_plateforme,CL_DEVICE_TYPE_ALL,2,liste_devices,&nb_devices) != CL_SUCCESS)
{
printf(« Erreur get device\n »);
exit(0);
};

int i=0 ;

for (j = 0; j < nb_devices-i; j++)
{

clGetDeviceInfo(liste_devices[j],CL_DEVICE_NAME,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetDeviceInfo(liste_devices[j],CL_DEVICE_NAME,taille_infos,infos,NULL);
printf(« DEVICE NAME :%s\n »,infos);
free(infos);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_VERSION,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetDeviceInfo(liste_devices[j],CL_DEVICE_VERSION,taille_infos,infos,NULL);
printf(« DEVICE VERSION :%s\n »,infos);
free(infos);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_OPENCL_C_VERSION,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetDeviceInfo(liste_devices[j],CL_DEVICE_OPENCL_C_VERSION,taille_infos,infos,NULL);
printf(« DEVICE OPENCL C VERSION :%s\n »,infos);
free(infos);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_PROFILE,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetDeviceInfo(liste_devices[j],CL_DEVICE_PROFILE,taille_infos,infos,NULL);
printf(« DEVICE PROFILE :%s\n »,infos);
free(infos);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_EXTENSIONS,0,NULL,&taille_infos);
infos = (char *)malloc(taille_infos*sizeof(char));
clGetDeviceInfo(liste_devices[j],CL_DEVICE_EXTENSIONS,taille_infos,infos,NULL);
printf(« DEVICE EXTENSIONS :%s\n »,infos);
free(infos);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_COMPUTE_UNITS,0,NULL,&nb_compute_units);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_COMPUTE_UNITS,nb_compute_units,&compute_units,NULL);
printf(« DEVICE MAX COMPUTE UNITS :%d\n »,compute_units);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS,0,NULL,&nb_dimensions);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS,nb_dimensions,&max_dimensions,NULL);
printf(« DEVICE MAX WORK ITEM DIMENSIONS :%d\n »,max_dimensions);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_WORK_ITEM_SIZES,0,NULL,&taille_par_dimension);
tableau_dimension = (size_t *)malloc(taille_par_dimension*sizeof(size_t));
clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_WORK_ITEM_SIZES,taille_par_dimension,tableau_dimension,NULL);
printf(« DEVICE MAX WORK ITEM SIZES :%ld %ld %ld\n »,tableau_dimension[0],tableau_dimension[1],tableau_dimension[2]);
free(tableau_dimension);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_WORK_GROUP_SIZE,0,NULL,&taille_par_groupe);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_WORK_GROUP_SIZE,taille_par_groupe,&max_work_group_size,NULL);
printf(« DEVICE MAX WORK GROUP SIZE :%ld\n »,max_work_group_size);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_GLOBAL_MEM_SIZE,0,NULL,&global_memory);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_GLOBAL_MEM_SIZE,global_memory,&global_mem_size,NULL);
printf(« DEVICE GLOBAL MEM SIZE :%ld\n »,global_mem_size);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_LOCAL_MEM_SIZE,0,NULL,&local_memory);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_LOCAL_MEM_SIZE,local_memory,&local_mem_size,NULL);
printf(« DEVICE LOCAL  MEM SIZE :%ld\n »,local_mem_size);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE,0,NULL,&buffer_memory);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE,buffer_memory,&buffer_constant_mem_size,NULL);
printf(« DEVICE MAX CONSTANT BUFFER SIZE :%ld\n »,buffer_constant_mem_size);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_GLOBAL_MEM_CACHE_TYPE,0,NULL,&global_mem_cache_type_size);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_GLOBAL_MEM_CACHE_TYPE,global_mem_cache_type_size,&global_mem_cache_type,NULL);
printf(« DEVICE GLOBAL MEM CACHE TYPE :%d\n »,global_mem_cache_type);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_LOCAL_MEM_TYPE,0,NULL,&local_mem_type_size);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_LOCAL_MEM_TYPE,local_mem_type_size,&local_mem_type,NULL);
printf(« DEVICE LOCAL MEM TYPE :%d\n »,local_mem_type);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_MEM_ALLOC_SIZE,0,NULL,&max_alloc_size);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_MAX_MEM_ALLOC_SIZE,max_alloc_size,&max_object_alloc_size,NULL);
printf(« OBJECT MAX MEM ALLOC SIZE :%ld\n »,max_object_alloc_size);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_GLOBAL_MEM_CACHE_SIZE,0,NULL,&global_memory_cache);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_GLOBAL_MEM_CACHE_SIZE,global_memory_cache,&global_mem_cache_size,NULL);
printf(« DEVICE GLOBAL MEM CACHE SIZE :%ld\n »,global_mem_cache_size);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE,0,NULL,&global_memory_cacheline);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE,global_memory_cache,&global_mem_cacheline_size,NULL);
printf(« DEVICE GLOBAL MEM CACHELINE SIZE :%d\n »,global_mem_cacheline_size);

clGetDeviceInfo(liste_devices[j],CL_DEVICE_ADDRESS_BITS,0,NULL,&address_bits_size);
clGetDeviceInfo(liste_devices[j],CL_DEVICE_ADDRESS_BITS,address_bits_size,&address_bits,NULL);
printf(« DEVICE ADDRESS BITS :%d\n »,address_bits);

printf(« \n »);

}
}
else printf(« Erreur clGetPlatformIDs\n »);

}

NOMBRE DEVICE :2

DEVICE NAME :GeForce GTX 470
DEVICE VERSION :OpenCL 1.1 CUDA
DEVICE OPENCL C VERSION :OpenCL C 1.1
DEVICE PROFILE :FULL_PROFILE
DEVICE EXTENSIONS :cl_khr_byte_addressable_store cl_khr_icd cl_khr_gl_sharing cl_nv_compiler_options cl_nv_device_attribute_query cl_nv_pragma_unroll  cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics cl_khr_local_int32_base_atomics cl_khr_local_int32_extended_atomics cl_khr_fp64
DEVICE MAX COMPUTE UNITS :14
DEVICE MAX WORK ITEM DIMENSIONS :3
DEVICE MAX WORK ITEM SIZES :1024 1024 64
DEVICE MAX WORK GROUP SIZE :1024
DEVICE GLOBAL MEM SIZE :1341849600
DEVICE LOCAL  MEM SIZE :49152
DEVICE MAX CONSTANT BUFFER SIZE :65536
DEVICE GLOBAL MEM CACHE TYPE :2
DEVICE LOCAL MEM TYPE :1
OBJECT MAX MEM ALLOC SIZE :335462400
DEVICE GLOBAL MEM CACHE SIZE :229376
DEVICE GLOBAL MEM CACHELINE SIZE :128
DEVICE ADDRESS BITS :32

DEVICE NAME :Quadro FX 1800
DEVICE VERSION :OpenCL 1.0 CUDA
DEVICE OPENCL C VERSION :OpenCL C 1.0
DEVICE PROFILE :FULL_PROFILE
DEVICE EXTENSIONS :cl_khr_byte_addressable_store cl_khr_icd cl_khr_gl_sharing cl_nv_compiler_options cl_nv_device_attribute_query cl_nv_pragma_unroll  cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics
DEVICE MAX COMPUTE UNITS :8
DEVICE MAX WORK ITEM DIMENSIONS :3
DEVICE MAX WORK ITEM SIZES :512 512 64
DEVICE MAX WORK GROUP SIZE :512
DEVICE GLOBAL MEM SIZE :804585472
DEVICE LOCAL  MEM SIZE :16384
DEVICE MAX CONSTANT BUFFER SIZE :65536
DEVICE GLOBAL MEM CACHE TYPE :0
DEVICE LOCAL MEM TYPE :1
OBJECT MAX MEM ALLOC SIZE :201146368
DEVICE GLOBAL MEM CACHE SIZE :0
DEVICE GLOBAL MEM CACHELINE SIZE :0
DEVICE ADDRESS BITS :32

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/tutoriels-opencl/

GPGPU

GPGPU est l’acronyme de General-Purpose Processing on Graphics Processing Units, désignant le calcul générique sur un processeur graphique. Un processeur graphique (ou GPU, de l’anglais Graphics Processing Unit) est un circuit intégré présent sur une carte graphique permettant, à la base, d’assurer les fonctions de calcul de l’affichage. Si les premiers GPU étaient à fonctions fixes, ils ont nettement évolué depuis les années 2000 et sont devenus programmables. Leur architecture hautement parallèle les rend, par conséquent, éligibles pour l’exécution de tâches lourdes en calcul, du moins celles qui se prêteraient aisément à une parallélisation massive.

Par ailleurs, la plupart des architectures modernes, en plus d’être onéreuses, sont très lourdes du point de vue de l’infrastructure et s’adressent à un marché de niches. Le GPU, pour sa part, est un produit grand public bénéficiant d’une large diffusion grâce au marché des jeux vidéo et permettant une réduction drastique des coûts par rapport à une architecture trop spécialisée. En d’autres termes, on disposerait d’une architecture relativement bon marché et permettant d’afficher, dans certains cas, des performances pour le calcul parallèle supérieures par rapport à celles d’un processeur généraliste CPU (de l’anglais Central Processing Unit) haut de gamme et récent.

Actuellement, un processeur généraliste est composé de nombreuses unités de traitement ainsi que de plusieurs niveaux de mémoires hiérarchisées et dont l’ensemble forme une structure relativement complexe faisant l’objet d’une duplication dans des coeurs distincts (de l’ordre de la dizaine, au plus, de nos jours). En revanche, l’unité de calcul de base d’un processeur graphique est plus simple. En effet, plusieurs dizaines de ces unités de calcul sont intégrées sur une seule puce graphique. Ce haut niveau de parallélisme, créé initialement pour traiter simultanément la projection de plusieurs textures (ou shaders), est devenu disponible pour tout autre usage avec l’apparition des kits de développement dédiés (NVIDIA CUDA, OpenCL du Khronos Group, ATI Stream d’AMD, DirectCompute de Microsoft, SDK d’Intel, SDK d’IBM…).

Néanmoins, le GPGPU seul ne peut pas être un modèle de remplacement du CPU. En effet, à en juger par les activités récentes des principaux constructeurs de circuits électroniques, on est amené à penser que les futurs microprocesseurs et les grands systèmes informatiques seront, par nature, hybrides voire hétérogènes. Ces systèmes reposeront sur l’intégration, dans des proportions variées, de deux types de composants principaux :

  • processeurs généraliste CPU multi-coeurs dont le nombre de coeurs ne cessera d’augmenter afin d’intégrer de plus en plus de composants sur le même circuit en évitant les obstacles d’alimentation, de parallélisme des instructions et de mémoire.
  • circuits spécialisés et accélérateurs massivement parallèles dont les performances en calcul virgule flottante dépassent, depuis plusieurs années déjà, celles des CPU classiques.

Les lecteurs peuvent approfondir ces aspects en consultant l’article (dont on s’est en partie inspiré) de Sébastien DEVAUX, intitulé « Le pixel, le polygone et la matrice », paru dans la revue mensuelle LINUX MAGAZINE, N°129, pages 60-69, en août 2010.

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/gpgpu/

Présentation

En construction

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/presentation-2/

Installation

En construction

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/installation-2/

Premiers pas

En construction

 

Lien Permanent pour cet article : https://calcul-scientifique.univ-tln.fr/2012/01/premiers-pas-2/