La Pandaboard au porteau de torture – 3 – Timers Linux et Linux-rt

Publié par cpb
Juil 02 2012

La Pandaboard au poteau de torture 3J’ai poursuivi les tests entamés dans l’article précédent de cette série,  en laissant tourner pendant de longues durées un programme qui vérifie les fluctuations d’un timer logiciel à 100 micro-secondes. Voici quelques résultats obtenus sur la Pandaboard avec un noyau Linux 3.4.1 en version “vanilla” pour commencer, puis avec l’application d’un patch Linux-rt par la suite.

Noyau Linux standard

Dans la première série d’expériences, mon programme de test se trouvait parfois sur le même cœur de processeur que les traitements d’interruption. Ceci pouvait provoquer des retards très longs (jusqu’à 6 millisecondes) dans le déclenchement des timers. J’ai alors essayé de mieux répartir les traitements.

Pendant plusieurs jours, j’ai fait fonctionner le programme de test sur un cœur de CPU, après avoir redirigé le traitement des interruptions sur l’autre cœur. Rappelons que pour transférer le traitement d’une interruption (par exemple 44) sur le second cœur, il faut écrire

[Panda]# echo 2 > /proc/irq/44/smp_affinity
[Panda]#

La valeur écrite est un masque représentant l’ensemble des CPU sur lesquels l’interruption peut être traitée. Pour rediriger toutes les interruptions vers un cœur, je fais

[Panda]# for i in /proc/irq/[0-9]*; do echo 2 > "$i/smp_affinity"; done
[Panda]#

Voici quelques résultats obtenus en plaçant successivement la tâche de mesure sur les cœurs 0 puis 1, et les interruptions sur l’autre cœur.

Fluctuation d'un timer Linux - jour 5Fluctuation d'un timer Linux - jour 6

Fluctuation d'un timer Linux - jour 7

Puisque nos résultats sont dépendants des traitements des interruptions, il est intéressant de réaliser les mêmes expérimentations avec le noyau Linux-rt qui améliorer les performances temps réel du noyau standard.

Noyau Linux modifié par le patch Linux-rt

J’ai compilé un noyau 3.4.1 après avoir appliqué un patch Linux-rt-9 adapté à ce noyau (avec ce fichier de configuration).

La première exécution s’est déroulée comme précédemment avec les interruptions sur un coeur et la tâche de mesure sur l’autre coeur. Les résultats sont comparables à ceux du noyau standard.

Fluctuations d'un timer Linux-rt - Essai 1

Pour vérifier si les résultats sont meilleurs avec Linux-rt ou non, j’ai à nouveau laissé le programme s’exécuter sur le même cœur que les traitements d’interruptions.

L’un des principaux intérêts du patch Linux-rt est de proposer des threaded interrupts, c’est-à-dire d’ordonnancer dans des threads du kernel les traitements à réaliser en réponse aux interruptions, plutôt que des les exécuter dans des tasklets (non ordonnancées, directement en sortie du handler bas-niveau) comme le fait le noyau standard. Nous pouvons profiter de ceci en fixant des priorités temps-réels aux traitements qui nous intéressent le plus.

J’ai tout d’abord voulu avoir un état des lieux sur les interrutions “threadées” et leur priorité. Voyons d’abord la liste des tâches après le boot d’un système Linux-rt sur la Pandaboard.

[Panda]# ps 
PID   USER     TIME   COMMAND
    1 root       0:01 init
    2 root       0:00 [kthreadd]
    3 root       0:02 [ksoftirqd/0]
    4 root       0:00 [kworker/0:0]
    5 root       0:00 [kworker/u:0]
    6 root       0:00 [posixcputmr/0]
    7 root       0:00 [migration/0]
    8 root       0:00 [posixcputmr/1]
    9 root       0:00 [migration/1]
   10 root       0:00 [kworker/1:0]
   11 root       0:01 [ksoftirqd/1]
   12 root       0:00 [khelper]
   13 root       0:00 [kworker/u:1]
   20 root       0:00 [irq/52-gpmc]
   49 root       0:00 [irq/41-l3-dbg-i]
   50 root       0:00 [irq/42-l3-app-i]
   96 root       0:00 [irq/44-DMA]
  249 root       0:00 [sync_supers]
  251 root       0:00 [bdi-default]
  253 root       0:00 [kblockd]
  266 root       0:00 [omap2_mcspi/1]
  268 root       0:00 [omap2_mcspi/2]
  270 root       0:00 [omap2_mcspi/3]
  272 root       0:00 [omap2_mcspi/4]
  282 root       0:00 [khubd]
  288 root       0:00 [irq/88-omap_i2c]
  293 root       0:00 [irq/39-TWL6030-]
  294 root       0:00 [twl6030-irq]
  315 root       0:00 [irq/89-omap_i2c]
  317 root       0:00 [irq/93-omap_i2c]
  320 root       0:00 [irq/94-omap_i2c]
  337 root       0:00 [cfg80211]
  432 root       0:00 [kswapd0]
  433 root       0:00 [fsnotify_mark]
  434 root       0:00 [crypto]
  448 root       0:00 [irq/57-OMAP DIS]
  451 root       0:00 [irq/85-omapdss_]
  452 root       0:00 [irq/116-omapdss]
  468 root       0:00 [OMAP UART0]
  470 root       0:00 [OMAP UART1]
  472 root       0:00 [OMAP UART2]
  474 root       0:00 [OMAP UART3]
  551 root       0:00 [irq/109-ehci_hc]
  557 root       0:00 [irq/108-ohci_hc]
  572 root       0:00 [kpsmoused]
  575 root       0:00 [kworker/1:1]
  579 root       0:00 [irq/363-rtc0]
  598 root       0:00 [irq/115-mmc0]
  600 root       0:00 [irq/91-mmc1]
  616 root       0:00 [irq/419-hwmod_i]
  627 root       0:00 [deferwq]
  633 root       0:00 [mmcqd/0]
  638 root       0:00 [kjournald]
  650 root       0:00 [flush-179:0]
  662 root       0:00 dropbear -r /etc/dbkey.rsa
  [...]
