214 votes

Objectif de l'alignement de la mémoire

J'avoue que je ne comprends pas. Disons que vous avez une mémoire avec un mot mémoire d'une longueur de 1 octet. Pourquoi ne pouvez-vous pas accéder à une variable de 4 octets de long en un seul accès 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 ?

20 votes

Après avoir fait quelques supplémentaire En cherchant sur Google, j'ai trouvé este excellent lien, qui explique très bien le problème.

1 votes

Consultez ce petit article pour les personnes qui commencent à apprendre cela : blog.virtualmethodstudio.com/2017/03/memory-alignment-run-fools

5 votes

Lien brisé avec @ark

338voto

joshperry Points 17727

Le sous-système de mémoire d'un processeur moderne est limité à l'accès à la mémoire à la granularité et à l'alignement de sa taille de mot ; ceci pour un certain nombre de raisons.

Vitesse

Les processeurs modernes disposent de plusieurs niveaux de mémoire cache à travers lesquels les données doivent être extraites ; la prise en charge de la lecture d'un seul octet rendrait le débit du sous-système de mémoire étroitement lié au débit de l'unité d'exécution (c'est-à-dire lié au processeur) ; tout ceci rappelle la façon dont le Le mode PIO a été surpassé par le DMA pour les mêmes raisons dans les disques durs.

L'unité centrale siempre lit à la taille de son mot (4 octets sur un processeur 32 bits). Par conséquent, lorsque vous effectuez un accès à une adresse non alignée - sur un processeur qui le prend en charge - le processeur va lire plusieurs mots. Le processeur lira chaque mot de mémoire que l'adresse demandée chevauche. Cela entraîne une amplification allant jusqu'à 2X le nombre de transactions mémoire nécessaires pour accéder aux données demandées.

De ce fait, il peut très facilement être plus lent de lire deux octets que quatre. Par exemple, disons que vous avez en mémoire une structure qui ressemble à ceci :

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

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

Struct Layout

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

Supposons que vous disposiez d'une version emballée de la structure, provenant peut-être du réseau où elle a été emballée pour des raisons d'efficacité de transmission ; elle pourrait ressembler à quelque chose comme ceci :

Packed Struct

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 vers la gauche pour le placer dans un registre de 16 bits ; un peu de travail supplémentaire, mais la plupart des processeurs peuvent gérer cela en un cycle.

Si vous demandez 32 bits à partir de 0x0001, vous obtiendrez une amplification de 2X. Le processeur lira de 0x0000 dans le registre de résultat et décalera vers la gauche d'un octet, puis lira à nouveau de 0x0004 dans un registre temporaire, décalera vers la droite de 3 octets, puis OR avec le registre des résultats.

Gamme

Pour un 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 conservés peuvent représenter 4 états distincts), ou à la même quantité de mémoire avec 2 bits pour quelque chose comme les drapeaux. En retirant les 2 LSB d'une adresse, on obtient un alignement sur 4 octets ; on parle aussi de foulée de 4 octets. Chaque fois qu'une adresse est incrémentée, c'est en fait le bit 2 qui est incrémenté, et non le bit 0, c'est-à-dire que les 2 derniers bits continueront toujours à être 00 .

Cela peut même affecter la conception physique du système. Si le bus d'adresses nécessite 2 bits de moins, il peut y avoir 2 broches de moins sur l'unité centrale et 2 traces de moins sur le circuit imprimé.

Atomicité

Le CPU peut opérer sur un mot aligné de la mémoire de manière atomique, ce qui signifie qu'aucune autre instruction ne peut interrompre cette opération. Ceci est essentiel pour le bon fonctionnement de nombreux structures de données sans verrouillage et autres Concurrence paradigmes.

Conclusion

Le système de mémoire d'un processeur est un peu plus complexe et impliqué que ce qui est décrit ici ; une discussion sur le système de mémoire de l'ordinateur est en cours. comment un processeur x86 adresse réellement la mémoire peut vous aider (de nombreux processeurs fonctionnent de manière similaire).

Il y a beaucoup d'autres avantages à adhérer à l'alignement de la mémoire que vous pouvez lire à l'adresse suivante cet article d'IBM .

L'utilisation principale d'un ordinateur est de transformer les données. Les architectures et les technologies de mémoire modernes ont été optimisées au fil des décennies pour faciliter l'entrée, la sortie et le transfert de données entre des unités d'exécution plus nombreuses et plus rapides, et ce de manière extrêmement fiable.

Bonus : Caches

Un autre alignement pour les performances auquel j'ai fait allusion précédemment est l'alignement sur les lignes de cache qui sont (par exemple, sur certains processeurs) de 64B.

Pour plus d'informations sur les gains de performances obtenus en exploitant les caches, consultez le site suivant Galerie des effets du cache du processeur ; de ce Question sur la taille des lignes 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.

0 votes

