Les latences de Xenomai

Publié par cpb
Juil 23 2012

Latences de Xenomai
J’ai abordé dans plusieurs articles (Xenomai sur Pandaboard, GPIO, Pandaboard et temps réel  – Gestion des interruptions, La Pandaboard au poteau de torture – Timers Xenomai…) la question des latences maximales de Xenomai. Mais il est aussi intéressant de connaître et de configurer correctement la latence minimale.

Mesure des latences

La notion de latence fait référence ici à la durée qui s’écoule entre le déclenchement d’une interruption et le début du traitement que nous avons associé à cette interruption. Cette durée dépend en grande partie du système d’exploitation et du matériel. On s’intéresse généralement à la latence maximale car c’est elle qui concerne les applications temps réel par exemple. Ainsi le cahier des charges d’un projet peut imposer qu’entre l’activation d’un capteur externe et la réponse du système il ne s’écoule pas plus de 100 microsecondes quels que soient la charge logicielle ou la quantité d’interruptions se déclenchant à ce moment.

La latence maximale se mesure avec des expériences de longues durées (plusieurs jours voire plusieurs semaines) sous une très haute charge (en tâches et en interruptions). À titre d’exemple, nous avons observé dans les articles mentionnés plus haut que sur une carte Pandaboard, le système Xenomai 2.6.1 nous permet d’obtenir une latence maximale de 50 microsecondes environ.

Pour cela, un utilitaire livré avec Xenomai mesure le temps s’écoulant entre le déclenchement d’un timer matériel et l’activation de la routine de traitement. Cet outil s’appelle latency, voici un exemple d’utilisation sur un système faiblement chargé.

