220 lines
14 KiB
TeX
220 lines
14 KiB
TeX
\chapterx*{Conclusion}
|
|
|
|
%{{{ introduction "
|
|
La programmation parallèle induit de nombreuses difficultés par rapport à la programmation
|
|
séquentielle classique.
|
|
En premier lieu, il faut identifier les portions de code source qui peuvent être exécutées en
|
|
parallèle sans invalider leur comportement, c'est-à-dire en conservant le même déroulement lors de
|
|
leur exécution jusqu'à l'obtention du même résultat.
|
|
Lorsque ces portions de code sont identifiées, la mise en place d'une stratégie de parallélisation
|
|
demande un nouvel effort.
|
|
De plus, une évolution du programme, même mineure, peut nécessiter une maintenance coûteuse
|
|
puisqu'il faut évaluer à nouveau s'il est possible de l'exécuter en parallèle et mettre à jour le
|
|
code en conséquence.
|
|
Un programme efficacement parallélisé, s'il utilise par exemple des nombres pseudo-aléatoires, peut
|
|
ne plus être répétable d'une exécution à l'autre.
|
|
D'autre part, en matière de vérification, il est précieux de pouvoir tester les résultats d'un
|
|
programme parallèle par rapport à son équivalent exécuté séquentiellement.
|
|
Cette thèse présente des outils conçus pour répondre à différents problèmes introduits par la
|
|
programmation parallèle, dont la répétabilité de codes stochastiques faisant usage de nombres
|
|
pseudo-aléatoires.
|
|
|
|
Afin de pouvoir expliquer la théorie et le fonctionnement des propositions faites dans cette thèse,
|
|
celle-ci explique les rudiments de la programmation parallèle ainsi que les différentes abstractions
|
|
et automatisations qui existent.
|
|
Deux chapitres sont ensuite dédiés à la généricité, notamment en C++, et à la métaprogrammation,
|
|
notamment celle dite template du C++.
|
|
Ils détaillent en particulier les fonctionnalités permises par ces paradigmes et qui servent ensuite
|
|
dans l'implémentation des bibliothèques actives que sont les outils proposés.
|
|
%}}}
|
|
|
|
%{{{ pfor "
|
|
La première bibliothèque, présentée dans \acref{ch:pfor}, propose une interface pour automatiser la
|
|
parallélisation d'instructions au sein d'une boucle.
|
|
Celle-ci emploie les patrons d'expressions pour acquérir une représentation des instructions de la
|
|
boucle sous la forme d'un \gls{ASA}.
|
|
Cet \gls{ASA} détaille jusqu'aux opérations sur les indices d'accès aux tableaux -- appelées
|
|
fonctions d'indice -- dont les opérandes sont alors connus dès la compilation.
|
|
Grâce à cela, la bibliothèque vérifie si tous les accès aux données permettent une exécution
|
|
parallèle, et ce selon les caractéristiques des fonctions d'indice :
|
|
\begin{enumerate}
|
|
\item si toutes sont affines, la bibliothèque répond, avec une spécificité et une sensibilité
|
|
parfaite, en calculant l'existence de solutions à un ensemble d'équations diophantiennes ;
|
|
\item sinon, si toutes sont injectives, elle répond, avec une sensibilité imparfaite, en utilisant
|
|
un test simplifié ;
|
|
\item sinon la bibliothèque suppose par défaut que les instructions ne peuvent être parallélisées.
|
|
\end{enumerate}
|
|
Cette séquence de tests garantit une spécificité parfaite et empêche donc la parallélisation d'un
|
|
code qui ne peut l'être sainement.
|
|
|
|
Ces tests sont appliqués à des groupes d'instructions qui sont formés de sorte que deux instructions
|
|
quelconques venant de groupes différents sont indépendantes quant aux données qu'elles utilisent.
|
|
De cette manière, les instructions qui ne doivent être exécutées en parallèle peuvent être
|
|
maintenues séparées de celles pouvant être exécutées en parallèle si elles sont indépendantes.
|
|
Ainsi, la non-parallélisabilité de ces premières instructions ne gêne pas la parallélisabilité des
|
|
dernières, alors qu'une analyse sur l'ensemble complet aurait logiquement rapporté une réponse
|
|
négative quant à la possibilité d'exécuter les instructions en parallèle.
|
|
|
|
À partir des fonctions d'indices seules, la bibliothèque détermine automatiquement si celles-ci sont
|
|
affines.
|
|
Quant aux autres propriétés telles que l'injectivité, elles peuvent être indiquées voire déduites.
|
|
C'est par exemple le cas de l'injectivité si la fonction d'indice est strictement croissante ou
|
|
strictement décroissante.
|
|
|
|
Une fois que les ensembles d'instructions parallélisables et non parallélisables sont ainsi définis,
|
|
la bibliothèque reproduit le code représenté par l'\gls{ASA} en intégrant ce qui est nécessaire pour
|
|
que soient exécutées en parallèles les instructions concernées.
|
|
Pour cela, il est possible d'utiliser différents générateurs.
|
|
La bibliothèque propose une parallélisation avec OpenMP ou en utilisant des \en{threads} \gls{POSIX}
|
|
ou encore une génération des instructions en utilisant la technique du déroulement de boucle.
|
|
|
|
La bibliothèque a été testée en comparant ses performances avec des programmes équivalents écrits
|
|
dans les meilleures règles de l'art, de façon \og artisanale \fg (et donc sans l'utiliser).
|
|
Les temps de compilation, bien qu'il y ait certainement encore des améliorations possibles sur cet
|
|
aspect, sont raisonnables et permettent une utilisation au sein de projets.
|
|
Les temps d'exécution montrent que l'abstraction apportée par la bibliothèque n'implique que des
|
|
surcoûts minimes.
|
|
%}}}
|
|
|
|
%{{{ alsk "
|
|
La seconde proposition faite dans cette thèse est une autre bibliothèque active ayant pour objectif
|
|
la parallélisation assistée par les squelettes algorithmiques.
|
|
Contrairement à la première proposition, les portions du programme qui peuvent être exécutées en
|
|
parallèle sont intrinsèquement liées au squelette algorithmique que définit le développeur.
|
|
|
|
Cette bibliothèque dispose de sa propre manière de concevoir des squelettes algorithmiques.
|
|
Celle-ci repose sur une séparation initiale de deux concepts : la structure et les liens.
|
|
La structure du squelette est une composition d'autres structures et d'os, les éléments structurels
|
|
atomiques introduits dans cette thèse.
|
|
Chaque os correspond à un motif d'exécution, par exemple l'exécution séquentielle de plusieurs
|
|
tâches ou l'exécution parallèle d'une même tâche répétée, suivie d'une autre pour sélectionner le
|
|
meilleur résultat produit.
|
|
Quant aux liens, il s'agit d'une description des transferts de données entre les différentes tâches
|
|
à exécuter.
|
|
Cela se définit en utilisant des paramètres spéciaux, lesquels indiquent à la bibliothèque ce par
|
|
quoi ils doivent être remplacés (un paramètre de la tâche appelante, la valeur de retour d'une
|
|
autre, ...).
|
|
|
|
La structure du squelette permet de savoir quels éléments peuvent être exécutés en parallèle.
|
|
Il est donc par exemple possible de déterminer le nombre de niveaux de parallélisation dont on
|
|
dispose pour un squelette donné.
|
|
Pour cela, une bibliothèque annexe d'outils pour la métaprogrammation template est utilisée.
|
|
Celle-ci comporte des algorithmes pour parcourir des listes et des arbres de types, et un squelette
|
|
algorithmique peut être transformé en arbre (et un arbre en liste si nécessaire).
|
|
|
|
En utilisant, notamment, l'information du nombre de niveaux parallélisables, la bibliothèque permet
|
|
l'optimisation de la répartition des tâches sur les différents \en{threads} selon plusieurs
|
|
politiques d'exécution : \en{thread pool} ; répartition équilibrée ; répartition équilibrée
|
|
n'utilisant que le premier niveau ; ...
|
|
Dans le cas du \en{thread pool}, l'équilibrage de la charge entre les différents \en{threads} est
|
|
automatique et dynamique, au coût d'une synchronisation à effectuer pour l'accès aux tâches à
|
|
exécuter.
|
|
La répartition équilibrée proposée suppose une durée similaire dans l'exécution des différentes
|
|
tâches et les distribue aux \en{threads} de manière à ce que chacun en ait, à une près, le même
|
|
nombre.
|
|
Cette hypothèse semble raisonnable en particulier pour des os répétant une même tâche plusieurs
|
|
fois, os fréquemment utilisés dans l'implémentation de métaheuristiques.
|
|
|
|
Grâce aux connaissances apportées par le choix d'une politique d'exécution et au contrôle permis par
|
|
les liens, cette thèse propose une solution au problème de la perte de répétabilité lors de
|
|
l'exécution parallèle d'un programme utilisant des nombres pseudo-aléatoires.
|
|
Cette solution permet plus généralement le maintien de la répétabilité lors de l'utilisation de
|
|
données qui doivent n'être utilisées que par un unique \en{thread}.
|
|
Ces données doivent donc être associées aux tâches qui partagent le \en{thread} qui les exécute.
|
|
Une solution triviale consiste à fournir à chaque tâche ses propres données.
|
|
Lorsqu'il s'agit de nombres pseudo-aléatoires, cela signifie qu'il faut déterminer une séquence
|
|
indépendante pour chaque tâche, ce qui devient coûteux, entre autres en mémoire, lorsque le nombre
|
|
de tâches augmente et que le statut initial du générateur est conséquent (proche de
|
|
\SI{2.5}{\kibi\octet} par exemple pour un état initial de Mersenne Twister MT19937).
|
|
En tenant compte de la distribution des tâches sur les \en{threads}, et ce pour différentes
|
|
quantités de \en{threads}, on détermine quelles tâches sont toujours exécutées par un \en{thread}
|
|
commun (indépendamment du nombre de \en{threads}) et on leur associe une séquence de nombres
|
|
pseudo-aléatoires commune (état initial partagé).
|
|
Ceci permet de garantir la répétabilité non seulement d'une exécution à l'autre, mais également
|
|
lorsque le nombre de \en{threads} varie.
|
|
Les tâches ayant besoin de nombres pseudo-aléatoires peuvent alors en recevoir un automatiquement au
|
|
moyen d'un paramètre spécial que les liens permettent d'utiliser.
|
|
|
|
Cette bibliothèque a été utilisée pour résoudre des instances de \gls{TSP} par la métaheuristique
|
|
\graspels{}.
|
|
Les temps d'exécution sont comparés à ceux obtenus avec une implémentation manuelle d'un \graspels{}
|
|
et correspondent à des exécutions parallèles et à des exécutions séquentielles (afin de valider que,
|
|
même dans ce cas, la bibliothèque n'induit pas de surcoût).
|
|
Dans tous les cas, les temps obtenus sont analogues.
|
|
%}}}
|
|
|
|
\chapterx*{Limites et perspectives}
|
|
|
|
%{{{ perspectives "
|
|
%{{{ pfor "
|
|
Nous avons bien conscience que notre première proposition, orientée sur l'analyse et la
|
|
parallélisation automatique de boucles, est incomplète dans la mesure où de multiples boucles
|
|
imbriquées ne sont pas détectées.
|
|
Pour le moment, l'utilisation de multiples boucles imbriquées signifie qu'une seule sera traitée
|
|
pour la parallélisation.
|
|
Ce fait n'est pas gênant si l'on considère les architectures matérielles multi-cœurs actuelles.
|
|
La bibliothèque ne propose pas d'outil pour mettre en place une parallélisation automatique sur
|
|
plusieurs niveaux car elle ne permet pas, à ce stade, l'utilisation de l'indice d'un niveau à un
|
|
niveau inférieur.
|
|
C'est une piste de recherche que nous envisageons d'explorer à l'avenir.
|
|
|
|
De plus, il sera intéressant de tester différentes méthodes pour appliquer la parallélisation.
|
|
Notamment l'utilisation d'un \en{thread pool} afin de voir si l'introduction de sections critiques
|
|
induit un coût négligeable par rapport au gain supposé apporté par le fait d'éviter la recréation de
|
|
\en{threads} à chaque nouvelle boucle parallélisée.
|
|
|
|
Au niveau de l'analyse et particulièrement des tests permettant de déterminer la parallélisabilité
|
|
des instructions, l'implémentation du modèle polyédral est également une piste.
|
|
Celle-ci peut notamment être utile au support de multiples boucles imbriquées, mais peut
|
|
éventuellement également servir à augmenter la sensibilité du test pour des boucles à un seul niveau
|
|
lorsque les fonctions d'indice ne sont ni affines ni injectives.
|
|
|
|
Une autre piste d'amélioration consiste en l'application de transformations sur le code source
|
|
traité.
|
|
Actuellement, celui-ci est analysé pour sa parallélisabilité, et s'il ne passe pas le test, il est
|
|
exécuté séquentiellement.
|
|
Il est possible, en modifiant astucieusement les instructions, de conserver le comportement du
|
|
programme en éliminant des dépendances, augmentant donc potentiellement sa parallélisabilité.
|
|
%}}}
|
|
|
|
%{{{ alsk "
|
|
Par rapport à la seconde proposition, axée sur la parallélisation assistée par l'utilisation de
|
|
squelettes algorithmiques, le travail effectué était principalement centré sur l'abstraction
|
|
apportée par la bibliothèque de squelettes algorithmiques, au détriment de l'optimisation des
|
|
différentes politiques d'exécution fournies.
|
|
Ces politiques d'exécution ne sont donc pas implémentées de manière optimale.
|
|
Une personne dont la parallélisation est le domaine d'expertise pourrait améliorer cela.
|
|
En outre, il serait très intéressant de tester la piste évoquée dans
|
|
\acref{subsubsec:alsk/exec/impl/static}, à savoir la préparation, dès la compilation, de la séquence
|
|
complète des tâches qu'exécutera chaque \en{thread} afin d'éviter un défaut actuel de la politique
|
|
d'exécution répartissant les tâches de manière équilibrée : les \en{threads} des niveaux parallèles,
|
|
à l'exception du tout premier, sont créés de multiples fois.
|
|
|
|
Une autre idée est de permettre l'ajustement du poids des tâches à exécuter afin de ne plus supposer
|
|
un temps d'exécution homogène.
|
|
En utilisant ces poids, une distribution équilibrée des tâches sur les différents \en{threads} peut,
|
|
peut-être, être aussi efficace en termes d'équilibrage de charge que ce que peut accomplir
|
|
dynamiquement un \en{thread pool}.
|
|
De plus, une exécution, partielle ou sur des données réduites, du programme permettrait
|
|
éventuellement la génération automatique de ces poids.
|
|
|
|
Les os proposés au sein de cette thèse répondent aux besoins levés par l'applicatif en \gls{RO} que
|
|
nous avons utilisé.
|
|
Néanmoins, des motifs tels que le \en{pipeline}, sont manquants pour une utilisation réellement
|
|
générale.
|
|
Certains de ces nouveaux os pourraient nécessiter l'ajout de primitives au sein des exécuteurs.
|
|
|
|
Le système de liens apporte des avantages intéressants, mais également une syntaxe plus lourde pour
|
|
le développeur qui, en utilisant d'autres bibliothèques de squelettes algorithmiques, pourrait
|
|
préférer une valeur par défaut.
|
|
L'\gls{EDSL} introduit en partie cette possibilité de valeur par défaut et même de déduction de
|
|
liens, mais cela manque aux couches plus basses.
|
|
|
|
Ce système de liens permet par ailleurs de connaître exactement quelles tâches nécessitent
|
|
l'utilisation, par exemple, de nombres pseudo-aléatoires.
|
|
En utilisant cette information, il est possible de réduire encore le nombre de \gls{PRNG} devant
|
|
être créés pour garantir la répétabilité du programme.
|
|
%}}}
|
|
%}}}
|
|
|