• Aucun résultat trouvé

3.3 Approches

3.3.1 Première approche : un cache mémoire

La solution de l'état de l'art qui s'impose tout naturellement et comme une évidence est celle de mettre en place un cache. Un cache est en eet reconnu comme une approche plus élaborée et plus ecace qu'un tampon. Son usage est d'ailleurs généralisé, chaque fois que surviennent des problématiques d'accès performants à des données d'une mémoire secondaire. La plupart du temps, un cache sert à réduire les temps d'accès à une mémoire à fort temps de latence, comme par exemple un disque dur. Ou lorsque la latence d'une mémoire, même faible, devient néanmoins un handicap à long terme. C'est le cas exemple des processeurs évolués face à la RAM.

3.3.1.1 Un cache d'instructions en logiciel

Plusieurs approches purement logicielles ont été proposées pour utiliser un cache comme passerelle d'accès à du code et des chiers exécutables stockés dans une mémoire secondaire

lente.

Entrelacé dans le code binaire Une première façon de procéder consiste à intégrer un cache et la gestion de la mémoire secondaire - par exemple la NAND - dès la compilation de l'application [Park 2004,Kim 2011]. Bien que cela fonctionne, les inconvénients à gérer cette intégration à la compilation sont :

• l'augmentation signicative de la taille du binaire,

• le peu de souplesse à avoir un cache par programme compilé,

• et un besoin en RAM d'au moins la moitié du binaire dans les solutions proposées par Park et al. et Kim et al. - avec des cas démontrés où le cache doit être quasiment aussi gros que ce binaire.

Mémoires Scratchpad Notre approche par cache d'instructions en logiciel ressemble en partie à un autre domaine, celui des mémoires Scratchpad3 [Panda 2000,Banakar 2002, Angiolini 2004]. L'idée est ici de supprimer la logique câblée des défauts de cache des caches processeurs (caches de premier niveau, d'instructions et/ou de données), pour avoir un es- pace de stockage alors plus vaste en terme de silicium. Le  cablage  du cache est remplacée par une implémentation logicielle intégrée au micro-code du CPU. Pour des raisons de per- formance et de part leur proximité avec le processeur, l'allocation dans les mémoires Scratch- pad est souvent déterminé à la compilation, ce qui représente une approche très rigide quant au contenu et élimine la stratégie de placement par segmentation. D'autre travaux proposent une approche plus dynamique [Kandemir 2001,Miller 2006,McIlroy 2008] où le compilateur insère cette fois des routines plutôt que des directives, ce qui laisse un peu plus de latitude quant au contenu de la mémoire à un instant T , mais dégrade les performances. Les Mémoires Scratchpad correspondent donc plus à des caches de données critiques, parfois hétérogènes (e.g. blocs de code  chaud  , copies de piles de processus, données produites par le CPU comme le déroulement de boucles, etc).

Imiter l'approche classique Une autre approche plus conventionnelle consiste à con- cevoir un cache d'instructions en s'inspirant des caches de données classiques où un cache est un composant logiciel indépendant placé entre la mémoire secondaire et un consomma- teur de données, comme une VM, un serveur web, une gestionnaire de base de données ou un OS. Ce type de conguration n'est pas directement lié aux données et son principe de base est la transformation d'une adresse logique en une adresse physique an de renvoyer une copie de la donnée cherchée. Cette approche rend le cache indépendant des données en mémoire non-adressable mais également indépendant du type de données qu'il contient lui- même. Cette approche apporte également un plus haut degré de exibilité, car si le cache est conçu pour, il peut alors très bien être reconguré à chaud pour s'adapter à un autre besoin. Généralement un cache logiciel de ce type utilise un placement par segmentation reposant sur la pagination à la demande [Park 2003a,Park 2004,Joo 2006].

3.3.1.2 Les clés de l'ecacité d'un cache

Les taux de Hit et de Miss sont les indicateurs les plus couramment utilisés pour estimer la performance d'un cache. Dans tous les cas, avoir un taux de Hit élevé est strictement équivalent à avoir un taux de Miss bas. Toutefois, ils ne donnent qu'une vision partielle de la performance d'un cache en occultant le temps nécessaire pour diérencier un Hit d'un

Miss par exemple, contrairement à la mesure du temps d'accès moyen. En se basant sur le fonctionnement général d'un cache présenté en section 2.3.1, page 19, le temps d'accès moyen à une donnée à travers un cache se calcule par la formule suivante :

Équation 1. Caractérisation du temps d'accès moyen à une instruction dans un cache           

TAcc`esmoyen = TRecherche+ (1 − PM iss) ∗ TGestionHit+ PM iss∗ TM iss

TM iss = TR´ecup´eration+ TEviction´ + TGestionM iss TR´ecuperation = TN AN D+ TF T L

Le temps d'accès à une donnée, TAcc`esmoyen, est ainsi égal au temps nécessaire pour trouver une donnée, TRecherche, auquel s'ajoute le temps nécessaire à la gestion d'un Hit ou d'un un Miss. Pour le temps d'accès moyen, ce temps de gestion est fonction de la probabilité d'occurrence d'un Miss, PM iss, probabilité égale à 0 en cas de Hit.

Un défaut de cache se décompose quand à lui en trois temps. Le premier est le temps nécessaire pour récupérer une ou plusieurs données depuis la mémoire secondaire, temps supposé incompressible, TR´ecup´eration. Le temps restant est consacré à choisir un emplace- ment dans le cache pour les données nouvellement récupérées, TEviction´ , et à maintenir un ordre susceptible d'aider à éviter d'autre défaut de cache, TGestionM iss (cf Politiques de remplacement, section 2.3.3 page 23).

De manière générale, cette équation donne les trois leviers principaux de performance d'un cache :

1. maximiser la probabilité de trouver une donnée dans le cache, ou de manière équiva- lente, minimiser la probabilité PM iss d'un défaut de cache ;

2. minimiser le temps de recherche d'une donnée eectivement en cache ;

3. minimiser le délai d'un défaut de cache TM iss en minimisant les temps TEviction´ et TGestionM issgrâce à des stratégies de placement et de renouvellement ecaces. 3.3.1.3 Limitations d'un cache

Comme nous l'avons vu, de simples tampons pour régler le problème de l'accessibilité n'étant pas susants au global, une solution à base de cache est connue comme une meilleure approche. De plus, l'intégration d'un cache est un problème d'ingénierie qui peut être résolu assez facilement.

Néanmoins, une telle solution est toujours limitée, car un cache continue à constituer un goulot d'étranglement. Mettre en place un cache est (re-)connu à tort comme une sorte d'accélération. À tort, car il n'accélère pas les accès à la mémoire secondaire mais masque une partie de son temps de latence global. Du point de vue du processeur, un cache continue donc à être un ralentissement dans l'exécution d'un programme si on le compare à l'exécution en place depuis la mémoire adressable. Tout simplement parce que l'accès à une instruction en cache ne peut pas se faire a priori en un cycle CPU. Il faut au moins compter le coût supplémentaire de la recherche en cache : comme il n'est pas possible d'exécuter une instruction qui n'est pas en cache, il faut au moins s'assurer de sa présence ou de son absence, ce qui cause un temps de latence minimal. Même si cette étape est optimisée au maximum, nement au cycle près, pour être par exemple de 30 cycles, il en résulte encore un écart de performance de 1 pour 30 entre la Flash NOR et un cache.

Dans l'absolu, un cache est donc un bon point de départ pour résoudre notre problé- matique et représente un socle de performance non-négligeable. Mais il est évident qu'il ne peut pas combler le décit de performance à lui-seul.

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