<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kernel on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/kernel/</link><description>Recent content in Kernel on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Mon, 06 Jul 2020 06:40:00 +0000</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/kernel/index.xml" rel="self" type="application/rss+xml"/><item><title>Optimisation de PFsense dans Proxmox VE</title><link>https://blog.zwindler.fr/2020/07/06/optimisation-de-pfsense-dans-proxmox-ve/</link><pubDate>Mon, 06 Jul 2020 06:40:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/07/06/optimisation-de-pfsense-dans-proxmox-ve/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/03/article_logo_pfsense_proxmox.webp" alt="Featured image of post Optimisation de PFsense dans Proxmox VE" /&gt;&lt;h2 id="pfsense--proxmox-ve--3"&gt;PFsense + Proxmox VE = &amp;lt;3
&lt;/h2&gt;&lt;p&gt;Si vous suivez ce blog, vous savez que je parle régulièrement de &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=proxmox" &gt;Proxmox VE&lt;/a&gt;. En particulier, j’ai travaillé avec 2 autres personnes (&lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=m4vr0x" &gt;M4vr0x&lt;/a&gt; et &lt;a class="link" href="https://blog.zwindler.fr/recherche/?keyword=charlesbordet" &gt;Charles BORDET&lt;/a&gt; pour écrire 2 suites de plusieurs articles sur Proxmox et PFsense.&lt;/p&gt;
&lt;p&gt;Dans ces deux suites d’articles, à chaque fois l’angle était le même. Débuter avec Proxmox en montant, de 0, un serveur Proxmox VE, mais sans non plus prendre trop de risques et en le sécurisant un maximum avant d’installer quoique ce soit dessus.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2020/03/02/deploiement-de-proxmox-ve-6-pfsense-sur-un-serveur-dedie" &gt;Proxmox VE 6 + pfsense sur un serveur dédié (1/2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sauf que, dans les deux cas, j’ai trouvé que les perfs des machines virtuelles avec PFsense étaient assez&amp;hellip; molles.&lt;/p&gt;
&lt;p&gt;Heureusement, après quelques années de déterrage de posts sur les forums de Proxmox VE, on finit par chopper des tips and tricks que je vous partage aujourd’hui.&lt;/p&gt;
&lt;h2 id="sur-les-vielles-versions-de-proxmox-ve"&gt;Sur les vielles versions de Proxmox VE
&lt;/h2&gt;&lt;p&gt;La première chose qui m’a gêné lorsque j’ai déployé la consommation CPU de PFsense alors que je n’avais encore rien commencé à faire avec.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/optimisation_proxmox_pfsense2.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Autour de 7-8% en idle, alors que je ne lui envoie pour l’instant aucun trafic. Juste faire tourner l’OS dans le vide.&lt;/p&gt;
&lt;p&gt;Pour ceux qui ne le savent pas, PFSense est un firewall basé sur l’OS FreeBSD. J’ai donc commencé à chercher des tips pour améliorer les perfs des VMs sous FreeBSD dans KVM.&lt;/p&gt;
&lt;p&gt;Je suis tombé &lt;a class="link" href="https://forum.proxmox.com/threads/high-cpu-idle-usage-with-pfsense-openbsd.19695/" target="_blank" rel="noopener"
&gt;là dessus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sur les plus vieux Proxmox (&amp;lt;6 en tout cas), un gain significatif en terme de CPU peut être trouvé en modifiant 2 paramètres dans le fichier /boot/loader.conf`&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;hint.apic.0.clock=0
kern.hz=100
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Là où la manœuvre est un peu &amp;ldquo;tricky&amp;rdquo; comme on peut dire, c’est que normalement, si vous êtes comme moi, même en ayant paramétré lors de l’installation le clavier Azerty, dans la console PFsense, vous allez être en Qwerty&amp;hellip;
Bref, avec un layout de clavier qwerty sous les yeux vous devriez vous en sortir (des consoles KVM, iLO, iDRAC qui déconnent, j’ai l’habitude au bout de 10 ans), mais la vraie solution est de corriger le layout de la façon suivante :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cd /usr/share/syscons/keymaps
kbdcontrol -l fr.iso.kbd
#ou en qwerty virtue sur votre clavier azerty physique
cd !usr!shqre!syscons!key,qps
kbdcontrol )l fr:iso
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;YOUHOU ! Enfin en azerty dans cette fichue console !&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2017/05/optimisation_proxmox_pfsense3.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Après reboot`, effectivement, sur un vieux Proxmox, j’ai gagné entre 3 et 4%. Pour d’autres personnes, les gains étaient bien plus significatifs, car ça dépend du CPU a priori.&lt;/p&gt;
&lt;p&gt;En revanche, sur mon Proxmox VE 6, pas de gain. C’est même le contraire, je suis passé de 2,5% en moyenne à 4% ! Argh&amp;hellip;&lt;/p&gt;
&lt;h2 id="deuxième-optim-qui-marche-presque-à-tous-les-coups"&gt;Deuxième optim, qui marche presque à tous les coups
&lt;/h2&gt;&lt;p&gt;Là par contre, celle ci à de la valeur même sur PVE6. Proxmox VE ajoute systématiquement sur les VMs une option : &amp;ldquo;Use tablet for pointer&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Je n’ai pas trouvé beaucoup de documentation à ce sujet, il semblerait que cela serve à améliorer la précision du pointeur de la souris dans la console. Autant dire que pour PFsense, on s’en cogne !&lt;/p&gt;
&lt;p&gt;Dans le menu de la VM, dans Options, cherchez Use tablet for pointer puis désactivez l’option :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/pfsense_use_tablet.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vous devriez avoir ce message qui s’affiche dans la console&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Et là, les gains sont significatifs ! On passe de 2,5% à moins de 1%.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/cpu_pfsense_pointer.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Ce qui est cool avec cette tips, c’est que ce conseil vaut aussi pour toutes les VMs que vous utilisez sans environnement graphique (et ça vaut aussi le coup de tester pour les envs graphiques).&lt;/p&gt;
&lt;p&gt;Voilà ce que ça donne sur un serveur Ubuntu 18.04 avec environnement graphique, qui fonctionne aussi bien avant qu’après.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/ubuntu_cpu_tablet.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Encore plus significatif !&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="virtio"&gt;VirtIO
&lt;/h2&gt;&lt;p&gt;Depuis FreeBSD 9, les pilotes pour le &lt;a class="link" href="https://www.linux-kvm.org/page/Virtio" target="_blank" rel="noopener"
&gt;matériel virtuel de type VirtIO&lt;/a&gt; sont directement intégrés. L’avantage de VirtIO par rapport à du matériel virtuel classique c’est que les pilotes sont &amp;ldquo;paravirtualisés&amp;rdquo;. Un gros mot pour dire que le pilote est &amp;ldquo;au courant&amp;rdquo; qu’il s’agit de matériel virtuel, permettant de bien meilleure performance.&lt;/p&gt;
&lt;p&gt;On a de la chance, la dernière version de PFsense (la 2.4.5) est basée sur FreeBSD 11 :-)&lt;/p&gt;
&lt;p&gt;Si vous avez le choix donc, c’est VirtIO en priorité !&lt;/p&gt;
&lt;h2 id="hardware-offloading-cest-non-"&gt;Hardware offloading, c’est non !
&lt;/h2&gt;&lt;p&gt;Maintenant que j’ai dis ça&amp;hellip; il faut quand même que je vous parle du pilote réseau VirtIO avec PFsense.&lt;/p&gt;
&lt;p&gt;Si jamais vous l’installez tel quel et que vous ne faites rien de plus, vous allez avoir des surprises&amp;hellip; Perfs pourries, NAT impossible, etc&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/optim_reseau_pfsense_virtio_offloading.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;En fait, il est nécessaire de cocher plusieurs cases dans l’interface de PFsense.&lt;/p&gt;
&lt;p&gt;Dans System / Advanced / Networking, il faut cocher les cases suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hardware TCP Segmentation Offloading&lt;/li&gt;
&lt;li&gt;Hardware Large Receive Offloading&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/05/pfsense_system_network.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Et tout de suite, ça ira beaucoup mieux :)&lt;/p&gt;
&lt;h2 id="sources-et-documentations"&gt;Sources et documentations
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://forum.proxmox.com/threads/high-cpu-idle-usage-with-pfsense-openbsd.19695/" target="_blank" rel="noopener"
&gt;Forum Proxmox - High CPU idle usage with pfsense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://forum.proxmox.com/threads/high-cpu-load-on-idle-kvm-host.28287/" target="_blank" rel="noopener"
&gt;Forum Proxmox - High load on idle KVM host&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://web.archive.org/web/20190514223831/http://blog.magiksys.net/pfsense-configure-keymap" target="_blank" rel="noopener"
&gt;Blog magiksys - pfsense configure keymap (lien mort, j&amp;rsquo;utilise Internet Archive)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://pve.proxmox.com/wiki/Performance_Tweaks" target="_blank" rel="noopener"
&gt;Doc officielle Proxmox - Performance Tweaks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://pve.proxmox.com/wiki/Qemu/KVM_Virtual_Machines" target="_blank" rel="noopener"
&gt;Doc officielle Proxmox - KVM Virtual machines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://web.archive.org/web/20201203112627/https://docs.netgate.com/pfsense/en/latest/recipes/virtualize-proxmox.html" target="_blank" rel="noopener"
&gt;Doc officielle Netgate - virtualizing PFsense (lien mort, j&amp;rsquo;utilise Internet Archive)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Transparent Hugepages : mesurer l’impact sur les performances</title><link>https://blog.zwindler.fr/2020/02/24/transparent-hugepages-mesurer-limpact-sur-les-performances/</link><pubDate>Mon, 24 Feb 2020 07:30:00 +0000</pubDate><guid>https://blog.zwindler.fr/2020/02/24/transparent-hugepages-mesurer-limpact-sur-les-performances/</guid><description>&lt;img src="https://blog.zwindler.fr/2020/02/thp_nothp-1.webp" alt="Featured image of post Transparent Hugepages : mesurer l’impact sur les performances" /&gt;&lt;h2 id="encore-les-transparent-hugepages-"&gt;Encore les Transparent Hugepages ?
&lt;/h2&gt;&lt;p&gt;Il y a quelques jours, j’ai posté un article pour vous aider à &lt;a class="link" href="https://blog.zwindler.fr/2020/02/10/redis-mongodb-rabbitmq-desactiver-les-transparent-huge-pages/" &gt;désactiver les Transparent Hugepages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A là suite de ça, Seboss666 (qui tient un &lt;a class="link" href="https://blog.seboss666.info/" target="_blank" rel="noopener"
&gt;super blog bien Geek/sysadmin comme j’aime&lt;/a&gt;) m’a fait remarquer en commentaire que j’expliquais surtout comment désactiver les THP. Mais je n’ai pas beaucoup parlé d’à quoi ça sert (à part que &lt;a class="link" href="https://blog.zwindler.fr/2016/10/26/comprendre-configurer-selinux-rhel-7/" &gt;c’est mal aimé, comme SELinux&lt;/a&gt;) et si ça a vraiment un impact sur les perfs.&lt;/p&gt;
&lt;p&gt;Il m’a passé un &lt;a class="link" href="https://alexandrnikitin.github.io/blog/transparent-hugepages-measuring-the-performance-impact/" target="_blank" rel="noopener"
&gt;article hyper intéressant, en anglais, sur le sujet&lt;/a&gt;. Comme je ne l’aurais pas mieux écris moi-même ET que le but du blog est d’être une ressource francophone, j’ai donc proposé à l’auteur, Alexandr Nikitin, de le traduire en français. Le voilà donc.&lt;/p&gt;
&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;TL;DR ce post a pour but d’expliquer en un mot ce que sont les Transparent Hugepages (THP), décrire les techniques qui seront utilisées pour mesurer leur impact sur les performances et enfin, montrer leur effet sur une application réelle.&lt;/p&gt;
&lt;p&gt;Il est inspiré par un &lt;a class="link" href="https://groups.google.com/forum/#!topic/mechanical-sympathy/sljzehnCNZU" target="_blank" rel="noopener"
&gt;thread a propos des Transparent Huge Pages sur le &amp;ldquo;Mechanical Sympathy group&amp;rdquo;&lt;/a&gt;. Ce thread expose les pièges, les problématiques de performances ainsi que l’état actuel dans les dernières versions du kernel. Une grosse quantité d’information peut y être trouvé.&lt;/p&gt;
&lt;p&gt;En général, vous allez trouver beaucoup de recommendations sur Internet à propos des Transparent Hugepages. La plupart d’entre eux vous diront de désactiver totalement les THP, comme Oracle Database (lien mort), &lt;a class="link" href="https://docs.mongodb.com/manual/tutorial/transparent-huge-pages/" target="_blank" rel="noopener"
&gt;MongoDB&lt;/a&gt;, &lt;a class="link" href="https://web.archive.org/web/20171212085403/https://developer.couchbase.com/documentation/server/current/install/thp-disable.html" target="_blank" rel="noopener"
&gt;Couchbase (lien mort, j&amp;rsquo;utilise Internet Archive)&lt;/a&gt;, MemSQL (lien mort), &lt;a class="link" href="http://doc.nuodb.com/Latest/Content/Note-About-%20Using-Transparent-Huge-Pages.htm" target="_blank" rel="noopener"
&gt;NuoDB&lt;/a&gt;. Certains logiciels utilise la fonctionnalité, comme par exemple &lt;a class="link" href="https://www.postgresql.org/docs/9.6/static/kernel-resources.html#LINUX-HUGE-PAGES" target="_blank" rel="noopener"
&gt;PostgreSQL&lt;/a&gt; (la fonctionnalité hugetlbpage, pas exactement les THP) et &lt;a class="link" href="https://my.vertica.com/docs/7.2.x/HTML/index.htm#Authoring/InstallationGuide/BeforeYouInstall/transparenthugepages.htm" target="_blank" rel="noopener"
&gt;Vertica&lt;/a&gt;. Il existe beaucoup de retours d’expériences de professionnels qui ont eu à se battre contre des freeze de leur système et l’ont &amp;ldquo;corrigé&amp;rdquo; simplement en désactivant les THP. &lt;a class="link" href="https://www.perforce.com/blog/tales-field-taming-transparent-huge-pages-linux" target="_blank" rel="noopener"
&gt;1&lt;/a&gt;, &lt;a class="link" href="https://community.microfocus.com/borland/managetrack/accurev/w/accurev_knowledge_base/27749/recommendation-to-disable-linux-kernel-transparent-hugepages-thp-setting-for-performance-improvement" target="_blank" rel="noopener"
&gt;2&lt;/a&gt;, &lt;a class="link" href="https://web.archive.org/web/20200702063613/http://structureddata.org/2012/06/18/linux-6-transparent-huge-pages-and-hadoop-workloads/" target="_blank" rel="noopener"
&gt;3 (lien mort, j&amp;rsquo;utilise Internet Archive)&lt;/a&gt;, &lt;a class="link" href="https://blogs.oracle.com/linux/performance-issues-with-transparent-huge-pages-thp" target="_blank" rel="noopener"
&gt;4&lt;/a&gt;, &lt;a class="link" href="https://www.percona.com/blog/why-tokudb-hates-transparent-hugepages/" target="_blank" rel="noopener"
&gt;5&lt;/a&gt;, &lt;a class="link" href="https://engineering.linkedin.com/performance/optimizing-linux-memory-management-low-latency-high-throughput-databases" target="_blank" rel="noopener"
&gt;6&lt;/a&gt;. Toutes ces histoires tendent à propager une vision faussée et le préjugé que cette fonctionnalité est dangereuse.&lt;/p&gt;
&lt;p&gt;Malheureusement, je n’ai pas trouvé de post qui mesure ou montre comment mesurer l’impact et les conséquences d’activer ou de désactiver cette fonctionnalité. C’est ce que ce post va tenter de répondre.&lt;/p&gt;
&lt;h2 id="les-transparent-hugepages-en-bref-presque"&gt;Les Transparent Hugepages en bref (presque)
&lt;/h2&gt;&lt;p&gt;Pour fonctionner, presque toutes les applications et les systèmes d’exploitation nécessitent de la mémoire &amp;ldquo;virtuelle&amp;rdquo;. La mémoire virtuelle de tous les logiciels est ensuite mappée dans la mémoire physique. Ce mapping est géré par le système d’exploitation, qui maintient &lt;a class="link" href="https://en.wikipedia.org/wiki/Page_table" target="_blank" rel="noopener"
&gt;une structure de donnée en RAM (page table)&lt;/a&gt;. Pour passer de l’adresse virtuelle à l’adresse physique (page table walking), &lt;a class="link" href="https://fr.wikipedia.org/wiki/Unit%C3%A9_de_gestion_m%C3%A9moire" target="_blank" rel="noopener"
&gt;on utilise un composant du CPU (la MMU)&lt;/a&gt;. En plus de servir de table de traduction, la MMU sert également de cache des pages récemment utilisées. On appelle ce cache le Translation lookaside buffer (TLB).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lorsqu’une adresse virtuelle doit être traduite dans une adresse physique, on cherche d’abord dans le TLB. Si un résultat est trouvé (TLB hit), l’adresse physique est retournée et l’accès à la mémoire peut continuer. Cependant, si on ne trouve pas de résultat (TLB miss), la MMU va devoir rechercher le mapping de l’adresse dans la table de pages (page table) si il existe.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ce processus de &amp;ldquo;page table walk&amp;rdquo; est coûteux en temps car il peut nécessiter plusieurs accès à la mémoire (cependant, avec de la chance on peut retrouver la page mémoire dans un des caches L1/L2/L3 du CPU). Cependant, on ne peut pas non plus compter tout le temps sur le TLB car sa taille est limitée (généralement quelques centaines de pages, au maximum).&lt;/p&gt;
&lt;p&gt;Les systèmes d’exploitation gèrent la mémoire virtuelle en utilisant des pages (des blocks contigus de mémoire). Généralement, la taille d’une page mémoire est de 4 Ko. Petite règle de trois, 1 Go de RAM équivaut à 256000 pages, et 128 Go à 32,7 millions de pages. Clairement, on ne va pas pouvoir tout stocker dans le TLB et nous allons donc souffrir de problèmes de performances à cause des &amp;ldquo;TLB miss&amp;rdquo;. Il y a deux façons d’améliorer cette situation. La première est d’augmenter la taille du TLB. Cependant, c’est coûteux et l’impact n’est pas significatif, surtout sur les systèmes disposant d’une très grande quantité de RAM. La seconde consiste à augmenter la taille d’une page est ainsi, avoir moins de pages à mapper. Les OS et les CPUs modernes sont typiquement capable de supporter des pages &amp;ldquo;larges&amp;rdquo; de 2 Mo, voire même de 1 Go. Ainsi, avec des pages de 2 Mo, 128 Go de RAM devient seulement 64000 pages.&lt;/p&gt;
&lt;p&gt;Ce n’est pas pour rien que Linux supporte les Transparent Hugepages. C’est une optimisation ! Cela permet de gérer un grand nombre de pages de manière automatique et transparente pour les applications. Les bénéfices sont évidents : pas de modification à faire du coté des application, le nombre de &amp;ldquo;TLB miss&amp;rdquo; est réduit, le &amp;ldquo;page table walking&amp;rdquo; devient moins coûteux. Cette fonctionnalité peut être découpée en deux parties : allocation et maintenance.&lt;/p&gt;
&lt;p&gt;Le THP fonctionne de la même manière pour ce qui est de l’allocation de la mémoire et nécessite que le système d’exploitation trouve des blocs alignés et contigus de mémoire. Dans ce cas précis, il souffre également des mêmes problèmes que les pages de mémoire classiques, à savoir la fragmentation. Si l’OS ne sait pas trouver de blocs de mémoire continus, il va essayer de &amp;ldquo;compacter&amp;rdquo;, réclamer les partions inutilisées ou &amp;ldquo;page out&amp;rdquo; les autres pages. Ce processus est couteux et peut provoquer de grosses latences (jusqu’à quelques secondes). Heureusement, ce problème a été adressé dans la &lt;em&gt;version 4.6 du kernel Linux&lt;/em&gt; (avec l’option defer) ; l’OS retourne dans le mode classique (page de 4K) si jamais il ne trouve pas de place pour une hugepage.&lt;/p&gt;
&lt;p&gt;La deuxième partie est la maintenance. Si une application ne modifie ne serait ce qu’un seul octet de mémoire, elle va consommer la taille d’une page entière, à savoir 2 Mo si on utilise des hugepages, ce qui est clairement un gaspillage de mémoire vive. Pour palier à ça, il existe une tâche de fond qui s’appelle khugepaged. Ce processus scanne les pages et essaye de défragmenter et concaténer toutes les pages presque vides dans une seule page. Cependant, même si c’est une tâche de fond, elle va bloquer les pages sur lesquelles elle fonctionne, ce qui peut aussi provoquer des pic de latence. Un dernier problème reste qu’il est parfois nécessaire de découper les grosses pages, car tous les composants de l’OS ne supportent pas les hugepages. C’est le cas de la swap par exemple. L’OS doit alors découper les grosses pages en plus petites pour ces composants là. Encore une fois, cette opération peut dans certain cas dégrader les performances et augmenter la fragmentation.&lt;/p&gt;
&lt;p&gt;Le meilleur endroit pour apprendre comment fonctionnent les Transparent Hugepage est évidemment &lt;a class="link" href="https://www.kernel.org/doc/Documentation/vm/transhuge.txt" target="_blank" rel="noopener"
&gt;la documentation officielle du Kernel Linux&lt;/a&gt;. Cette fonctionnalité dispose de plusieurs éléments de configuration ainsi que des flags pour modifier son comportement. Ils évoluent avec le Kernel lui même.&lt;/p&gt;
&lt;h2 id="comment-le-mesurer-"&gt;Comment le mesurer ?
&lt;/h2&gt;&lt;p&gt;C’est probablement la partie la plus importante de ce post. Basiquement, il y a deux façon de mesurer l’impact de cette fonctionnalité : les CPU counters et les kernel functions.&lt;/p&gt;
&lt;h3 id="cpu-counters"&gt;CPU counters
&lt;/h3&gt;&lt;p&gt;Commençons par les CPU counters. J’utilise &lt;em&gt;perf&lt;/em&gt;, qui est un outil génial et simple pour réaliser ce genre de mesures. &lt;em&gt;Perf&lt;/em&gt; dispose nativement d’alias pour les événements du TLB : dTLB-loads, dTLB-load-misses pour les hit et les miss en load; dTLB-stores, dTLB-store-misses (idem mais pour les stores).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e dTLB-loads,dTLB-load-misses,dTLB-stores,dTLB-store-misses -a -I 1000
# time counts unit events
1.006223197 85,144,535 dTLB-loads
1.006223197 1,153,457 dTLB-load-misses # 1.35% of all dTLB cache hits
1.006223197 153,092,544 dTLB-stores
1.006223197 213,524 dTLB-store-misses
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et la même chose pour les instructions (iTLB-load, iTLB-load-misses).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e iTLB-load,iTLB-load-misses -a -I 1000
# time counts unit events
1.005591635 5,496 iTLB-load
1.005591635 18,799 iTLB-load-misses # 342.05% of all iTLB cache hits
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;En réalité, perf supporte seulement un petit sous ensemble de tous les événements alors que les CPUs ont des centaines de compteurs pour évaluer la performance. Pour les CPUs Intels par exemple, on peut trouver la liste de tous les compteurs disponibles sur le site &lt;a class="link" href="https://download.01.org/perfmon/index/" target="_blank" rel="noopener"
&gt;Intel Processor Event Reference&lt;/a&gt;, dans le &lt;a class="link" href="https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3b-part-2-manual.html" target="_blank" rel="noopener"
&gt;Intel® 64 and IA-32 Architectures Developer’s Manual: Vol. 3B&lt;/a&gt; ou bien encore dans &lt;a class="link" href="https://github.com/torvalds/linux/blob/510c8a899caf095cb13d09d203573deef15db2fe/tools/perf/pmu-events/arch/x86/haswell/virtual-memory.json" target="_blank" rel="noopener"
&gt;les sources du Kernel Linux&lt;/a&gt;. Le manuel du développeur contient également des codes d’événements que nous devons passer pour analyser les performances.&lt;/p&gt;
&lt;p&gt;Si on regarde les compteurs relatifs au TLB, voilà ce qu’on peut trouver d’intéressant :&lt;/p&gt;
&lt;table class=""&gt;
&lt;tr&gt;
&lt;th&gt;
Mnemonic
&lt;/th&gt;
&lt;th&gt;
Description
&lt;/th&gt;
&lt;th&gt;
Event Num.
&lt;/th&gt;
&lt;th&gt;
Umask Value
&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK
&lt;/td&gt;
&lt;td&gt;
Misses in all TLB levels that cause a page walk of any page size.
&lt;/td&gt;
&lt;td&gt;
08H
&lt;/td&gt;
&lt;td&gt;
01H
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
DTLB_STORE_MISSES.MISS_CAUSES_A_WALK
&lt;/td&gt;
&lt;td&gt;
Miss in all TLB levels causes a page walk of any page size.
&lt;/td&gt;
&lt;td&gt;
49H
&lt;/td&gt;
&lt;td&gt;
01H
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
DTLB_LOAD_MISSES.WALK_DURATION
&lt;/td&gt;
&lt;td&gt;
This event counts cycles when the page miss handler (PMH) is servicing page walks caused by DTLB load misses.
&lt;/td&gt;
&lt;td&gt;
08H
&lt;/td&gt;
&lt;td&gt;
10H
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
ITLB_MISSES.MISS_CAUSES_A_WALK
&lt;/td&gt;
&lt;td&gt;
Misses in ITLB that causes a page walk of any page size.
&lt;/td&gt;
&lt;td&gt;
85H
&lt;/td&gt;
&lt;td&gt;
01H
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
ITLB_MISSES.WALK_DURATION
&lt;/td&gt;
&lt;td&gt;
This event counts cycles when the page miss handler (PMH) is servicing page walks caused by ITLB misses.
&lt;/td&gt;
&lt;td&gt;
85H
&lt;/td&gt;
&lt;td&gt;
10H
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
PAGE_WALKER_LOADS.DTLB_MEMORY
&lt;/td&gt;
&lt;td&gt;
Number of DTLB page walker loads from memory.
&lt;/td&gt;
&lt;td&gt;
BCH
&lt;/td&gt;
&lt;td&gt;
18H
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
PAGE_WALKER_LOADS.ITLB_MEMORY
&lt;/td&gt;
&lt;td&gt;
Number of ITLB page walker loads from memory.
&lt;/td&gt;
&lt;td&gt;
BCH
&lt;/td&gt;
&lt;td&gt;
28H
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Perf&lt;/em&gt; supporte le compteur &lt;code&gt;*MISS_CAUSES_A_WALK&lt;/code&gt; via un alias. Mais nous devrons trouver l’identifiant numérique des autres événements pour les passer en arguments. Point important, les numéros d’événements et les valeurs &lt;em&gt;umask&lt;/em&gt; associées dépendent de chaque CPU. Par exemple, la liste ci dessus est spécifique à l’architecture Intel Haswell ! Il vous sera nécessaire d’adapter ces codes à votre CPU.&lt;/p&gt;
&lt;p&gt;Une des métriques clé est le nombre de cycle CPU passés à faire du page table walking :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e cycles \
&amp;gt; -e cpu/event=0x08,umask=0x10,name=dcycles/ \
&amp;gt; -e cpu/event=0x85,umask=0x10,name=icycles/ \
&amp;gt; -a -I 1000
# time counts unit events
1.005079845 227,119,840 cycles
1.005079845 2,605,237 dcycles
1.005079845 806,076 icycles
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Une autre métrique importante est le nombre de lecture mémoire qui causent des TLB miss ; ces lectures ne profitent pas du cache CPU et sont donc coûteuses :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e cache-misses \
&amp;gt; -e cpu/event=0xbc,umask=0x18,name=dreads/ \
&amp;gt; -e cpu/event=0xbc,umask=0x28,name=ireads/ \
&amp;gt; -a -I 1000
# time counts unit events
1.007177568 25,322 cache-misses
1.007177568 23 dreads
1.007177568 5 ireads
...
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="kernel-functions"&gt;Kernel functions
&lt;/h3&gt;&lt;p&gt;Une autre façon surpuissante de mesurer l’impact des THP sur les performances et la latence est d’utiliser les fonctions de tracing/probing du Kernel Linux. J’utilise &lt;a class="link" href="https://sourceware.org/systemtap/" target="_blank" rel="noopener"
&gt;SystemTap&lt;/a&gt; pour ça, qui est un outil pour instrumenter dynamiquement les systèmes Linux en production.&lt;/p&gt;
&lt;p&gt;La première fonction intéressante pour le cas qui nous intéresse est &lt;code&gt;__alloc_pages_slowpath&lt;/code&gt;. Elle est exécutée lorsqu’il n’y a pas de bloc contigu de mémoire vive disponible lors d’une allocation. A son tour, cette fonction appelle la fonction de &amp;ldquo;récupération&amp;rdquo; et de &amp;ldquo;compaction&amp;rdquo; des pages, qui je le rappelle est une opération très couteuse qui peut engendrer des pics de latence.&lt;/p&gt;
&lt;p&gt;La seconde fonction intéressante est &lt;code&gt;khugepaged_scan_mm_slot&lt;/code&gt;. Elle est exécutée en tâche de fond par le thread &lt;em&gt;khugepaged&lt;/em&gt; du Kernel. Ce thread scanne les &lt;em&gt;hugepages&lt;/em&gt; et essaye de les compacter en une seule.&lt;/p&gt;
&lt;p&gt;J’utilise un script SystemTap pour mesurer le temps d’exécution d’une fonction. Ce script stocke tous les temps d’exécution en microsecondes et affiche périodiquement un histogramme. Il ne consomme que quelques Mo par heure, en fonction du nombre d’exécutions. Le premier argument est la sonde à utiliser, le second est un nombre (en ms) pour afficher les statistiques.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#! /usr/bin/env stap
global start, intervals
probe $1 { start[tid()] = gettimeofday_us() }
probe $1.return
{
t = gettimeofday_us()
old_t = start[tid()]
if (old_t) intervals &amp;lt;&amp;lt;&amp;lt; t - old_t
delete start[tid()]
}
probe timer.ms($2)
{
if (@count(intervals) &amp;gt; 0)
{
printf(&amp;#34;%-25s:\n min:%dus avg:%dus max:%dus count:%d \n&amp;#34;, tz_ctime(gettimeofday_s()),
@min(intervals), @avg(intervals), @max(intervals), @count(intervals))
print(@hist_log(intervals));
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Voici un exemple avec la fonction &lt;code&gt;__alloc_pages_slowpath&lt;/code&gt; :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# ./func_time_stats.stp &amp;#39;kernel.function(&amp;#34;__alloc_pages_slowpath&amp;#34;)&amp;#39; 1000
Thu Aug 17 09:37:19 2017 CEST:
min:0us avg:1us max:23us count:1538
value |-------------------------------------------------- count
0 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 549
1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 541
2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 377
4 |@@@@ 54
8 |@ 12
16 | 5
32 | 0
64 | 0
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Il est également intéressant de savoir observer l’état général de l’OS. Un bon exemple peut être la fragmentation de la mémoire. &lt;strong&gt;/proc/buddyinfo&lt;/strong&gt; est un outil utilise pour aider au diagnostic dans ce genre de cas. &lt;strong&gt;Buddyinfo&lt;/strong&gt; va nous donner des pistes pour estimer la taille maximale que l’on peut allouer sans risque, ou pourquoi la précédent allocation a échoué par exemple. De même, on peut aussi trouver des informations utiles dans &lt;strong&gt;/proc/pagetypeinfo&lt;/strong&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cat /proc/buddyinfo
cat /proc/pagetypeinfo
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Vous pouvez en apprendre plus en lisant &lt;a class="link" href="https://elixir.bootlin.com/linux/v3.10.107/source/Documentation/filesystems/proc.txt" target="_blank" rel="noopener"
&gt;la documentation officielle (lien mort, j&amp;rsquo;utilise Internet Archive)&lt;/a&gt; ou alors en lisant &lt;a class="link" href="http://andorian.blogspot.lt/2014/03/making-sense-of-procbuddyinfo.html" target="_blank" rel="noopener"
&gt;cet article&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="jvm"&gt;JVM
&lt;/h2&gt;&lt;p&gt;La JVM supporte les Transparent Hugepages via l’ajout de l’option &lt;code&gt;-XX:+UseTransparentHugePages&lt;/code&gt;. Cependant, on aura alors un message d’avertissement contre de possibles problèmes de performance :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;-XX:+UseTransparentHugePages On Linux, enables the use of large pages that can dynamically grow or shrink. This option is disabled by default. You may encounter performance problems with transparent huge pages as the OS moves other pages around to create huge pages; this option is made available for experimentation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Il est intéressant d’activer l’usage des large pages pour le &amp;ldquo;Metaspace&amp;rdquo; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;-XX:+UseLargePagesInMetaspace Use large page memory in metaspace. Only used if UseLargePages is enabled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;De plus, utiliser l’option -XX:+AlwaysPreTouch avec les hugepages peut être une bonne idée. Cela permet de réallouer toute la mémoire physique utilisé par le tas (heap) et ainsi éviter une surcharge supplémentaire due à l’initialisation ou à la compaction. Cependant, cela induira une augmentation du temps nécessaire pour initialiser la JVM.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;-XX:+AlwaysPreTouch Enables touching of every page on the Java heap during JVM initialization. This gets all pages into the memory before entering the main() method. The option can be used in testing to simulate a long-running system with all virtual memory mapped to physical memory. By default, this option is disabled and all pages are committed as JVM heap space fills.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Aleksey Shipilёv montre l’impact sur la performance dans son article de post &lt;a class="link" href="https://shipilev.net/jvm-anatomy-park/2-transparent-huge-pages/" target="_blank" rel="noopener"
&gt;JVM Anatomy Park #2: Transparent Huge Pages&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="un-exemple-de-la-vie-réelle--une-jvm-très-chargée"&gt;Un exemple de la vie réelle : une JVM très chargée
&lt;/h2&gt;&lt;p&gt;Regardons maintenant quel impact ont réellement les Transparent Hugepages sur une application réelle. Prenons une application lancée dans une JVM : un serveur TCP basé sur netty et recevant un trafic important. Le serveur reçoit jusqu’à 100k requêtes par secondes, analyse chaque requête, effectue un appel réseau à une base de données pour chacun des appels, fait un certain nombre de calculs dessus, puis retourne un réponse. L’application en question possède une heapsize de 200 Go. Les mesures ont été réalisées sur des serveurs de production, ainsi que la charge réelle de production. Les serveurs n’étaient pas surchargés et recevaient 50% du nombre maximal de requêtes qu’ils étaient capables de traiter.&lt;/p&gt;
&lt;h3 id="transparent-hugepages-désactivées"&gt;Transparent Hugepages désactivées
&lt;/h3&gt;&lt;p&gt;Désactivons les THP :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled
echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;La première chose à faire et de mesurer les TLB misses. Ici on a environ 130 millions de TLB misses. Le ratio Miss/Hit est de 1% (ce qui ne semble pas énorme, au premier abord).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e dTLB-loads,dTLB-load-misses,iTLB-load-misses,dTLB-store-misses -a -I 1000
# time counts unit events
...
10.007352573 9,426,212,726 dTLB-loads
10.007352573 99,328,930 dTLB-load-misses # 1.04% of all dTLB cache hits
10.007352573 26,021,651 iTLB-load-misses
10.007352573 10,955,696 dTLB-store-misses
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Cependant, regardons plus précisément combien nous ont coûté en temps CPU ces TLB misses :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e cycles \
&amp;gt; -e cpu/event=0x08,umask=0x10,name=dcycles/ \
&amp;gt; -e cpu/event=0x85,umask=0x10,name=icycles/ \
&amp;gt; -a -I 1000
# time counts unit events
...
12.007998332 61,912,076,685 cycles
12.007998332 5,615,887,228 dcycles
12.007998332 1,049,159,484 icycles
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Oui, vous avez bien vu ! Plus de 10% des cycles CPUs sont utilisés pour parcourir la page table.&lt;/p&gt;
&lt;p&gt;Le compteur suivant montre que nous avons 1 million de lectures RAM causées par des TLB misses (sachant que chacunes de ces lectures coûtent 100 ns chacunes) :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e cpu/event=0xbc,umask=0x18,name=dreads/ \
&amp;gt; -e cpu/event=0xbc,umask=0x28,name=ireads/ \
&amp;gt; -a -I 1000
# time counts unit events
...
6.003683030 1,087,179 dreads
6.003683030 100,180 ireads
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Tous les nombres que je viens de vous montrer sont intéressants, mais ils ne sont pas vraiment &amp;ldquo;exploitables&amp;rdquo;. Les métriques les plus importantes pour un développeur d’application sont les métriques de l’application elle-même. Regardons donc comment la métrique de la latence end-to-end de l’application. Voilà les mesures (en microsecondes) qui ont été récoltées pendant quelques minutes :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;#34;max&amp;#34; : 16414.672,
&amp;#34;mean&amp;#34; : 1173.2799067016406,
&amp;#34;min&amp;#34; : 52.112,
&amp;#34;p50&amp;#34; : 696.885,
&amp;#34;p75&amp;#34; : 1353.116,
&amp;#34;p95&amp;#34; : 3769.844,
&amp;#34;p98&amp;#34; : 5453.675,
&amp;#34;p99&amp;#34; : 6857.375,
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="transparent-hugepages-activées"&gt;Transparent Hugepages activées
&lt;/h2&gt;&lt;p&gt;Maintenant on va pouvoir commencer à faire des comparaisons ! Activons les THP :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;echo always &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled
echo always &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag # consider other options too
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et lançons la JVM avec les options &lt;code&gt;-XX:+UseTransparentHugePages&lt;/code&gt;, &lt;code&gt;-XX:+UseLargePagesInMetaspace&lt;/code&gt; et &lt;code&gt;-XX:+AlwaysPreTouch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La première métrique que nous avions collecté (les TLB misses) ont été divisés par 6, passant de 130 millions à environ 20 millions. Mathématiquement, le ratio miss/hit tombe de 1% à 0,15%. Voici les nombres exacts :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e dTLB-loads,dTLB-load-misses,iTLB-load-misses,dTLB-store-misses -a -I 1000
# time counts unit events
1.002351984 10,757,473,962 dTLB-loads
1.002351984 15,743,582 dTLB-load-misses # 0.15% of all dTLB cache hits
1.002351984 4,208,453 iTLB-load-misses
1.002351984 1,235,060 dTLB-store-misses
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Les cycles CPU passés à parcourir la page table ont également diminué d’un facteur 5, d’environ 6,7 milliards à 1,3 milliards. Cette fois ci, nous avons donc utilisé seulement 2% de notre CPU à réaliser du &amp;ldquo;page table walking&amp;rdquo; :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e cycles \
&amp;gt; -e cpu/event=0x08,umask=0x10,name=dcycles/ \
&amp;gt; -e cpu/event=0x85,umask=0x10,name=icycles/ \
&amp;gt; -a -I 1000
# time counts unit events
...
8.006641482 55,401,975,112 cycles
8.006641482 1,133,196,162 dcycles
8.006641482 167,646,297 icycles
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et enfin, le nombre de lecture en RAM a diminué de 1 million à 350k&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# perf stat -e cpu/event=0xbc,umask=0x18,name=dreads/ \
&amp;gt; -e cpu/event=0xbc,umask=0x28,name=ireads/ \
&amp;gt; -a -I 1000
# time counts unit events
...
12.007351895 342,228 dreads
12.007351895 17,242 ireads
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Tout ça c’est bien beau, mais, une fois encore, les nombres qui vont le plus nous intéresser, c’est l’effet réel que ça va avoir sur notre application. Voici les chiffres de la latence end-to-end de l’application :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;#34;max&amp;#34; : 16028.281,
&amp;#34;mean&amp;#34; : 946.232869010599,
&amp;#34;min&amp;#34; : 41.977000000000004,
&amp;#34;p50&amp;#34; : 589.297,
&amp;#34;p75&amp;#34; : 1080.305,
&amp;#34;p95&amp;#34; : 2966.102,
&amp;#34;p98&amp;#34; : 4288.5830000000005,
&amp;#34;p99&amp;#34; : 5918.753,
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;La différence entre les deux runs sur les 95 percentiles est quasiment de 1 milliseconde ! Voici ce que cela représente visuellement :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2020/02/grafana.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Source : &lt;a class="link" href="https://alexandrnikitin.github.io/blog/images/transparent-hugepages-measuring-the-performance-impact/grafana.png" target="_blank" rel="noopener"
&gt;https://alexandrnikitin.github.io/blog/images/transparent-hugepages-measuring-the-performance-impact/grafana.png&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nous venons donc de mesurer l’amélioration apportée par l’activation des Transparent Hugepages. Cependant, nous savons que l’activation des THP peut avoir un impact sur les performances (à cause de l’overhead de la &amp;ldquo;maintenance&amp;rdquo; que nous avons expliqué plus haut) ainsi que les risques de pic de latence. Nous devons donc également les mesurer. Regardons le thread &lt;code&gt;kernel khugepaged&lt;/code&gt; qui s’occupe de la défragmentation des hugepages. La mesure qui suit a été réalisée sur une durée d’environ 24 heures. Comme vous pouvez le constater, le temps maximum d’exécution est de 6 millisecondes et il y a de nombreuses exécutions qui ont pris moins d’une milliseconde. Si ce processus est en tâche de fond, mais il bloque les pages concernées pendant qu’il travaille dessus. Voici l’histogramme :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# ./func_time_stats.stp &amp;#39;kernel.function(&amp;#34;khugepaged_scan_mm_slot&amp;#34;)&amp;#39; 60000 -o khugepaged_scan_mm_slot.log
[~]# tail khugepaged_scan_mm_slot.log
Thu Aug 17 13:38:59 2017 CEST:
min:0us avg:321us max:6382us count:10834
value |-------------------------------------------------- count
0 |@ 164
1 |@ 197
2 |@@@ 466
4 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6074
8 |@@@@@@ 761
16 |@@ 318
32 | 65
64 | 13
128 | 1
256 | 3
512 |@@@ 463
1024 |@@@@@@@@@@@@@@@@@@ 2211
2048 | 85
4096 | 13
8192 | 0
16384 | 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Une autre fonction important du kernel est &lt;code&gt;__aloc_pages_slowpath&lt;/code&gt;. Cette fonction aussi peut provoquer des pics de latence si un block contigue de mémoire n’est pas disponible. Lors de la mesure, l’histogramme est bien meilleur ici. Le temps maximum d’allocation était de 288 microsecondes. Même en le faisant tourner pendant des heures voire même des jours, nous sommes devenus confiant dans le fait que cette fonctionnalité n’allait pas provoquer de longs pics de latence.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[~]# ./func_time_stats.stp &amp;#39;kernel.function(&amp;#34;__alloc_pages_slowpath&amp;#34;)&amp;#39; 60000 -o alloc_pages_slowpath.log
[~]# tail alloc_pages_slowpath.log
Tue Aug 15 10:35:03 2017 CEST:
min:0us avg:2us max:288us count:6262185
value |-------------------------------------------------- count
0 |@@@@ 237360
1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2308083
2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2484688
4 |@@@@@@@@@@@@@@@@@@@@@@ 1136503
8 |@ 72701
16 | 22353
32 | 381
64 | 7
128 | 105
256 | 4
512 | 0
1024 | 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Alors comment se fait il que les Transparents Hugepages fonctionnent aussi bien dans ce cas précis ? D’abord, on remarque un amélioration significative de la performance car dans ce cas précis on travaille avec une grande quantité de RAM. De même, on ne remarque pas de pics de latences car il n’y a pas de surcharge en terme de RAM sur le serveur. Il y a beaucoup de RAM (256 Go), la JVM sait tirer partie des THP, pré-alloue la totalité des 200 Go de heap dès le démarrage et ne la redimensionne jamais.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Ne suivez pas aveuglément les recommandation que vous trouvez sur Internet ! Mesurez, mesurez, mesurez encore !&lt;/p&gt;
&lt;p&gt;Les Transparent Hugepages sont une optimisation et qui peut avoir de réelles conséquences positives sur la performance, mais avec des inconvénients et des risques qui peuvent entrainer des conséquences imprévues. Le but de ce post était de donner les clés pour mesurer les gains potentiels et gérer les risques. Le Kernel Linux et ces fonctionnalités évoluent et certains des problèmes des THP ont été adressés dans les dernières versions, comme par exemple l’option &amp;ldquo;defer&amp;rdquo; de la défragmentation, qui permet à l’OS de repasser sur une allocation de taille normale, si jamais il n’est pas possible d’en allouer une large.&lt;/p&gt;
&lt;p&gt;Note de zwindler : Encore merci à l’auteur (&lt;a class="link" href="https://alexandrnikitin.github.io/blog/transparent-hugepages-measuring-the-performance-impact/" target="_blank" rel="noopener"
&gt;Alexandr Nikitin&lt;/a&gt;) pour son article, qui m’a appris beaucoup de choses !&lt;/p&gt;</description></item><item><title>Bug : unable to execute QEMU command &amp;lsquo;cont’ sous KVM et RHEL/CentOS</title><link>https://blog.zwindler.fr/2015/10/10/bug-unable-to-execute-qemu-command-cont-sous-kvm-et-rhelcentos/</link><pubDate>Sat, 10 Oct 2015 10:30:00 +0000</pubDate><guid>https://blog.zwindler.fr/2015/10/10/bug-unable-to-execute-qemu-command-cont-sous-kvm-et-rhelcentos/</guid><description>&lt;img src="https://blog.zwindler.fr/2015/10/kvm.webp" alt="Featured image of post Bug : unable to execute QEMU command &amp;lsquo;cont’ sous KVM et RHEL/CentOS" /&gt;&lt;p&gt;Cet article est encore un vieil article que je n’ai jamais pris le temps de sortir. Voilà maintenant c’est fait ;-)&lt;/p&gt;
&lt;h2 id="bug-unable-to-execute-qemu-command-cont"&gt;Bug unable to execute QEMU command ‘cont’
&lt;/h2&gt;&lt;p&gt;Aussi rare que cela soit, après ma migration de KVM sur Ubuntu a KVM sur CentOS, je suis tombé sur un bug du Kernel Linux qui affectait directement ma capacité à faire fonctionner des machines virtuelles sous Windows 7 ou Windows 2008 ! Mais toutes les autres fonctionnaient normalement.&lt;/p&gt;
&lt;h3 id="symptôme"&gt;Symptôme
&lt;/h3&gt;&lt;p&gt;Lorsqu’on démarre la VM ou qu’elle démarre seule au boot, elle se met en pause. Si on essaye de la sortir du mode pause on reçoit l’erreur suivante.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Error unpausing domain: internal error unable to execute QEMU command ‘cont’: Resetting the Virtual Machine is required&amp;lt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;L’erreur en elle même n’est pas très explicite. Dans le log de la machine virtuelle en question, on a un message plus long mais guère plus évocateur :&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;/var/log/libvirt/qemu/[maVM]
kvm: unhandled exit 80000021
kvm_run returned -22
If you’re running a guest on an Intel machine without unrestricted mode
support, the failure can be most likely due to the guest entering an invalid
state for Intel VT. For example, the guest maybe running in big real mode
which is not supported on less recent Intel processors.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Bien évidemment, toutes les autres VMs sous Linux fonctionnent parfaitement donc on ne peut pas accuser Qemu de ne pas fonctionner correctement.&lt;/p&gt;
&lt;h3 id="solution"&gt;Solution
&lt;/h3&gt;&lt;p&gt;En théorie, j’ai lu à plusieurs endroits que le bug était censé être corrigés sur des patchs des kernels de CentOS 5 ou 6 (toujours présent en 2.6.32-431.3.1.el6.x86_64 par exemple) et même pour Ubuntu.&lt;br&gt;
Dans la pratique, même en mettant l’OS CentOS à jour, impossible de faire fonctionner cette VM.&lt;br&gt;
La seule vrai solution que j’avais trouvé à l’époque était de forcer le passage à un kernel plus récent, à savoir au moins 3.+.&lt;/p&gt;
&lt;p&gt;Pour ceux qui se sentiraient un peu perdu, le plus simple est de changer de version de CentOS ou d’Ubuntu. Sur les dernière version le bug n’est plus présent.&lt;/p&gt;
&lt;p&gt;Cependant, si vous avez un système en place et qu’une migration n’est pas à l’ordre du jour, voici la marche à suivre pour installer un kernel plus récent. Voici la procédure que j’ai utilisée pour installer un 3.13 sur lequel la VM fonctionne à nouveau (3.11 fonctionne aussi, je ne sais pas avant).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;yum install gcc ncurses ncurses-devel
yum update
wget https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.13.1.tar.gz
tar xzf linux-3.13.1.tar.gz -C /usr/src/
cd /usr/src/linux-3.13.1/
make menuconfig
make
make modules_install install
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;N’oubliez pas de vérifier que votre kernel est bien choisi en premier dans le boot loader, ce qui n’est souvent pas le cas par défaut (modifier la valeur &lt;strong&gt;default&lt;/strong&gt; dans le &lt;strong&gt;grub.conf&lt;/strong&gt; pour correspondre à la bonne entrée) sinon le problème ne sera pas résolu au reboot.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;vi /etc/grub.conf
default=X
[...]
root (hd0,0)
kernel /vmlinuz-3.13.1 ro root=/dev/mapper/vg_root-lv_root rd_LVM_LV=vg_root/lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_MD_UUID=8f43b4fe:e72ed9aa:2da568b5:5f43b223 SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=fr-latin9 rd_LVM_LV=vg_endeavour/lv_swap rd_NO_DM rhgb quiet
initrd /initramfs-3.13.1.img
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Et vous pouvez vérifier que vous êtes sur le bon kernel avec un uname.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;reboot
uname -r
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="erreurbug-error-starting-virt-manager"&gt;Erreur/bug Error starting virt-manager
&lt;/h2&gt;&lt;p&gt;En bonus track, je voudrais aussi ajouter un petit bug de plus pour la route, sur l’utilisation de l’interface graphique virt-manager cette fois ci.&lt;/p&gt;
&lt;p&gt;Pour une raison obscure, lorsque je voulais lancer ma GUI virt-manager, il m’est arrivé une ou deux fois de suivre la procédure décrite sur &lt;a class="link" href="http://nutanix.blogspot.fr/2013/06/kvm-virt-manager-startup-failure.html" target="_blank" rel="noopener"
&gt;le blog de nutanix&lt;/a&gt; lorsque je recevais l’erreur suivante :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Error starting virt-manager&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;dbus-uuidgen --get
cat /var/lib/dbus/machine-id
dbus-uuidgen &amp;gt; /var/lib/dbus/machine-id
&lt;/code&gt;&lt;/pre&gt;</description></item></channel></rss>