OpenHMPP

OpenHMPP

Le Standard Ouvert OpenHMPP (HMPP pour Hybrid Multicore Parallel Programming) est un modèle de programmation basé sur un jeu de directives, conçu pour manipuler les accélérateurs matériels sans se soucier de la complexité associée à la programmation GPU. Le choix d’implémentation concernant ce modèle s’est porté sur les directives car elles permettent une relation déliée entre le code de l’application et l’utilisation des accélérateurs matériels.

Note : Cet article porte sur les directives OpenHMPP qui constituent l'Open Standard, mais ne traite pas de l'exécution des directives, liée à l'implémentation des directives.

Sommaire

Introduction

La syntaxe offerte par le modèle OpenHMPP permet de répartir efficacement les calculs sur les accélérateurs matériels et d’optimiser les mouvements de données de/vers la mémoire du matériel.
Le modèle est basé sur le projet CAPS (Compiler and Architecture for Embedded and Superscalar Processors) mené en commun par l'INRIA, le CNRS, l'Université de Rennes 1 et l'INSA de Rennes.

Le concept du standard OpenHMPP

Le standard OpenHMPP est basé sur le concept de codelet, qui est une fonction qui peut être exécutée à distance sur le matériel.

Le concept de codelet

Un codelet a les propriétés suivantes :

  1. C'est une fonction pure.
    • Il ne contient pas de déclarations de variables statiques ou volatiles et ne fait aucune référence à des variables globales, exception faite des variables déclarées comme "resident" par une directive OpenHMPP.
    • il ne contient pas d'appels à des fonctions avec un contenu non visible (c'est-à-dire qu'il ne peut pas être inliné). Cela inclut l'utilisation de librairies et de fonctions systèmes telles que malloc, printf, ...
    • Chaque appel à la fonction doit faire référence à une fonction statique pure (pas de pointeurs de fonction).
  2. Il ne retourne aucune valeur (l'équivalent en C est une fonction void; l'équivalent en FORTRAN est une subroutine).
  3. Le nombre d'arguments doit être fixé (pas de vararg comme en C).
  4. Il n'est pas récursif.
  5. Ces paramètres sont supposés ne pas être aliasés (au sens pointeur du terme).
  6. Il ne contient pas de directives callsite (c'est-à-dire pas d'appel RPC à un autre codelet) ou d'autres directives HMPP.

Ces propriétés permettent de s'assurer qu'un codelet RPC peut être exécuté à distance par un matériel. Cet appel RPC et ses transferts de données associés peuvent être asynchrones.

L'exécution RPC d'un codelet

OpenHMPP fournit un protocole d'appel de procédures à distance synchrone et asynchrone.
L'implémentation d'opération asynchrone est dépendante du matériel.

Synchronous versus asynchronous RPC

Le modèle de mémoire mis en œuvre

OpenHMPP prend en compte deux espaces d'adressage :

  • celui du processeur hôte
  • celui de la mémoire du matériel.
HMPP memory Model

Les directives HMPP

Les directives OpenHMPP peuvent être vues comme des “méta-informations” que l’on ajoute dans le code source de l’application. Ce sont donc des méta-informations inoffensives, c’est-à-dire qu’elle ne changent pas le comportement original du code.
Elles adressent l’exécution à distance (RPC) de la fonction ainsi que les transferts de données de/vers la mémoire du matériel. Le tableau qui suit introduit les directives OpenHMPP, classées selon le besoin adressé : certaines sont dédiées à des déclarations, d’autres sont dédiées à la gestion de l’exécution.

Instructions

de contrôle de flux

Directives

pour la gestion des données

Déclarations codelet
group
resident
map
mapbyname
Directives opérationnelles callsite
synchronize
region
allocate
release
advancedload
delegatedstore

Concept de jeu de directives

L’un des points fondamentaux de l’approche proposée par le modèle OpenHMPP est le concept de directives, associées à des labels, qui rendent possible la mise en place d’une structure cohérente pour un jeu de directives entier, disséminé dans l’application.

Il existe deux types de labels :

  • Le premier est associé à un codelet. En général, les directives portant ce genre de label sont limitées à la gestion d’un seul codelet, appelé codelet autonome dans la suite de l’article (pour le distinguer d’un groupe de codelets).
  • Le second est associé à un groupe de codelets. Ces labels sont notés comme suit : “<LabelOfGroup>“, où “LabelOfGroup” est un nom spécifié par l’utilisateur. En général, les directives avec un label de cet type se rapportent au groupe entier. Le concept de groupe est réservé à une classe de problèmes qui nécessitent une gestion spécifique des données à travers l'ensemble de l’application, dans le but d'améliorer les performances.

Syntaxe des directives OpenHMPP

