TPS is not dead !

Depuis l’introduction sur le marché x86 des serveurs capables de “hardware-assisted memory virtualization”, la question de Transparent Page Sharing (TPS) vs large pages (ou huges pages) revient souvent dans les discussions en rapport avec l’overcommit mémoire. En effet, nous avons souvent abordé le sujet, TPS ne supporte pas (pour des raisons évidentes) les large pages :

ESX will not share large physical pages because:

The probability of finding two large pages that are identical is very low.
The overhead of performing a bit-by-bit comparison for a 2MB page is much higher than for a 4KB page.

Paradoxalement, c’est dans l’excellent Windows Internals que nous avons trouvé l’explication la plus synthétique à propos des large pages :

The primary advantage of large pages is speed of address translation for references to other data within the large page. This advantage exists because the first reference to any byte within a large page will cause the hardware’s translation look-aside buffer (TLB, described in a later section) to have in its cache the information necessary to translate references to any other byte within the large page. If small pages are used, more TLB entries are needed for the same range of virtual addresses, thus increasing recycling of entries as new virtual addresses require translation. This, in turn, means having to go back to the page table structures when references are made to virtual addresses outside the scope of a small page whose translation has been cached. The TLB is a very small cache, and thus large pages make better use of this limited resource.

On comprend donc aisément que sur des systèmes avec de plus en plus de RAM, les accès au TLB puissent être coûteux en CPU sans l’utilisation des large pages. Par contre, lorsqu’il n’y a plus de pages de 2Mo disponibles et parce que les large pages ne peuvent pas être swappées, ESX “casse” les large pages en small pages (dont le hash a déjà été computé) et TPS déduplique le tout :

Since ESX will not swap out large pages, during host swapping, a large page will be broken into small pages. ESX tries to share those small pages using the pre-generated hashes before they are swapped out.

Sur un système raisonnablement overcommité et sans tuning spécifique, l’ESX risque de ne pas “casser” et dedupliquer les pages suffisamment rapidement pour répondre à la demande de mémoire, ce qui peut engendrer une dégradation de performance (ballooning/zipping/swapping). A l’inverse, si le coût CPU est acceptable, le même système tuné pour ne faire que (ou presque que) des small pages n’aura pas cette problématique.

Ci dessous, la comparaison des stats mémoire d’un cluster (composé de serveurs à base d’Intel Nehalem) sans tuning spécifique et des stats de ce même cluster après avoir forcé l’utilisation des small pages sur les vm (workload comparable) :

La première chose qui frappe c’est le compteur “consumed” qui a diminué de moitié (le workload s’y prête bien dans ce cas puisqu’il s’agit d’une ferme de serveurs xenapp) grâce à TPS,  le compteur “shared” a en effet été multiplié par 10. Dans le cas présent, la consommation CPU a augmenté d’environ 15% lors du passage aux small pages.

Voici la commande powershell qui a permis de désactiver les large pages sur les vm (vm reboot ou “vmotion shake” pour la prise en compte) :

Get-View -ViewType VirtualMachine|?{!$_.Config.Template -and $_.Runtime.ConnectionState -eq "connected"}|?{!($_.Config.ExtraConfig|?{$_.Key -eq "monitor_control.disable_mmu_largepages"}|?{$_.value -match "true|1"})}|%{$_.ReconfigVM((New-Object VMware.Vim.VirtualMachineConfigSpec -Property @{extraconfig=(New-Object Vmware.Vim.OptionValue -Property @{Key="monitor_control.disable_mmu_largepages";Value="1"})}))}

Il est également possible d’obtenir un résultat similaire en forçant la VMM a utiliser le mode mmu software :

C’est quasiment identique mais la grande classe c’est qu’en powershell on peut forcer le mode cpu auto et le mode mmu software de la VMM (impossible en GUI) :

Get-View -ViewType virtualmachine|?{!$_.Config.Template -and $_.Runtime.ConnectionState -eq "connected"}|?{!($_.Config.Flags.VirtualExecUsage -eq "hvauto" -and $_.Config.Flags.VirtualMmuUsage -eq "off")}|%{($_.ReconfigVM_Task((New-Object VMware.Vim.VirtualMachineConfigSpec -Property @{flags=(New-Object VMware.Vim.VirtualMachineFlagInfo -property @{virtualExecUsage="hvauto";virtualMmuUsage="off"})})))}

