FR2996654A1 - Procede de generation d'un graphe a partir d'un code source ecrit en un langage de description de processus flot de donnees - Google Patents

Procede de generation d'un graphe a partir d'un code source ecrit en un langage de description de processus flot de donnees Download PDF

Info

Publication number
FR2996654A1
FR2996654A1 FR1259547A FR1259547A FR2996654A1 FR 2996654 A1 FR2996654 A1 FR 2996654A1 FR 1259547 A FR1259547 A FR 1259547A FR 1259547 A FR1259547 A FR 1259547A FR 2996654 A1 FR2996654 A1 FR 2996654A1
Authority
FR
France
Prior art keywords
source code
tasks
parameters
program
task
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
FR1259547A
Other languages
English (en)
Inventor
Loic Cudennec
Renaud Sirdey
Paul Dubrulle
Thierry Goubier
Stephane Louise
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Commissariat a lEnergie Atomique et aux Energies Alternatives CEA
Original Assignee
Commissariat a lEnergie Atomique CEA
Commissariat a lEnergie Atomique et aux Energies Alternatives CEA
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Commissariat a lEnergie Atomique CEA, Commissariat a lEnergie Atomique et aux Energies Alternatives CEA filed Critical Commissariat a lEnergie Atomique CEA
Priority to FR1259547A priority Critical patent/FR2996654A1/fr
Publication of FR2996654A1 publication Critical patent/FR2996654A1/fr
Pending legal-status Critical Current

Links

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/40Transformation of program code
    • G06F8/41Compilation
    • G06F8/45Exploiting coarse grain parallelism in compilation, i.e. parallelism between groups of instructions
    • G06F8/451Code distribution

Landscapes

  • Engineering & Computer Science (AREA)
  • General Engineering & Computer Science (AREA)
  • Theoretical Computer Science (AREA)
  • Software Systems (AREA)
  • Physics & Mathematics (AREA)
  • General Physics & Mathematics (AREA)
  • Devices For Executing Special Programs (AREA)

Abstract

L'invention est relative à un procédé de compilation d'un programme destiné à être exécuté sur une plateforme multiprocesseurs, comprenant les étapes consistant à : prévoir un code source d'origine dans un langage haut-niveau de description d'un traitement flot de données, le langage disposant de déclarations permettant d'instancier et de connecter des tâches de manière paramétrique ; produire un programme intermédiaire (20) à partir des déclarations d'instanciation et de connexion (12) du code source d'origine ; exécuter le programme intermédiaire, d'où il résulte que toutes les instances des tâches sont identifiées et leurs paramètres de connexion sont évalués ; et utiliser les valeurs des paramètres produites par l'exécution du programme intermédiaire pour construire un graphe (24) reliant les tâches entre elles.

Description