Dans le but de simplifier les notations, les expressions régulières seront utilisées pour décrire la syntaxe des directives OpenHMPP.
Les conventions de couleurs suivantes seront également utilisées :

  • Les mots-clés réservés à HMPP sont en bleu;
  • Les éléments de la grammaire qui peuvent être déclinés en mots-clés HMPP sont en rouge;
  • les variables de l’utilisateur reste en noir.

Syntaxe générale

La syntaxe générale des directives OpenHMPP est :

  • Pour le langage C :
    #pragma hmpp <grp_label> [codelet_label]? directive_type [,directive_parameters]* [&]
    
  • Pour le langage FORTRAN :
    !$hmpp <grp_label> [codelet_label]? directive_type [,directive_parameters]* [&]
    

où:

  • <grp_label>: est un identifiant unique représentant un groupe de codelets. Dans le cas où aucun groupe n’est defini dans l’application, ce label peut être absent. Pour être valide, le nom du label doit obligatoirement suivre la grammaire suivante : [a-z,A-Z,_][a-z,A-Z,0-9,_]*. Notez que les caractères “< >” appartiennent à la syntaxe et sont obligatoires dans ce contexte de label.
  • codelet_label: est un identifiant unique nommant un codelet. Pour être valide, le nom du label doit obligatoirement suivre la grammaire suivante : [a-z,A-Z,_][a-z,A-Z,0-9,_]*
  • directive: est le nom de la directive;
  • directive_parameters: désigne les paramètres associés à la directive. Ces paramètres peuvent être de différents types et spécifient soit des arguments passés à la directive soit un mode d’exécution (asynchronse ou synchrone par exemple) ;
  • [&]: est un caractère utilisé pour indiquer que la directive continue sur la ligne suivante (identique pour le C et le FORTRAN).

Paramètres des directives

Les paramètres associés à une directive peuvent avoir plusieurs types.
A suivre, les paramètres définis avec OpenHMPP :

  • version = major.minor[.micro]: spécifie la version des directives HMPP prise en compte par le préprocesseur;
  • args[arg_items].size={dimsize[,dimsize]*}: spécifie la taille des paramètres non scalaires (un tableau);
  • args[arg_items].io=[in|out|inout]: indique le statut des arguments de la fonction spécifiée (input, output ou les deux). Par défaut, les arguments non qualifiés sont des input;
  • cond = "expr": spécifie une condition pour l’exécution, sous forme d’une expression booléenne C ou FORTRAN qui doit être vraie pour que l’exécution du groupe ou du codelet commence;
  • target=target_name[:target_name]*: spécifie la liste des cibles à essayer d’utiliser, l’ordre d’apparition étant l’ordre de vérification de la disponibilité;
  • asynchronous: spécifie que l’exécution du codelet n’est pas bloquante (par défaut, synchrone);
  • args[<arg_items>].advancedload=true: indique que les paramètres spécifiés sont pré-chargés. Seuls les paramètres ayant pour statut in ou inout peuvent être pré-chargés;
  • args[arg_items].noupdate=true: spécifie que la donnée est déjà disponible sur le matériel et que son transfert n’est donc pas nécessaire. Lorsque cette propriété est fixée, aucun transfert n’est fait sur l’argument considéré;
  • args[<arg_items>].addr="<expr>": est une expression fournissant explicitement l’adresse de la donnée;
  • args[<arg_items>].const=true: indique que l’argument doit être téléchargé une et une seule fois.

Les directives OpenHMPP

Déclaration et exécution d'un codelet

Une directive codelet spécifie qu'une version de la fonction qui suit doit être optimisée pour un matériel spécifié.
Pour la directive codelet :

  • Le label du codelet est obligatoire et doit être unique dans l'application.
  • Le label du groupe n'est pas obligatoire si aucun groupe n'est défini.
  • La directive doit être insérée immédiatement avant la déclaration de la fonction concernée.

La syntaxe de la directive est:

#pragma hmpp <grp_label> codelet_label codelet 
                            [, version = major.minor[.micro]?]?
                            [, args[arg_items].io=[[in|out|inout]]*
                            [, args[arg_items].size={dimsize[,dimsize]*}]*
                            [, args[arg_items].const=true]*
                            [, cond = "expr"]
                            [, target=target_name[:target_name]*]

Il est possible d'avoir plusieurs directives codelet pour une fonction donnée, chacune spécifiant différents usages ou différents contextes d'exécution. Toutefois, il ne peut y avoir qu'une directive callsite pour un label codelet donné.

La directive callsite spécifie l'usage d'un codelet à un point donné dans le programme.
La syntaxe de la directive est:

#pragma hmpp <grp_label> codelet_label callsite
                     [, asynchronous]?
                     [, args[arg_items].size={dimsize[,dimsize]*}]*
                     [, args[arg_items].advancedload=[[true|false]]*
                     [, args[arg_items].addr="expr"]*
                     [, args[arg_items].noupdate=true]*

Un exemple à suivre :

/* déclaration du codelet */
#pragma hmpp simple1 codelet, args[outv].io=inout, target=CUDA
static void matvec(int sn, int sm, loat inv[sm], float inm[sn][sm], float *outv){
    int i, j;
    for (i = 0 ; i < sm ; i++) {
      float temp = outv[i];
      for (j = 0 ; j < sn ; j++) {
        temp += inv[j] * inm[i][ j];
    }
   outv[i] = temp;
 }
 
 int main(int argc, char **argv) {
   int n;
   ........
 
 /* Utilisation du codelet */
 #pragma hmpp simple1 callsite, args[outv].size={n}
 matvec(n, m, myinc, inm, myoutv);
   ........
 }

Dans certains cas, une gestion spécifique des données est nécessaire dans l'application (optimisation des mouvements de données entre CPU et GPU, variables partagées...).
La directive group permet la déclaration d'un groupe de codelets. Les paramètres définis pour cette directive sont appliqués à tous les codelets associés à ce groupe.
La syntaxe de la directive est:

#pragma hmpp <grp_label> group 
                          [, version = <major>.<minor>[.<micro>]?]? 
                          [, target = target_name[:target_name]*]? 
                          [, cond  = “expr]?

Directives appliquées aux transferts de données (optimisation des surcoûts liés aux communications)

Le principal goulet d'étranglement lors de l'utilisation du HWA réside souvent dans les transferts de données entre le matériel et le processeur principal.
Pour limiter les surcoûts liés aux communications, les transferts de données peuvent être communes à des exécutions successives d'un même codelet en utilisant la propriété asynchrone du matériel.

  • la directive "allocate"

Elle verrouille le matériel et alloue la quantité de mémoire nécessaire.

#pragma hmpp <grp_label> allocate [,args[arg_items].size={dimsize[,dimsize]*}]*
  • la directive "release"

Elle spécifie à quel moment le matériel doit être libéré pour un groupe ou pour un codelet autonome.

#pragma hmpp <grp_label> release
  • la directive "advancedload"

Elle charge les données avant l'exécution à distance du codelet.

#pragma hmpp <grp_label> [codelet_label]? advancedload
                  ,args[arg_items]
                  [,args[arg_items].size={dimsize[,dimsize]*}]*
                  [,args[arg_items].addr="expr"]*
                  [,args[arg_items].section={[subscript_triplet,]+}]*
                  [,asynchronous]
  • la directive "delegatedstore"

Elle constitue une barrière synchrone qui permet d'attendre la complétion de l'exécution d'un codelet asynchrone puis avant de télécharger les résultats.

#pragma hmpp <grp_label> [codelet_label]? delegatedstore 
                ,args[arg_items]
                [,args[arg_items].addr="expr"]*
                [,args[arg_items].section={[subscript_triplet,]+}]*
  • Calculs asynchrones

La directive synchronize spécifie qu'il faut attendre la fin de l'exécution asynchrone du callsite.
Pour cette directive, le label du codelet est toujours obligatoire et le label group est nécessaire si le codelet est associé à un groupe. La syntaxe de la directive est:

#pragma hmpp <grp_label> codelet_label synchronize
  • Exemple

Dans l'exemple qui suit, l'initialisation du matériel, l'allocation de la mémoire et le téléchargement des données d'entrée sont effectués une seule fois, en dehors de la boucle au lieu d'être effectués à chaque itération de la boucle.
La directive synchronize permet d'attendre la fin de l'exécution asynchrone du codelet avant de démarrer une autre itération. Finalement, la directive delegatedstore, placée en dehors de la boucle, télécharge le résultat de "sgemm".

int main(int argc, char **argv) {

#pragma hmpp sgemm allocate, args[vin1;vin2;vout].size={size,size}
#pragma hmpp sgemm advancedload, args[vin1;vin2;vout], args[m,n,k,alpha,beta]
  
for ( j = 0 ; j < 2 ; j ++) {
   #pragma hmpp sgemm callsite, asynchronous, args[vin1;vin2;vout].advancedload=true, args[m,n,k,alpha,beta].advancedload=true
   sgemm (size, size, size, alpha, vin1, vin2, beta, vout);
   #pragma hmpp sgemm  synchronize
}

#pragma hmpp sgemm delegatedstore, args[vout]
#pragma hmpp sgemm release

Partage de données entre codelets

Ces directives permettent de partager tous les arguments ayant le même nom pour tout un groupe.
Les types et dimensions de tous les arguments partagés doivent être identiques.

La directive map permet d'associer plusieurs arguments sur le matériel.

#pragma hmpp <grp_label>  map, args[arg_items]

La directive mapbyname est semblable à la directive map sauf que les arguments à mapper sont directement spécifiés par leur nom. La directive mapbyname est équivalente a de multiples directives map.
La notation est la suivante :

#pragma hmpp <grp_label> mapbyname [,variableName]+

Variable globale

La directive resident déclare des variables comme globales au sein d'un groupe.
Ces variables peuvent être directement accédées à partir de n'importe quel codelet du groupe sur le matériel (elles sont en quelque sorte considérées comme "résidentes" sur le matériel).
Cette directive s'applique à la déclaration qui la suit dans le code source.
La syntaxe de cette directive est :

#pragma hmpp <grp_label> resident 
               [, args[::var_name].io=[[in|out|inout]]*
               [, args[::var_name].size={dimsize[,dimsize]*}]*
               [, args[::var_name].addr="expr"]*
               [, args[::var_name].const=true]*

La notation ::var_name, avec le préfixe ::, indique une variable d'application déclarée comme resident.

Accélération de région

Une région est un mélange des directives codelet/callsite. Son but est d'éviter la restructuration du code imposée par la création explicite des codelets. Par conséquent, tous les attributs disponibles pour les directives codelet ou callsite peuvent être utilisés pour la directive region.

La syntaxe est la suivante :

#pragma hmpp [<MyGroup>] [label] region         
                           [, args[arg_items].io=[[in|out|inout]]*
                           [, cond = "expr"]<
                           [, args[arg_items].const=true]*
                           [, target=target_name[:target_name]*]
                           [, args[arg_items].size={dimsize[,dimsize]*}]*
                           [, args[arg_items].advancedload=[[true|false]]*
                           [, args[arg_items].addr="expr"]*
                           [, args[arg_items].noupdate=true]*
                           [, asynchronous]?
                           [, private=[arg_items]]*
   {
C BLOCK STATEMENTS
   }

Implémentations

OpenHMPP est basé sur la version 2.3 de HMPP (mai 2009, CAPS entreprise).

Le modèle proposé par OpenHMPP est implémenté par :

  • HMPP Workbench, le compilateur fourni par CAPS Entreprise pour le calcul hybride
  • PathScale ENZO Compiler Suite (support des GPU NVIDIA)

De plus, OpenHMPP est utilisé dans le cadre de projet HPC mené dans des domaines tels que le pétrole, l'énergie, l'industrie, l'éducation et la recherche et permet de développer des versions hautes performances de leurs applications, tout en préservant le code déjà produit.

Voir aussi

Références




Wikimedia Foundation. 2010.

Contenu soumis à la licence CC-BY-SA. Source : Article OpenHMPP de Wikipédia en français (auteurs)

Игры ⚽ Поможем сделать НИР

Regardez d'autres dictionnaires:

  • OpenHMPP — HMPP for Hybrid Multicore Parallel Programming. Based on a set of directives, OpenHMPP Standard is a programming model designed to handle hardware accelerators without the complexity associated with GPU programming. This approach based on… …   Wikipedia

  • Parallel computing — Programming paradigms Agent oriented Automata based Component based Flow based Pipelined Concatenative Concurrent computing …   Wikipedia

  • Multiprocessing — (see also Multiprocessor) Multiprocessing is the use of two or more central processing units (CPUs) within a single computer system. The term also refers to the ability of a system to support more than one processor and/or the ability to allocate …   Wikipedia

  • Message Passing Interface — MPI, the Message Passing Interface, is standardized and portable message passing system designed by a group of researchers from academia and industry to function on a wide variety of parallel computers. The standard defines the syntax and… …   Wikipedia

  • Directive (programming) — In computer programming, the term directive is applied in a variety of ways that are similar to the term command. It is also used to describe some programming language constructs (e.g. those specifying how a compiler or assembler should process… …   Wikipedia

  • Hybrid Multicore Parallel Programming — HMPP (Hybrid Multicore Parallel Programming) est un ensemble d outils de développement au service de la programmation multi cœurs hybride. HMPP est un produit commercial de CAPS entreprise [1]. Sommaire 1 Description 2 Les principes 3 …   Wikipédia en Français

  • Multi-core processor — Diagram of a generic dual core processor, with CPU local level 1 caches, and a shared, on die level 2 cache …   Wikipedia

  • Computer multitasking — In computing, multitasking is a method where multiple tasks, also known as processes, share common processing resources such as a CPU. In the case of a computer with a single CPU, only one task is said to be running at any point in time, meaning… …   Wikipedia

  • Distributed computing — is a field of computer science that studies distributed systems. A distributed system consists of multiple autonomous computers that communicate through a computer network. The computers interact with each other in order to achieve a common goal …   Wikipedia

  • Non-Uniform Memory Access — (NUMA) is a computer memory design used in Multiprocessing, where the memory access time depends on the memory location relative to a processor. Under NUMA, a processor can access its own local memory faster than non local memory, that is, memory …   Wikipedia

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”