• Aucun résultat trouvé

Deuxième approche : le recouvrement d'opérations

3.3 Approches

3.3.2 Deuxième approche : le recouvrement d'opérations

Les politiques de remplacement sont considérés comme le principal levier algorithmique d'optimisation des caches, car ils travaillent directement sur ce qui coûte le plus cher dans l'usage d'un cache, à savoir l'accès à la mémoire secondaire. Certes, cet objectif est déjà l'essence même d'un cache, mais l'algorithme MIN montre que le point optimal n'a pas encore été atteint dans la gestion des défauts de cache. Cependant, il s'est très vite avéré que chaque nouvelle amélioration de ces politiques et que chaque apport à l'état de l'art n'amenait que des gains de plus en plus faibles par rapport aux précédents.

De nouvelles approches ont donc été proposées, dont la plus intéressante est le recouvre- ment d'opération. Elle se base sur l'hypothèse que la mémoire secondaire peut-être accédée de manière asynchrone. Le principe est de proter du temps de préparation par la mé- moire secondaire des données à récupérer lors d'un défaut de cache pour eectuer d'autres opérations en parallèle.

Deux directions sont utilisées dans la littérature pour occuper ce temps de recouvrement. La première est  réactive  et n'agit que lorsqu'un défaut de cache intervient. La seconde est  pro-active  et tente de prévoir à l'avance un défaut de cache pour anticiper son traitement. Cette approche est aussi connue sur les termes de pré-chargement4. Ces deux approches proposent donc des réponses diérentes sur le type de tâches qui peuvent être exécutées en parallèle.

3.3.2.2 Recouvrement par ré-ordonnancement

L'approche réactive est très souvent mise-en ÷uvre sur des architectures multi-c÷urs, sur des systèmes supportant les processus légers, ou des architectures matérielles dotées de DMA5. En cas de défaut de cache, l'ordonnanceur système suspend la tâche courante, engage le pré-chargement et passe automatiquement la main à une autre tâche jusque là en attente. Le recouvrement d'exécution des deux tâches permet ainsi un gain de temps global.

Lorsque le recouvrement peut être supporté par des environnements déjà orientés par- allélisme, alors cette approche est un bénéce indéniable sur les performances d'un cache. Malheureusement, cette conguration n'est pas celle des cartes à puce.

3.3.2.3 Pré-chargement sans matériel

Un algorithme de pré-chargement[Smith 1982, Callahan 1991, Grioen 1994] commence d'abord par prédire, selon certains critères, qu'une information (e.g. donnée, instruction) nécessaire dans un futur proche n'est pas présente en cache. L'idée est ensuite de soumettre à l'avance la demande à la mémoire secondaire, laisser le système reprendre là où il en est resté, puis si besoin le bloquer au moment où il a eectivement besoin de l'information, si la mémoire secondaire n'a pas encore terminé sa tâche.

4En anglais, prefetching

5Direct Memory Access, module matériel permettant des échanges de données entre mémoires sans

Pour mettre en application cet algorithme, deux stratégies sont possibles : l'injection d'informations à la compilation, ou la découverte dynamique de ces mêmes informations pendant l'exécution du programme.

Injection à la compilation Lors de la compilation du binaire, des instructions spé- ciales ou un appel à une routine de pré-chargement sont insérées à des endroits permettant d'anticiper de futurs défauts de cache. Notons que pour que ce soit une instruction, il faut bien évidemment qu'elle soit supportée par le processeur s'il s'agit de code natif, ou la VM pour du code interprété, ce qui n'assure plus la portabilité.

Déterminer où un programme peut déclencher un défaut de cache est assez facile à isoler puisqu'il s'agit, pour une très grande majorité, de branchements, conditionnels ou inconditionnels. Ce qui rend ces lieux de défauts de cache potentiels facilement identiables à l'aide du graphe de ot de contrôle.

Déterminer, quelle page de mémoire secondaire devra être pré-chargée devient légère- ment plus complexe. Pour que cette information soit non-équivoque, il faut calculer d'une manière ou d'une autre, des transpositions d'adresses virtuelles fournies au cache en adresses physiques à l'intérieur de celui-ci. [Park 2004] et al. mettent en ÷uvre cette approche dans leurs travaux pour améliorer les performances de leur solution de cache  compilé . Ils utilisent une table de mappage d'adresses virtuelles/physiques construite à la compilation à l'aide d'une approximation de l'algorithme de clustering, connu pour être NP-dur. Ils ne considèrent toutefois que les branchements de type appels de fonction C, pour simplier fortement le problème et pour garder une table de taille raisonnable, et non la liste complète des n÷uds du graphe de ots de contrôle.

Le dernier élément à prendre en compte, est la détermination du meilleur endroit dans le code où placer le pré-chargement. L'algorithme de clustering n'est déjà qu'une approxi- mation ce qui montre que cet élément est non-trivial. Nous appellerons cet endroit dans le code, le point d'insertion.

