• Aucun résultat trouvé

5.6 Un Code, Plusieurs Architectures

5.6.3 OpenCL

Le langage OpenCL36 est une interface de programmation en open source qui a pour objec-

tif l’implémentation de solution parallèle dans un environnement hétérogène architecturale. Le

but étant de fournir aux ingénieurs une structure de code portable et efficiente qui est capable d’exploiter la puissance développée par les CPUs multicœurs, les GPUs et autres cartes accéléra-

trices (FPGA37. MIC, ASICs38 etc. . .). Un des atouts extrêmement important de l’OpenCL

est qu’il cible toutes les différentes architectures de carte graphique i.e. AMD, Intel etc. . . à l’encontre de CUDA.

5.6.3.1 Composition du Langage

La plateforme OpenCL fournit un modèle qui sépare conceptuellement l’ordinateur (ou le serveur) qui est considéré comme l’hôte et les différentes cartes de calculs. En général, les nœuds de calculs sont confiés aux cartes puisqu’elle dispose d’une puissance de calcul nettement supérieure au serveur. L’hôte garde le contrôle sur l’exécution d’une application plus générale et distribue les tâches plus petites aux cartes de calculs. Ces cartes sont composées d’une ou plusieurs unités de calcul qui sont eux-mêmes divisées en plusieurs plus petits composants de calcul. Par exemple, les cartes graphiques de Nvidia sont composés de plusieurs multiprocesseurs qui sont composés de plusieurs centaines d’unité de calcul scalaire.

Ces unités sont soient scalaire (instruction SISD) soient vectoriel (instruction SIMD), c’est- à-dire respectivement capable de procéder à une instruction d’une donnée et d’une instruction pour plusieurs données à la fois.

5.6.3.2 Application, Groupe de Travail et Entité de Travail

Un programme en OpenCL (guide de programmation dans Munshi et al. [135]) est exécuté sur l’hôte de la même façon qu’un autre programme, à la différence est que cette première peut envoyer des ordres aux cartes accélé- ratrices en utilisant l’interface de programmation des différentes machines. Ces ordres sont appelés kernel ou application qui sont soient une ou un ensemble de fonctions d’instructions à exécuter. Ces petites applications sont écrites en C ou C++ et avec quelques extensions dûes à la librairie d’OpenCL. Il est possible de créer un fil d’exécution des applications sur les cartes de calculs.

Il y a deux niveaux de granularités des applications exécutées sur les cartes, les work-item ou les entités de travail qui définissent un point en espace. Ce point en espace peut être représenté en une, deux ou trois dimensions en fonction de la structure de l’algorithme et du confort voulu par le développeur sur la maintenabilité du code produit. Ces entités de travail sont regroupés en work-group ou groupe de travail. Les entités de travail au sein d’un même groupe ont une indexation locale. L’indexation globale du groupe de travail permet de retrouver l’indexation globale d’une entité de travail dans un groupe.

5.6.3.3 Hiérarchie des Mémoires

OpenCL dispose d’un modèle à plusieurs niveaux pour la mémoire. La hiérarchie des mémoires est plus détaillée dans Tay [177]. Chaque entité de travail a accès à 4 types de mémoires qui sont les suivantes:

• Mémoire globale, une région de mémoire où tous les entités et les groupes de travail peu-

vent aller écrire et lire des informations. Généralement, c’est elle qui comporte la plus

37Un dispositif FPGA est un circuit logique programmable, son circuit intégré logique peut être reconfiguré

après sa fabrication (modification des connexions, du comportement du composant en connectant ou non les portes logiques entre elles)

38Une carte ASIC est un circuit propre intégré à une application ou appelé circuit intégré spécialisé qui peut

5.6. Un Code, Plusieurs Architectures

grande taille de mémoire. Mais, le temps d’accès est très lent en comparaison des 3 autres mémoires.

• Mémoire locale, cette région de mémoire n’est visible que par les entités de travail appar-

tenant au même groupe. Ils peuvent tous écrire et lire dans cette partie. Elle est beaucoup plus petite que la mémoire globale mais le temps d’accès est plus rapide.

• Mémoire constante, une région qui est inchangée pendant toute l’exécution de l’application.

Seulement l’hôte peut modifier cette zone de mémoire.

• Mémoire privée, une très petite zone de mémoire qui n’est accessible (lecture et écriture)

seulement par une entité de travail. Cette mémoire dispose d’un accès très rapide. L’hôte alloue, gère et peut lire ou écrire en mémoire globale ainsi que dans la mémoire constante tout au long de l’exécution d’un programme OpenCL. La mémoire locale et privée sont seulement accessibles par le dispositif de calcul pendant l’exécution d’un noyau d’application. Les mémoires des deux machines sont séparées physiquement ou reliées virtuellement mais seul l’hôte peut communiquer. Il est important de noter que cette mémoire hiérarchique n’est pas physique mais virtuelle, ce qui permet au langage OpenCL d’adresser n’importe quelle architecture.

5.6.3.4 Exemple de Code int m a i n () { c o n s t s i z e _ t N = 1 < < 20; std :: vector < cl :: P l a t f o r m > p l a t f o r m ; cl :: P l a t f o r m :: get (& p l a t f o r m ); cl :: C o n t e x t t ; std :: vector < cl :: Device > d e v i c e ; d e v i c e = g e t D e v i c e s ( C L _ D E V I C E _ T Y P E _ G P U ); t = cl :: C o n t e x t ( d e v i c e ); cl :: C o m m a n d Q u e u e q u e u e ( t , d e v i c e [ 0 ] ) ; cl :: P r o g r a m p r o g r a m ( t , cl :: P r o g r a m :: S o u r c e s ( 1 , std :: m a k e _ p a i r ( source , s t r l e n ( s o u r c e ) ) ) ) ; p r o g r a m . b u i l d ( d e v i c e );

cl :: K e r n e l add ( program , " add ");

std :: vector <double> a ( N , 1) , b ( N , 2) , c ( N ); int s = a . s i z e () * s i z e o f(d o u b l e); cl :: B u f f e r A ( t , C L _ M E M _ R E A D _ O N L Y | C L _ M E M _ C O P Y _ H O S T _ P T R , s , a . d a t a ( ) ) ; cl :: B u f f e r B ( t , C L _ M E M _ R E A D _ O N L Y | C L _ M E M _ C O P Y _ H O S T _ P T R , s , b . d a t a ( ) ) ; cl :: B u f f e r C ( t , C L _ M E M _ R E A D _ W R I T E , s );

add . s e t A r g (0 , s t a t i c _ c a s t< c l _ u l o n g >( N )); add . s e t A r g (1 , A ); add . s e t A r g (2 , B ); add . s e t A r g (3 , C ); q u e u e . e n q u e u e N D R a n g e K e r n e l ( add , cl :: N u l l R a n g e , N , cl :: N u l l R a n g e ); q u e u e . e n q u e u e R e a d B u f f e r ( C , CL_TRUE , 0 , s , c . d a t a ( ) ) ; r e t u r n 0; }

Code 5.8: Code OpenCL permettant l’addition de deux vecteurs.

On peut voir la nette différence de complexité entre les programmations du code CUDA 5.7 et du code OpenCL 5.8. Ce dernier demande un effort plus conséquent.

Documents relatifs