« Fonctionnement d'un ordinateur/Le modèle mémoire : alignement et boutisme » : différence entre les versions

Contenu supprimé Contenu ajouté
Ligne 38 :
Pour résumer, les avantages et inconvénients de chaque boutisme sont mineurs. Le gain en performance est nul sur les architectures modernes, qui ont des unités de calcul capables de faire des additions multi-octets. L'usage d'opérations de lecture de taille variable est aujourd'hui tombé en désuétude, vu que cela ne sert pas à grand chose et complexifie le jeu d'instruction. Enfin, l'avantage de lecture n'est utile que dans situations tellement rares qu'on peut légitimement questionner son statut d'avantage. En bref, les différentes formes de boutisme se valent.
 
==AlignementL'alignement mémoire==
 
Il arrive que le bus de données ait une largeur de plusieurs motscases mémoire. : leLe processeur peut charger 2, 4 ou 8 motscases mémoire d'un seul coup (parfois plus). Une donnée qui a la même taille que le bus de données est appelée un mot mémoire. Quand on veut accéder à une donnée sur un bus plus grand que celle-ci, le processeur ignore les mots mémoire en trop.
 
[[File:Exemple du chargement d'un octet dans un registre de trois octets.jpg|centre|vignette|upright=2|Exemple du chargement d'un octet dans un registre de trois octets.]]
 
Sur certains processeurs, il existe des restrictions sur la place de chaque mot en mémoire, restrictions résumées sous le nom d''''alignement mémoire'''.
Ligne 50 :
Sans alignement, on peut lire ou écrire un mot, peu importe son adresse. Pour donner un exemple, je peux parfaitement lire une donnée de 16 bits localisée à l'adresse 4, puis lire une autre donnée de 16 bits localisée à l'adresse 5 sans aucun problème.
 
[[File:Chargement d'une donnée sur un processeur sans contraitnes d'alignement.jpg|centre|vignette|upright=2|Chargement d'une donnée sur un processeur sans contraintes d'alignement.]]
 
===Avec alignement mémoire===
 
Mais dD'autres processeurs imposent des restrictions dans la façon de gérer ces mots : ils imposent un alignement mémoire. Tout se passe comme si chaque motla mémoire deétait ladécoupée mémoireen avaitblocs de la taille d'un mot : le processeur voit la mémoire comme si ces mots mémoire avaient la taille d'un mot, alorset que ce n'est pas forcément le cas.processeur Avecaccédait alignement,à l'unitédes deblocs lecture/écritureen est le mot, pas le mot mémoireentier. Par contre, la capacité de la mémoire reste inchangée, ce qui fait que le nombre d'adresses utilisables diminue : il n'y a plus besoin que d'une adresse par mot mémoire et non par byte.
 
[[File:Chargement d'une donnée sur un processeur avec contraintes d'alignement.jpg|centre|vignette|upright=2|Chargement d'une donnée sur un processeur avec contraintes d'alignement.]]
 
====La validité des adresses avec alignement mémoire====
====Adresses valides et invalides====
 
Avec cette technique, il y a une différence entre l'adresses d'un mot et l'adresses d'un byte. Les bytes ont une adresse qui est gérée par le processeur, alors que la mémoire ne gère que les adresses des mots. Par convention, l'adresse d'un mot est l'adresse de son byte de poids faible. Les autres bytes du mot ne sont pas adressables par la mémoire. Par exemple, si on prend un mot de 8 octets, on est certain qu'une adresse sur 8 disparaitra. L'adresse du mot est utilisée pour communiquer avec la mémoire, mais cela ne signifie pas que l'adresse des bytes est inutile au-delà du calcul de l'adresse du mot. En effet, l'accès à un byte précis est encore possible : le processeur lit un mot entier, sélectionne le byte adéquat et oublie les autres. Et pour cela, il doit déterminer la position du byte dans le mot. C'està partir quede l'adresse du byte est utile. ElleSes donnebits de poids faibles donnent la position du byte dans le mot, elle indique si le byte à lire/écrire est le premier du mot, le second, le troisième, etc.
 
Prenons un exemple, afin de détailler quelque peu le propos. Prenons un processeur ayant des mots de 4 octets et répertorions les adresses utilisables. Le premier mot contient les ''bytes'' d'adresse 0, 1, 2 et 3. L'adresse zéro est l'adresse de l'octet de poids faible et sert donc d'adresse au premier mot, les autres sont inutilisables sur le bus mémoire. Le second mot contient les adresses 4, 5, 6 et 7, l'adresse 4 est l'adresse du mot, les autres sont inutilisables. Et ainsi de suite. Si on fait une liste exhaustive des adresses valides et invalides, on remarque que seules les adresses multiples de 4 sont utilisables. Et ceux qui sont encore plus observateurs remarqueront que 4 est la taille d'un mot.
 
