43 717
modifications
La première version de ce genre de caches a une correspondance ligne de cache → bloc de mémoire statique : on ne peut pas déplacer le contenu d'une ligne de cache dans une autre portion de mémoire plus rapide suivant les besoins. Mais des versions plus optimisées en sont capables : la correspondance entre une ligne de cache et un bloc de mémoire cache peut varier à l’exécution. Ainsi, les lignes de cache les plus utilisées peuvent migrer dans un bloc de mémoire plus rapide : cela demande juste de copier les données entre blocs de mémoire et de mettre à jour la correspondance entre ligne de cache et bloc de mémoire.
==
Un '''cache bloquant''' est un cache auquel le processeur ne peut pas accéder pendant un défaut de cache. Il faut
Su un cache bloquant, lors d'un défaut de cache, le cache et la mémoire RAM communiquent directement. Pendant un défaut de cache, le contrôleur mémoire charge la donnée depuis la mémoire et la copie plus ou moins directement dans le cache. Le cache étant utilisé, il ne peut pas être utilisé aussi bien le lecture qu'en écriture. Pour rendre un cache non-bloquant, il faut ajouter un intermédiaire entre la RAM et le cache, typiquement une mémoire tampon. Lors d'un défaut de cache, le contrôleur mémoire charge la donnée de la RAM dans la mémoire tampon, avant que le contenu du tampon soit recopié dans le cache. La conséquence est que le cache n'est pas utilisé, ni en lecture, ni en écriture, ce qui permet de l'utiliser. Il faut aussi rajouter quelques circuits pour gérer, par exemple, la survenue de défauts de cache successifs.
Les caches non bloquants sont de deux types, qui portent les noms barbare de caches de type succès après défaut et défaut après défaut. Sur le premier type, il ne peut pas y avoir plusieurs défauts de cache simultanés. Le second type est plus souple et autorise la survenue de plusieurs défauts de cache simultanés, jusqu'à une certaine limite. Dans ce qui va suivre, nous allons voir comment ces deux types de cache fonctionnent et comment ils sont fabriqués.
===Les caches non bloquants de type succès après défaut===
Sur certaines mémoires cache, lors d'un défaut de cache, on doit attendre que toute la ligne concernée par le défaut de cache soit chargée avant d'être utilisable. Un cache stocke des lignes de cache dont la taille est supérieure à la largeur du bus mémoire. En conséquence, une ligne de cache est chargée en plusieurs fois, morceaux par morceaux. Certains se sont demandés si on ne pouvait pas gagner quelques cycles en jouant dessus. Eh bien c'est le cas ! Certains processeurs sont capables d'utiliser un morceau de ligne de cache tout juste chargé alors que la ligne de cache complète n'est pas totalement lue depuis la mémoire. Avec cette technique, le cache est utilisable lors d'un défaut de cache, ce qui fait qu'il est légèrement non bloquant. Ces processeurs incorporent un tampon de remplissage de ligne (line-fill buffer), une sorte de registre, qui stocke le dernier morceau d'une ligne de cache à avoir été chargé depuis la mémoire. Ce morceau est stocké avec un tag, qui indique l'adresse du bloc stocké dans le tampon de remplissage de ligne. Ainsi, un processeur qui veut lire dans le cache après un défaut peut accéder à la donnée directement depuis le tampon de remplissage de ligne, alors que la ligne de cache n'a pas encore été totalement recopiée en mémoire.
Pour améliorer encore plus les performances, et utiliser au mieux ce tampon de remplissage de ligne, les processeurs actuels implémentent des techniques de critical word load. Pour faire simple, on va comparer le chargement d'une ligne de cache avec et sans critical word load. Sans critical word load, la ligne de cache est chargée morceau par morceau, dans l'ordre de placement de ces morceaux en mémoire. Mais si l'adresse lue ou écrite par le processeur n'est pas le premier mot mémoire de la ligne de cache, il devra attendre que celui-ci soit chargé. Durant ce temps d'attente, les blocs qui précédent la donnée demandée par le processeur seront chargés. Avec le critical word load, le contrôleur mémoire va charger les blocs en commençant par le bloc dans lequel se trouve la donnée demandée, avant de poursuivre avec les blocs suivants, avant de revenir au début du bloc pour charger les blocs restants. Ainsi, la donnée demandée par le processeur sera la première disponible.
===
Au-dessus, on a vu des caches capables de lire ou d'écrire lors d'un défaut. Ceux-ci sont incapables de mettre en attente d'autres défauts en attendant que le défaut en cours soit terminé. Mais sur d'autres caches, on peut gérer un nombre arbitraire de défaut de cache avant de bloquer, permettant ainsi aux lectures et écritures qui suivent un deuxième ou troisième défaut de fonctionner. Ceux-ci sont dits de type défaut après défaut (miss under miss).
Ceci dit, ces caches doivent être adaptés. Pendant qu'une lecture ou une écriture est démarrée par le contrôleur mémoire, il ne peut pas démarrer de nouvelle lecture ou écriture immédiatement après (sauf dans certains cas exceptionnels) : il y a toujours un temps d'attente entre l'envoi de deux requêtes d'accès mémoire. Dans ces conditions, les autres défauts doivent être mis en attente : la lecture/écriture doit être mémorisée, et est démarrée par le contrôleur mémoire une fois que celui-ci est libre, qu'il peut démarrer une nouvelle requête. Cette mise en attente s’effectue avec des miss status handling registers. Les miss status handling registers, que j’appellerais dorénavant MSHR, sont des registres qui vont mettre en attente les défauts de cache. Le nombre de MSHR indique combien de blocs de mémoire, de lignes de cache, peuvent être lues en même temps depuis la mémoire. Chacun de ces registres stocke au minimum trois informations :
* l'adresse à l'origine du défaut de cache ;
* sa destination : le numéro de la ligne de cache où stocker la donnée du défaut de cache ;
La solution la plus simple consiste à utiliser des MSHR adressés implicitement. Ces MSHR contiennent une entrée pour chaque mot mémoire dans la ligne de cache concernée par le défaut. Chacune de ces entrées dira si un défaut de cache compte lire ou écrire dans le mot mémoire en question. Ces entrées contiennent diverses informations :
* la destination de la lecture effectuée par le défaut de cache (généralement un registre) ;
* un format, qui donne des informations sur l'instruction à l’origine du défaut ;
Pour éviter de bloquer le cache lors d'accès à la même ligne de cache, certains chercheurs ont inventés des MSHR adressés explicitement. Ces MSHR sont aussi constitués d'entrées. La différence, c'est qu'une entrée est réservée à un accès mémoire, et non à un mot mémoire dans le cache. Chaque entrée va ainsi stocker :
* les index et décalages d'un accès mémoire dans la ligne de cache ;
* la destination de la lecture effectuée par le défaut de cache (généralement un registre) ;
|