[Panda]#

Tous les processus dont les noms sont indiqués entre crochets par ps sont des threads du kernel. Nous pouvons remarquer ceux qui servent à exécuter les traitements en réception d’interruption, dont le nom est préfixé par irq/ suivi du numéro de l’IRQ. Pour connaître les priorités temps réel de ces threads, j’ai écrit le petit script suivant

liste-taches-rt: 
#! /bin/sh

LISTE_PID=$(ps | awk '{print $1}')

for PID in $LISTE_PID
do 
    chrt -p $PID 2>/dev/null | grep 'FIFO|RR' >/dev/null 2>&1
    if [ $? -eq 0 ];  then

        PRIO=$(chrt -p $PID | grep 'priority' | sed 's/^.*priority: //')
        CMD="$(cat /proc/$PID/comm)"
        printf "%2d %6d %sn" $PRIO $PID "$CMD"
    fi
done | sort -r

Voici le résultat sur un noyau Linux-rt fraîchement booté

[Panda]# liste-taches-rt 
99      9 migration/1
99      8 posixcputmr/1
99      7 migration/0
99      6 posixcputmr/0
50    616 irq/419-hwmod_i
50    600 irq/91-mmc1
50    598 irq/115-mmc0
50    579 irq/363-rtc0
50    557 irq/108-ohci_hc
50    551 irq/109-ehci_hc
50    452 irq/116-omapdss
50    451 irq/85-omapdss_
50    448 irq/57-OMAP DIS
50    320 irq/94-omap_i2c
50    317 irq/93-omap_i2c
50    315 irq/89-omap_i2c
50    293 irq/39-TWL6030-
50    288 irq/88-omap_i2c
50     96 irq/44-DMA
50     50 irq/42-l3-app-i
50     49 irq/41-l3-dbg-i
50     20 irq/52-gpmc
 1     11 ksoftirqd/1
 1      3 ksoftirqd/0
[Panda]#

Nous remarquons que les tâches migration et posixcputmr (un exemplaire sur chaque cœur) sont les plus prioritaires du système. Ensuite se trouvent les traitements pour les interruptions matérielles. Enfin les tâches ksoftirq sont les plus faibles en priorités temps réel (elle sont toutefois plus prioritaires que toutes les tâches temps partagé).

J’ai choisi de lancer la tâche de mesure sur le même CPU que les interruptions, mais à une priorité (70)  plus élevée que les interruptions traitées par les drivers de périphériques et inférieure à celles des handlers les plus prioritaires.

Fluctuation d'un timer Linux-rt - Jour 2

Afin de soumettre la carte à une charge très élevée en interruptions, elle était la cible de deux “ping” en mode flood supplémentaires par rapport aux expériences précédentes (donc trois ping en tout provenant de trois hôtes sur le même réseau).

Nous voyons que les performances moyennes sont équivalentes à celles obtenues avec un noyau Linux standard dans les mêmes circonstances (dans l’article précédent). Les résultats pour les pires fluctuations sont assez sensiblement meilleurs qu’avec Linux vanilla.

J’ai prolongé ce test durant une  journée supplémentaire, ce qui confirme ces résultats :

Fluctuation d'un timer Linux-rt - Jour 3

Conclusion

En utilisant sur la Pandboard le noyau Linux standard ou celui “patché” Linux-rt, nous avons observé que les timers logiciels offraient une très bonne stabilité en moyenne : sur chaque intervalle de cinq secondes, la période mesurée moyenne est entre 99 et 100 microsecondes pour une période demandée de 100 microsecondes.

Lorsque le système n’est pas particulièrement chargé ou lorsque la tâche de mesure s’exécute sur un coeur de processeur peu sollicité par les interruptions, les retards de traitement restent inférieurs à la milliseconde.

En revance, si le système est très chargé – notamment en interruption – les pires retards peuvent atteindre plusieurs millisecondes (2 à 3 avec Linux-rt, plus de 6 avec Linux standard). Ceci est représentatif d’un système temps réel souple (soft realtime), et ces performances peuvent s’avérer insuffisantes dans certaines applications. Dans le prochain article nous allons reprendre les mêmes mesures sur un noyau comportant l’extension Xenomai et vérifier si le comportement temps réel est vraiment amélioré.

Pour en savoir plus…

URL de trackback pour cette page