{"id":374,"date":"2011-03-25T16:00:18","date_gmt":"2011-03-25T15:00:18","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=374"},"modified":"2011-03-25T16:00:18","modified_gmt":"2011-03-25T15:00:18","slug":"partager-le-temps-reel","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2011\/03\/25\/partager-le-temps-reel\/","title":{"rendered":"Partager le temps-r\u00e9el&nbsp;?"},"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> \u00bb en cours d\u2019\u00e9criture)<\/p>\n<p style=\"text-align: justify;\">&nbsp;<\/p>\n<p style=\"text-align: justify;\">Lorsque l&rsquo;on teste le fonctionnement d&rsquo;un syst\u00e8me temps-r\u00e9el Posix, en particulier les priorit\u00e9s entre les diff\u00e9rentes t\u00e2ches, il est fr\u00e9quent d&rsquo;utiliser un petit programme comme celui-ci&nbsp;:<\/p>\n<pre style=\"padding-left: 30px;\"><strong>boucle-15s.c\u00a0:<\/strong>\n#include &lt;unistd.h&gt;:\n\nint main(void)\n{\n    alarm(15);\n    while(1)\n        ;\n}<\/pre>\n<p>\n<!--more-->\n<\/p>\n<p style=\"text-align: justify;\">Ce programme, ex\u00e9cut\u00e9 avec un ordonnancement temps-r\u00e9el va r\u00e9aliser une boucle active qui va monopoliser le processeur. Au bout de 15 secondes, l&rsquo;alarme programm\u00e9e avant la boucle va se d\u00e9clencher et le noyau va envoyer un signal <em>SIGALRM<\/em> au processus. Celui-ci ne traite pas le signal et va donc \u00eatre tu\u00e9 (ce qui nous permet de reprendre le contr\u00f4le).<\/p>\n<p style=\"text-align: justify;\">On peut tester ce programme sur un syst\u00e8me unicoeur simplement ainsi&nbsp;:<\/p>\n<pre># <strong>chrt -f 80 .\/boucle-15s<\/strong>\n#<\/pre>\n<p style=\"text-align: justify;\">Et voir que le syst\u00e8me est totalement fig\u00e9 pendant quinze secondes. Sur un syst\u00e8me multicoeur ou multiprocesseur, je conseillerai de regrouper les commandes dans un script qui r\u00e9partit les boucles sur les diff\u00e9rents CPU. Par exemple, on peut utiliser le script suivant.<\/p>\n<pre style=\"padding-left: 30px;\"><strong>boucles-paralleles.sh\u00a0:<\/strong>\n#! \/bin\/sh\n[...]\n# Le nombre de boucles paralleles est precise en argument\nNB=$(($1))\n[...]\n# Le script tourne sur le CPU 0\ntaskset -pc 0 $$\n\n# Il lance les boucles sur les autres CPU\ni=1\nwhile [ $i -lt \"$NB\" ]\ndo\n        taskset -c \"$i\" .\/boucle-15s &amp;\n        i=$((i+1))\ndone\n\n# Puis sur son CPU\ntaskset -c 0 .\/boucle-15s<\/pre>\n<p style=\"text-align: justify;\">Il faut naturellement le d\u00e9marrer sous un ordonnancement temps-r\u00e9el pour que les boucles actives s&rsquo;approprient tout le temps CPU disponible. Toutefois, avant de r\u00e9aliser cette op\u00e9ration, je conseille de tester le programme en l&rsquo;ex\u00e9cutant avec l&rsquo;ordonnancement temps-partag\u00e9 usuel, et de visualiser \u00e0 l&rsquo;aide d&rsquo;un utilitaire syst\u00e8me l&rsquo;activit\u00e9 des diff\u00e9rents CPU. Personnellement j&rsquo;aime beaucoup l&rsquo;application <strong>Gkrellm<\/strong> (existant sous forme de packages pr\u00e9compil\u00e9s pour la plupart des distributions Linux). Sur la capture d&rsquo;\u00e9cran suivante, par exemple, nous voyons que seuls trois coeurs ex\u00e9cutent des boucles, le quatri\u00e8me \u00e9tant relativement au repos&nbsp;:<\/p>\n<pre># <strong>.\/boucles-paralleles.sh 3<\/strong>\npid 21810's current affinity list: 0-3\npid 21810's new affinity list: 0<\/pre>\n<pre><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-381 aligncenter\" title=\"Partager le temps-r\u00e9el ? - 01\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2011\/03\/partager-le-temps-reel-01.gif\" alt=\"Partager le temps-r\u00e9el ? - 01\" width=\"112\" height=\"509\" \/><\/pre>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">Le lancement des quatre boucles en temps-r\u00e9el s&rsquo;effectue ainsi&nbsp;:<\/p>\n<pre># <strong>chrt -f 80 .\/boucles-paralleles.sh 4<\/strong><\/pre>\n<p style=\"text-align: justify;\">J&rsquo;utilise notamment cette m\u00e9thode lors de sessions de <a title=\"Formation Linux Temps-R\u00e9el\" href=\"http:\/\/www.logilin.fr\/Formation_Linux_Temps_Reel_Embarque.html\">formations sur Linux temps-r\u00e9el<\/a> depuis de nombreuses ann\u00e9es. Imaginez ma surprise, au printemps 2008 en lan\u00e7ant un tel programme, de voir les applications tournant en ordonnancement temps-partag\u00e9 (comme Gkrellm lui-m\u00eame) continuer \u00e0 s&rsquo;ex\u00e9cuter lors des boucles actives temps-r\u00e9el.<\/p>\n<p style=\"text-align: justify;\">Depuis la version 2.6.25 de Linux, sortie en avril 2008, une petite partie (5&nbsp;%) du temps CPU disponible est en effet r\u00e9serv\u00e9e aux t\u00e2ches temps-partag\u00e9, <strong>m\u00eame lorsque des t\u00e2ches temps-r\u00e9el s&rsquo;ex\u00e9cutent&nbsp;!<\/strong><\/p>\n<p style=\"text-align: justify;\">Ce comportement &#8211; qui avait \u00e9t\u00e9 introduit sans grande publicit\u00e9 dans le nouveau noyau &#8211; viole bien entendu les principes m\u00eames des syst\u00e8mes temps-r\u00e9el. Il est con\u00e7u comme une sorte de garde-fou qui prot\u00e8ge l&rsquo;usager inconscient contre les boucles infinies qu&rsquo;il aurait malencontreusement lanc\u00e9es sous un ordonnancement temps-r\u00e9el. Bien s\u00fbr cela peut s&rsquo;av\u00e9rer tr\u00e8s utile lors de la mise au point d&rsquo;un syst\u00e8me temps-r\u00e9el, ou pour son d\u00e9bogage. Toutefois j&rsquo;estime que c&rsquo;est une option qui ne devrait pas \u00eatre active par d\u00e9faut. N&rsquo;oublions pas que l&rsquo;ex\u00e9cution d&rsquo;une t\u00e2che sous un ordonnancement temps-r\u00e9el doit \u00eatre demand\u00e9e explicitement et que l&rsquo;utilisateur doit disposer des privil\u00e8ges <em>root<\/em>. On peut consid\u00e9rer qu&rsquo;il est alors responsable de ses actes et qu&rsquo;il peut activer volontairement le garde-fou s&rsquo;il le d\u00e9sire.<\/p>\n<p style=\"text-align: justify;\">Les noyaux Linux depuis le 2.6.25 (jusqu&rsquo;au 2.6.38 du moins) adoptent l&rsquo;attitude inverse, pr\u00e9f\u00e9rant, par d\u00e9faut, p\u00e9naliser le comportement temps-r\u00e9el plut\u00f4t que de risquer un d\u00e9ni de service par une boucle infinie.<\/p>\n<p style=\"text-align: justify;\">Heureusement il est possible de d\u00e9brayer ce garde-fou, en \u00e9crivant dans un pseudo-fichier de <code>\/proc<\/code> &#8211; m\u00eame si l&rsquo;on peut regretter qu&rsquo;il n&rsquo;y ait pas une option pour d\u00e9sactiver ce comportement par d\u00e9faut lors de la compilation du noyau. Le fichier <code>\/proc\/sys\/kernel\/sched_rt_period_us<\/code> repr\u00e9sente une p\u00e9riode, exprim\u00e9e en micro-secondes que partagent les t\u00e2ches temps-r\u00e9el et les t\u00e2ches temps-partag\u00e9. Son contenu par d\u00e9faut est 1.000.000, ce qui correspond \u00e0 1\u00a0seconde. Dans cette p\u00e9riode, on r\u00e9serve aux t\u00e2ches temps-r\u00e9el la dur\u00e9e indiqu\u00e9e dans <code>\/proc\/sys\/kernel\/sched_rt_runtime_us<\/code>. Par d\u00e9faut, il contient 950.000, ainsi chaque seconde, on r\u00e9serve 50\u00a0millisecondes pour les t\u00e2ches temps-partag\u00e9, et les t\u00e2ches temps-r\u00e9el peuvent consommer jusqu&rsquo;\u00e0 950\u00a0millisecondes.<\/p>\n<p style=\"text-align: justify;\">&nbsp;<\/p>\n<p style=\"text-align: justify;\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-395\" title=\"partager-le-temps-reel-02\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2011\/03\/partager-le-temps-reel-023-e1300785773968.gif\" alt=\"partager-le-temps-reel-02\" width=\"535\" height=\"184\" \/><\/p>\n<p style=\"text-align: justify;\">Afin de d\u00e9sactiver ce comportement, il suffit d&rsquo;\u00e9crire, dans un script de <em>boot<\/em> du syst\u00e8me par exemple&nbsp;:<\/p>\n<pre><strong>echo -1 &gt; \/proc\/sys\/kernel\/sched_rt_runtime_us<\/strong><\/pre>\n<p style=\"text-align: justify;\">Ainsi les t\u00e2ches temps-r\u00e9el pourront consommer tout le temps CPU dont elles ont besoin sans jamais \u00eatre pr\u00e9empt\u00e9es par les t\u00e2ches temps-partag\u00e9. Il est important d&rsquo;y penser sur les syst\u00e8mes \u00e0 vocation temps-r\u00e9el, sous peine de voir nos applications pr\u00e9empt\u00e9es temporairement par des processus de moindre importance.<\/p>\n<p style=\"text-align: justify;\">Les derniers noyaux ont \u00e9tendu ce m\u00e9canisme en permettant de rassembler des t\u00e2ches (temps-r\u00e9el ou temps-partag\u00e9) dans des groupes, et de r\u00e9partir le temps CPU disponible entre ces diff\u00e9rents groupes. Dans le noyau 2.6.38, les groupes peuvent m\u00eame se constituer \u00e0 partir des TTY de contr\u00f4le. Ce syst\u00e8me n\u00e9cessite un soin m\u00e9ticuleux lors de la mise au point si des contraintes temps-r\u00e9el entrent en jeu, mais il peut s&rsquo;av\u00e9rer tr\u00e8s utile lorsqu&rsquo;on doit garder une disponibilit\u00e9 absolue du processeur pour certaines t\u00e2ches, alors que d&rsquo;autres, aux comportements et aux nombres <em>a priori<\/em> inconnus, s&rsquo;ex\u00e9cutent simultan\u00e9ment. Nous \u00e9tudierons ce m\u00e9canisme dans un prochain article&#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; Lorsque l&rsquo;on teste le fonctionnement d&rsquo;un syst&egrave;me temps-r&eacute;el Posix, en particulier les priorit&eacute;s entre les diff&eacute;rentes t&acirc;ches, il est fr&eacute;quent d&rsquo;utiliser un petit programme comme celui-ci&nbsp;: boucle-15s.c&nbsp;: #include &lt;unistd.h&gt;: int main(void) { alarm(15); while(1) [&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-374","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\/374","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=374"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/374\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=374"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=374"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=374"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}