Les structures suivantes x y z ont des tailles différentes, en raison de la règle suivante : chaque membre doit commencer par une adresse multiple de sa taille et la chaîne de caractères doit se terminer par une adresse multiple de la plus grande taille du membre de la structure. struct x { short s ; //2 bytes and 2 padding tytes int i ; //4 bytes char c ; //1 bytes and 3 padding bytes long long l ; } ; struct y { int i ; //4 bytes char c ; //1 bytes and 1 padding byte short s ; //2 bytes } ; struct z { int i ; //4 bytes short s ; // 2 bytes char c ; //1 bytes and 1 padding byte } ;

0 votes

Il s'agit également d'un bon lien, basé sur un chapitre du livre "Game Engine Programming" de Jason Gregory : hjistcgam475.blogspot.se/2013/02/

1 votes

Si j'ai bien compris, la raison pour laquelle un ordinateur ne peut pas lire un mot non aligné en une seule étape est que les adresses utilisent 30 bits et non 32 bits ?

69voto

Paul Tomblin Points 83687

C'est une limitation de nombreux processeurs sous-jacents. Elle peut généralement être contournée en faisant 4 recherches inefficaces d'un seul octet plutôt qu'une recherche efficace d'un mot, mais de nombreux spécificateurs de langage ont décidé qu'il serait plus facile de les interdire et de forcer tout à être aligné.

Il y a beaucoup plus d'informations dans ce lien que le PO a découvert.

0 votes

Merci, @AveMilia, j'ai mis à jour la réponse.

25voto

gbjbaanb Points 31045

Vous pouvez avec certains processeurs ( le nehalem peut le faire ), mais auparavant, tous les accès à la mémoire étaient alignés sur une ligne de 64 bits (ou 32 bits), parce que le bus est large de 64 bits, vous deviez récupérer 64 bits à la fois, et il était beaucoup plus facile de les récupérer par "morceaux" alignés de 64 bits.

Ainsi, si vous vouliez obtenir un seul octet, vous alliez chercher le morceau de 64 bits et masquiez ensuite les bits que vous ne vouliez pas. Facile et rapide si votre octet se trouvait à la bonne extrémité, mais s'il se trouvait au milieu de ce morceau de 64 bits, vous deviez masquer les bits non désirés et ensuite déplacer les données au bon endroit. Pire encore, si vous vouliez une variable de 2 octets, mais qu'elle était répartie sur 2 morceaux, cela nécessitait le double des accès mémoire requis.

Donc, comme tout le monde pense que la mémoire est bon marché, ils ont simplement fait en sorte que le compilateur aligne les données sur les tailles des morceaux du processeur afin que votre code s'exécute plus rapidement et plus efficacement au prix d'un gaspillage de mémoire.

7voto

DigitalRoss Points 80400

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

Le processeur lit donc dans le cache L1 de la puce, qui est souvent de 32 Ko de nos jours. Mais le bus mémoire qui relie le cache L1 à l'UC aura la largeur beaucoup plus petite de la taille de la ligne de cache. Celle-ci sera de l'ordre de 128 bits .

Donc :

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

Les accès mal alignés chevaucheront parfois deux lignes de cache, ce qui nécessitera une toute nouvelle lecture du cache afin d'obtenir les données. Il se peut même que les données ne soient pas lues jusqu'à la DRAM.

En outre, une partie de l'unité centrale devra se mettre en quatre pour assembler un objet unique à partir de ces deux lignes de cache différentes qui contiennent chacune une partie des données. Sur une ligne, il s'agira des bits de très haut rang, sur l'autre, des bits de très bas rang.

Il y aura du matériel dédié entièrement intégré dans le pipeline qui s'occupera de déplacer les objets alignés sur les bits nécessaires du bus de données du CPU, mais ce matériel peut faire défaut pour les objets mal alignés, car il est probablement plus logique d'utiliser ces transistors pour accélérer les programmes correctement optimisés.

De toute façon, la deuxième lecture de la mémoire qui est parfois nécessaire ralentirait le pipeline, quelle que soit la quantité de matériel spécialisé (hypothétiquement et bêtement) dédié à Parcheando les opérations de mémoire mal alignées.

1 votes

peu importe la quantité de matériel spécialisé (hypothétiquement et stupidement) dédié à Parcheandoles opérations de mémoire mal alignées. - CPU Intel modernes, levez-vous et agitez vous :P La gestion efficace des charges AVX 256 bits mal alignées (tant qu'elles ne traversent pas une limite de ligne de cache) est pratique pour les logiciels. Même les chargements fractionnés ne sont pas si mauvais, avec Skylake qui a grandement amélioré la pénalité pour les chargements/stockages de pages fractionnées, de ~100 cycles à ~10 (ce qui arrivera si l'on vectorise sur un tampon non aligné, avec une boucle qui ne dépense pas de code de démarrage/de nettoyage supplémentaire pour aligner les pointeurs).

1 votes

Les processeurs AVX512 avec des chemins de 512 bits entre le cache L1d et les unités d'exécution load/store souffrent beaucoup plus des pointeurs mal alignés car chaque La charge est désalignée, au lieu d'une sur deux.

5voto

ark Points 479

Après avoir fait quelques supplémentaire En cherchant sur Google, j'ai trouvé este excellent lien, qui explique très bien le problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X