Ce qui guide le choix du point d'insertion est dans un premier temps, la durée de préparation de données de la part de la mémoire secondaire. Si cette durée est de N cycles CPU, le point d'insertion optimal se situe donc N cycles avant l'exécution de la dernière instruction d'un bloc de base B. Cette optimalité est pratiquement inatteignable car ce point d'insertion optimal se situera majoritairement en dehors du B et donc dans un ou plusieurs n÷uds indéterminés du graphe. Pour rappel, lire une page de Flash NAND dure un peu plus de 2900 cycles, ce qui pousse la profondeur de recherche du point d'insertion dans la graphe à des distances et un nombre exponentiel d'arcs à suivre.

Néanmoins, une version assez simple, consistant à positionner le point d'insertion au niveau de l'instruction de tête d'un bloc de base, pourrait convenir au code interprété. En eet, dans ce type d'exécution, l'interprétation d'une instruction prend beaucoup plus de cycles CPU qu'une instruction native, puisqu'elle consiste en l'exécution d'une routine plus ou moins complexe. Dans nos résultats qui seront présentés par la suite, lire une page de Flash NAND prend le même temps, en moyenne, que l'exécution de blocs de base de 4 à 6 bytecodes. Les points d'insertion en tête de bloc sont alors susamment ables et évite tout pré-calcul.

L'inconvénient majeur de cette approche est son caractère systématique, qui fait que la détermination d'un pré-chargement peut rapidement devenir une surcharge de travail, comparé au nombre réel de pré-chargements déclenchés. En eet, le pré-chargement est avant tout l'évaluation d'une condition, qui ne déclenche donc pas nécessairement de re- nouvellement du cache et donc de recouvrement d'opérations.

Prédiction dynamique Chilimbi et al. présentent dans [Chilimbi 2002] une autre ap- proche destinée à découvrir pendant l'exécution, les mêmes informations que celles produites précédemment par analyse statique lors de la compilation. La technique dynamique utilisée est un prolage des accès mémoires qui fournit des statistiques amenant à identier des  points chauds  , i.e. des données très fréquemment utilisées. Après un certain temps d'exécution, lorsque des points chauds sont identiés, leur système injecte dynamiquement du code machine de pré-chargement à des points d'insertion qu'il juge opportun (non- présentés). Dans son mode de fonctionnement, cette approche est donc une hybridation des approches réactive/pro-active. Dans le sens où elle réagit à un historique pour anticiper l'avenir. Ce qui est intéressant par rapport aux inconvénients de la compilation, c'est que cette approche insère des tests de pré-chargements uniquement des endroits anticipant des accès à une donnée vitale. Donc en enlevant le caractère systématique obligatoire dans l'approche statique.

Cependant, le prolage et la détection des points ajoutent un coût d'exécution sup- plémentaire (overhead) comme toute approche dynamique. Leur contribution est évaluée selon cet aspect et les conclusions sont riches d'enseignements. Il démontre que l'overhead de la partie prolage/analyse est plus que compensé par la qualité des points d'insertion et des pré-chargements déclenchés. Malheureusement, l'absence d'une comparaison avec d'autres approches de pré-chargement, notamment statique, rend leur contribution impos- sible à évaluer dans l'absolu. De plus, celle-ci se base sur des hypothèses de taux de Miss relativement élevés et est donc plutôt une stratégie palliant des caches déjà peu perfor- mants. Enn, l'infrastructure complète utilisée dans ce papier ne peut être utilisée dans une carte à puce et n'est pas reproductible dans ce contexte.

Une autre stratégie un peu plus éloignée encore du contexte carte à puce, connue sous le nom de Runahead Processing (exécution à l'avance) [Mutlu 2003, Mutlu 2005], a été implémentée avec succès dans des processeurs Intel. Bien que matériel, l'esprit de cette approche est une piste intéressante.

Cette approche est également une hybridation dynamique des approches réactive/pro- active mais matérielle cette fois. L'idée principale est toujours d'attendre que se produise un défaut de cache, de soumettre la demande à la mémoire secondaire et d'essayer d'utiliser le CPU à d'autres choses pendant le temps d'attente qui en résulte. À la diérence des solutions matérielles déjà présentées et uniquement réactives, Mutlu et al. utilise le temps de recouvrement pour analyser le ots d'exécution disponible dans le cache d'instructions. Cette analyse commence à l'instruction fautive et suit le graphe de ot de contrôle qui en part jusqu'à constater une instruction manquante en cache, dans toutes les directions possibles du graphe de ot de contrôle. Un algorithme de décision est ensuite utilisé pour choisir si un pré-chargement peut être eectué. Dans cette approche, si le défaut de cache qui n'a pu être évité est géré  réactivement  , le prochain s'il existe peut alors être soumis pro-activement, dès que la mémoire secondaire a ni son traitement en cours.

Synthèse sur le pré-chargement Le recouvrement d'opération par pré-chargement n'est réellement utile que lorsque le nombre de défaut de cache est important et les approches présentées se basent sur cette hypothèse de départ. Mais en dehors de ce cas de gure, qui n'est pas le meilleur comportement attendu d'un cache, le recouvrement d'opération par pré-chargement peut aller jusqu'à devenir un handicap. En eet, les solutions par injec- tions d'instructions ou par analyses dynamiques augmentent signicativement le coût en cycles CPU. Dans ces conditions, si l'overhead est supérieur au gain apporté par les re- couvrements effectifs, alors le recouvrement d'opération par pré-chargement dégrade les performances.

une valeur ajoutée est concrètement dicile sans support matériel ou sans circonstances adaptées.