{"id":2781,"date":"2012-07-23T02:01:13","date_gmt":"2012-07-23T01:01:13","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=2781"},"modified":"2012-11-30T13:33:55","modified_gmt":"2012-11-30T12:33:55","slug":"les-latences-de-xenomai","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2012\/07\/23\/les-latences-de-xenomai\/","title":{"rendered":"Les latences de Xenomai"},"content":{"rendered":"<p style=\"text-align: justify;\"><a href=\"http:\/\/www.blaess.fr\/christophe\/2012\/07\/23\/les-latences-de-xenomai\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-full wp-image-2787\" title=\"Latences de Xenomai\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/07\/img.jpg\" alt=\"Latences de Xenomai\" width=\"150\" height=\"150\" \/><\/a><br \/>\nJ&rsquo;ai abord\u00e9 dans plusieurs articles (<a title=\"Xenomai sur Pandaboard\" href=\"http:\/\/www.blaess.fr\/christophe\/2011\/11\/27\/xenomai-sur-pandaboard\/\">Xenomai sur Pandaboard<\/a>, <a title=\"GPIO, Pandaboard et temps r\u00e9el \u2013 4 \u2013 Gestion des interruptions\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/05\/28\/gpio-pandaboard-et-temps-reel-4-gestion-des-interruptions\/\">GPIO, Pandaboard et temps r\u00e9el\u00a0 \u2013 Gestion des interruptions<\/a>, <a title=\"La Pandaboard au poteau de torture \u2013 4 \u2013 Timers Xenomai\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/07\/09\/la-pandaboard-au-poteau-de-torture-4-timers-xenomai\/\">La Pandaboard au poteau de torture \u2013 Timers Xenomai<\/a>&#8230;) la question des latences maximales de Xenomai. Mais il est aussi int\u00e9ressant de conna\u00eetre et de configurer correctement la latence minimale.<\/p>\n<p>\n<!--more-->\n<\/p>\n<h1>Mesure des latences<\/h1>\n<p style=\"text-align: justify;\">La notion de latence fait r\u00e9f\u00e9rence ici \u00e0 la dur\u00e9e qui s&rsquo;\u00e9coule entre le d\u00e9clenchement d&rsquo;une interruption et le d\u00e9but du traitement que nous avons associ\u00e9 \u00e0 cette interruption. Cette dur\u00e9e d\u00e9pend en grande partie du syst\u00e8me d&rsquo;exploitation et du mat\u00e9riel. On s&rsquo;int\u00e9resse g\u00e9n\u00e9ralement \u00e0 la latence maximale car c&rsquo;est elle qui concerne les applications temps r\u00e9el par exemple. Ainsi le cahier des charges d&rsquo;un projet peut imposer qu&rsquo;entre l&rsquo;activation d&rsquo;un capteur externe et la r\u00e9ponse du syst\u00e8me il ne s&rsquo;\u00e9coule pas plus de 100 microsecondes quels que soient la charge logicielle ou la quantit\u00e9 d&rsquo;interruptions se d\u00e9clenchant \u00e0 ce moment.<\/p>\n<p style=\"text-align: justify;\">La latence maximale se mesure avec des exp\u00e9riences de longues dur\u00e9es (plusieurs jours voire plusieurs semaines) sous une tr\u00e8s haute charge (en t\u00e2ches et en interruptions). \u00c0 titre d&rsquo;exemple, nous avons observ\u00e9 dans les articles mentionn\u00e9s plus haut que sur une carte Pandaboard, le syst\u00e8me Xenomai 2.6.1 nous permet d&rsquo;obtenir une latence maximale de 50 microsecondes environ.<\/p>\n<p style=\"text-align: justify;\">Pour cela, un utilitaire livr\u00e9 avec Xenomai mesure le temps s&rsquo;\u00e9coulant entre le d\u00e9clenchement d&rsquo;un timer mat\u00e9riel et l&rsquo;activation de la routine de traitement. Cet outil s&rsquo;appelle <code>latency<\/code>, voici un exemple d&rsquo;utilisation sur un syst\u00e8me faiblement charg\u00e9.<\/p>\n<pre># <strong>\/usr\/xenomai\/bin\/latency -p 100 -T 14400<\/strong>\n== Sampling period: 100 us\n== Test mode: periodic user-mode task\n== All results in microseconds\nwarming up...\nRTT|  00:00:01  (periodic user-mode task, 100 us period, priority 99)\nRTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst\nRTD|      0.724|      0.996|     13.918|       0|     0|      0.724|     13.918\nRTD|      0.490|      1.182|     12.357|       0|     0|      0.490|     13.918\nRTD|      0.486|      0.966|      8.396|       0|     0|      0.486|     13.918\nRTD|      0.468|      1.001|     14.261|       0|     0|      0.468|     14.261\nRTD|      0.478|      0.970|     12.934|       0|     0|      0.468|     14.261\nRTD|      0.476|      0.988|      6.640|       0|     0|      0.468|     14.261\nRTD|      0.494|      1.001|      8.414|       0|     0|      0.468|     14.261\nRTD|      0.488|      0.964|      9.918|       0|     0|      0.468|     14.261\nRTD|      0.476|      0.956|      7.882|       0|     0|      0.468|     14.261\nRTD|      0.484|      0.956|      8.386|       0|     0|      0.468|     14.261\nRTD|      0.486|      0.960|      7.815|       0|     0|      0.468|     14.261\nRTD|      0.486|      0.972|      8.244|       0|     0|      0.468|     14.261\n[...]<\/pre>\n<p style=\"text-align: justify;\">Les options utilis\u00e9es ici indiquent que le timer doit suivre une p\u00e9riode de 100\u00a0microsecondes, et que la dur\u00e9e totale de la mesure sera de 14400\u00a0secondes soient 4\u00a0heures.<\/p>\n<p style=\"text-align: justify;\">L&rsquo;outil <code>latency<\/code> affiche une ligne de r\u00e9sultats interm\u00e9diaires toutes les secondes, sur lesquelles il pr\u00e9sente les latences minimales (<code>lat min<\/code>), moyennes (<code>lat avg<\/code>) et maximales (<code>lat max<\/code>) rencontr\u00e9es pendant la seconde \u00e9coul\u00e9e. Ensuite il indique les d\u00e9passements de timers (<code>overrun<\/code>) et les changements de mode (<code>msw<\/code>) au sens de Xenomai.<br \/>\nEnfin les deux derni\u00e8res colonnes indiquent les plus courtes (<code>lat best<\/code>) et plus longues (<code>lat worst<\/code>) latences rencontr\u00e9es sur tout le d\u00e9roulement du processus.<\/p>\n<p style=\"text-align: justify;\">Au bout de quatre heures l&rsquo;exp\u00e9rience se termine sur les r\u00e9sultats suivants.<\/p>\n<pre>RTD|      0.482|      0.976|      8.652|       0|     0|     -0.393|     31.192\nRTD|      0.496|      0.968|      6.450|       0|     0|     -0.393|     31.192\nRTD|      0.527|      0.982|     13.291|       0|     0|     -0.393|     31.192\nRTD|      0.494|      0.964|      7.890|       0|     0|     -0.393|     31.192\nRTD|      0.456|      0.960|      6.482|       0|     0|     -0.393|     31.192\nRTD|      0.492|      0.970|     12.140|       0|     0|     -0.393|     31.192\nRTD|      0.498|      0.966|      7.265|       0|     0|     -0.393|     31.192\nRTD|      0.503|      0.980|      9.224|       0|     0|     -0.393|     31.192\n---|-----------|-----------|-----------|--------|------|-------------------------\nRTS|     -0.393|      0.900|     31.192|       0|     0|    04:00:00\/04:00:00\n#<\/pre>\n<p style=\"text-align: justify;\">Nous voyons que la pire latence rencontr\u00e9e ici est de 31.192 microsecondes. Mais le syst\u00e8me n&rsquo;\u00e9tait pas tr\u00e8s sollicit\u00e9 et on pourrait rencontrer des latences jusqu&rsquo;\u00e0 50 microsecondes environ sous une forte charge.<\/p>\n<p style=\"text-align: justify;\">Ce qui est plus surprenant c&rsquo;est la latence minimale&nbsp;: elle est n\u00e9gative&nbsp;! Cela signifierait donc que la routine de traitement se d\u00e9clenche avant l&rsquo;interruption timer&nbsp;? Plut\u00f4t \u00e9trange&#8230;<\/p>\n<h1>Anticipation de la latence minimale<\/h1>\n<p style=\"text-align: justify;\">En r\u00e9alit\u00e9, lorsque Xenomai programme le d\u00e9clenchement d&rsquo;un timer, il anticipe la dur\u00e9e qui s&rsquo;\u00e9coulera entre l&rsquo;interruption mat\u00e9rielle et l&rsquo;arriv\u00e9e dans la routine de traitement. Ainsi nous obtenons de meilleures performances pour l&rsquo;ensemble des t\u00e2ches diff\u00e9r\u00e9es ou p\u00e9riodiques.<\/p>\n<p style=\"text-align: justify;\">Mais comment peut-il anticiper la dur\u00e9e&nbsp;? Simplement en se basant sur une valeur pr\u00e9programm\u00e9e, que l&rsquo;on peut consulter dans le pseudo-fichier <code>\/proc\/xenomai\/latency<\/code>. En voici un exemple.<\/p>\n<pre>[Panda]# cat <strong>\/proc\/xenomai\/latency <\/strong>\n2499\n[Panda]#<\/pre>\n<p style=\"text-align: justify;\">Xenomai consid\u00e8re qu&rsquo;il s&rsquo;\u00e9coulera environ 2.5 microsecondes au minimum entre l&rsquo;arriv\u00e9e d&rsquo;une interruption et son traitement, aussi avance-t-il de cette dur\u00e9e les timers qu&rsquo;il programme.<\/p>\n<p style=\"text-align: justify;\">Mais cette valeur est pr\u00e9programm\u00e9e arbitrairement. Il serait int\u00e9ressant de l&rsquo;ajuster exp\u00e9rimentalement en fonction de notre mat\u00e9riel. Pour cela il faut simplement effacer la latence minimale, et relancer le programme <code>latency<\/code>.<\/p>\n<pre># <strong>echo 0 &gt; \/proc\/xenomai\/latency<\/strong>\n# <strong>\/usr\/xenomai\/bin\/latency -p 100 -T 14400<\/strong>\n== Sampling period: 100 us\n== Test mode: periodic user-mode task\n== All results in microseconds\nwarming up...\nRTT|  00:00:01  (periodic user-mode task, 100 us period, priority 99)\nRTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst\nRTD|      3.204|      3.355|      9.928|       0|     0|      3.204|      9.928\nRTD|      2.950|      3.234|      9.692|       0|     0|      2.950|      9.928\nRTD|      2.962|      3.317|     11.464|       0|     0|      2.950|     11.464\nRTD|      2.948|      3.134|     15.281|       0|     0|      2.948|     15.281\nRTD|      2.930|      3.140|      9.974|       0|     0|      2.930|     15.281\n[...]\nRTD|      2.966|      3.275|     10.553|       0|     0|      2.136|     18.827\nRTD|      2.962|      3.283|     10.033|       0|     0|      2.136|     18.827\nRTD|      2.962|      3.277|      9.607|       0|     0|      2.136|     18.827\nRTD|      2.952|      3.277|     10.422|       0|     0|      2.136|     18.827\n---|-----------|-----------|-----------|--------|------|-------------------------\nRTS|      2.136|      3.216|     18.827|       0|     0|    04:00:00\/04:00:00<\/pre>\n<p style=\"text-align: justify;\">Il n&rsquo;y a plus d&rsquo;anticipation, les latences sont donc naturellement un peu plus longues. Au bout de quatre heures, avec un syst\u00e8me tr\u00e8s peu charg\u00e9, nous avons obtenue une latence la plus faible de 2.136 microsecondes. Ce qui est plus faible que les 2.5 qui \u00e9taient pr\u00e9programm\u00e9s auparavant et explique donc l&rsquo;\u00e9cart n\u00e9gatif de 0.39 microsecondes observ\u00e9 durant la premi\u00e8re exp\u00e9rience.<\/p>\n<p style=\"text-align: justify;\">Connaissant cette valeur minimale, nous pouvons l&rsquo;inscrire dans <code>\/proc\/xenomai\/latency<\/code> et relancer l&rsquo;exp\u00e9rience.<\/p>\n<pre># <strong>echo 2136 &gt; \/proc\/xenomai\/latency<\/strong>\n# <strong>\/usr\/xenomai\/bin\/latency -p 100 -T 14400<\/strong>\n== Sampling period: 100 us\n== Test mode: periodic user-mode task\n== All results in microseconds\nwarming up...\nRTT|  00:00:01  (periodic user-mode task, 100 us period, priority 99)\nRTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst\nRTD|      1.103|      1.265|      8.152|       0|     0|      1.103|      8.152\nRTD|      0.853|      1.204|      8.138|       0|     0|      0.853|      8.152\nRTD|      0.857|      1.216|      7.853|       0|     0|      0.853|      8.152\n[...]\nRTD|      0.827|      1.047|      8.321|       0|     0|      0.039|     21.178\nRTD|      0.839|      1.043|      7.926|       0|     0|      0.039|     21.178\nRTD|      0.831|      1.041|      7.188|       0|     0|      0.039|     21.178\nRTD|      0.829|      1.039|      7.587|       0|     0|      0.039|     21.178\n---|-----------|-----------|-----------|--------|------|-------------------------\nRTS|      0.039|      1.130|     21.178|       0|     0|    04:00:00\/04:00:00<\/pre>\n<p style=\"text-align: justify;\">Cette fois notre syst\u00e8me est tr\u00e8s bien calibr\u00e9, la latence minimale \u00e9tant descendue \u00e0 39 nanosecondes.<\/p>\n<p style=\"text-align: justify;\">Notez que la valeur exacte peut \u00eatre ainsi inscrite dans <code>\/proc\/xenomai\/latency<\/code> dans le cours d&rsquo;un script de d\u00e9marrage par exemple, mais \u00e9galement \u00eatre programm\u00e9e \u00ab\u00a0en dur\u00a0\u00bb \u00e0 la compilation du noyau dans le menu <em>Real Time Sub-system<\/em>, sous-menu <em>Timing<\/em>, option <em>Scheduling latency (ns)<\/em>.<\/p>\n<p><a href=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/07\/capture-menuconfig.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-2785\" title=\"Configuration dans le noyau de la latence\" src=\"http:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2012\/07\/capture-menuconfig-300x192.png\" alt=\"Configuration dans le noyau de la latence\" width=\"300\" height=\"192\" \/><\/a><\/p>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">La configuration compl\u00e8te d&rsquo;un syst\u00e8me temps r\u00e9el est un processus long, qui n\u00e9cessite des exp\u00e9rimentations sur de longues dur\u00e9es avec des charges tr\u00e8s vari\u00e9es tant en processus qu&rsquo;en interruptions. Xenomai nous permet de r\u00e9gler beaucoup de param\u00e8tres pour ajuster au mieux le syst\u00e8me au mat\u00e9riel cible.<\/p>\n<p style=\"text-align: justify;\">PS: Je manque un peu de temps pour tenir le blog en ce moment, une partie non n\u00e9gligeable de mon temps libre \u00e9tant consacr\u00e9 \u00e0 l&rsquo;exploration du Raspberry Pi (dont je reparlerai ici tr\u00e8s prochainement bien s\u00fbr).<\/p>","protected":false},"excerpt":{"rendered":"<p>J&rsquo;ai abord&eacute; dans plusieurs articles (Xenomai sur Pandaboard, GPIO, Pandaboard et temps r&eacute;el&nbsp; &ndash; Gestion des interruptions, La Pandaboard au poteau de torture &ndash; Timers Xenomai&hellip;) la question des latences maximales de Xenomai. Mais il est aussi int&eacute;ressant de conna&icirc;tre et de configurer correctement la latence minimale.<\/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-2781","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\/2781","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=2781"}],"version-history":[{"count":1,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/2781\/revisions"}],"predecessor-version":[{"id":3229,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/2781\/revisions\/3229"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=2781"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=2781"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=2781"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}