4.2 Parall´elisation des noyaux
4.2.3 Consistance des donn´ees d’incidence
A ce point nous disposons de moyens pour extraire le parall´elisme amorphe inh´erent `` a chaque noyau. En fait nous n’avons g´er´e que les conflits de tˆaches relatives `a laconformit´e de la topologie,
45Uner´eductionest une agr´egation de donn´ees locales aux processus.
c2018.HOBYRAKOTOARIVELO
afin de maximiser le nombre de tˆaches extraites en vue d’alimenter suffisamment les cores. Ainsi il nous reste `a g´erer explicitement la consistance des donn´ees d’incidence lorsqu’elles sont mises `a jour de mani`ere concurrente. Rappelons que la topologie est stock´ee et maintenue dans les listes d’incidences (page58). Maintenant, on vise `a d´efinir une synchronisationlock-freepour la mise `a jour concurrente de ces listes de mani`ere `a minimiser les transferts de donn´ees.
4.2.3.1 Contraintes en lock-free
approches. En fait fournir une strat´egie lock-freeet non coˆuteusepour la mise `a jour des donn´ees d’incidence n’est pas trivial. Le probl`eme est souvent r´esolu de deux mani`eres :
• ´evitement. Le recours `a une structure de donn´ees orient´ee de type carte combinatoire46 per-met d’´eviter ce probl`eme, comme ´enonc´e `a la section 4.2.1.3. En fait les mises `a jour restent locales au sous-ensemble de mailles en cours de modification, et aucune synchronisation n’est n´ecessaire dans ce cas. N´eanmoins elle induit un nombre important d’indirections m´emoire lors des requˆetes de voisinage47: cela impacte directement au scaling des noyaux, notamment pour la simplification (page153). Une autre alternative possible est de prendre en compte les mises
`
a jour du graphe d’incidence au moment de l’extraction des tˆaches. Dans [210] par exemple, freitag contourne le probl`eme grˆace `a une 2-coloration de graphes. N´eanmoins elle est plus coˆuteuse et requiert plus de couleurs que le cas classique : comme la partition obtenue est plus grande, la taille des stables est r´eduite. Ainsi le nombre de tˆaches extraites par it´er´e est r´eduit, tandis que le nombre d’it´er´es n´ecessaire pour converger augmente. En effet le nombre chroma-tiqueχ2,G est plus grand que χ1,G et croˆıt selon le degr´e maximal ∆ deG. Plus pr´ecis´ement, si la triangulation est :
isotropealors on aχ1,G≤χ2,G≤∆ + 5, avec un degr´e max ∆≈6.
anisotropealors on aχ1,G≤χ2,G≤ 32∆ avec ∆≥8 (preuve dans [201]).
• gestion diff´er´ee. Une autre solution consiste `a stocker localement les mises `a jour `a chaque it´er´e, puis de proc´eder `a une r´eduction dans le conteneur partag´e en fin d’it´er´e. Dans [199,167]
par exemple,rokosfournit une alternative lock-free pour la mise `a jour du graphe d’incidence.
A l’it´er´e` t, elle consiste `a reporter la copie des donn´ees topologiques en fin du traitement des tˆaches deU[t], ce qui garantit d’utiliser des donn´ees valides puisque la topologie est fig´ee `a cet instant. Pour cela, il dispose d’une matrice de listes de mise `a joursdef d´ecrite `a (4.1).
updates
commits
t0 t1 t2 ··· tp
t0 def[0][0] def[1][0] def[2][0] · · · def[p][0]
t1 def[0][1] def[1][1] def[2][1] · · · def[p][1]
t2 def[0][2] def[1][2] def[2][2] · · · def[p][2]
... ... ... ... . .. ...
tp def[0][p] def[1][p] def[2][p] · · · def[p][p]
(4.1)
Ici, on distingue deux vagues d’op´erations :
updates: lorsque un thread i doit mettre `a jour le voisinage d’un point, il copie la liste partielledans celle du thread index´e parj =i modp, avecple nombre total de threads.
commits : `a l’issue du traitement de U[t], chaque thread i parcourt le tableau de listes de chaque thread k ∈ [1,p], puis rep`ere la liste def[k][i] qui lui a ´et´e r´eserv´ee. Ensuite il transf`ere chaque liste`∈def[k][i] dans le conteneur associ´e au graphe (P,M,N).
In fine les listes partielles{`i,j}i=1,prelative `a un pointpjsont bien copi´ees par ununique thread: il n’y a donc pas dedata races. L’inconv´enient de cette strat´egie est qu’elle engendre ´enorm´ement de transferts et recopies de donn´ees, ce qui est r´eellement critique dans notre contexte.
46Dans ce cas, la topologie est repr´esent´ee par les relations d’adjacence des demi-arˆetes (next,twin), voir page27.
47boule d’un point, mailles voisines, coquilles d’une arˆete par exemple.
c2018.HOBYRAKOTOARIVELO
116 4.2. Parall´elisation des noyaux
4.2.3.2 Notre synchronisation
principe. Partant de ces constats, nous proposons une mise `a jour synchronis´ee en deux temps.
Rappelons qu’ici, chaque point garde les r´ef´erences des mailles qui lui sont incidentes. Ici, nous distinguons les op´erations d’insertions et de suppressions de r´ef´erences dans la liste d’incidenceincid[p]
de chaque pointp. Pour chaque noyau, l’id´ee est de permettre aux threads de rajouter les r´ef´erences de mani`ere asynchrone dans une vague `a part. Pour cela, les threads incr´ementent de mani`ere atomique le degr´edeg[p] du point qui est stock´e explicitement sous forme d’un tableau. En effet, cela va permettre de d´eterminer les offsets des listes d’incidences de mani`ere asynchrone : chaque thread met `a jour incid[p] et poursuit son chemin. Comme sa liste d’incidence peut contenir des r´ef´erences obsol`etes, le point est ensuite marqu´e comme ´etant `a r´eparer, et cela de mani`ere atomique par le biais d’un flag fix[p]. Enfin quand tous les threads ont termin´e leurs modifications, les listes d’incidence de chaque point marqu´e sont r´epar´ees dans une vague `a part comme illustr´e sur l’exemple de la figure4.12.
1
4 primitives bas-niveau peu coˆuteuses.
r´eduction avecdeg: fetch add
marquage avecfix: compare swap 4 pas de transferts inutiles de donn´ees.
ETAT INITIAL´
Figure 4.12: Mise `a jour synchronis´ee en deux temps du graphe d’incidence.
Notons juste que les listes d’incidence ont une capacit´e fixe, et il se peut qu’un thread ne puisse plus ins´erer ses donn´ees. Apr`es avoir calcul´e son offset, le thread v´erifie si la taille des donn´ees `a ins´erer exc`ede cette capacit´e, auquel cas il r´ealloue la liste d’incidence en doublant sa capacit´e actuelle. Pour
´eviter une r´eallocation multiple (plusieurs threads), nous recourons au patternsingleton impl´ement´e par un double checking (voir algorithme4.3). En pratique, la m´emoire allou´ee au graphe d’incidence est ajust´ee aux param`etres des noyaux (seuil sur les it´er´es, nombre de mailles cr´e´ees etc.) de mani`ere
`a minimiser ces r´eallocations. La routine compl`ete est d´ecrite `a l’algorithme4.3.
efficacit´e. Compar´ee aux alternatives pr´ec´edentes, notre strat´egie pr´esente quelques avantages :
• les primitives atomiques utilis´ees sontpeu coˆuteuses48, et on a peu d’indirectionscontrairement
`a une carte combinatoire.
• elle pr´eserve un degr´e de parall´elisme ´elev´e, car seuls les conflits de conformit´e sont consid´er´ees au moment de l’extraction de tˆaches, contrairement `a l’approche defreitag[210].
• il induit un mouvement minimal de donn´ees contrairement `a l’approche de rokos [199, 167].
En fait les threads mettent directement `a jour les listes d’incidences au moment o`u elles doivent l’ˆetre, au lieu d’en garder une copie locale puis de proc´eder `a une r´eduction des listes partielles au sein du graphe d’incidence.
∗ ∗ ∗
48Ils sont de l’ordre de 15-30 cyclescpusi le compteur est d´ej`a en cacheL1.
c2018.HOBYRAKOTOARIVELO
Algorithme 4.3: Primitives de mise `a jour du graphe d’incidence.
fonctionins´erer(pi, `tid)
atomic compare swap(fix[i],1)a k=atomic fetch add(deg[i], n)b
sin+kexc`ede la capacit´e de incid[i]alors
#critical . double check pattern si pas encore reallou´ealors
doubler la capacit´e de incid[i]c. fin si
fin si
copier`tid dans incid[i][k].
fin
afix: marqueurs des points `a r´eparer.
bdeg: degr´e des points⇔offsets sur incid.
cincid: listes d’incidence des points.
fonction r´eparer(pi, `tid) sifix[i]a alors
pourchaque maille K de incid[i]faire sipi r´ef´erenc´e dans Kalors
ajouter K dans`tid fin
vider incid[i]
r´einitialiser deg[i] =|`tid|b.
trier`tid and ´echanger avec incid[i]c. fin si
fin
afix: marqueurs des points `a r´eparer.
bdeg: degr´e des points⇔offsets sur incid.
cincid: listes d’incidence des points.
4.3 EVALUATION NUM´´ ERIQUE