Dans l'exemple précédent, les adresses utilisables sont multiples de la taille d'un mot. Et bien sachez que cela fonctionne aussiquel avecque d'autressoit taillesla detaille du mot que 4. En fait, ça fonctionne même tout le temps ! Si N est la taille d'un mot, alors seules les adresses multiples de mN seront utilisables. Avec ce résultat, on peut trouver une procédure qui nous donne l'adresse d'un mot à partir de l'adresse d'un byte : il suffit de diviser l'adresse du byte par N (le nombre de bytes dans un mot). Et le reste de cette division donne la position du byte dans le mot : un reste de 0 nous dit que le byte est le premier du mot, un reste de 1 nous dit qu'il est le second, etc.
 
[[File:Adresse d'un mot avec alignement mémoire strict.png|centre|vignette|upright=2|Adresse d'un mot avec alignement mémoire strict.]]
 
Dans la réalité, ces blocs ont une taille égale à une puissance de deux, pour diverses raisons. Le fait est que lL'usage de ''bytes'' qui ne sont pas des puissances de 2 posent quelques problèmes techniques en terme d'adressage., ce qui fait que tous Enles premiermots lieu,ont celaune permettaille égale à une puissance de fairedeux. quelquesLa bidouillespremière surraison leest busque d'adressecela pourpermet d'économiser des fils sur le bus d'adresse. Si la taille d'un mot est égale à <math>2^{n}</math>, seules les adresses multiples de <math>2^{n}</math> seront utilisables. Hors, ces adresses se reconnaissent facilement : leurs n bits de poids faibles valent zéro. On n'a donc pas besoin de câbler les fils correspondant à ces bits de poids faible et on peut se contenter de les connecter à la masse (le zéro volt vu dans le second chapitre). En second lieu, cela permet de simplifier le calcul de l'adresse d'un mot, ainsi que le calcul de la position du byte dans le mot. Rappelons que pour un mot de N ''bytes'', le calcul de l'adresse du mot est une division, alors que celui de la position du byte est un modulo. Dans le cas général, ce sont deux opérations excessivement lentes, ce qui fait que les calculs d'adresse sont censés être lents. Mais avecAvec <math>N = 2^n</math>, la division est un simple décalage et le modulo est un simple ET logique, deux opérations très rapides par rapport à une division généraliste. Les calculs d'adresse sont donc beaucoup plus rapides et très simples.
 
====AccèsLes accès mémoire non-alignés====
 
Maintenant imaginons un cas particulier : je dispose d'un processeur utilisant des mots de 4 octets. Je dispose aussi d'un programme qui doit manipuler un caractère stocké sur 1 octet, un entier de 4 octets et une donnée de deux octets. Mais un problème se pose : le programme qui manipule ces données a été programmé par quelqu'un qui n'était pas au courant de ces histoire d'alignement, et il a répartit mes données un peu n'importe comment. Supposons que cet entier soit stocké à une adresse non-multiple de 4. Par exemple :
Ligne 104 :
Dans ce cas, il peut se passer des tas de choses suivant le processeur. Sur certains processeurs, la donnée est chargée en deux fois : c'est légèrement plus lent que la charger en une seule fois, mais ça passe. Mais sur d'autres processeurs, la situation devient nettement plus grave : le processeur ne peut en effet gérer ce genre d'accès mémoire dans ses circuits et considère qu'il est face à une erreur, similaire à une division par zéro ou quelque chose dans le genre. Il va alors interrompre le programme en cours d’exécution et exécuter un petit sous-programme qui gérera cette erreur. On dit que notre processeur effectue une exception matérielle. Si on est chanceux, ce programme de gestion d'erreur chargera cette donnée en deux fois : ça prend beaucoup de temps. Mais sur d'autres processeurs, le programme responsable de cet accès mémoire en dehors des clous se fait sauvagement planter. Par exemple, essayez de manipuler une donnée qui n'est pas "alignée" dans un mot de 16 octets avec une instruction SSE, vous aurez droit à un joli petit crash !
 
Pour éviter ce genre de choses, les compilateurs utilisés pour des langages de haut niveau préfèrent rajouter des données inutiles (on dit aussi du paddingbourrage) de façon à ce que chaque donnée soit bien alignée sur le bon nombre d'octets. En reprenant notre exemple du dessus, et en notant le paddingbourrage X, on obtiendrait ceci :
 
{|class=wikitable
Ligne 133 :
|}
 
Comme vous le voyez, ça prend un peu plus de place, et de la mémoire est gâchée inutilement. C'est pas grand chose, mais quand on sait que de la mémoire cache est gâchée ainsi, ça peut jouer un peu sur les performances. Il y a aussi des situations dans lesquelles rajouter du paddingbourrage est une bonne chose et permet des gains en performances assez abominables : une sombre histoire de cache dans les architectures multiprocesseurs ou multicores, mais je n'en dit pas plus. Cet alignement se gère dans certains langages (comme le C, le C++ ou l'ADA), en gérant l'ordre de déclaration de vos variables. Essayez toujours de déclarer vos variables de façon à remplir un mot intégralement ou le plus possible. Renseignez-vous sur le paddingbourrage, et essayez de savoir quelle est la taille de vos données en regardant la norme de vos langages. Moralité : programmeurs, faites gaffe à bien gérer l'alignement en mémoire !
 
<noinclude>