C’est beau mais pas vraiment pratique à maintenir à cause des erreurs possibles via la GUI. De plus, nous avons eu l’opportunité précieuse d’échanger avec un Senior Staff Engineer de chez VMware qui nous a laissé entendre que ce n’était pas la meilleure option :

The sw-mmu [...] has slightly higher overheads (for the shadow pagetables and related data structures) and this will reduce the total available memory for backing guest pages.

Dans notre grande quête d’overcommit, notre contact chez VMware nous a parlé d’un paramètre assez génial qui permet de changer la politique d’allocation agressive de large pages de la mmu (en anglais c’est plus facile à comprendre) :

The heuristic, when enabled, basically says that whenever possible when backing any part of a 2MB-region of guest memory, try to do so with a large 2MB page. This may involve remapping existing small 4KB pages into that new 2MB page. But it basically tries to aggressively back everything large

Ce qui explique pourquoi, par défaut, TPS n’a presque pas d’effet (sauf pour les zero) même pour les guest qui ne “demandent” pas de large pages. La raison est bien liée aux performances :

When overcommitment isn’t an issue, large pages really do help TLB-performance with hw-mmu on most workloads.

A l’inverse, si on passe le paramètre à 0 (sched.mem.alwaysTryLPageAlloc pour une vm ou LPage.LPageAlwaysTryForNPT pour un host) la mmu n’allouera une large page qu’à la demande du guest. L’explication est d’ailleurs disponible au fin fond du documentation center de VMware :

Try to allocate large pages for nested page tables (called ‘RVI’ by AMD or ‘EPT’ by Intel). If you enable this option, all guest memory is backed with large pages in machines that use nested page tables. If NPT is not available, only some portion of guest memory is backed with large pages.

Vous aurez compris où nous voulons en venir : trouver un bon équilibre entre le bénéfice en matière de performance des large pages (presque incontestable lorsque c’est le guest qui en fait la demande) et le bénéfice de TPS en matière de consolidation mémoire. Exemple sur notre fameux cluster :

Si vous êtes attentif vous aurez remarqué qu’il n’y a que très peu de différence de consolidation avec les résultats en mode small pages forcées, c’était une feinte pour ceux du fond qui ne suivent pas… Dans ce cas c’est parfaitement normal car aucun des guestOS présent dans cet exemple n’utilise de large pages (windows 2003 32bit). Si les vm avaient été, par exemple, des windows 2008 R2, le niveau de consommation se serait situé quelque part entre le “full” large pages et le “full” small pages en fonction des applications et du comportement de l’OS. Nous ne manquerons pas de compléter ce post avec un exemple impliquant des guestOS et des applications exploitant les large pages.

Voici la commande powershell qui a permis de désactiver sched.mem.alwaysTryLPageAlloc sur les vm (vm reboot ou “vmotion shake” pour la prise en compte) :

Get-View -ViewType VirtualMachine|?{!$_.Config.Template -and $_.Runtime.ConnectionState -eq "connected"}|?{!($_.Config.ExtraConfig|?{$_.Key -eq "sched.mem.alwaysTryLPageAlloc"}|?{$_.value -match "false|0"})}|%{$_.ReconfigVM((New-Object VMware.Vim.VirtualMachineConfigSpec -Property @{extraconfig=(New-Object Vmware.Vim.OptionValue -Property @{Key="sched.mem.alwaysTryLPageAlloc";Value="0"})}))}

Pour afficher un tableau récapitulatif des infos qui nous intéressent :

Get-View -ViewType VirtualMachine|?{!$_.Config.Template -and $_.Runtime.ConnectionState -eq "connected"}|select @{n="VM";e={$_.Name}}, @{n="HV";e={$_.Config.Flags.VirtualExecUsage}}, @{n="HVMMU";e={$_.Config.Flags.VirtualMmuUsage}}, @{n="disable_mmu_largepages";e={($_.Config.ExtraConfig|?{$_.Key -eq "monitor_control.disable_mmu_largepages"}).value}}, @{n="alwaysTryLPageAlloc";e={($_.Config.ExtraConfig|?{$_.Key -eq "sched.mem.alwaysTryLPageAlloc"}).value}}, @{n="ESX";e={(Get-View -property Name $_.Runtime.Host).Name}}|sort hv,hvmmu,disable_mmu_largepages,alwaysTryLPageAlloc,ESX|ft -AutoSize

Pour information, depuis ESXi 5.0, il existe une commande très utile pour monitorer l’utilisation des large pages (memstats -r lpage-stats -v) :

En cas de vmotion, les pages de la “future” vm sont allouées au format 4k et reconverties par la suite :

