{"id":265,"date":"2011-03-04T16:00:01","date_gmt":"2011-03-04T15:00:01","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=265"},"modified":"2011-03-04T16:00:01","modified_gmt":"2011-03-04T15:00:01","slug":"temps-reel-et-economie-d-energie-1","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2011\/03\/04\/temps-reel-et-economie-d-energie-1\/","title":{"rendered":"Temps-r\u00e9el et \u00e9conomie d&rsquo;\u00e9nergie (1)"},"content":{"rendered":"<p style=\"text-align: justify;\">(Cet article est un extrait de la version pr\u00e9paratoire de mon livre \u00ab\u00a0<em>Applications temps-r\u00e9el avec Linux<\/em>\u00a0\u00bb en cours d&rsquo;\u00e9criture)<\/p>\n<p style=\"text-align: justify;\">&nbsp;<\/p>\n<h1 style=\"text-align: justify;\">\u00c9conomie ou performance&nbsp;: arbitrage pour le temps-r\u00e9el embarqu\u00e9 (Partie 1)<\/h1>\n<p style=\"text-align: justify;\">Sur la plupart des syst\u00e8mes interactifs, la charge du processeur varie en permanence entre des \u00e9tats d&rsquo;intense activit\u00e9 (calcul, compilation, compression, encodage, etc.) et des p\u00e9riodes de repos durant lesquelles aucune op\u00e9ration n&rsquo;a lieu, jusqu&rsquo;\u00e0 la prochaine sollicitation provenant de l&rsquo;utilisateur.<\/p>\n<p>\n<!--more-->\n<\/p>\n<p style=\"text-align: justify;\">En fait, sur un syst\u00e8me de type bureautique, la charge est g\u00e9n\u00e9ralement tr\u00e8s basse, et la puissance compl\u00e8te du processeur n&rsquo;est n\u00e9cessaire que pendant des pics d&rsquo;activit\u00e9 ponctuels. Voici par exemple la charge de la station Linux sur laquelle je r\u00e9dige ces lignes\u00a0:<\/p>\n<pre>$ <strong>uptime<\/strong>\n11:44:07 up 29 days,  2:26,  9 users,  load average: 0.11, 0.10, 0.08\n$<\/pre>\n<p style=\"text-align: justify;\">La commande <a title=\"uptime(1)\" href=\"http:\/\/www.blaess.fr\/christophe\/manuel-linux-en-francais\/uptime1\/\">uptime(1)<\/a> permet de voir la charge du syst\u00e8me (le nombre moyen de t\u00e2ches en ex\u00e9cution ou en attente d&rsquo;ex\u00e9cution) pour la derni\u00e8re minute (0.11 ici), les cinq (0.10) et quinze (0.08) derni\u00e8res minutes. Nous pouvons estimer que sur cet exemple le processeur n&rsquo;est utilis\u00e9 en moyenne que 10% du temps environ. Naturellement, il y a d&rsquo;autres moments o\u00f9 la charge peut-\u00eatre beaucoup plus \u00e9lev\u00e9e (compilation d&rsquo;un noyau Linux par exemple).<\/p>\n<p style=\"text-align: justify;\">Un processeur qui fonctionne \u00e0 plein rendement consomme de l&rsquo;\u00e9nergie et s&rsquo;\u00e9chauffe sensiblement (ce qui n\u00e9cessite la mise en marche d&rsquo;un ventilateur consommant \u00e0 son tour de l&rsquo;\u00e9nergie \u00e9lectrique). Pour limiter la consommation \u00e9lectrique et retarder le vieillissement pr\u00e9matur\u00e9 du processeur surchauff\u00e9, plusieurs techniques sont utilis\u00e9es de nos jours.<\/p>\n<h2 style=\"text-align: justify;\">Variation de fr\u00e9quence d&rsquo;horloge<\/h2>\n<p style=\"text-align: justify;\">Pour les processeurs r\u00e9cents, il est possible de contr\u00f4ler la fr\u00e9quence de fonctionnement du CPU (par exemple gr\u00e2ce \u00e0 la technologie <a title=\"Intel SpeedStep sur Wikipedia\" href=\"http:\/\/fr.wikipedia.org\/wiki\/Intel_SpeedStep\">SpeedStep d&rsquo;Intel<\/a> ou <a title=\"AMD Cool'n'Quiet sur Wikipedia\" href=\"http:\/\/fr.wikipedia.org\/wiki\/Cool'n'Quiet\">Cool&rsquo;n&rsquo;Quiet d&rsquo;AMD<\/a>). Lorsque la charge est faible on se contentera d&rsquo;une vitesse d&rsquo;ex\u00e9cution du code basse. Si la charge augmente, on pourra \u00e9lever (suivant divers crit\u00e8res) la fr\u00e9quence d&rsquo;interpr\u00e9tation des instructions-machine. La consommation \u00e9lectrique du processeur est proportionnelle \u00e0 sa fr\u00e9quence. Le noyau Linux est tout \u00e0 fait capable de prendre en charge cette variation de fr\u00e9quence, en utilisant un algorithme dont l&rsquo;heuristique (le\u00a0<em>governor<\/em>)\u00a0est configurable par l&rsquo;administrateur (par le biais du pseudo-fichier\u00a0<code>\/sys\/devices\/system\/cpu\/<\/code>(num\u00e9ro de cpu)<code>\/cpufreq\/scaling_governor<\/code>). La liste des heuristiques disponibles se trouvent dans le pseudo-fichier\u00a0<code>\/sys\/devices\/system\/cpu\/<\/code>(num\u00e9ro de cpu)<code>\/cpufreq\/scaling_available_governors<\/code>. Il existe par exemple les heuristiques suivantes&nbsp;:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><em>powersave<\/em> : utiliser toujours la fr\u00e9quence la plus basse pour limiter la consommation (utile pour un ordinateur portable sur batterie)&nbsp;;<\/li>\n<li style=\"text-align: justify;\"><em>performance<\/em> : utiliser toujours la fr\u00e9quence la plus haute pour optimiser les temps de traitement (serveurs de calcul, d&rsquo;applications, etc.)&nbsp;;<\/li>\n<li style=\"text-align: justify;\"><em>ondemand<\/em> : faire varier automatiquement la fr\u00e9quence en fonction de la charge syst\u00e8me pour ajuster la puissance disponible aux demandes de l&rsquo;utilisateur (poste de travail)&nbsp;;<\/li>\n<li><em>conservative<\/em> : comme <em>ondemand<\/em>, mais en minimisant les changements de fr\u00e9quence&nbsp;;<\/li>\n<li style=\"text-align: justify;\"><em>userspace<\/em> : laisser l&rsquo;administrateur param\u00e9trer la fr\u00e9quence depuis l&rsquo;espace utilisateur (en fixant dans\u00a0<code>\/sys\/devices\/system\/cpu\/<\/code>(num\u00e9ro de cpu)<code>\/cpufreq\/scaling_cur_freq<\/code> une des valeurs propos\u00e9es dans\u00a0<code>\/sys\/devices\/system\/cpu\/<\/code>(num\u00e9ro de cpu)<code>\/cpufreq\/scaling_available_frequencies<\/code>).<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">Ainsi, un \u00ab\u00a0<code>echo powersave &gt; \/sys\/devices\/system\/cpu\/<\/code>(num\u00e9ro de cpu)<code>\/cpufreq\/scaling_governor<\/code>\u00a0\u00bb permettra-t&rsquo;il de basculer le processeur sur une fr\u00e9quence r\u00e9duite \u00e9conomisant l&rsquo;\u00e9nergie de la batterie.<\/p>\n<p style=\"text-align: justify;\">Dans le cadre d&rsquo;un syst\u00e8me devant r\u00e9pondre \u00e0 des contraintes temps-r\u00e9el, ce comportement devra bien \u00e9videmment \u00eatre pris en consid\u00e9ration. Plusieurs approches sont possibles&nbsp;:<\/p>\n<ul>\n<li style=\"text-align: justify;\">Bloquer en permanence le processeur \u00e0 sa fr\u00e9quence la plus \u00e9lev\u00e9e en basculant d\u00e8s le boot du syst\u00e8me sur le <em>governor<\/em> \u00ab\u00a0performance\u00a0\u00bb. Cette solution est la plus co\u00fbteuse en \u00e9nergie \u00e9lectrique (donc en autonomie sur batterie), et nous perdons l&rsquo;int\u00e9r\u00eat de la variabilit\u00e9 de la f&rsquo;r\u00e9quence du processeur.<\/li>\n<li style=\"text-align: justify;\">Utiliser d\u00e8s le boot le <em>governor<\/em> \u00ab\u00a0powersave\u00a0\u00bb qui basculera le processeur sur sa fr\u00e9quence la plus faible et la plus \u00e9conomique. Bien qu&rsquo;\u00e9conomique en \u00e9nergie et en usure du processeur, cette approche perd tout l&rsquo;int\u00e9r\u00eat de la variation de fr\u00e9quence, et des vitesses d&rsquo;ex\u00e9cution plus rapides disponibles.<\/li>\n<li style=\"text-align: justify;\">Laisser le <em>governor<\/em> \u00ab\u00a0ondemand\u00a0\u00bb choisir pour nous la fr\u00e9quence ad\u00e9quate. Cette m\u00e9thode est <em>a priori<\/em> s\u00e9duisante, mais nous n&rsquo;avons aucune garantie de la r\u00e9activit\u00e9 du syst\u00e8me lors d&rsquo;une demande importante de charge CPU. Nous allons devoir effectuer quelques exp\u00e9riences pour v\u00e9rifier le comportement du noyau Linux avec cette heuristique.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">&nbsp;<\/p>\n<p style=\"text-align: justify;\">On trouvera dans l&rsquo;archive suivante&nbsp;: <a title=\"Test Governors\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/test-governors-1.tar.bz2\">http:\/\/www.blaess.fr\/christophe\/files\/test-governors-1.tar.bz2<\/a> quelques fichiers permettant de v\u00e9rifier le comportement du syst\u00e8me. Commen\u00e7ons par le programme test-governor.c&nbsp;: il attend en argument une cha\u00eene de caract\u00e8res repr\u00e9sentant le nom de l&rsquo;heuristique \u00e0 tester, qu&rsquo;il active sur un CPU donn\u00e9. Ensuite il d\u00e9marre un thread temps-r\u00e9el sur ce CPU, qui va effectuer un nombre donn\u00e9 de boucles actives consommant du temps CPU en mesurant la dur\u00e9e des boucles. En fin de programme la dur\u00e9e des boucles est affich\u00e9e sur la sortie standard. Nous nous en servirons pour produire des graphes. Le num\u00e9ro du CPU, la priorit\u00e9 temps-r\u00e9el, le nombre et la longueur des boucles sont configurables en d\u00e9but de fichier.<\/p>\n<h2>Heuristique \u00ab\u00a0performance\u00a0\u00bb<\/h2>\n<p style=\"text-align: justify;\">Commen\u00e7ons par lancer notre programme avec le <em>governor<\/em> \u00ab\u00a0performance\u00a0\u00bb. Cela va nous permettre de calibrer le nombre et la longueur des boucles actives en fonction du processeur. Disons qu&rsquo;une dur\u00e9e de quelques centaines de micro-secondes repr\u00e9sente une valeur convenable. Le programme doit \u00eatre lanc\u00e9 depuis l&rsquo;identit\u00e9 <em>root<\/em> pour modifier le <em>governor<\/em> et acc\u00e9der \u00e0 une priorit\u00e9 temps-r\u00e9el.<\/p>\n<pre># <strong>.\/test-governor performance<\/strong>\n    0 \u00a0 \u00a0753\n\u00a0   1 \u00a0 \u00a0765\n \u00a0\u00a0 2 \u00a0 \u00a0761\n \u00a0\u00a0 3 \u00a0 \u00a0761\n[...]\n   96    754\n   97    760\n   98    761\n   99    760\n#<\/pre>\n<p>Sur ce poste, la dur\u00e9e des boucles \u00e0 fr\u00e9quence maximale est de 763 micro-secondes environ.<\/p>\n<h2>Heuristique \u00ab\u00a0powersave\u00a0\u00bb<\/h2>\n<p>Essayons \u00e0 pr\u00e9sent avec le <em>governor<\/em> \u00e9conomique afin de voir la dur\u00e9e des boucles avec la fr\u00e9quence minimale&nbsp;:<\/p>\n<pre># <strong>.\/test-governor powersave<\/strong>\n    0   1785\n    1   1768\n    2   1777\n    3   1777\n[...]\n   96   1777\n   97   1779\n   98   1768\n   99   1777\n#<\/pre>\n<p style=\"text-align: justify;\">Dans ce cas, la dur\u00e9e moyenne des boucles est d&rsquo;environ 1777 micro-secondes, un peu plus du double de la dur\u00e9e en mode \u00ab\u00a0performance\u00a0\u00bb.<\/p>\n<h2>Heuristique \u00ab\u00a0On Demand\u00a0\u00bb<\/h2>\n<p style=\"text-align: justify;\">A la premi\u00e8re ex\u00e9cution, le test avec l&rsquo;heuristique \u00ab\u00a0On Demand\u00a0\u00bb (qui devrait acc\u00e9l\u00e9rer dynamiquement afin de r\u00e9pondre \u00e0 la demande soutenu de temps CPU) para\u00eet bien d\u00e9cevant&nbsp;:<\/p>\n<pre># <strong>.\/test-governor ondemand<\/strong>\n    0   1781\n    1   1768\n    2   1777\n    3   1776\n[...]\n   96   1777\n   97   1766\n   98   1777\n   99   1777\n#<\/pre>\n<p style=\"text-align: justify;\">Le r\u00e9sultat n&rsquo;est pas meilleur qu&rsquo;avec le <em>governor<\/em> \u00e9conomique \u00ab\u00a0Powersave\u00a0\u00bb !<\/p>\n<p style=\"text-align: justify;\">Apr\u00e8s investigation, il appara\u00eet que dans le noyau Linux (2.6.34.7 pour cet essai), le <em>governor <\/em> \u00ab\u00a0On Demand\u00a0\u00bb est impl\u00e9ment\u00e9 sous forme d&rsquo;un <em>\u00ab\u00a0kernel thread\u00a0\u00bb<\/em>, c&rsquo;est \u00e0 dire d&rsquo;une t\u00e2che, ex\u00e9cut\u00e9e dans l&rsquo;espace m\u00e9moire du noyau et poss\u00e9dant les privil\u00e8ges du noyau, ordonnanc\u00e9e toutefois au m\u00eame titre que tous les autres processus et threads de l&rsquo;espace utilisateur. Il existe un thread <em>kondemand<\/em> par CPU (ou par coeur). Nous les voyons avec la commande ps(1).<\/p>\n<pre># <strong>ps aux<\/strong>\n[...]\nroot      1364  0.0  0.0      0     0 ?        S    20:33   0:00 [kondemand\/0]\nroot      1365  0.0  0.0      0     0 ?        S    20:33   0:00 [kondemand\/1]\n[...]\n#<\/pre>\n<p style=\"text-align: justify;\">Nous ex\u00e9cutons notre programme de test sur le CPU 1, aussi pouvons-nous nous interroger sur le type et la priorit\u00e9 de l&rsquo;ordonnancement du thread kondemand\/1. Utilisons la commande chrt(1) pour obtenir ces informations&nbsp;:<\/p>\n<pre># <strong>chrt -p 1365<\/strong>\nstrat\u00e9gie de planification d'ex\u00e9cution pour pid 1365 actuel :SCHED_OTHER\npriorit\u00e9 de planification d'ex\u00e9cution pour le pid 1365 actuel : 0\n#<\/pre>\n<p style=\"text-align: justify;\">Le thread est ex\u00e9cut\u00e9 suivant l&rsquo;ordonnancement OTHER, autrement dit en temps partag\u00e9&nbsp;! Naturellement, nos boucles \u00e9tant ex\u00e9cut\u00e9es en temps r\u00e9el (avec la priorit\u00e9 10) le pr\u00e9emptent et l&#8217;emp\u00eachent d&rsquo;agir. Nous allons augmenter la priorit\u00e9 de ce <em>kernel thread<\/em> :<\/p>\n<pre># <strong>chrt -pf 20 1365<\/strong>\n# <strong>chrt -p 1365<\/strong>\nstrat\u00e9gie de planification d'ex\u00e9cution pour pid 1365 actuel :SCHED_FIFO\npriorit\u00e9 de planification d'ex\u00e9cution pour le pid 1365 actuel : 20\n#<\/pre>\n<p>Cette fois, la fr\u00e9quence va bien \u00eatre modifi\u00e9e&nbsp;:<\/p>\n<pre># <strong>.\/test-governor ondemand<\/strong>\n    0   1797\n    1   1782\n    2   1779\n    3   1779\n[...]\n   96    761\n   97    753\n   98    767\n   99    761\n#<\/pre>\n<p style=\"text-align: justify;\">En redirigeant les sorties des programmes de test dans des fichiers, et en utilisant Gnuplot pour tracer les courbes, nous obtenons la figure suivante.<\/p>\n<pre>#\u00a0<strong>echo 'set terminal gif giant size 640,480;\n        set output \"resultats.gif\";\n        set multiplot;\n        set yrange [0:] ;\n        plot \"resultat-powersave\" with lines title \"Powersave\" lw 3;\n        replot \"resultat-performance\" with lines title \"Performance\" lw 3;\n        replot \"resultat-ondemand\" with lines title \"On Demand\" lw 3'  |  gnuplot<\/strong>\n#<\/pre>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2011\/03\/test-governors.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-294\" title=\"test-governors\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2011\/03\/test-governors.gif\" alt=\"\" width=\"640\" height=\"480\" \/><\/a>Sur ce graphique, on trouve en abcisse les num\u00e9ros des boucles actives, et en ordonn\u00e9e leur dur\u00e9es. Plus le trac\u00e9 est haut, plus le temps d&rsquo;ex\u00e9cution est long, donc la fr\u00e9quence processeur faible. Nous retrouvons nos dur\u00e9es de boucle de 765 et 1770 approximativement avec de l\u00e9g\u00e8res ondulations dues probablement aux d\u00e9clenchement du <em>timer<\/em> syst\u00e8me. La petite pointe pour l&rsquo;it\u00e9ration 79 du test \u00ab\u00a0Performance\u00a0\u00bb est caus\u00e9e sans doute par l&rsquo;arriv\u00e9e d&rsquo;une interruption mat\u00e9rielle (disque, r\u00e9seau, etc.).<\/p>\n<p style=\"text-align: justify;\">Nous voyons bien que le <em>governor<\/em> \u00ab\u00a0On Demand\u00a0\u00bb bascule bien d&rsquo;un comportement privil\u00e9giant l&rsquo;\u00e9conomie \u00e0 un comportement privil\u00e9giant les performances. Toutefois, sur cette machine cela se produit au bout de six boucles durant chacune 1,8 milli-secondes, ce qui conduit \u00e0 une latence d&rsquo;environ 10 millisecondes avant d&rsquo;atteindre une fr\u00e9quence processeur optimale.<\/p>\n<p style=\"text-align: justify;\">Pour certaines applications temps-r\u00e9el, c&rsquo;est beaucoup trop&nbsp;!\u00a0Nous devrons donc g\u00e9rer nous-m\u00eame le basculement d&rsquo;un <em>governor<\/em> \u00e0 l&rsquo;autre.<\/p>\n<p style=\"text-align: right;\">(\u00c0 suivre&#8230;)<\/p>","protected":false},"excerpt":{"rendered":"<p>(Cet article est un extrait de la version pr&eacute;paratoire de mon livre &laquo;&nbsp;Applications temps-r&eacute;el avec Linux&nbsp;&raquo; en cours d&rsquo;&eacute;criture) &nbsp; &Eacute;conomie ou performance&nbsp;: arbitrage pour le temps-r&eacute;el embarqu&eacute; (Partie 1) Sur la plupart des syst&egrave;mes interactifs, la charge du processeur varie en permanence entre des &eacute;tats d&rsquo;intense activit&eacute; (calcul, compilation, compression, encodage, etc.) et des [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,8,14],"tags":[],"class_list":["post-265","post","type-post","status-publish","format-standard","hentry","category-embarque","category-linux-2","category-temps-reel"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/265","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=265"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/265\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}