PROCEDE DE GENERATION D'UN GRAPHE A PARTIR D'UN CODE SOURCE ECRIT EN UN LANGAGE DE DESCRIPTION DE PROCESSUS FLOT DE DONNEES Domaine technique de l'invention L'invention est relative aux outils de développement destinés à produire des programmes exécutables sur des matrices de processeurs, notamment dans le cas où les programmes sont écrits sous forme de processus de type flot de données dans un langage de programmation haut niveau. État de la technique Afin de programmer une matrice de processeurs, on cherche à décomposer un traitement complexe en une multitude de tâches qui peuvent être exécutées en parallèle sur des processeurs distincts de la matrice. Une méthode pour décomposer le traitement en tâches consiste à organiser le traitement en processus de type flot de données. Dans un processus flot de données, des tâches 15 prédéfinies communiquent des données entre elles par l'intermédiaire de mémoires tampon. Les tâches sont récurrentes et opèrent sur des vagues successives de données. Il existe des langages de programmation haut-niveau qui permettent au programmeur de définir un traitement sous forme de processus flot de données. Le langage Streamlt, décrit dans ["Streamlt: A Language for Streaming Applications", William Thies, 20 Michal Karczmarek, and Saman Amarasinghe; Laboratory for Computer Science Massachusetts Institute of Technology Cambridge, MA 02139], permet de décrire des organisations série-parallèle de tâches à l'aide d'opérateurs de séparation « split » et de jointure « join ». Une tâche, en dehors des tâches « split » et « join », ne peut avoir de multiples ports d'entrée ou de sortie. 25 Le langage SigmaC autorise par contre la définition de tâches à multiples ports d'entrées et/ou de sortie, et organisées de manière quelconque. Ce langage est en partie décrit dans ["Sigma-C: a programming model and language for embedded manycores", T. Goubier, R. Sirdey, S. Louise and V. David; Lecture Notes in Computer Science 7016:385-394 (Proceedings of the 1 lth International Conference on Algorithms and 30 Architectures for Parallel Processing, Melbourne, Australia), 2011].
Une fois que le programmeur a écrit un code source dans le langage haut niveau de son choix, ce code source doit être compilé pour produire un code exécutable sur les processeurs de la matrice. Pour faciliter la tâche du programmeur, le langage permet généralement de définir des tâches de manière paramétrique, c'est-à-dire à l'aide de variables qui seront calculées seulement à l'exécution du code. Par exemple, en SigmaC, le programmeur peut définir un groupe de tâches identiques à l'aide d'une boucle, dans laquelle chaque itération définit des ports d'entrée et de sortie différents en fonction de l'indice de boucle. Si la matrice de processeurs est conçue pour allouer les ressources (processeurs et mémoire) de manière dynamique aux tâches, la production du code exécutable correspondant à la boucle, ou autre définition paramétrique, ne pose pas de problème majeur. Le code exécutable est fourni à un ordonnanceur qui identifie les tâches et les répartit dynamiquement sur les ressources disponibles. Si le nombre de processeurs est important, cet ordonnancement prend des ressources significatives et l'allocation est difficile à optimiser. On préfère alors que l'allocation des ressources soit en partie statique et déterminée hors-ligne, à la compilation, comme cela est proposé dans la demande de brevet US2011093854. Le code exécutable doit alors être produit avec des informations d'affectation des ressources, ce qui pose des difficultés lorsque les tâches sont définies de manière paramétrique, c'est-à-dire lorsque les informations permettant l'affectation des ressources ne sont connues qu'au moment de l'exécution. Résumé de l'invention On souhaite donc effectuer une allocation de ressources hors-ligne pour des tâches définies de manière paramétrique dans un langage de programmation dédié.
On tend à satisfaire ce besoin en prévoyant un procédé de compilation d'un programme destiné à être exécuté sur une plateforme multiprocesseurs, comprenant les étapes consistant à : prévoir un code source d'origine dans un langage haut-niveau de description d'un traitement flot de données, le langage disposant de déclarations permettant d'instancier et de connecter des tâches de manière paramétrique ; produire un programme intermédiaire à partir des déclarations d'instanciation et de connexion du code source d'origine ; exécuter le programme intermédiaire, d'où il résulte que toutes les instances des tâches sont identifiées et leurs paramètres de connexion sont évalués ; et utiliser les valeurs des paramètres produites par l'exécution du programme intermédiaire pour construire un graphe reliant les tâches entre elles. Selon un mode de mise en oeuvre, le procédé comprend les étapes suivantes pour produire le programme intermédiaire : effectuer une analyse syntaxique du code source 5 d'origine pour produire un code source d'instanciation dans lequel les déclarations d'instanciation et de connexion du code source d'origine sont remplacées par des fonctions de suivi conçues pour, à l'exécution, évaluer les paramètres et écrire leurs valeurs sous forme de liste d'interconnexions dans un fichier de graphe ; et compiler le code source d'instanciation en le liant à une bibliothèque définissant les fonctions de 10 suivi pour produire le programme intermédiaire. Selon un mode de mise en oeuvre, le code source d'origine dispose de déclarations de quantification définissant des paramètres de quantification représentatifs des quantités de données transitant par les connexions de chaque tâche. Le procédé comprend alors les étapes suivantes : dans le code source d'instanciation, remplacer les déclarations de 15 quantification du code source d'origine par des fonctions de suivi conçues pour, à l'exécution, évaluer les paramètres de quantification et écrire leurs valeurs dans le fichier de graphe ; et déterminer les ressources requises par chaque tâche à partir des paramètres de quantification du fichier de graphe. Selon un mode de mise en oeuvre, dans l'étape d'analyse syntaxique, on produit en outre 20 un code source de traitement correspondant aux opérations effectuées par les tâches définies dans le code source d'origine, et, dans le code source d'instanciation, on remplace des déclarations de constantes et de variables du code source d'origine par des fonctions de suivi conçues pour, à l'exécution, évaluer ces constantes et variables et écrire leurs valeurs dans des fichiers de données associés aux tâches. On analyse alors le 25 fichier de graphe pour produire un plan d'affectation définissant un mappage des tâches sur des ressources ; et on compile le code source de traitement en le combinant au plan d'affectation et aux fichiers de données pour produire un programme exécutable sur la plateforme multiprocesseurs. Selon un mode de mise en oeuvre, la première étape de compilation est une étape de 30 compilation croisée pour produire un programme intermédiaire exécutable sur la plateforme multiprocesseurs, et l'étape d'exécution est une étape d'exécution sur une machine virtuelle représentant la plateforme multiprocesseurs.
Description sommaire des dessins Des modes de réalisation seront exposés dans la description suivante, faite à titre non limitatif en relation avec les figures jointes parmi lesquelles : - la figure 1 est un graphe flot de données partiel représentant un exemple de traitement d'image ; - la figure 2 est un graphe partiel correspondant à une redéfinition du graphe de la figure 1 par un langage de programmation dédié ; et - la figure 3 représente un organigramme d'une chaîne de compilation permettant de produire une allocation statique de ressources à partir d'un code source définissant des tâches de manière paramétrique. Description d'un mode de réalisation préféré de l'invention Pour permettre une allocation de ressources à un traitement flot de données, il est préférable de disposer du graphe complet, définissant toutes les tâches et leurs canaux de communication.
La figure 1 illustre un exemple de graphe flot de données d'un traitement d'image que l'on peut définir en SigmaC. Le traitement est le calcul du laplacien de l'image à l'aide d'un filtre séparable (opérateur de Huertas-Médioni). Une tâche de lecture séquentielle R, prédéfinie dans le langage, lit les données d'une image stockée dans une zone mémoire. Une tâche de séparation S, également prédéfinie dans le langage, est configurée pour envoyer les lignes de l'image sur des sorties respectives distinctes. Chaque ligne est traitée par une tâche de filtrage L respective. Chaque tâche L produit deux lignes traitées de manières différentes sur deux sorties respectives. Les premières sorties des tâches L sont fournies à une première tâche de jonction J, prédéfinie dans le langage. Une deuxième tâche de jonction J reçoit les deuxièmes sorties des tâches L. Ainsi, les tâches J produisent deux images qui ont été calculées à partir de l'image de départ de manières différentes. Les images produites par les tâches de jonction J sont fournies à deux nouvelles tâches de séparation S respectives, chacune produisant les colonnes de l'image sur des sorties respectives. Chaque paire de colonnes de même rang des tâches S est fournie à un tâche de filtrage C respective, qui combine les deux colonnes en une seule. Les colonnes produites par les tâches C sont combinées par une nouvelle tâche de jonction J, produisant une image qui est récrite dans une zone mémoire par une tâche d'écriture prédéfinie W. Le langage SigmaC permet au programmeur de définir un graphe de manière hiérarchique. Il peut notamment décomposer le graphe en des sous-graphes contenant des groupes de tâches liées, puis de relier les sous-graphes comme s'il s'agissait également de tâches. On décrit ci-après en détail une décomposition possible d'une partie du graphe de la figure 1, représentée dans un cadre en pointillés LP. Le code source en SigmaC d'une tâche L de filtrage ligne peut s'exprimer selon le tableau (1) en annexe.
La tâche L est déclarée comme étant un « agent » dénommé LineFilter, prenant un entier width comme paramètre. Ce paramètre définit la largeur de l'image en pixels, c'est-à-dire la longueur d'une ligne. Une section « interface » définit les ports d'entrée et de sortie de la tâche, à savoir une entrée (in) dénommée fine, destinée à recevoir des entiers (int), et deux sorties (out) dénommées output] et output2, destinées à produire des entiers. Une déclaration « spec » indique que les entrées et sorties sont traitées par séries de width pixels. Ainsi, les noms des entrées et sorties désignent par la suite des variables de type tableau de width entiers ou pixels. Un mot clé « exchange » dans la déclaration de la fonction principale start0 de l'agent 20 définit des alias a, b et c pour les variables line, output] et output2 pour faciliter l'écriture des calculs définis ensuite. Le reste du code source de l'agent est du langage C classique qu'il n'est pas utile de décrire plus en détail ici. Le sous-graphe LP de la figure 1 peut alors s'exprimer selon le code source du tableau (2) en annexe. 25 Le sous-graphe est déclaré avec le mot-clé « subgraph », il est dénommé LinePass, et il prend comme paramètres deux entiers width et height pour la largeur et la hauteur de l'image. La section « interface » définit une entrée imag de type entier et deux sorties output] et output2 de type entier. La déclaration « spec » définit les variables correspondantes comme des tableaux de taille width*height, c'est-à-dire pouvant 30 contenir une image entière.
On remarque ici une section « map » - elle est destinée à instancier toutes les tâches du sous-graphe, et à définir leurs interconnexions. Par « instancier » une tâche, on entend notamment la réservation d'un espace mémoire dimensionné pour contenir toutes les données nécessaires à la tâche, et la définition dans cet espace des adresses de toutes les variables utilisées par la tâche. Dans la section « map », on instancie successivement des tâches S, J1 et J2 comme des agents respectifs « split », « join » et « join » à l'aide de la fonction « new ». Les agents « split » et « join » sont des agents système spécialisés dans la réorganisation de données, prédéfinis dans le langage SigmaC. Ils sont paramétrés ici pour traiter height groupes de width entiers (en fait height lignes de width pixels). Les tâches individuelles de filtrage L sont nombreuses et semblables. Le programmeur ne souhaite pas écrire explicitement le code d'instanciation de chacune de ces tâches elles sont définies dans une boucle d'indice i, avec i allant de 0 à height-1. A chaque itération, une nouvelle tâche L est instanciée comme un agent LineFilter (tel que défini en (1)), avec le paramètre width. On définit en outre les interconnexions des tâches L avec les tâches S, J1 et J2 à l'aide de la fonction « connect ». Plus spécifiquement : l'entrée fine de la tâche L instancée dans l'itération i est connectée à la sortie output[i] de la tâche S ; la sortie outputl de la tâche L est connectée à l'entrée input[i] de la tâche J1 ; et la sortie output2 de la tâche L est connectée à l'entrée input[i] de la tâche J2. Les ports output[] et input[] appartiennent à la définition des agents système « split » et « join » - chacune est instanciée par un variable de type tableau de height lignes de width pixels, chaque ligne étant accessible par l'indice du tableau. On définit enfin les connexions des tâches aux ports du sous-graphe. Plus 25 spécifiquement : l'entrée imag du sous-graphe est connectée à l'entrée input de la tâche S ; la sortie output de la tâche J1 est connectée à la sortie outputl du sous-graphe ; et la sortie output de la tâche J2 est connectée à la sortie output2 du sous-graphe.
Les ports input et output des tâches S, J1 et J2 appartiennent également à la définition des agents système « split » et « join ». Finalement, on souhaite connecter les sous-graphes entre eux ou à des tâches périphériques pour compléter le graphe de la figure 1 et exécuter le traitement. Cela 5 peut être exprimé selon le code du tableau (3) en annexe, définissant le graphe « racine ». Ce graphe est déclaré comme un agent système « root ». Il ne comporte pas d'interface - seulement une section « map » servant à instancier les tâches périphériques et les sous-graphes, et à les interconnecter. On déclare par ailleurs des constantes WIDTH, 10 HEIGHT (les dimensions de l'image à traiter - 8x8 dans cet exemple), et ADDRIN, ADDROUT (l'adresse de lecture de l'image originale et l'adresse d'écriture de l'image traitée). Dans ce graphe racine, des tâches de lecture et d'écriture R et W sont instanciées comme des agents système « LinearReader » et « LinearWriter ». Le premier a pour 15 paramètres l'adresse de lecture de l'image et la taille de l'image en pixels. Le second a pour paramètres l'adresse d'écriture de l'image, sa hauteur, et sa largeur. Une tâche LP est instanciée comme un agent « LinePass », qui n'est autre que le sous-graphe de même nom défini en (2), avec les paramètres WIDTH et HEIGHT. Une tâche CP est instanciée comme un agent « ColumnPass », un sous-graphe non-20 décrit correspondant au traitement des colonnes de la partie droite de la figure 1. Finalement, par une série de fonctions « connect », on connecte entre elles les interfaces des tâches LP, CP, R et W. Afin de lancer l'exécution du traitement, un programme principal, non décrit, instancie une occurrence de l'agent « root » et l'exécute. Cette exécution provoque l'exécution 25 des tâches définies dans l'agent « root » et de toutes les tâches de hiérarchie inférieure définies par les sous-graphes. La compilation du code fourni ci-dessus pour un système à allocation dynamique des ressources ne pose pas de problème particulier. Le code exécutable serait alors généré pour placer les tâches au fur et à mesure qu'elles sont instanciées dans un pool de tâches 30 à exécuter, dans lequel un ordonnanceur vient chercher des tâches pour les affecter à des ressources disponibles.
Dans un système à allocation statique des ressources, les affectations des tâches aux ressources sont définies hors-ligne, à la compilation. Pour cela, la chaîne de compilation est paramétrée pour connaître les ressources de l'architecture cible, telles que le nombre de processeurs, la taille mémoire disponible pour chaque processeur, et la structure des interconnexions entre processeurs. Une étape de « placement » dans la compilation consiste alors à mapper les tâches de manière statique sur les processeurs, de sorte que les tâches qui interagissent le plus soient mappées sur des processeurs proches. Les canaux de communication entre processeurs peuvent être alloués de manière dynamique ou statique. Dans le cas d'une allocation statique, la chaîne de compilation est également paramétrée avec une connaissance de la structure d'interconnexion des processeurs. Cela permet de réaliser une opération de « routage » pour définir hors-ligne les chemins à emprunter par les différentes communications entre les tâches. Néanmoins, pour qu'une allocation statique des ressources soit possible pendant la compilation, il est souhaitable d'identifier les tâches individuelles avec les ressources qu'elles demandent, et les canaux de communication entre les tâches, avec leurs bandes passantes. Ces informations ne sont pas disponibles de manière exploitable lorsqu'on utilise les chaînes de compilation classiques. Pour effectuer une allocation statique des ressources à la compilation, on souhaite disposer d'un graphe regroupant les informations nécessaires.
La figure 2 est un graphe partiel, tiré des informations du code source exposé ci-dessus, pouvant servir de base à une allocation de ressources statique. Chaque tâche de la figure 1 est reportée dans ce graphe sous forme d'une instance ayant un identifiant unique, ici préfixé par la désignation de la tâche. Le graphe montre également les interfaces de chaque instance, et les liaisons entre les tâches de la figure 1 sont matérialisées par des connexions entre des ports correspondants des instances. Une difficulté rencontrée pour construire un tel graphe à partir du code source provient du fait que les tâches sont généralement définies de manière paramétrique. Par exemple, la définition de l'agent « LineFilter » utilise le paramètre width qui s'avère ici être une constante définie dans l'agent « root » deux niveaux hiérarchiques plus haut. Mais des paramètres peuvent également être définis par un calcul, comme l'indice de boucle i pour instancier les tâches L dans le sous-graphe « LinePass ». Certains paramètres pourraient n'être définis qu'à l'exécution du programme et dépendre de la plateforme matérielle sur laquelle le programme est exécuté, comme les adresses des espaces mémoire alloués aux instances et aux interfaces.
Afin de construire un graphe exploitable pour une allocation statique de ressources à la compilation, on propose une phase d'exécution hors-ligne du code d'instanciation des fichiers source. Par « code d'instanciation » on entend le code qui définit chaque tâche et ses canaux de communication avec d'autres tâches (notamment les sections « interface » et « map » des exemples de code SigmaC exposés plus haut). Lors de cette exécution, les paramètres sont évalués pour chaque instance de tâche créée. A partir des valeurs ainsi évaluées des paramètres, on peut déduire un graphe détaillé tel que représenté en figure 2. La figure 3 est un organigramme simplifié d'une chaîne de compilation illustrant une 10 utilisation particulière de l'exécution hors-ligne pour créer un graphe facile à exploiter par des phases ultérieures de la compilation. Un code source 8 écrit en un langage haut-niveau de programmation de processus flot de données, tel que le SigmaC, est contenu dans plusieurs fichiers (.sc) qui sont soumis à une analyse syntaxique en 10. L'analyse syntaxique produit deux jeux de fichiers (.c) 15 en un langage de programmation générique, tel que le C ; un premier jeu 12 produit à partir du seul code d'instanciation des tâches (par exemple les sections « interface » et « map »), et un deuxième jeu 14 produit à partir du code restant, le code de traitement utilisateur à exécuter en ligne sur la plateforme cible (par exemple la fonction « start » de l'agent « LineFilter »). 20 Plutôt que de produire du code C classique pour le code d'instanciation, comme on l'aurait fait si le code d'instanciation et le code de traitement n'avaient pas été dissociés, l'analyse syntaxique remplace les mots réservés du langage de programmation, dont les fonctions d'instanciation et de déclaration des connexions, par des fonctions de suivi. A l'exécution, ces fonctions de suivi réalisent les opérations traditionnelles requises pour 25 évaluer les différents paramètres. Une fois les paramètres évalués, les fonctions de suivi peuvent en déduire des informations utiles pour construire un graphe et estimer les ressources nécessaires. Ces fonctions de suivi sont définies dans une bibliothèque 16. Des exemples de fonctions de suivi seront décrits ultérieurement. Les fichiers 12 sont compilés en 18 et les appels aux fonctions de suivi qu'ils 30 contiennent sont liés à la bibliothèque 16 pour produire un programme exécutable 20. Le programme 20 est ensuite exécuté en 22. De façon générale, le programme 8 ne sera pas destiné à être exécuté sur le poste de développement, mais sur une plateforme cible différente. Ainsi, comme cela est indiqué sur l'organigramme, on effectue en 18 plutôt une compilation croisée destinée à produire un exécutable pour la plateforme cible, et le programme résultant est exécuté en 22 sur une machine virtuelle reflétant la plateforme cible, laquelle machine virtuelle peut bien entendu tourner sur le poste de développement. A l'exécution en 22, les fonctions de suivi du programme 20 réalisent les instanciations et les connexions dans leur environnement réel puis, toutes les variables étant évaluées, celles utiles à la construction d'un graphe et au calcul de ressources sont écrites dans un fichier de graphe 24. Le graphe est décrit dans ce fichier sous forme d'une liste d'interconnexions (« netlist » en anglais), par exemple au format XML. Généralement le code de traitement 14 fait appel à des constantes et variables définies dans le code d'instanciation 12. Le code d'instanciation 12 et le code de traitement 14 ayant été dissociés, il convient de réintégrer ces paramètres au code de traitement à la compilation. Ainsi, les fonctions de suivi sont également prévues pour écrire les valeurs de ces paramètres dans des fichiers 26 associés aux agents définis dans le code d'instanciation.
Le fichier de graphe 24 est analysé par un outil d'affectation de ressources 28 pour produire un plan d'affectation 30 dans un fichier, au format XML par exemple. Dans le cadre d'un programme écrit pour une matrice de processeurs ou calculateurs, le plan d'affectation 30 mappe les tâches sur des calculateurs respectifs et, si les interconnexions sont établies de manière fixe, mappe les différentes connexions entre tâches sur les liens interconnectant les calculateurs. Ainsi, l'affectation de ressources 28 consiste en une opération de placement-routage des tâches sur la matrice de calculateurs afin d'optimiser l'exploitation des calculateurs (en termes de cycles d'instruction et d'utilisation mémoire). Le placement-routage est conçu de manière générale pour regrouper sur des calculateurs rapprochés les tâches qui communiquent le plus. On peut à cet effet adapter des algorithmes connus de placement-routage contraint. Bien entendu, si les ressources des calculateurs le permettent, on peut affecter plusieurs tâches à un seul calculateur. Ainsi, le placement-routage a également besoin d'informations sur les ressources utilisées par les tâches. Les fonctions de suivi que l'analyse syntaxique 10 place dans le code d'instanciation 12 ont également pour rôle d'écrire ces informations dans le fichier de graphe 24. De telles informations peuvent notamment être déduites des déclarations « spec » du code source, qui définissent les quantités de données que chaque tâche consomme ou produit. Par exemple, la déclaration suivante dans l'agent « LineFilter » : spec { { line [width]; outputl [width]; output2[width]II; indique que chacun des ports line, outputl et output2 de la tâche consomme ou produit à chaque occurrence une salve de width entiers (puisque ces ports ont été déclarés de type « int »). Ainsi, on compte width transitions de line vers outputl et autant de line vers 5 output2, soit 2*width transitions d'entiers pour chaque occurrence de la tâche. Si le calculateur traite un entier par cycle, il faut au moins 2*width cycles pour compléter la tâche. On connaît en outre la mémoire maximale requise par la tâche, qui est de 3*width entiers, en supposant qu'une nouvelle salve de width entiers a été reçue sur l'entrée line tandis que les sorties outputl et output2 s'apprêtent à fournir les width entiers provenant 10 du traitement de la salve précédente. Le code de traitement 14 est compilé en 32 et le code objet produit passe par une édition de liens en 34 pour produire un programme 36 exécutable sur la plateforme cible. L'édition de liens 34 intègre le plan d'affectation 30 et les données d'agent 26 dans le programme 36. 15 Le programme 36 pourra être conçu sous forme de modules exécutables correspondant aux différentes tâches et d'un programme de démarrage à exécuter en premier. Le programme de démarrage est alors conçu pour charger les modules dans les mémoires des calculateurs correspondants de la matrice et paramétrer les liens entre calculateurs, en fonction du plan d'affectation. 20 Le tableau (4) en annexe fournit un exemple simplifié d'une description d'instance telle qu'écrite dans le fichier de graphe 24 par le programme 20. L'exemple considéré est celui de l'instanciation d'un agent « LineFilter » dans la boucle « for » du sous-graphe « LinePass » (tableau 2). Chaque tâche est identifiée dans le fichier de graphe par une balise <instance>. 25 L'attribut « id » de cette balise contient un identifiant unique, 8 dans l'exemple, et l'attribut « name » contient le nom de l'agent, « LineFilter » dans l'exemple. Une balise <parameters> introduit une liste de paramètres avec leurs valeurs, chaque paramètre de la liste étant défini par une balise <parameter>. Cette liste de paramètres est en fait optionnelle, car elle ne sert pas à définir le graphe ou à l'affectation des 30 ressources - elle est insérée dans un but informatif pour le développeur et pour faciliter le débogage. L'attribut « type » de la balise <parameter> contient le type du paramètre et l'attribut « name » contient le nom du paramètre. Les paramètres définis dans l'exemple sont width, gl et g2. Les valeurs trouvées à l'exécution pour ces paramètres sont écrites en notation hexadécimale. Dans l'exemple, la notation hexadécimale correspond à des entiers signés de 32 bits. Une section introduite par la balise <interface> définit l'interface de la tâche et la connexion de cette interface dans le graphe, et contient des informations sur les 5 ressources requises. Une section introduite par la balise <ports> définit les ports de l'interface. Chaque port est défini par une balise <port> ayant les attributs « id », « narre » et « direction », indiquant respectivement un identifiant unique, le nom, et si le port est une entrée ou une sortie. Une sous-section introduite par la balise <connection> définit la connexion 10 du port à l'aide de balises <from> et <to>. La balise <from> est utilisée lorsque le port, local, est une entrée, et la balise <to> est utilisée lorsque le port local est une sortie. L'attribut « portid » de ces balises identifie le port distant correspondant. L'attribut « linkid » définit par un identifiant unique le lien entre le port local et le port distant. Les attributs « portid » et « linkid » ont la valeur « -1 » lorsque la balise <from> ou 15 <to> n'a pas de signification, par exemple la balise <to> pour un port d'entrée. Les deux balises <to> et <from> ont une signification dans un sous-graphe pour lequel on définit des ports périphériques qui sont reliés à des ports de tâches internes au sous-graphe, par exemple l'entrée « imag » du sous-graphe LP, qui est reliée à l'entrée « input » de la tâche interne S_2 en figure 2. 20 Finalement une section introduite par une balise <spec> caractérise les transitions sur les différents ports de la tâche, à savoir le nombre de cycles d'horloge nécessaires à traiter les données transitant par les ports de la tâche, pour chaque occurrence de la tâche. Chaque transition est introduite par une balise <transition>, sous laquelle on trouve une balise <amount> par port impliqué dans la transition. Les attributs « portid », 25 « qmin » et « qmax » de cette balise identifient le port, le nombre minimal de données d'une salve, et le nombre maximal de données d'une salve. Dans l'exemple, les salves sont de taille constante de 8 entiers pour chacun des ports, et les trois ports de la tâche sont impliqués dans la transition, car chaque pixel entrant est traité et envoyé sur chacun des deux ports sortants. Pour une tâche « Split », on aurait 30 autant de transitions que de ports sortants, chacune impliquant le port entrant et un port sortant différent, car une ligne d'image arrivant sur le port entrant est envoyée à un seul des ports sortants.
Les informations de la section <spec> permettent d'évaluer les ressources nécessaires à la tâche, en termes de capacité mémoire et de nombre de cycles de processeur. Lorsque le programme 20 est exécuté, l'ensemble de la section <instance> ci-dessus est écrit à l'exécution d'une itération de la boucle « for » du sous-graphe « LinePass », 5 grâce aux fonctions de suivi insérées par l'analyse syntaxique. Parmi ces fonctions de suivi, on peut citer : Une fonction, disons SigmaCprintVariable, qui évalue les paramètres, écrit la section <parameters> du fichier de graphe 24 (ci-dessus), et écrit ces informations également dans un fichier de données d'agent 26 correspondant. Elle remplace les déclarations de 10 variables et de constantes locales à l'agent. Ces informations permettent d'écrire des nouvelles définitions des variables et constantes propres à chaque instance. Les valeurs d'initialisation associées à ces définitions proviennent de l'exécution du programme intermédiaire 20, le cas échéant dans une machine virtuelle reflétant la plateforme cible. Ceci permet de garantir que la représentation des valeurs d'initialisation soit conforme 15 à celle utilisée par la plateforme cible, par exemple l'inversion des bits de poids forts et faibles (« endianness »). Une fonction, disons SigmaC allocate, crée une nouvelle instance d'agent ou de sous-graphe dans le fichier graphe par l'insertion d'une balise <instance>. La valeur unique de l'attribut « id » est fournie par un compteur global à l'application. Elle remplace les 20 déclarations du type « agent X = new XX() ». Une fonction, disons SigmaC addPort, crée un port dans le fichier de graphe par l'insertion d'une balise <port>. La valeur unique de l'attribut « id » est fournie par un compteur global à l'application. Elle remplace les déclarations « in » et « out » de la section « interface » de l'agent. 25 Une fonction, disons SigmaC connect, crée un lien dans le fichier de graphe entre deux ports précédemment déclarés, par l'écriture d'une section <connection>. Elle remplace les déclarations « connect » de l'agent. Un lien correspond à un tampon mémoire dans lequel les instances d'agent écrivent et lisent pour échanger les données. Ainsi, lorsqu'un port périphérique d'un sous-graphe 30 se trouve dans une connexion entre deux agents, on ne crée pas deux liens, mais un seul reliant les deux agents de part et d'autre de la frontière du sous-graphe. Un compteur global à l'application définit l'identifiant unique du lien, l'attribut « linkid » des balises <to> et <from>. Le nombre de liens entre également en compte dans la détermination des ressources mémoire requises par la tâche. Une fonction, disons SigmaC Transition, crée des transitions sous la balise <spec> dans le fichier de graphe selon le contenu de la section « spec » de l'agent. On a préféré concevoir cette fonction pour écrire dans le fichier de graphe des informations directement exploitables par l'étape d'affectation de ressources 28. Selon une alternative, cette fonction peut n'écrire que les paramètres évalués des déclarations « spec » du code source d'origine. L'opération d'affectation de ressources 28 se charge alors de calculer les ressources nécessaires.
Bien que la présente description soit basée sur des exemples de code source écrits en SigmaC, les principes décrits ici s'appliquent à tout langage de description de processus flot de données, par exemple Streamlt.
ANNEXES (1) Tâche de filtrage d'une ligne (L) agent LineFilter(int width) interface in<int> line; out<int> outputl, output2; spec {{line[width]; output1[width]; output2[width]}}; shared const int g1[11] = { -1, -6, -17, -17, 18, 46, 18, -17, -17, -6, -1}, g2[11] = {0, 1, 5, 17, 36, 46, 36, 17, 5, 1, 0}; void start() exchange (line a[width], outputl b[width], output2 c[width]) int i,j; for(i=0;i<width;i++) b[i] = 0; c[i] = 0; if(i<width-11) for(j=0;j<11;j++) b[i] += g1[j] * a[i+j]; c[i] += g2[j] * a[i+j]; (2) Sous-graphe (LP) subgraph LinePass(int width,int height) 1 interface 1 in<int> imag; out<int> outputl, output2; spec {{imag[width*height]; outputl[width*height]; output2[width*height]}}; map 1 int i; agent S = new split<int>(height, width); agent J1 = new join<int>(height, width); agent J2 = new join<int>(height, width); for(i=0;i<height;i++) 1 agent L = new LineFilter(width); connect(S.output[i], L.line); connect(L.outputl, J1.input[i]); connect(L.output2, J2.input[i]); 1 connect(imag, S.input); connect(J1.output, outputl); connect(J2.output, output2); (3) Graphe racine #define WIDTH 8 #define HEIGHT 8 #define ADDRIN Oxdeadbeef #define ADDROUT Oxdeadbeef agent root { map { agent R = new LinearReader<int>(ADDRIN, WIDTH*HEIGHT); agent W = new LinearWriter<int>(ADDROUT, WIDTH, HEIGHT); agent LP = new LinePass(WIDTH, HEIGHT); agent CP = new ColumnPass(WIDTH, HEIGHT); connect(R.output, LP.imag); connect(LP.outputl, CP.inputl); connect(LP.output2, CP.input2); connect(CP.laplacian, W.input); (4) Extrait du fichier de graphe (24) <instance id="8" name="LineFiltern> <parameters> <parameter paramtype="0" type="char" name="width"> \x08\x00\x00\x00 </parameter> <parameter paramtype="1" type="char" name="q1"> \xff\xff\xff\xff\xfa\xff\xff\xff\xef\xff\xff\xff\xef\xff\xff\xff\x12\x00\x 00\x00\ x2e\x00\x00\x00\x12\x00\x00\x00\xef\xff\xff\xff\xef\xff\xff\xff\xfa\xff\xf f\xff\x ff\xff\xff\xff </parameter> <parameter paramtype="1" type="char" name="q2"> \x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x11\x00\x00\x00\x24\x00\x 00\x00\ x2e\x00\x00\x00\x24\x00\x00\x00\x11\x00\x00\x00\x05\x00\x00\x00\x01\x00\x0 0\x00\x 00\x00\x00\x00 </parameter> </parameters> <interface> <ports> <port id="33" name="line" direction="IN" incut="IN"> <connection> <from portid="7" linkid="0"/> <to portid="-1" linkid="-1"/> </connection> </port> <port id="34" name="cutput1" direction="OUT" incut="OUT"> <connection> <from portid="-1" linkid="-1"/> <to portid="15" linkid="1"/> </connection> </port> <port id="35" name="cutput2" direction="OUT" incut="OUT"> <connection> <from portid="-1" linkid="-1"/> <to portid="24" linkid="2"/> </connection> </port> </ports> <spec nr="1"> <transition num="0" type="0"> <amount portid="33" qmin="8" qmax="8"/> <amount portid="34" qmin="8" qmax="8"/> <amount portid="35" qmin="8" qmax="8"/> </transition> </spec> </interface> </instance>

Claims (5)

  1. REVENDICATIONS1. Procédé de compilation d'un programme destiné à être exécuté sur une plateforme multiprocesseurs, comprenant les étapes suivantes : - prévoir un code source d'origine dans un langage haut-niveau de description d'un traitement flot de données, le langage disposant de déclarations permettant d'instancier et de connecter des tâches de manière paramétrique ; - produire un programme intermédiaire (20) à partir des déclarations d'instanciation et de connexion (12) du code source d'origine ; - exécuter le programme intermédiaire, d'où il résulte que toutes les instances des tâches sont identifiées et leurs paramètres de connexion sont évalués ; et - utiliser les valeurs des paramètres produites par l'exécution du programme intermédiaire pour construire un graphe (24) reliant les tâches entre elles.
  2. 2. Procédé selon la revendication 1, comprenant les étapes suivantes pour produire le programme intermédiaire : - effectuer une analyse syntaxique (10) du code source d'origine pour produire un code source d'instanciation (12) dans lequel les déclarations d'instanciation et de connexion du code source d'origine sont remplacées par des fonctions de suivi conçues pour, à l'exécution, évaluer les paramètres et écrire leurs valeurs sous forme de liste d'interconnexions dans un fichier de graphe (24) ; et - compiler (18) le code source d'instanciation en le liant à une bibliothèque (16) définissant les fonctions de suivi pour produire le programme intermédiaire.
  3. 3. Procédé selon la revendication 2, dans lequel le code source d'origine dispose de déclarations de quantification définissant des paramètres de quantification représentatifs des quantités de données transitant par les connexions de chaque tâche, procédé comprenant les étapes suivantes : - dans le code source d'instanciation, remplacer les déclarations de quantification du code source d'origine par des fonctions de suivi conçues pour, à l'exécution, évaluer les paramètres de quantification et écrire leurs valeurs dans le fichier de graphe ; et- déterminer (28) les ressources requises par chaque tâche à partir des paramètres de quantification du fichier de graphe.
  4. 4. Procédé selon la revendication 3, comprenant les étapes suivantes : - dans l'étape d'analyse syntaxique (10) - produire en outre un code source de traitement (14) correspondant aux opérations effectuées par les tâches définies dans le code source d'origine, dans le code source d'instanciation (12), remplacer des déclarations de constantes et de variables du code source d'origine par des fonctions de suivi conçues pour, à l'exécution, évaluer ces constantes et variables et écrire leurs valeurs dans des fichiers de données (26) associés aux tâches ; - analyser (28) le fichier de graphe (24) pour produire un plan d'affectation (30) définissant un mappage des tâches sur des ressources ; et - compiler le code source de traitement en le combinant au plan d'affectation et aux fichiers de données pour produire un programme exécutable sur la plateforme multiprocesseurs.
  5. 5. Procédé selon la revendication 2, dans lequel l'étape de compilation est une étape de compilation croisée pour produire un programme intermédiaire exécutable sur la plateforme multiprocesseurs, et l'étape d'exécution est une étape d'exécution sur une machine virtuelle représentant la plateforme multiprocesseurs.
FR1259547A 2012-10-08 2012-10-08 Procede de generation d'un graphe a partir d'un code source ecrit en un langage de description de processus flot de donnees Pending FR2996654A1 (fr)

Priority Applications (1)

Application Number Priority Date Filing Date Title
FR1259547A FR2996654A1 (fr) 2012-10-08 2012-10-08 Procede de generation d'un graphe a partir d'un code source ecrit en un langage de description de processus flot de donnees

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
FR1259547A FR2996654A1 (fr) 2012-10-08 2012-10-08 Procede de generation d'un graphe a partir d'un code source ecrit en un langage de description de processus flot de donnees

Publications (1)

Publication Number Publication Date
FR2996654A1 true FR2996654A1 (fr) 2014-04-11

Family

ID=48050821

Family Applications (1)

Application Number Title Priority Date Filing Date
FR1259547A Pending FR2996654A1 (fr) 2012-10-08 2012-10-08 Procede de generation d'un graphe a partir d'un code source ecrit en un langage de description de processus flot de donnees

Country Status (1)

Country Link
FR (1) FR2996654A1 (fr)

Citations (2)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US20060136878A1 (en) * 2004-12-17 2006-06-22 Arun Raghunath Method and apparatus for enabling compiler and run-time optimizations for data flow applications in multi-core architectures
US20100293535A1 (en) * 2009-05-14 2010-11-18 International Business Machines Corporation Profile-Driven Data Stream Processing

Patent Citations (2)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US20060136878A1 (en) * 2004-12-17 2006-06-22 Arun Raghunath Method and apparatus for enabling compiler and run-time optimizations for data flow applications in multi-core architectures
US20100293535A1 (en) * 2009-05-14 2010-11-18 International Business Machines Corporation Profile-Driven Data Stream Processing

Non-Patent Citations (3)

* Cited by examiner, † Cited by third party
Title
BUGRA GEDIK ET AL: "A code generation approach to optimizing high-performance distributed data stream processing", PROCEEDING OF THE 18TH ACM CONFERENCE ON INFORMATION AND KNOWLEDGE MANAGEMENT, CIKM '09, January 2009 (2009-01-01), New York, New York, USA, pages 847 - 856, XP055072359, ISBN: 978-1-60-558512-3, DOI: 10.1145/1645953.1646061 *
THIERRY GOUBIER ET AL: "Sigma C: A Programming Model and Language for Embedded Manycores", January 2011, ALGORITHMS AND ARCHITECTURES FOR PARALLEL PROCESSING, SPRINGER BERLIN HEIDELBERG, BERLIN, HEIDELBERG, PAGE(S) 385 - 394, ISBN: 978-3-642-24649-4, XP019168278 *
ZBIGNIEW CHAMSKI ET AL: "The SANDRA project: cooperative architecture/compiler technology for embedded real-time streaming applications", RAPPORT DE RECHERCHE INRIA N 4773, MARS 2003, March 2003 (2003-03-01), pages 1 - 16, XP055006885, Retrieved from the Internet <URL:http://hal.inria.fr/docs/00/07/18/13/PDF/RR-4773.pdf> [retrieved on 20110912] *

Similar Documents

Publication Publication Date Title
Kim et al. Serverless data analytics with flint
EP1805611B1 (fr) Procede d&#39;ordonnancement de traitement de tâches et dispositif pour mettre en oeuvre le procede
Varga et al. An overview of the OMNeT++ simulation environment
US20120144376A1 (en) Embedded system development
US11188348B2 (en) Hybrid computing device selection analysis
Wang et al. Big data applications using workflows for data parallel computing
Veen et al. Easing multiscale model design and coupling with MUSCLE 3
Han et al. A generic parallel processing model for facilitating data mining and integration
Welivita et al. Managing complex workflows in bioinformatics: an interactive toolkit with gpu acceleration
Bonfietti et al. Throughput constraint for synchronous data flow graphs
Suriano et al. DAMHSE: Programming heterogeneous MPSoCs with hardware acceleration using dataflow-based design space exploration and automated rapid prototyping
Ajwani et al. Generating synthetic task graphs for simulating stream computing systems
Weder et al. Analysis and Rewrite of Quantum Workflows: Improving the Execution of Hybrid Quantum Algorithms.
Aldegheri et al. Enhancing performance of computer vision applications on low-power embedded systems through heterogeneous parallel programming
Bonfietti et al. Maximum-throughput mapping of SDFGs on multi-core SoC platforms
FR2914525A1 (fr) Procede de simulation transactionnelle d&#39;un modele generique de noeud de communication, produit programme d&#39;ordinateur et moyen de stockage correspondants
FR2996654A1 (fr) Procede de generation d&#39;un graphe a partir d&#39;un code source ecrit en un langage de description de processus flot de donnees
da Rosa Righi et al. Designing Cloud-Friendly HPC Applications
Leppänen et al. Cross-vendor programming abstraction for diverse heterogeneous platforms
Rehfeld et al. Estimating latency and concurrency of asynchronous real-time interactive systems using model checking
Janjic et al. Using erlang skeletons to parallelise realistic medium-scale parallel programs
Roussel Parallelization of iterative methods to solve sparse linear systems using task based runtime systems on multi and many-core architectures: application to Multi-Level Domain Decomposition methods
EP1082656A1 (fr) Procede generique d&#39;aide au placement d&#39;applications de traitement de signal sur calculateurs paralleles
Ruggiero et al. Cellflow: A parallel application development environment with run-time support for the Cell BE processor
EP3874368B1 (fr) Executer des portions de code sur des ressources d´execution

Legal Events

Date Code Title Description
PLFP Fee payment

Year of fee payment: 4

PLFP Fee payment

Year of fee payment: 5

PLFP Fee payment

Year of fee payment: 6