161 lines
9.8 KiB
TeX
161 lines
9.8 KiB
TeX
\section{Travaux connexes}
|
|
|
|
Les squelettes algorithmiques, introduits par \autocite{ref:cole1989}, proposent une solution de
|
|
parallélisation assistée.
|
|
L'objectif des squelettes est de masquer l'implémentation parallèle d'un algorithme en fournissant
|
|
une interface permettant au développeur de choisir parmi des patrons de conception celui qui
|
|
correspond à son besoin.
|
|
Un avantage des squelettes par rapport à des interfaces plus simples, comme un ensemble de fonctions
|
|
correspondant directement aux différents patrons, réside dans leur capacité à être
|
|
composés~\autocite{ref:benoit2005}.
|
|
|
|
\autocite{ref:cole1989} les définit comme des fonctions d'ordre supérieur, c'est-à-dire des
|
|
fonctions capables d'utiliser des fonctions comme paramètres ou retournant d'autres fonctions.
|
|
L'exemple de la fonction d'ordre supérieur \og map \fg{} y est donné ainsi :
|
|
\begin{align*}
|
|
map : (a \to b) \to ([a] \to [b]).
|
|
\end{align*}
|
|
|
|
Il s'agit d'une fonction acceptant une autre fonction en paramètre et retournant une nouvelle
|
|
fonction.
|
|
Cette dernière agit sur un vecteur d'éléments du type de l'unique paramètre de la fonction unaire en
|
|
entrée ($a$) et retournant un vecteur d'éléments du même type que ce qui est retourné par la
|
|
fonction en entrée ($b$).
|
|
Pour produire le vecteur de type $[b]$, la fonction en entrée est appliquée sur chaque élément du
|
|
vecteur de type $[a]$.
|
|
Des fonctions d'ordre supérieur ont été présentées dans \acref{ch:mp},
|
|
\cref{subsubsec:mp/mpt/et/curry}.
|
|
|
|
De nombreux travaux ont proposé des modèles et implémentations de squelettes algorithmiques dans
|
|
différents langages de programmation depuis l'introduction de ce concept.
|
|
Ceux-ci proposent généralement des patrons classiques~\autocite{ref:campbell1996} : parmi ceux
|
|
orientés vers la parallélisation de données, on trouve \en{map}, \en{zip}, \en{reduce} ; et parmi
|
|
ceux travaillant sur la parallélisation de tâches, il existe \en{farm}, \en{pipeline}, \en{divide
|
|
and conquer}~\autocite{ref:kuchen2002a}.
|
|
|
|
Cette section illustre certains patrons.
|
|
Si l'on considère, dans un premier temps, le patron \en{fork-join} qui consiste simplement en
|
|
l'exécution de deux tâches $T_0$ et $T_1$ en parallèle, on peut utiliser la représentation faite
|
|
dans \acref{fig:alsk/relwork/forkjoin}.
|
|
Dans celle-ci, les tâches exécutées sont représentées par des blocs et nommées $T_i$ où $i$ est un
|
|
entier en l'absence duquel toutes les tâches $T$ effectuent la même chose.
|
|
Les zones englobant plusieurs tâches indiquent une exécution parallèle de celles-ci.
|
|
|
|
\begin{figure}
|
|
\inputfig{relwork/forkjoin}
|
|
{Patron d'exécution parallèle \en{fork-join}}
|
|
\end{figure}
|
|
|
|
Le patron \en{map} a déjà été abordé dans l'introduction de ce chapitre et correspond à l'exécution
|
|
de $n$ instances d'une tâche $T$ sur $n$ données, comme illustré par \acref{fig:alsk/relwork/map}.
|
|
En remplaçant l'ensemble défini de données par un flux, un \en{map} devient un \en{farm}.
|
|
|
|
\begin{figure}[!hb]
|
|
\inputfig{relwork/map}
|
|
{Patron d'exécution parallèle \en{map}}
|
|
\end{figure}
|
|
|
|
À nouveau comparable à \en{map}, la fonction d'ordre supérieure \en{zip} peut être définie ainsi :
|
|
\begin{align*}
|
|
zip : ((a, b) \to c) \to ([a], [b] \to [c]).
|
|
\end{align*}
|
|
|
|
Cela correspond donc à l'application d'une fonction d'arité \num{2} sur chaque élément de deux
|
|
vecteurs de données de même cardinalité ($\vert [a] \vert = \vert [b] \vert$) pour produire un
|
|
unique vecteur.
|
|
Il est possible de généraliser le principe à des arités quelconques.
|
|
|
|
L'application d'une fonction de projection (\texttt{min}, \texttt{sum}, ...) sur un ensemble de
|
|
données pour le réduire à une seule est appelée réduction, et le patron associé \en{reduce} ou plus
|
|
rarement \en{fold}.
|
|
Il est très souvent appliqué après un \en{map}, ce qui correspond alors au patron
|
|
\en{map-reduce}.% ref? illustré par \acref{fig:alsk/relwork/map}.
|
|
|
|
Le \en{pipeline} permet l'exécution parallèle de plusieurs tâches $T_0$, $T_1$, ... $T_n$ par
|
|
lesquelles les données en entrée passent successivement (\cref{fig:alsk/relwork/pipeline}).
|
|
Le principe de \og diviser pour régner \fg, en anglais \en{divide and conquer}, est de répartir le
|
|
travail initial entre les travailleurs par séparation successives de l'ensemble de données en
|
|
entrée.
|
|
Après cette étape, les résultats sont fusionnés successivement jusqu'à obtenir un résultat final.
|
|
Il est possible de diviser les données jusqu'à atteindre un niveau atomique (sans fixer le nombre de
|
|
travailleurs) ou de définir la profondeur maximale (limitant le nombre de travailleurs).
|
|
|
|
\begin{figure}
|
|
\inputfig{relwork/pipeline}
|
|
{Patron d'exécution parallèle \en{pipeline}}
|
|
\end{figure}
|
|
|
|
Les structures de contrôle classiques (branches conditionnelles, boucles, ...) peuvent également
|
|
être proposées comme squelette.
|
|
Il existe d'autres patrons, mais ceux qui ont été présentés ci-dessus et les combinaisons
|
|
concevables entre ceux-ci sont plus que suffisants pour le propos de cette thèse.
|
|
|
|
La bibliothèque C++ \gls{TBB} propose des fonctions correspondant à divers patrons parallèles tels
|
|
que \cppinline{parallel_for}, \cppinline{parallel_reduce}, \cppinline{parallel_pipeline}, ...
|
|
Ces fonctions sont conçues de manière similaire à la bibliothèque standard du langage (génériques
|
|
par template, utilisation d'itérateurs).
|
|
|
|
L'exécution est parallélisée et équilibrée dynamiquement, et \gls{TBB} détecte l'utilisation
|
|
imbriquée de plusieurs de ses fonctions.
|
|
Cette fonctionnalité permet de distinguer cette bibliothèque d'un simple ensemble de fonctions et la
|
|
rapproche des squelettes algorithmiques.
|
|
|
|
De manière similaire, le langage de programmation Cilk++ implémente des mots-clés pour faciliter
|
|
l'exécution parallèle ainsi qu'une structure de contrôle utilisant la syntaxe de la boucle
|
|
\cppinline{for} du C++, \cppinline{cilk_for}.
|
|
Ainsi, bien que cela ne soit pas un outil dont la conception repose spécifiquement sur les
|
|
squelettes algorithmiques (à l'instar de \gls{TBB}), les éléments proposés s'en rapprochent.
|
|
|
|
En revanche, \autocite{ref:rieger2019} propose un langage, Musket, fondamentalement basé sur le
|
|
concept de squelettes algorithmiques.
|
|
Celui-ci est un \gls{DSL}, dont la syntaxe est volontairement proche de celle du C++, l'objectif
|
|
étant de permettre la génération de code C++ parallèle.
|
|
Des types de données spécifiques, permettant la parallélisation, sont fournis (des types primitifs
|
|
jusqu'aux matrices).
|
|
Les motifs de parallélisation proposés sont \en{map}, \en{reduce}, \en{zip} et \en{shift partition}.
|
|
|
|
Les auteurs de Musket ont détaillé les raisons pour lesquelles ils ont choisi de développer un
|
|
langage plutôt qu'une bibliothèque~\autocite{ref:wrede2020}.
|
|
Celles-ci entraînent un surcoût en temps d'exécution par rapport à une implémentation manuelle ou
|
|
une génération de code comme peut le faire le compilateur d'un langage.
|
|
D'autre part, les bibliothèques étant contraintes à respecter la syntaxe du langage hôte, il est
|
|
plus facile de proposer une meilleure lisibilité du code au sein d'un \gls{DSL}.
|
|
Enfin, cette dernière contrainte apporte un autre argument au choix d'un langage dédié : cela permet
|
|
davantage de flexibilité dans les transformations appliquées sur le code pour produire un programme
|
|
parallèle.
|
|
|
|
De nombreuses bibliothèques de squelettes algorithmiques
|
|
ont été proposées~\autocite{ref:aldinucci2009,ref:ciechanowicz2009,ref:leyton2010,ref:legaux2013,ref:ernstsson2018,ref:philippe2019}.
|
|
\autocite{ref:striegnitz2000} a montré que le langage C++ permettait probablement l'implémentation
|
|
de bibliothèques de squelettes algorithmiques.
|
|
Plus tard, \autocite{ref:falcou2006a} l'a prouvé et a également montré que l'utilisation des
|
|
templates permettait d'obtenir un moindre surcoût en temps d'exécution.
|
|
La différence notable entre une bibliothèque \og classique \fg{} et ce que permettent les templates
|
|
en C++ est la possibilité de réellement agir durant la compilation, les rendant \og actives
|
|
\fg~\autocite{ref:veldhuizen1998a}.
|
|
Enfin, il est possible de proposer un \gls{DSL} au sein de certains langages existants, comme c'est
|
|
le cas du C++ : on parle alors d'un \gls{EDSL}~\autocite{ref:saidani2009}.
|
|
Cela permet de mitiger la scission entre langage et bibliothèque en termes de performances et de
|
|
flexibilité, au moins dans le cadre du C++.
|
|
|
|
Les travaux effectués durant cette thèse sur les squelettes algorithmiques ont ainsi été orientés
|
|
vers le C++, et plus spécifiquement vers l'implémentation de bibliothèques faisant usage de la
|
|
métaprogrammation template de ce langage.
|
|
Les inconvénients des bibliothèques par rapport à la création d'un langage ou même par rapport à
|
|
l'implémentation d'une extension pour un compilateur sont amoindris par l'utilisation de la
|
|
métaprogrammation.
|
|
En revanche, une bibliothèque apporte des avantages que nous avons jugé importants.
|
|
Premièrement, elles s'inscrivent dans un cadre qui peut déjà être connu par le développeur, et dans
|
|
le cas du langage C++, qui est très vastement utilisé, c'est particulièrement le cas.
|
|
L'implémentation d'un nouveau langage nécessite également la mise en place des nombreuses
|
|
optimisations déjà présentes et à venir sur les compilateurs de langages existants, alors qu'une
|
|
bibliothèque profitera de celles-ci automatiquement.
|
|
Certes, un nouveau langage peut, plutôt que d'être compilé directement vers de l'assembleur, générer
|
|
du code dans un autre langage bénéficiant de ces optimisations~\autocite{ref:rieger2019}, cependant,
|
|
cela requiert une maintenance parallèle des deux langages.
|
|
Il existe également le cas des extensions pour un compilateur, mais celles-ci doivent alors être
|
|
implémentées pour chaque compilateur, ou bien imposer aux utilisateurs de n'utiliser qu'un
|
|
sous-ensemble des compilateurs disponibles.
|
|
Une bibliothèque dont l'implémentation ne repose que sur le standard du langage ne crée aucune de
|
|
ces contraintes.
|