The vmkernel allocates the memory for a VM during precopy using small pages. These are then converted to large as the VM begins to run but it is based on guest accesses. esx5.0 and esx5.1 each improved on the ability to recover the large mappings.

Et parce que nous sommes de grands fan de l’overcommit mémoire, voici notre poudre de perlimpinpin à ajouter dans vos recettes de scripts de déploiements si vous voulez overcommiter bien comme il faut (nous déclinons toute implosion de votre infra…) :

vim-cmd hostsvc/advopt/update VMkernel.Boot.sharePerNode bool false
vim-cmd hostsvc/advopt/update Mem.ShareRateMax long 32768
vim-cmd hostsvc/advopt/update Mem.ShareScanTime long 10
vim-cmd hostsvc/advopt/update Mem.ShareScanGHz long 32
vim-cmd hostsvc/advopt/update Mem.IdleTax long 95
#vim-cmd hostsvc/advopt/update Mem.AllocGuestLargePage long 0
#vim-cmd hostsvc/advopt/update Mem.AllocGuestRemoteLargePage long 0
#vim-cmd hostsvc/advopt/update LPage.LPageAlwaysTryForNPT long 0
vim-cmd hostsvc/advopt/update Mem.MemZipMaxPct long 25
#vsish -e set /sched/freeMemoryState/minFreePct 3

Nous finirons par une petite citation pour ceux qui ne jurent que par les large pages (qui a dit Hyper-V ?!) :

The performance increase is somewhat dependant upon the type of workload the virtual machine is executing; memory-intensive applications see more performance improvement than applications that are not heavily dependent on memory access.

Un grand merci à Alex Garthwaite pour son aide à la rédaction de ce post et à la compréhension des mécanismes de gestion de la mémoire d’ESX.

Tags: , , , , ,

11 Responses to “TPS is not dead !”

  1. … et un grand merci à toi pour cet article très complet !
    David.

  2. Merci pour ton soutien David !

  3. MrPochpoch Says:
    December 5th, 2012 at 15:26

    “c’était une feinte pour ceux du fond qui ne suivent pas”

    Trop fort raph … ;-)

  4. Je vois qu’on a quand même des élèves studieux :)

  5. [...] l’optique de rattraper un peu le coût CPU de nos petits excès d’overcommit, nous nous sommes penché sur les gains potentiel du vNUMA “forcé” sur des petites VM [...]

  6. [...] Comme nous vous l’avions promis, voici un retour d’expérience sur l’implémentation du paramètre LPageAlwaysTryForNPT à “0″ qui force ESX à n’allouer une Large Page que lorsque le GuestOS d’une VM le lui demande explicitement et qui permet de bénéficier de TPS sans attendre que l’ESX n’ai à les “casser” en cas de contention. In the cases where host memory is overcommitted, ESX may have to swap out pages. Since ESX will not swap out large pages, during host swapping, a large page will be broken into small pages. [...]

  7. [...] que TPS ne supporte pas les large pages qui sont la configuration par défaut d’ESX depuis des années, non seulement ESX ne serait [...]

  8. Le sujet commence à se faire un peu vieux, mais je me pose la question pour vSphere 6.0, dites moi si je me trompe mais en High State le TPS est censé être actif et casser les Larges Pages. Hors je n’ai pas l’impression quand je regarde la quantité de mémoire gagnée via ce mécanisme.

  9. Le sujet est toujours largement d’actualité et ce que vous constatez est très probablement du au salage introduit par VMware pour “renforcer” la sécurité d’ESX… Vous trouverez plus d’infos à ce sujet dans ce post : http://www.hypervisor.fr/?p=5298

  10. Je cite
    “Nous ne manquerons pas de compléter ce post avec un exemple impliquant des guestOS et des applications exploitant les large pages.”

    On serait au super heureux d’avoir un listing des principales applications utilisant les LP.

    Merci pour tout

  11. Et bien moi aussi parce qu’à présent je n’ai rencontré qu’une seule application (du java) qui utilisais massivement les LP.

    Meme une application comme SQL server ne les utilise que tres peu par defaut (https://blogs.msdn.microsoft.com/psssql/2009/06/05/sql-server-and-large-pages-explained/) :

    “LargePageSupport is enabled and used by the engine even if you don’t enable trace flag 834. But not much memory is used for this and buffer pool memory is not used unless trace flag 834 is enabled”

    Ca semble toujours valable pour MSSQL 2016 : https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA6-5301ENW.pdf

Leave a Reply