Question

processeurs x86 modernes ont la capacité de supporter la taille des pages plus grandes que l'héritage 4K (c.-à-2MB ou 4MB), et il y a des installations OS ( Linux , de Windows ) pour accéder à cette fonctionnalité.

Le lien ci-dessus Microsoft états grandes pages « augmenter l'efficacité de la mémoire tampon de traduction, ce qui peut augmenter les performances de la mémoire fréquemment consultées ». Ce qui est pas très utile pour prévoir si grandes pages amélioreront une situation donnée. Je suis intéressé par du béton, de préférence quantifié, des exemples où le déplacement de la logique du programme (ou une application entière) d'utiliser des pages énormes a donné lieu à une certaine amélioration de la performance. Tout le monde a des histoires de succès?

Il y a un cas particulier, je connais moi-même : l'utilisation énorme pages peuvent réduire considérablement le temps nécessaire pour la fourche d'un grand processus (probablement en tant que le nombre d'enregistrements qui ont besoin de TLB copie est réduite par un facteur de l'ordre de 1000). Je suis intéressé à savoir si les pages énormes peuvent également être un avantage dans les scénarios moins exotiques.

Était-ce utile?

La solution 2

J'ai essayé d'inventer un code qui maximiserait raclée du TLB avec 4k pages afin d'examiner les gains possibles de grandes pages. Les trucs ci-dessous fonctionne 2.6 fois plus rapide (à 4 Ko pages) lorsque les pages sont 2MByte sont fournis par malloc libhugetlbfs (Intel Core i7, Debian Lenny 64bit); nous l'espérons évident que scoped_timer et random0n faire.

  volatile char force_result;

  const size_t mb=512;
  const size_t stride=4096;
  std::vector<char> src(mb<<20,0xff);
  std::vector<size_t> idx;
  for (size_t i=0;i<src.size();i+=stride) idx.push_back(i);
  random0n r0n(/*seed=*/23);
  std::random_shuffle(idx.begin(),idx.end(),r0n);

  {
    scoped_timer t
      ("TLB thrash random",mb/static_cast<float>(stride),"MegaAccess");
    char hash=0;
    for (size_t i=0;i<idx.size();++i) 
      hash=(hash^src[idx[i]]);
    force_result=hash;
  }

Une simple version "ligne droite" avec juste hash=hash^src[i] seulement gagné 16% des grandes pages, mais (spéculation sauvage) Intel fantaisie préchargement matériel peut être l'aide 4K cas où les accès sont prévisibles (je suppose que je pourrais désactiver le préchargement pour vérifier si cela est vrai).

Autres conseils

La plus grande différence de performance viendra où vous faites des accès aléatoires largement espacés dans une grande partie de la mémoire - où « grands » signifie beaucoup plus grand que la plage qui peut être mis en correspondance par toutes les petites entrées de page dans le TLB (qui ont généralement plusieurs niveaux dans les processeurs modernes).

Pour rendre les choses plus complexes, le nombre d'entrées TLB pour les pages de 4 Ko est souvent plus grand que le nombre d'entrées pour les pages 2MB, mais cela varie beaucoup par le processeur. Il y a aussi beaucoup de variation dans le nombre d'entrées « page grand » sont disponibles dans le niveau 2 TLB.

Par exemple, sur un système AMD Opteron Famille D Révision 10 h ( "Istanbul"), CPUID rapports:

  • L1 DTLB: pages 4Ko: 48 entrées; pages 2MB: 48 entrées; pages 1 Go: 48 entrées
  • L2 TLB: pages 4 Ko: 512 entrées; pages 2MB: 128 entrées; pages 1 Go: 16 entrées

Alors que sur un système Intel Xeon 56xx ( "Westmere"), CPUID rapports:

  • L1 DTLB: pages 4 Ko: 64 entrées; pages 2MB: 32 entrées
  • L2 TLB: pages 4 Ko: 512 entrées; pages 2MB: none

