But de l’alignement de la mémoire

Certes je ne comprends pas. Disons que vous avez une mémoire avec un mot de mémoire de longueur de 1 octet. Pourquoi ne pouvez-vous pas accéder à une variable longue de 4 octets dans un seul access mémoire sur une adresse non alignée (c’est-à-dire non divisible par 4), comme c’est le cas avec les adresses alignées?

C’est une limitation de nombreux processeurs sous-jacents. On peut généralement y remédier en effectuant 4 extractions uniques à un octet plutôt qu’une récupération de mots efficace, mais de nombreux spécificateurs de langage ont décidé qu’il serait plus simple de les interdire et de tout forcer à les aligner.

Il y a beaucoup plus d’informations dans ce lien que l’OP a découvert.

Le sous-système de mémoire sur un processeur moderne est limité à l’access à la mémoire à la granularité et à l’alignement de sa taille de mot; c’est le cas pour plusieurs raisons.

La vitesse

Les processeurs modernes possèdent plusieurs niveaux de mémoire cache sur lesquels les données doivent être extraites. La prise en charge des lectures à un octet rendrait le débit du sous-système de mémoire étroitement lié au débit de l’unité d’exécution (aka, lié au processeur); tout cela rappelle la façon dont le mode PIO a été dépassé par DMA pour la plupart des mêmes raisons sur les disques durs.

Le processeur lit toujours à sa taille de mot (4 octets sur un processeur 32 bits), donc lorsque vous faites un access d’adresse non aligné – sur un processeur qui le prend en charge – le processeur va lire plusieurs mots. Le CPU lit chaque mot de mémoire que l’adresse demandée chevauche. Cela provoque une amplification de 2 fois le nombre de transactions mémoire nécessaires pour accéder aux données demandées.

De ce fait, il est très facile de lire deux octets de moins que quatre. Par exemple, disons que vous avez une structure en mémoire qui ressemble à ceci:

struct mystruct { char c; // one byte int i; // four bytes short s; // two bytes } 

Sur un processeur 32 bits, il serait très probablement aligné comme indiqué ici:

Structure Layout

Le processeur peut lire chacun de ces membres en une seule transaction.

Supposons que vous ayez une version compacte de la structure, peut-être du réseau où elle était compressée pour une efficacité de transmission; cela pourrait ressembler à ceci:

Structure emballée

La lecture du premier octet sera la même.

Lorsque vous demandez au processeur de vous donner 16 bits à partir de 0x0005, il devra lire un mot à partir de 0x0004 et décaler d’un octet à gauche pour le placer dans un registre à 16 bits; un travail supplémentaire, mais la plupart peuvent gérer cela en un seul cycle.

Lorsque vous demandez 32 bits à partir de 0x0001, vous obtenez une amplification 2X. Le processeur va lire à partir de 0x0000 dans le registre de résultats et décaler à gauche 1 octet, puis relire de 0x0004 dans un registre temporaire, décaler à droite 3 octets, puis OR avec le registre de résultats.

Gamme

Pour tout espace d’adressage donné, si l’architecture peut supposer que les 2 LSB sont toujours à 0 (par exemple, les machines 32 bits), elle peut accéder à 4 fois plus de mémoire (les 2 bits enregistrés peuvent représenter 4 états distincts). de mémoire avec 2 bits pour quelque chose comme drapeaux. En prenant les 2 LSB d’une adresse, vous obtenez un alignement sur 4 octets. également appelé une foulée de 4 octets. Chaque fois qu’une adresse est incrémentée, elle incrémente effectivement le bit 2, et non le bit 0, c’est-à-dire que les 2 derniers bits continueront toujours d’être 00 .

Cela peut même affecter la conception physique du système. Si le bus d’adresse nécessite 2 bits de moins, il peut y avoir 2 broches de moins sur le processeur et 2 traces de moins sur la carte de circuit.

Atomicité

Le processeur peut fonctionner de manière atomique sur un mot de mémoire aligné, ce qui signifie qu’aucune autre instruction ne peut interrompre cette opération. Ceci est essentiel au bon fonctionnement de nombreuses structures de données sans verrou et d’autres paradigmes de concurrence .

Conclusion

Le système de mémoire d’un processeur est un peu plus complexe et complexe que celui décrit ici. une discussion sur la manière dont un processeur x86 traite réellement la mémoire peut aider (de nombreux processeurs fonctionnent de manière similaire).

Il y a beaucoup plus d’avantages à respecter l’alignement de la mémoire que vous pouvez lire dans cet article IBM .

L’utilisation principale d’un ordinateur consiste à transformer des données. Les architectures et technologies de mémoire modernes ont été optimisées au fil des décennies pour faciliter l’obtention de plus de données, d’entrée, de sortie et entre des unités d’exécution plus nombreuses et plus rapides.

Bonus: Caches

Un autre alignement des performances auquel j’ai fait allusion précédemment est l’alignement sur les lignes de cache qui sont (par exemple, sur certaines CPU) 64B.

Pour plus d’informations sur les performances pouvant être obtenues en tirant parti des caches, consultez la galerie des effets de cache du processeur . de cette question sur les tailles de ligne de cache

La compréhension des lignes de cache peut être importante pour certains types d’optimisations de programmes. Par exemple, l’alignement des données peut déterminer si une opération touche une ou deux lignes de cache. Comme nous l’avons vu dans l’exemple ci-dessus, cela peut facilement signifier que dans le cas d’un mauvais alignement, l’opération sera deux fois plus lente.

vous pouvez avec certains processeurs ( le nehalem peut le faire ), mais auparavant tous les access à la mémoire étaient alignés sur une ligne 64 bits (ou 32 bits), car le bus a une largeur de 64 bits, vous devez chercher 64 bits à la fois , et il était beaucoup plus facile de les récupérer dans des «morceaux» alignés de 64 bits.

Donc, si vous vouliez obtenir un seul octet, vous avez récupéré le bloc 64 bits puis masqué les bits que vous ne vouliez pas. Facile et rapide si votre octet était au bon bout, mais s’il se trouvait au milieu de ce bloc 64 bits, vous devrez masquer les bits indésirables et transférer les données au bon endroit. Pire encore, si vous vouliez une variable de 2 octets, mais que celle-ci était divisée en deux parties, cela nécessitait le double des access mémoire requirejs.

Donc, comme tout le monde pense que la mémoire est bon marché, ils ont simplement obligé le compilateur à aligner les données sur la taille des blocs du processeur afin que votre code s’exécute plus rapidement et plus efficacement au prix d’une perte de mémoire.

Fondamentalement, la raison en est que le bus de mémoire a une longueur spécifique beaucoup plus petite que la taille de la mémoire.

Ainsi, le processeur lit sur le cache L1 sur puce, qui est souvent de 32 Ko ces jours-ci. Mais le bus de mémoire qui connecte le cache L1 au processeur aura la largeur de la ligne de cache beaucoup plus petite. Ce sera de l’ordre de 128 bits .

Alors:

 262,144 bits - size of memory 128 bits - size of bus 

Les access mal alignés chevaucheront parfois deux lignes de cache, ce qui nécessitera une lecture de cache entièrement nouvelle pour obtenir les données. Il pourrait même manquer tout le chemin à la DRAM.

De plus, une partie du processeur devra restr sur sa tête pour rassembler un seul object parmi ces deux lignes de cache différentes, chacune contenant une partie des données. Sur une ligne, ce sera dans les bits de très haut niveau, dans l’autre, les bits de très faible poids.

Il y aura du matériel dédié entièrement intégré dans le pipeline qui gère le déplacement des objects alignés sur les bits nécessaires du bus de données du processeur, mais ce matériel manque peut-être d’objects mal alignés, car il est probablement plus judicieux d’utiliser ces transistors pour accélérer correctement optimisé programmes.

Quoi qu’il en soit, la seconde lecture de mémoire parfois nécessaire ralentirait le pipeline, quel que soit le niveau de matériel dédié (hypothétiquement et bêtement) à la correction des opérations de mémoire mal alignées.

@joshperry a donné une excellente réponse à cette question. En plus de sa réponse, j’ai des chiffres qui montrent graphiquement les effets décrits, en particulier l’amplification 2X. Voici un lien vers une google spreadsheet montrant l’effet des différents alignements de mots. En outre, voici un lien vers une liste Github avec le code pour le test. Le code de test est adapté de l’article écrit par Jonathan Rentzsch auquel @joshperry a fait référence. Les tests ont été exécutés sur un Macbook Pro avec un processeur Intel Core i7 64 bits à 2 cœurs à 2,8 GHz et 16 Go de RAM.

entrer la description de l'image ici

Si un système avec une mémoire adressable par octet dispose d’un bus de mémoire de 32 bits, cela signifie qu’il existe des systèmes de mémoire de quatre octets, tous câblés pour lire ou écrire la même adresse. Une lecture alignée de 32 bits nécessitera des informations stockées dans la même adresse dans les quatre systèmes de mémoire, de sorte que tous les systèmes puissent fournir des données simultanément. Une lecture non alignée de 32 bits nécessiterait que certains systèmes de mémoire renvoient des données d’une adresse, et certains renvoient des données provenant de l’adresse suivante. Bien que certains systèmes de mémoire soient optimisés pour pouvoir répondre à de telles demandes (en plus de leur adresse, ils ont effectivement un signal “plus un” qui leur permet d’utiliser une adresse supérieure à celle spécifiée) et la complexité d’un système de mémoire; la plupart des systèmes de mémoire de base ne peuvent tout simplement pas retourner des portions de mots de 32 bits différents en même temps.

Si vous avez un bus de données à 32 bits, les lignes d’adresse du bus d’adresse connectées à la mémoire démarreront à partir de A 2 , de sorte que seules les adresses alignées à 32 bits soient accessibles dans un seul cycle de bus.

Donc, si un mot couvre une limite d’alignement d’adresse – c’est-à-dire que 0 pour les données à 16/32 bits ou A 1 pour les données à 32 bits ne sont pas nulles, deux cycles de bus sont nécessaires pour obtenir les données.

Certains architectures / jeux d’instructions ne prennent pas en charge les access non alignés et génèrent une exception sur de telles tentatives. Par conséquent, le code d’access non aligné généré par le compilateur nécessite non seulement des cycles de bus supplémentaires, mais aussi des instructions supplémentaires.

Sur PowerPC, vous pouvez charger un entier à partir d’une adresse impaire sans problème.

Sparc et I86 et (je pense) Itatnium soulèvent des exceptions matérielles lorsque vous essayez ceci.

Une charge de 32 bits par rapport à quatre charges de 8 bits ne fera pas beaucoup de différence sur la plupart des processeurs modernes. Que les données soient déjà en cache ou non aura un effet beaucoup plus important.