# /usr/xenomai/bin/latency -p 100 -T 14400
== Sampling period: 100 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT|  00:00:01  (periodic user-mode task, 100 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|      0.724|      0.996|     13.918|       0|     0|      0.724|     13.918
RTD|      0.490|      1.182|     12.357|       0|     0|      0.490|     13.918
RTD|      0.486|      0.966|      8.396|       0|     0|      0.486|     13.918
RTD|      0.468|      1.001|     14.261|       0|     0|      0.468|     14.261
RTD|      0.478|      0.970|     12.934|       0|     0|      0.468|     14.261
RTD|      0.476|      0.988|      6.640|       0|     0|      0.468|     14.261
RTD|      0.494|      1.001|      8.414|       0|     0|      0.468|     14.261
RTD|      0.488|      0.964|      9.918|       0|     0|      0.468|     14.261
RTD|      0.476|      0.956|      7.882|       0|     0|      0.468|     14.261
RTD|      0.484|      0.956|      8.386|       0|     0|      0.468|     14.261
RTD|      0.486|      0.960|      7.815|       0|     0|      0.468|     14.261
RTD|      0.486|      0.972|      8.244|       0|     0|      0.468|     14.261
[...]

Les options utilisées ici indiquent que le timer doit suivre une période de 100 microsecondes, et que la durée totale de la mesure sera de 14400 secondes soient 4 heures.

L’outil latency affiche une ligne de résultats intermédiaires toutes les secondes, sur lesquelles il présente les latences minimales (lat min), moyennes (lat avg) et maximales (lat max) rencontrées pendant la seconde écoulée. Ensuite il indique les dépassements de timers (overrun) et les changements de mode (msw) au sens de Xenomai.
Enfin les deux dernières colonnes indiquent les plus courtes (lat best) et plus longues (lat worst) latences rencontrées sur tout le déroulement du processus.

Au bout de quatre heures l’expérience se termine sur les résultats suivants.

RTD|      0.482|      0.976|      8.652|       0|     0|     -0.393|     31.192
RTD|      0.496|      0.968|      6.450|       0|     0|     -0.393|     31.192
RTD|      0.527|      0.982|     13.291|       0|     0|     -0.393|     31.192
RTD|      0.494|      0.964|      7.890|       0|     0|     -0.393|     31.192
RTD|      0.456|      0.960|      6.482|       0|     0|     -0.393|     31.192
RTD|      0.492|      0.970|     12.140|       0|     0|     -0.393|     31.192
RTD|      0.498|      0.966|      7.265|       0|     0|     -0.393|     31.192
RTD|      0.503|      0.980|      9.224|       0|     0|     -0.393|     31.192
---|-----------|-----------|-----------|--------|------|-------------------------
RTS|     -0.393|      0.900|     31.192|       0|     0|    04:00:00/04:00:00
#

Nous voyons que la pire latence rencontrée ici est de 31.192 microsecondes. Mais le système n’était pas très sollicité et on pourrait rencontrer des latences jusqu’à 50 microsecondes environ sous une forte charge.

Ce qui est plus surprenant c’est la latence minimale : elle est négative ! Cela signifierait donc que la routine de traitement se déclenche avant l’interruption timer ? Plutôt étrange…

Anticipation de la latence minimale

En réalité, lorsque Xenomai programme le déclenchement d’un timer, il anticipe la durée qui s’écoulera entre l’interruption matérielle et l’arrivée dans la routine de traitement. Ainsi nous obtenons de meilleures performances pour l’ensemble des tâches différées ou périodiques.

Mais comment peut-il anticiper la durée ? Simplement en se basant sur une valeur préprogrammée, que l’on peut consulter dans le pseudo-fichier /proc/xenomai/latency. En voici un exemple.

[Panda]# cat /proc/xenomai/latency 
2499
[Panda]#

Xenomai considère qu’il s’écoulera environ 2.5 microsecondes au minimum entre l’arrivée d’une interruption et son traitement, aussi avance-t-il de cette durée les timers qu’il programme.

Mais cette valeur est préprogrammée arbitrairement. Il serait intéressant de l’ajuster expérimentalement en fonction de notre matériel. Pour cela il faut simplement effacer la latence minimale, et relancer le programme latency.

# echo 0 > /proc/xenomai/latency
# /usr/xenomai/bin/latency -p 100 -T 14400
== Sampling period: 100 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT|  00:00:01  (periodic user-mode task, 100 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|      3.204|      3.355|      9.928|       0|     0|      3.204|      9.928
RTD|      2.950|      3.234|      9.692|       0|     0|      2.950|      9.928
RTD|      2.962|      3.317|     11.464|       0|     0|      2.950|     11.464
RTD|      2.948|      3.134|     15.281|       0|     0|      2.948|     15.281
RTD|      2.930|      3.140|      9.974|       0|     0|      2.930|     15.281
[...]
RTD|      2.966|      3.275|     10.553|       0|     0|      2.136|     18.827
RTD|      2.962|      3.283|     10.033|       0|     0|      2.136|     18.827
RTD|      2.962|      3.277|      9.607|       0|     0|      2.136|     18.827
RTD|      2.952|      3.277|     10.422|       0|     0|      2.136|     18.827
---|-----------|-----------|-----------|--------|------|-------------------------
RTS|      2.136|      3.216|     18.827|       0|     0|    04:00:00/04:00:00

Il n’y a plus d’anticipation, les latences sont donc naturellement un peu plus longues. Au bout de quatre heures, avec un système très peu chargé, nous avons obtenue une latence la plus faible de 2.136 microsecondes. Ce qui est plus faible que les 2.5 qui étaient préprogrammés auparavant et explique donc l’écart négatif de 0.39 microsecondes observé durant la première expérience.

Connaissant cette valeur minimale, nous pouvons l’inscrire dans /proc/xenomai/latency et relancer l’expérience.

# echo 2136 > /proc/xenomai/latency
# /usr/xenomai/bin/latency -p 100 -T 14400
== Sampling period: 100 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT|  00:00:01  (periodic user-mode task, 100 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|      1.103|      1.265|      8.152|       0|     0|      1.103|      8.152
RTD|      0.853|      1.204|      8.138|       0|     0|      0.853|      8.152
RTD|      0.857|      1.216|      7.853|       0|     0|      0.853|      8.152
[...]
RTD|      0.827|      1.047|      8.321|       0|     0|      0.039|     21.178
RTD|      0.839|      1.043|      7.926|       0|     0|      0.039|     21.178
RTD|      0.831|      1.041|      7.188|       0|     0|      0.039|     21.178
RTD|      0.829|      1.039|      7.587|       0|     0|      0.039|     21.178
---|-----------|-----------|-----------|--------|------|-------------------------
RTS|      0.039|      1.130|     21.178|       0|     0|    04:00:00/04:00:00

Cette fois notre système est très bien calibré, la latence minimale étant descendue à 39 nanosecondes.

Notez que la valeur exacte peut être ainsi inscrite dans /proc/xenomai/latency dans le cours d’un script de démarrage par exemple, mais également être programmée « en dur » à la compilation du noyau dans le menu Real Time Sub-system, sous-menu Timing, option Scheduling latency (ns).

Configuration dans le noyau de la latence

Conclusion

La configuration complète d’un système temps réel est un processus long, qui nécessite des expérimentations sur de longues durées avec des charges très variées tant en processus qu’en interruptions. Xenomai nous permet de régler beaucoup de paramètres pour ajuster au mieux le système au matériel cible.

PS: Je manque un peu de temps pour tenir le blog en ce moment, une partie non négligeable de mon temps libre étant consacré à l’exploration du Raspberry Pi (dont je reparlerai ici très prochainement bien sûr).

2 Réponses

  1. chc69 dit :

    Hi,

    It’s a great job of Xenomai latency utility.
    I have few question about the calibration.

    1. the target of calibration is to make « RTS lat min » approach to ZERO, am I right?

    2. when I try to test kernel mode(Test mode: in-kernel periodic task), should I do it(re-calibrate) again?

    • cpb dit :

      Hi,

      1. Yes, the calibration goal is to have the minimal latency as close as possible to zero.
      2. I’m not sure about the need to run calibration for kernel mode. I would probably write the previously measured latency into the kernel configuration (in the Realtime subsystem menu) and use the system as is.

URL de trackback pour cette page