Les deux peuvent carte 2MB (512 * 4 Ko) en utilisant les pages de petites avant le niveau de souffrance 2 misses TLB, alors que le système Westmere peut carte 64Mo en utilisant ses 32 entrées 2MB TLB et le système AMD peut mapper 352MB en utilisant les 176 entrées 2MB TLB dans sa L1 et L2 TLB. Soit le système aura une importante accélération en utilisant de grandes pages pour les accès aléatoires sur des plages de mémoire qui sont beaucoup plus grandes que 2 Mo et moins de 64Mo. Le système AMD devrait continuer à afficher de bonnes performances en utilisant de grandes pages pour les plages de mémoire beaucoup plus.

Ce que vous essayez d'éviter dans tous ces cas est le pire des cas (note 1) scénario de parcourir les quatre niveaux de la traduction d'adresse hiérarchique x86_64.
Si aucun des mécanismes de mise en cache de traduction d'adresses (note 2) de travail, il faut:

  • 5 voyages en mémoire aux données de charge mis en correspondance sur une page 4Ko,
  • 4 voyages en mémoire aux données de charge mis en correspondance sur une page 2MB et
  • 3 voyages en mémoire aux données de charge mis en correspondance sur une page 1 Go.

Dans chaque cas, le dernier voyage à la mémoire est d'obtenir les données demandées, alors que les autres voyages sont nécessaires pour obtenir les différentes parties de l'information de traduction de page. La meilleure description que j'ai vu est dans la section 5.3 de AMD "Manuel AMD64 architecture programmeur Volume 2: Programmation du système" (publication 24593) http://support.amd.com/us/Embedded_TechDocs/24593.pdf

Note 1: Les chiffres ci-dessus ne sont pas vraiment pire cas. Fonctionnant sous une machine virtuelle rend ces chiffres plus mauvais. Courir dans un environnement qui provoque la mémoire contenant les différents niveaux des tables de page pour obtenir permuté sur le disque rend la performance beaucoup pire.

Note 2: Malheureusement, même en sachant ce niveau de détail ne suffit pas, parce que tous les processeurs modernes ont des caches supplémentaires pour les niveaux supérieurs de la hiérarchie de traduction de page. Pour autant que je peux dire elles sont très mal documentés en public.

Je l'ai vu une amélioration dans certains scénarios HPC / grille - packages spécifiquement la physique avec très, très grands modèles sur les machines avec beaucoup, beaucoup de RAM. De plus, le processus en cours d'exécution le modèle était la seule chose actif sur la machine. Je soupçonne, ont ne sont pas mesurés, que certaines fonctions de DB (par exemple les importations en vrac) bénéficieraient ainsi.

Personnellement, je pense que si vous avez un très bien profilé / compris le profil d'accès mémoire et il fait beaucoup de grand accès à la mémoire, il est peu probable que vous verrez une amélioration significative.

Cela devient ésotérique, mais les pages énormes TLB faire une différence significative sur l'architecture Intel Xeon Phi (MIC) lorsque vous effectuez des transferts de mémoire DMA (de l'hôte à Phi via PCIe). Ce lien Intel décrit comment activer les pages énormes . J'ai trouvé en augmentant la taille de transfert DMA au-delà de 8 Mo avec une taille normale page TLB (4K) a commencé à la performance de baisse, d'environ 3 Go / s à moins de 1 Go / s une fois la taille de transfert a atteint 512 MB.

Après avoir activé grandes pages TLB (2MB), le débit de données a continué d'augmenter à plus de 5 Go / s pour les transferts DMA de 512 MB.

Je reçois ~ 5% sur les serveurs avec speedup beaucoup de mémoire (> = 64 Go) en cours d'exécution de grands processus. par exemple. pour un processus java 16 Go, qui est 4M x 4Ko pages mais seulement 4k x 4Mo pages.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top