{"id":1359,"date":"2012-01-07T10:10:12","date_gmt":"2012-01-07T09:10:12","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=1359"},"modified":"2012-01-07T10:10:12","modified_gmt":"2012-01-07T09:10:12","slug":"linux-3-2-cfs-cpu-bandwidth","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2012\/01\/07\/linux-3-2-cfs-cpu-bandwidth\/","title":{"rendered":"Linux 3.2 &#8211; CFS CPU Bandwidth"},"content":{"rendered":"<p style=\"text-align: justify;\">(<a title=\"Linux 3.2 \u2013 CFS CPU bandwidth (english version)\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/01\/07\/linux-3-2-cfs-cpu-bandwidth-english-version\/\">English translation here<\/a>)<\/p>\n<p style=\"text-align: justify;\">Linus Torvalds a <a title=\"Linux 3.2\" href=\"http:\/\/article.gmane.org\/gmane.linux.kernel\/1235375\" target=\"_blank\">publi\u00e9<\/a> le noyau Linux 3.2 il y a deux jours. Ce dernier contient comme d&rsquo;habitude de nombreux ajouts. L&rsquo;un d&rsquo;eux a attir\u00e9 mon attention et j&rsquo;ai souhait\u00e9 observer son fonctionnement, il s&rsquo;agit du contr\u00f4leur de consommation CPU pour l&rsquo;ordonnanceur CFS.<\/p>\n<p>\n<!--more-->\n<\/p>\n<p style=\"text-align: justify;\">Il existait d\u00e9j\u00e0 de nombreux moyens de r\u00e9gler le pourcentage de CPU dont pouvait disposer une t\u00e2che par rapport aux autres pour l&rsquo;ordonnancement temps-partag\u00e9 (entre autres avec l&rsquo;appel-syst\u00e8me <code>setpriority()<\/code>, la commande en ligne <code>nice<\/code>, ou les param\u00e8tres du syst\u00e8mes de fichiers <code>\/sys\/fs\/cgroup\/cpu<\/code>). On pouvait ainsi attribuer facilement 25% du temps processeur \u00e0 une t\u00e2che et 75% \u00e0 une autre par exemple. Mais jusqu&rsquo;alors, si la seconde se terminait, la premi\u00e8re disposait alors de 100% du temps CPU.<\/p>\n<p style=\"text-align: justify;\">Autrement dit, la \u00ab\u00a0bande passante CPU\u00a0\u00bb d&rsquo;une t\u00e2che seule active \u00e9tait toujours de 100%. Il est \u00e0 pr\u00e9sent possible de modifier ceci afin de lui attribuer une portion plus r\u00e9duite du temps processeur, <strong>m\u00eame lorsqu&rsquo;elle est seule<\/strong>.<\/p>\n<p style=\"text-align: justify;\">Quel peut-\u00eatre l&rsquo;int\u00e9r\u00eat de r\u00e9duire la consommation CPU instantan\u00e9e d&rsquo;un processus&nbsp;? Pour les syst\u00e8mes courants, il faut bien l&rsquo;avouer, cet int\u00e9r\u00eat est r\u00e9duit. Mais il en va autrement pour certains gros serveurs o\u00f9 l&rsquo;on facture le temps processeur consomm\u00e9 mais \u00e9galement la puissance CPU mise \u00e0 disposition instantan\u00e9ment. Dans ces environnements il est tr\u00e8s int\u00e9ressant de limiter la puissance CPU dont disposera un processus quelle que soit la charge globale du syst\u00e8me.<\/p>\n<p style=\"text-align: justify;\">Un autre int\u00e9r\u00eat de cette limitation est de r\u00e9guler la disponibilit\u00e9 du CPU en \u00e9vitant les pointes de puissance et les brusques ralentissements. On peut imaginer\u00a0encore un environnement h\u00f4te sur lequel on est amen\u00e9 \u00e0 faire fonctionner simultan\u00e9ment plusieurs &#8211; disons 4 &#8211; \u00e9mulateurs (de type Qemu par exemple). En limitant \u00e0 25% la puissance CPU accord\u00e9e \u00e0 chacun d&rsquo;entre-eux, le comportement d&rsquo;un syst\u00e8me virtuel ne d\u00e9pendra pas de la pr\u00e9sence ou non d&rsquo;un autre \u00e9mulateur sur l&rsquo;h\u00f4te.<\/p>\n<h1>Mise en oeuvre<\/h1>\n<p style=\"text-align: justify;\">Il existe une nouvelle option de compilation que l&rsquo;on trouve dans le menu de configuration du kernel dans l&rsquo;arborescence suivante&nbsp;: \u00ab\u00a0<em>General Setup<\/em>\u00a0\u00bb &#8211; \u00ab\u00a0<em>Control Group support<\/em>\u00a0\u00bb &#8211; \u00ab\u00a0<em>Group CPU scheduler<\/em>\u00a0\u00bb &#8211; \u00ab\u00a0<em>CPU bandwith provisioning for FAIR_GROUP_SCHED<\/em>\u00ab\u00a0. Il est n\u00e9cessaire d&rsquo;activer toutes les options de ce chemin.<\/p>\n<p style=\"text-align: justify;\">Voici un <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-07\/config-linux-3.2-x86\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-07\/config-linux-3.2-x86\" target=\"_blank\">fichier de configuration<\/a> g\u00e9n\u00e9rique Linux 3.2 pour PC (provenant d&rsquo;une distribution Ubuntu 11.10) avec l&rsquo;option \u00ab\u00a0<em>CPU bandwidth provisioning<\/em>\u00a0\u00bb activ\u00e9e.<\/p>\n<p style=\"text-align: justify;\">Apr\u00e8s compilation et red\u00e9marrage sur le nouveau kernel, nous observons la pr\u00e9sence d&rsquo;un nouveau fichier\u00a0 <code>\/proc\/sys\/kernel\/sched_cfs_bandwidth_slice_us<\/code> qui indique la dur\u00e9e des tranches de temps employ\u00e9es lorsqu&rsquo;une t\u00e2che b\u00e9n\u00e9ficie d&rsquo;une puissance CPU reposant sur plusieurs processeurs. Par d\u00e9faut cette valeur est de 5 millisecondes.<\/p>\n<pre># <strong>cat \/proc\/sys\/kernel\/sched_cfs_bandwidth_slice_us<\/strong>\n5000\n#<\/pre>\n<p style=\"text-align: justify;\">Pour acc\u00e9der au param\u00e9trage de la puissance CPU accord\u00e9e \u00e0 un groupe ou \u00e0 une t\u00e2che nous devons passer par le syst\u00e8me de fichiers <em style=\"text-align: justify;\">cgroup<\/em> :<\/p>\n<pre># <strong>mount none \/sys\/fs\/cgroup -t tmpfs<\/strong>\n# <strong>mkdir \/sys\/fs\/cgroup\/cpu<\/strong>\n# <strong>mount none \/sys\/fs\/cgroup\/cpu\/ -t cgroup -o cpu<\/strong>\n# <strong>ls \/sys\/fs\/cgroup\/cpu\/<\/strong>\ncgroup.clone_children  cgroup.procs       cpu.cfs_quota_us  cpu.rt_runtime_us  cpu.stat           release_agent\ncgroup.event_control   cpu.cfs_period_us  cpu.rt_period_us  cpu.shares         notify_on_release  tasks\n#<\/pre>\n<h1>Essais<\/h1>\n<h2 style=\"text-align: justify;\">T\u00e2che unique<\/h2>\n<p style=\"text-align: justify;\">Pour verifier la puissance CPU accord\u00e9e \u00e0 une t\u00e2che nous allons cr\u00e9er un petit programme qui boucle ind\u00e9finiment, et affiche toutes les secondes sur sa sortie standard le nombre de boucles qu&rsquo;il a pu r\u00e9aliser durant la seconde \u00e9coul\u00e9e.<\/p>\n<pre><a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-07\/consomme-cpu.c\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-01-07\/consomme-cpu.c\" target=\"_blank\"><strong>consomme-cpu.c<\/strong>:<\/a>\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;time.h&gt;\n#include &lt;unistd.h&gt;\n\nint main(void)\n{\n    long long int compteur;\n    time_t debut = time(NULL);\n    \/\/ Attendre un debut de seconde\n    while (time(NULL) == debut)\n        ;\n    while (1) {\n        compteur = 0;\n        time (&amp; debut);\n        while (time(NULL) == debut)\n            compteur ++;\n        fprintf(stdout, \"[%u]%lldn\", getpid(), compteur);\n    }\n    return 0;\n}<\/pre>\n<p style=\"text-align: justify;\">Lan\u00e7ons ce processus dans un terminal et laissons-le tourner.<\/p>\n<pre>$ <strong>.\/consomme-cpu <\/strong>\n          [3040]8046202\n          [3040]8051003\n          [3040]8038645\n          [3040]8049329\n          [3040]8378210\n          [3040]8419106\n          [3040]8416285\n          [3040]8418075\n          [3040]8415878\n          [3040]8419727\n          [3040]8416073\n          [3040]8417343\n          [3040]8414809\n          ...<\/pre>\n<p style=\"text-align: justify;\">Il r\u00e9alise environ huit millions de boucles par seconde. Dans une autre console, cr\u00e9ons un groupe de contr\u00f4le sp\u00e9cifique et inscrivons notre processus.<\/p>\n<pre># <strong>cd \/sys\/fs\/cgroup\/cpu\/<\/strong>\n# <strong>mkdir groupe-1<\/strong>\n# <strong>echo 3040 &gt; groupe-1\/tasks<\/strong>\n#<\/pre>\n<p style=\"text-align: justify;\">Les param\u00e8tres de contr\u00f4le de la bande passante sont par d\u00e9faut les suivants.<\/p>\n<pre># <strong>cat groupe-1\/cpu.cfs_period_us<\/strong>\n100000\n# <strong>cat groupe-1\/cpu.cfs_quota_us<\/strong>\n-1\n#<\/pre>\n<p style=\"text-align: justify;\">La p\u00e9riode de r\u00e9gulation de la bande passante est donc de 100 millisecondes, et le quota CPU accord\u00e9 \u00e0 la t\u00e2che vaut <code>-1<\/code>, une valeur n\u00e9gative indiquant qu&rsquo;aucune contrainte n&rsquo;est appliqu\u00e9e au processus.<\/p>\n<p style=\"text-align: justify;\">Nous allons modifier cette valeur pour lui accorder un quota de 25 millisecondes par p\u00e9riodes de 100 millisecondes.<\/p>\n<pre># <strong>echo 25000 &gt; groupe-1\/cpu.cfs_quota_us<\/strong>\n#<\/pre>\n<p style=\"text-align: justify;\">Le comportement du processus varie alors&nbsp;:<\/p>\n<pre>          [3040]8416132\n          [3040]8417509\n          [3040]4302933\n          [3040]1766917\n          [3040]1763016\n          [3040]1798414\n          [3040]1740740\n          ...<\/pre>\n<p style=\"text-align: justify;\">Le nombre de boucles descend alors \u00e0 18 millions environ. R\u00e9-augmentons le quota \u00e0 50%.<\/p>\n<pre># <strong>echo 50000 &gt; groupe-1\/cpu.cfs_quota_us<\/strong>\n#<\/pre>\n<p style=\"text-align: justify;\">Nous voyons alors le nombre de boucles par secondes augmenter \u00e0 nouveau.<\/p>\n<pre>          [3040]1672509\n          [3040]2776452\n          [3040]3662061\n          [3040]3777860\n          [3040]3694039\n          [3040]3768352\n          [3040]3745732\n          [3040]3822385\n          ...<\/pre>\n<p style=\"text-align: justify;\">Restaurons-la valeur 100000 microsecondes et notre processus reprend son comportement initial.<\/p>\n<pre># <strong>echo 100000 &gt; groupe-1\/cpu.cfs_quota_us<\/strong>\n#<\/pre>\n<pre>          [3040]3708664\n          [3040]3779417\n          [3040]5944852\n          [3040]8051275\n          [3040]8049984\n          [3040]8050405\n          ...<\/pre>\n<h2 style=\"text-align: justify;\">Groupe de t\u00e2ches<\/h2>\n<p style=\"text-align: justify;\">Observons \u00e0 pr\u00e9sent le comportement lorsque nous lan\u00e7ons plusieurs t\u00e2ches en parall\u00e8le que nous inscrivons dans le m\u00eame groupe de contr\u00f4le.<\/p>\n<pre>          $ .\/consomme-cpu &amp; .\/consomme-cpu\n          [6105]8051374\n          [6106]8050150\n          [6106]8047698\n          [6105]8046993\n          [6106]8046275\n          [6105]8046629\n          [6106]8050943\n          [6105]8044749\n          [6106]8049421\n          [6105]8047196\n          ...<\/pre>\n<p style=\"text-align: justify;\">Nos t\u00e2ches ont \u00e9t\u00e9 plac\u00e9es sur deux processeurs (ou c\u0153urs) distincts et arrivent ainsi \u00e0 r\u00e9aliser chacune 8 millions de boucles par seconde. Toutefois nous pouvons les limiter et leur attribuer un quota de temps-processeur plus faible. Par exemple 100% CPU en tout (pour les deux).<\/p>\n<pre># <strong>echo 6105 &gt; groupe-1\/tasks<\/strong>\n# <strong>echo 6106 &gt; groupe-1\/tasks<\/strong>\n# <strong>echo 100000 &gt; groupe-1\/cpu.cfs_quota_us<\/strong>\n#<\/pre>\n<p style=\"text-align: justify;\">Chacune arrive \u00e0 r\u00e9aliser environ 4 millions de boucles par seconde.<\/p>\n<pre>          [6105]8055582\n          [6106]8023743\n          [6105]7876233\n          [6106]7598323\n          [6106]3678658\n          [6105]3910164\n          [6105]3800836\n          [6106]3753870\n          [6105]3776468\n          [6106]3659704\n          ...<\/pre>\n<p style=\"text-align: justify;\">Ou encore une valeur de 150% CPU (en s&rsquo;appuyant sur deux processeurs bien s\u00fbr).<\/p>\n<pre># <strong>echo 150000 &gt; groupe-1\/cpu.cfs_quota_us<\/strong>\n#<\/pre>\n<pre>          [6105]3667414\n          [6106]3831150\n          [6106]3839798\n          [6105]3714979\n          [6105]5004119\n          [6106]5851544\n          [6106]5801272\n          [6105]6028022\n          [6105]5810675\n          [6106]5749970\n          [6106]5784018\n          [6105]5769202\n          ...<\/pre>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">Les valeurs observ\u00e9es ci-dessus ne sont pas parfaitement stables et exactes, eu \u00e9gard \u00e0 l&rsquo;ordonnancement temps-partag\u00e9 qui prend en compte l&rsquo;ensemble des t\u00e2ches pr\u00eates \u00e0 s&rsquo;ex\u00e9cuter et le comportement de chacune d&rsquo;entre-elles vis-\u00e0-vis de la consommation de temps processeur.<\/p>\n<p style=\"text-align: justify;\">Le contr\u00f4le de la puissance CPU disponible pour chaque groupe de t\u00e2ches est \u00e0 mon avis principalement int\u00e9ressant pour les serveurs d&rsquo;applications et les containers de machines virtuelles. Dans mon cas particulier, je pense l&#8217;employer lorsque je fais tourner des programmes de tests sur plusieurs instances de <em>Qemu<\/em> afin d&rsquo;isoler chacune de la puissance CPU globalement disponible sur le serveur h\u00f4te.<\/p>\n<p>&lt;p style=\u00a0\u00bbtext-align: justify;\u00a0\u00bb&gt;<\/p>","protected":false},"excerpt":{"rendered":"<p>(English translation here) Linus Torvalds a publi&eacute; le noyau Linux 3.2 il y a deux jours. Ce dernier contient comme d&rsquo;habitude de nombreux ajouts. L&rsquo;un d&rsquo;eux a attir&eacute; mon attention et j&rsquo;ai souhait&eacute; observer son fonctionnement, il s&rsquo;agit du contr&ocirc;leur de consommation CPU pour l&rsquo;ordonnanceur CFS.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,14],"tags":[],"class_list":["post-1359","post","type-post","status-publish","format-standard","hentry","category-linux-2","category-temps-reel"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1359","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=1359"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1359\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=1359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=1359"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=1359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}