Premiers pas avec Xenomai

Image non disponible


précédentsommairesuivant

VI. Installation et configuration

VI-A. Configuration utilisée pour la rédaction de ce document

Sauf mention contraire, les exemples présentés dans ce document ont été développés et testés sur un PC portable Fujitsu-Siemens Esprimo D9500, Intel Core 2 Duo 2,2 GHz (T7500), 2 Go de RAM.

Les versions utilisées sont :

  • Mandriva Free 2008.0 x86_64 ;
  • vanilla kernel Linux 2.6.24 ;
  • Xenomai 2.4.3 ;
  • ADEOS 2.6.24-2.0-06.

VI-B. Récupération des sources

Quelle que soit la distribution utilisée, Xenomai se greffe toujours sur le vanilla kernel. En effet, les sources livrées avec les distributions étant modifiées, l'application du patch échouera.

Le code source « originel » du noyau se trouve sur www.kernel.org.

Quant aux sources de Xenomai, elles sont téléchargeables à l'adresse suivante : http://download.gna.org/xenomai/stable.

ADEOS est présent dans le package Xenomai. Cependant, il se peut que de nouvelles versions soient disponibles. C'est pourquoi vous devez vérifier à l'adresse http://download.gna.org/adeos/patches, si en fonction de la version du noyau Linux et de l'architecture, une version plus récente existe.

Attention à ne pas télécharger des versions de test. Leur nom contient rc (Release Candidate).

VI-C. Procédure d'installation, patch des sources du noyau

L'installation nécessite d'être root.

Les sources et une version plus récente d'ADEOS ont été récupérées et placées dans le répertoire /usr/src.

 
Sélectionnez
[root@localhost src]# pwd
/usr/src
[root@localhost src]# whoami
root
[root@localhost src]# ls
adeos-ipipe-2.6.24-x86-2.0-06.patch  linux-2.6.24.tar.bz2  xenomai-2.4.3.tar.bz2
[root@localhost src]# tar xjf linux-2.6.24.tar.bz2
[root@localhost src]# tar xjf xenomai-2.4.3.tar.bz2
[root@localhost src]# ls
adeos-ipipe-2.6.24-x86-2.0-06.patch  linux-2.6.24/  linux-2.6.24.tar.bz2  xenomai-2.4.3/  xenomai-2.4.3.tar.bz2
[root@localhost src]# xenomai-2.4.3/scripts/prepare-kernel.sh
Linux tree [default /lib/modules/2.6.25.4/source]: /usr/src/linux-2.6.24
Target architecture [default x86_64]:
Adeos patch [default /usr/src/xenomai-2.4.3/ksrc/arch/x86/patches/adeos-ipipe-2.6.24-x86-2.0-04.patch]: /usr/src/adeos-ipipe-2.6.24-x86-2.0-06.patch
patching file Makefile
patching file arch/x86/Kconfig
patching file arch/x86/Makefile_32
patching file arch/x86/boot/Makefile
patching file arch/x86/boot/compressed/Makefile_32
patching file arch/x86/kernel/Makefile_32
patching file arch/x86/kernel/Makefile_64
patching file arch/x86/kernel/apic_32.c
patching file arch/x86/kernel/apic_64.c
patching file arch/x86/kernel/cpu/mtrr/cyrix.c
patching file arch/x86/kernel/cpu/mtrr/generic.c
patching file arch/x86/kernel/entry_32.S
patching file arch/x86/kernel/entry_64.S
patching file arch/x86/kernel/genapic_flat_64.c
patching file arch/x86/kernel/head64.c
patching file arch/x86/kernel/i8253.c
patching file arch/x86/kernel/i8259_32.c
patching file arch/x86/kernel/i8259_64.c
patching file arch/x86/kernel/io_apic_32.c
patching file arch/x86/kernel/io_apic_64.c
patching file arch/x86/kernel/ipipe.c
patching file arch/x86/kernel/mcount_32.S
patching file arch/x86/kernel/mcount_64.S
patching file arch/x86/kernel/nmi_32.c
patching file arch/x86/kernel/nmi_64.c
patching file arch/x86/kernel/process_32.c
patching file arch/x86/kernel/process_64.c
patching file arch/x86/kernel/setup64.c
patching file arch/x86/kernel/smp_32.c
patching file arch/x86/kernel/smp_64.c
patching file arch/x86/kernel/smpboot_32.c
patching file arch/x86/kernel/smpboot_64.c
patching file arch/x86/kernel/time_32.c
patching file arch/x86/kernel/traps_32.c
patching file arch/x86/kernel/traps_64.c
patching file arch/x86/kernel/vm86_32.c
patching file arch/x86/kernel/vsyscall_64.c
patching file arch/x86/lib/mmx_32.c
patching file arch/x86/lib/thunk_64.S
patching file arch/x86/mach-visws/visws_apic.c
patching file arch/x86/mm/fault_32.c
patching file arch/x86/mm/fault_64.c
patching file drivers/pci/htirq.c
patching file drivers/serial/8250.c
patching file include/asm-x86/apic_32.h
patching file include/asm-x86/apic_64.h
patching file include/asm-x86/hw_irq_32.h
patching file include/asm-x86/hw_irq_64.h
patching file include/asm-x86/i8259.h
patching file include/asm-x86/io_apic_64.h
patching file include/asm-x86/ipi.h
patching file include/asm-x86/ipipe.h
patching file include/asm-x86/ipipe_32.h
patching file include/asm-x86/ipipe_64.h
patching file include/asm-x86/ipipe_base.h
patching file include/asm-x86/ipipe_base_32.h
patching file include/asm-x86/ipipe_base_64.h
patching file include/asm-x86/irqflags_32.h
patching file include/asm-x86/irqflags_64.h
patching file include/asm-x86/mmu_context_32.h
patching file include/asm-x86/mmu_context_64.h
patching file include/asm-x86/nmi_32.h
patching file include/asm-x86/nmi_64.h
patching file include/asm-x86/processor_64.h
patching file include/asm-x86/spinlock_32.h
patching file include/asm-x86/system_64.h
patching file include/asm-x86/unistd_64.h
patching file include/asm-x86/vsyscall.h
patching file include/linux/hardirq.h
patching file include/linux/ipipe.h
patching file include/linux/ipipe_base.h
patching file include/linux/ipipe_compat.h
patching file include/linux/ipipe_percpu.h
patching file include/linux/ipipe_tickdev.h
patching file include/linux/ipipe_trace.h
patching file include/linux/irq.h
patching file include/linux/kernel.h
patching file include/linux/linkage.h
patching file include/linux/mm.h
patching file include/linux/preempt.h
patching file include/linux/sched.h
patching file include/linux/spinlock.h
patching file include/linux/spinlock_types.h
patching file init/Kconfig
patching file init/main.c
patching file kernel/Makefile
patching file kernel/exit.c
patching file kernel/fork.c
patching file kernel/ipipe/Kconfig
patching file kernel/ipipe/Kconfig.debug
patching file kernel/ipipe/Makefile
patching file kernel/ipipe/core.c
patching file kernel/ipipe/tracer.c
patching file kernel/irq/chip.c
patching file kernel/lockdep.c
patching file kernel/power/disk.c
patching file kernel/power/swsusp.c
patching file kernel/printk.c
patching file kernel/sched.c
patching file kernel/signal.c
patching file kernel/spinlock.c
patching file kernel/time/tick-common.c
patching file lib/Kconfig.debug
patching file lib/bust_spinlocks.c
patching file lib/ioremap.c
patching file lib/smp_processor_id.c
patching file lib/spinlock_debug.c
patching file mm/memory.c
patching file mm/mlock.c
patching file mm/vmalloc.c
[root@localhost src]#

Il ne doit pas y avoir de message « Hunk... ».

On peut maintenant passer à la configuration proprement dite du noyau...

VI-D. Configuration de Xenomai dans le noyau Linux

VI-D-1. Lancement de l'utilitaire de configuration du noyau

La configuration de Xenomai est réalisée à travers la même interface que celle du noyau Linux.

Tapez les commandes suivantes 

 
Sélectionnez
[root@localhost src]# cd linux-2.6.24
[root@localhost linux-2.6.24]#  make menuconfig

Optimisez le noyau afin qu'il soit le plus proche possible de la configuration matérielle (29). Supprimez tout ce qui est en trop (SMP sur uniprocesseur) et traquez les parties non optimisées (choix du type de CPU...).
Vous risquez de faire de nombreuses compilations avant de trouver la bonne combinaison d'options. Supprimez les options et les drivers inutiles afin de gagner du temps !

VI-D-2. Le choix des options

Xenomai se trouve dans le menu Real-time sub-system.

Image non disponible

Ce paragraphe détaille les différentes options de ce menu(30).

Xenomai

Nucleus

Nucleus est le nom du noyau interne Xenomai. Ce « Nucleus » n'a pas de rapport avec celui de Mentor Graphics.

Pervasive real-time support in user-space

Active le support temps réel depuis le mode user (processus Linux).
Activé par défaut, sinon les fonctionnalités temps réel ne sont disponibles que depuis le noyau Linux.

Interrupt shield support

Active l'Interrupt Shield comme décrit § V.B.5.
Désactivé par défaut car diminue les performances, à activer uniquement si nécessaire.

Priority coupling support

Politique de co-scheduling décrite § V.B.2, la priorité des tâches prend le pas sur le mode. En cas de désactivation, les tâches en primarymode seront alors toujours prioritaires par rapport à celles en secondary.
Activé par défaut. Configurable par la suite tâche par tâche.

Optimize as pipeline head

Force Xenomai comme le premier à traiter les interruptions.
Activé par défaut (est prévu pour le cas - très théorique - où il y aurait d'autres noyaux en plus de Xenomai et Linux).

Number of pipe devices

 

Nombres de pipes utilisables pour la communication avec Linux.
À modifier si le nombre de devices /dev/rtpn n'est pas suffisant.

Number of registry slots

Nombre total d'objets temps réel instantiables à un instant. Par objet temps réel on désigne les tâches, les sémaphores...

Size of the system heap (Kb)

 

Zone de mémoire allouée pour le noyau Nucleus. Si certains appels système Xenomai renvoient ENOMEM, cette valeur devra être augmentée.

Size of the private stack pool (Kb)

 

Pile allouée aux tâches en mode noyau (pour driver RTDM et tâche Xenomai implémentée dans un module noyau).

Statistics collection

Collecte de statistiques dans le fichier.

Debug support

Nucleus Debugging support

Active le débogage Nucleus (ajoute des traces printk) : trace les spinlocks...
Désactivé par défaut, utilisé pour le développement de Xenomai.

Queue Debugging support

Active le débogage des files de messages internes et utilisées via les skins (ajoute des traces printk et des contrôles).
Désactivé par défaut.

Registry Debugging support

Fonctionnalité sans effet dans la version 2.4.3.

Timer Debugging support

Fonctionnalité sans effet dans la version 2.4.3.

Watchdog support

Détecte si une tâche Xenomai garde le processeur plus de [Watchdog timeout] secondes sans rescheduler. Si c'est le cas, la tâche est suspendue. Utilisée lors de la mise au point d'applications, cette option évite de redémarrer la machine si une tâche ne rend pas la main.

En cas de déclenchement, un message du type :
Xenomai: watchdog triggered -- killing runaway thread '...' sera accessible par dmesg.

Watchdog timeout

Valeur de ce timeout comprise entre 1 et 60 secondes.

Shared interrupts (31)

Le partage d'interruptions est à activer si Xenomai doit prendre en charge des périphériques partageant la même interruption (exemple : carte à quatre ports série). Ce type de configuration est cependant à éviter car il introduit des latences.

Timing

Enable periodic timing

 

Le temps peut être manipulé à travers deux « unités » lors de l'utilisation de l'API Xenomai  :

  • soit en ticks si cette option est activée, comme sous VxWorks par exemple. La durée d'un tick est alors fixée lors de la compilation du noyau et éventuellement modifiable lors de l'exécution (rt_timer_set_mode dans l'API native par exemple) ;
  • soit en nanosecondes.

Scheduling latency (ns)

 

Délai de retour à l'exécution d'une tâche après une interruption (timer notamment). Si ce paramètre vaut 0 (défaut), une valeur par défaut sera considérée.

Ce délai est utilisé en interne pour corriger la date d'échéance des timers.

Scalability

O(1) scheduler

Active le scheduler en O(1), c'est-à-dire que le temps mis pour choisir une tâche parmi les éligibles est constant, et ce quel que soit leur nombre. Cette option présente un intérêt si ce nombre est supérieur à 10.
L'implémentation de ce scheduler est réalisée par une liste chaînée par niveau de priorité.

Timer indexing method

Le nombre de timers à gérer influe sur les performances du scheduler Xenomai, c'est pourquoi plusieurs algorithmes sont proposés.
Détermine l'algorithme utilisé pour démarrer, arrêter, échoir les timers apériodiques (les périodiques sont toujours indexés selon la méthode linéaire). Les choix ci-dessous sont les structures de données utilisées par ces algorithmes. Si l'option « Enable periodic timing » est activée, ce sera forcément la structure « Timer wheel » qui sera utilisée.

Linear

Complexité en O(N), le temps dépend du nombre de timers utilisés, recommandé jusqu'à 10 timers. Choix par défaut.

Tree

Complexité en O(log N) reposant sur un arbre binaire.

Binary heap capacity

L'arbre binaire étant alloué de manière statique, ce paramètre fixe le nombre maximum de timers simultanés.

Hash

Complexité en O(1), c'est-à-dire indépendante du nombre de timers. L'algorithme utilisé est décrit dans le paragraphe XXI.B.

Timer wheel step

Le Timer wheel step est la durée d'un slot (entrée dans la structure de donnée circulaire contenant les timers non échus). Le nombre de slots est fixé à 64 et il n'est pas modifiable.

Machine

Enable FPU support

Réservé aux processeurs sans FPU, ce qui n'est pas le cas sur les PC. Il n'y a priori aucune raison de la désactiver.

NMI watchdog

Le NMI est utilisé dans Linux pour le débogage du noyau lorsque le système est gelé.

Enable NMI watchdog

Sert au débogage du noyau Nucleus.
Active un watchdog hardware via une interruption non masquable (NMI). Le watchdog est armé à chaque programmation du timer. Si le timer n'a pas expiré après [NMI watchdog latency threshold]ns, le watchdog claque en collectant des informations de débogage.

NMI watchdog latency threshold

Tolérance du watchdog à l'égard du timer.

SMI workaround

Le SMI est un système de gestion d'interruptions utilisé par certains composants (USB...). Les interruptions générées ne sont pas masquables et introduisent des temps de latence parasites pour Xenomai.

Disable SMI detection

Pour les systèmes non équipés du SMI.

Enable SMI workaround

Détecte les composants équipés du SMI et en désactive la partie SMI.

Globally disable SMI

Inhibe le SMI de tous les périphériques lorsque Xenomai a la main. Les options ci-dessous permettent une granularité plus fine.

Enable Intel-Specific USB2 SMI

Enable legacy USB2 SMI

Enable periodic SMI

Enable TCO SMI

Enable microcontroller SMI

Enable APM SMI

Enable legacy USB SMI

Enable ACPI BIOS SMI

Number of pre-allocated kernel stacks

Spécificité Intel Itanium 64.

Interfaces

Gestion des skins. Les options les plus triviales ne sont pas décrites.
La customisation très fine des skins et des fonctionnalités utilisées à l'intérieur de celles-ci permet de réduire l'empreinte mémoire.

Native API

Base period (us)

Dans le cas où l'option « Enable periodic timing » est activée, on configure ici l'équivalence 1 tick = x microsecondes.

Message pipes

Active le support des pipes, le nombre de pipes est configuré dans Number of pipe devices. Nécessaire pour l'appel des fonctions rt_pipe_* et donc la communication avec les tâches Linux « classiques ».

Bytes in buffer space

Taille du buffer par pipe.

Registry support

Counting semaphores

Nécessaire pour l'appel des fonctions rt_sem_*.

Events flags

Nécessaire pour l'appel des fonctions rt_event_*.

Mutexes

Nécessaire pour l'appel des fonctions rt_mutex_*.

Condition variables

Nécessaire pour l'appel des fonctions rt_cond_*.

Messages queues

Nécessaire pour l'appel des fonctions rt_queue_*.

Memory heaps

Active l'allocation dynamique de mémoire depuis les tâches Xenomai. Nécessaire pour l'appel des fonctions rt_heap_*.

Alarms

Active les watchdogs. Nécessaire pour l'appel des fonctions rt_alarm_*.

Message passing support

Active l'échange de messages entre tâches. Nécessaire pour l'appel des fonctions rt_task_send/receive/reply.

Interrupts

Nécessaire pour l'appel des fonctions rt_intr_*.

Debugging support

Dans les versions antérieures de Xenomai, les objets « orphelins » (files de messages...) persistaient après la fin de l'application. Ils devaient alors être explicitement détruits (de même qu'au début de l'application supportant ainsi les cas de terminaisons brutales). Dorénavant, les destructions d'objets sont automatiques, cette option produit un message lors de celles-ci.

POSIX API

Base period (us)

Shared Memory

Interrupts

Select syscall

Debugging support

pSOS+ emulator

uITRON API

VRTX emulator

RTAI emulator

Fifos

Semaphores

Shared Memory

Real-Time Driver Model

Active le support RTDM, à utiliser pour le support des cartes série, CAN et autres.

Base period (us)

Maximum number of RTDM file descriptors

Nombre maximum de descripteurs ouverts à un instant donné. La valeur par défaut apparaît largement suffisante pour la plupart des applications.

Select support for RTDM file descriptors

Support de la fonctionnalité équivalente au select.

RTDM debugging support

Drivers

Active les drivers fournis par défaut. Ils peuvent correspondre à des interfaces physiques ou virtuelles.

Serial drivers

16550A UART driver

Ce driver supporte les chipsets 8250 et 16550x.

Hardware access mode

Port-based I/O

Option correspondant à la plupart des configurations PC (où il y a un espace d'adressage distinct pour les périphériques).

Memory-mapped I/O

Pour les configurations autres que PC.

Any access mode

Les deux modes d'accès sont supportés.

Testing drivers

Drivers virtuels établissant des benchmarks.

Timer benchmarck driver

Kernel-only latency measurement module

IRQ benchmark driver

Context switch unit testing driver

CAN drivers

RT-Socket-CAN, CAN raw socket interface

Le noyau Nucleus et les drivers peuvent être soit compilés avec le noyau Linux, soit en tant que modules.

Les modules permettent de mettre au point les options sans redémarrer et ainsi de disposer d'un système plus flexible. Dans la suite du document la configuration utilisée repose sur Xenomai intégré au noyau.

VI-D-3. Amélioration de la latence de Linux (pour le secondary mode)

Comme nous l'avons vu, l'option « Low-Latency Desktop » améliore la latence de Linux, ce qui est important pour les tâches Xenomai en secondary mode.

Pour cela, il faut sélectionner :

Processor type and features/Preemption Model/Low-Latency Desktop.

VI-D-4. Fonctionnalités ou options Linux potentiellement problématiques ou incompatibles

Ce paragraphe rappelle(32) les options Linux à désactiver, pour quelle raison, et où les désactiver dans le noyau Linux. Le positionnement d'options incompatibles provoque des warnings lors de la configuration du noyau.

ACPI Support (processor) : [incompatible] gestion de l'énergie, la fréquence du processeur peut être diminuée ce qui introduit des latences lors du retour à la vitesse nominale.

Power management options/Power Management support/ACPI Support/Processor.

CPU frequency scaling :[incompatible] driver modulant la fréquence du processeur en fonction de sa charge. L'horloge TSC (compteur de cycles processeur utilisé pour les timers) peut être instable et le processeur peut mettre du temps à retrouver sa vitesse nominale.

Se trouve dans :

Power management options/CPU Frequency scaling.

PC speaker : [incompatible] risque de conflit avec le timer Xenomai pour les architectures utilisant un timer 8254

Device Drivers/Input device support/Miscellaneous devices/PC Speaker support.

Tout ce qui est graphique repose sur des timers, il peut être souhaitable de désactiver le serveur X.

VI-E. Compilation et installation du nouveau noyau

Tapez les commandes :

 
Sélectionnez
[root@localhost linux-2.6.24]#  make && make modules_install install

Le nouveau noyau s'appelle 2.6.24 par défaut, on peut lui donner un nom plus parlant (Linux_Xenomai...).

Pour accélérer la compilation : l'option -j<2 *nb CPU> de GNU Make parallélise les commandes.
Exemple : make -j4 pour un Intel Dual Core.

VI-F. Installation des bibliothèques Xenomai

Et enfin pour terminer, on installe les bibliothèques et les fichiers d'en-tête avant de rebooter la machine sur le nouveau noyau :

 
Sélectionnez
[root@localhost linux-2.6.24]# cd ../xenomai-2.4.3
[root@localhost xenomai-2.4.3]# ./configure && make && make install

VI-G. Démarrage sur le noyau incluant Xenomai

On jette un œil au log de démarrage pour s'assurer que tout va bien :

 
Sélectionnez
[dchabal@localhost ~]$ dmesg
I-pipe 2.0-06: pipeline enabled.
...
I-pipe: Domain Xenomai registered.
Xenomai: hal/x86_64 started.
Xenomai: real-time nucleus v2.4.3 (Back to Shalla-Bal) loaded.
Xenomai: SMI-enabled chipset found
Xenomai: SMI workaround enabled
Xenomai: starting native API services.
Xenomai: starting POSIX services.
Xenomai: starting RTDM services.
...

VI-H. Xenomai et le noyau Linux sont-ils correctement installés ?

Nous avons vu que certaines options étaient systématiques dans la dégradation des performances. Mais comme les configurations sont très différentes (version de noyau Linux ou Xenomai, matériel), à cette étape on ne peut pas encore affirmer qu'il ne reste pas des latency killers.

Image non disponible Cette étape est impérative car elle valide l'intégration de Linux et Xenomai avec le hardware.
En cas de problème, la mise au point peut être longue.
Les architectures de type PC sont délicates à évaluer car d'une machine à l'autre (même sous une dénomination commerciale similaire), il n'y a aucune garantie que les composants et les configurations (BIOS) soient identiques.

VI-H-1. Première mesure de la latence

En tant que root, exécutez /usr/xenomai/bin/latency.

Ce programme mesure par défaut la latence d'une tâche périodique, c'est-à-dire l'écart entre le moment où elle devrait être active et celui où elle l'est réellement.

Ce test est exécuté dans des conditions longues (plusieurs minutes voire heures) et de stress, en parallèle nous lançons la commande :

 
Sélectionnez
[dchabal@localhost ~]$ dd if=/dev/zero of=/dev/null

Lors de la première exécution, nous avons au bout de quelques secondes :

 
Sélectionnez
[root@localhost bin]# /usr/xenomai/bin/latency
== 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|----lat best|---lat worst
RTD|       0.235|       0.565|       1.347|       0|       0.235|       1.347
RTD|       0.226|       0.568|       3.734|       0|       0.226|       3.734
RTD|       0.258|       0.565|       1.463|       0|       0.226|       3.734
RTD|       0.219|       0.566|       1.357|       0|       0.219|       3.734
RTD|       0.200|       0.567|       1.400|       0|       0.200|       3.734
RTD|       0.282|       0.567|       2.192|       0|       0.200|       3.734
RTD|       0.218|       0.565|       2.295|       0|       0.200|       3.734
RTD|       0.235|       0.567|       2.710|       0|       0.200|       3.734
RTD|       0.221|       0.568|       3.701|       0|       0.200|       3.734
RTD|       0.222|       0.632|       2.052|       1|       0.200|     198.581
RTD|       0.201|       0.625|       2.078|       1|       0.200|     198.581
RTD|       0.223|       0.627|       3.737|       1|       0.200|     198.581
RTD|       0.179|       0.627|       2.217|       1|       0.179|     198.581
RTD|       0.345|       0.624|       1.957|       1|       0.179|     198.581
RTD|       0.202|       0.625|       2.149|       1|       0.179|     198.581
---|------------|------------|------------|--------|-------------------------
RTS|       0.179|       0.593|     198.581|       1|    00:00:17/00:00:17

Le cas le plus défavorable (qui est toujours celui à considérer) donne une latence de 198 µs.

On considère un temps supérieur à 100 µs comme pathologique. Sur une architecture de type PC, on s'attend à trouver des valeurs comprises entre 10 et 50 µs(33).

La valeur obtenue n'est pas acceptable, le paragraphe suivant décrit la procédure d'investigation afin de l'expliquer et la diminuer.

VI-H-2. Le fichier TROUBLESHOOTING

Le fichier TROUBLESHOOTING contient des problèmes fréquemment rencontrés.

Les grandes pistes à suivre sont :

  • un problème d'accélération matérielle du serveur X, relancez le programme en mode console ;
  • une mauvaise configuration du noyau :
    • SMI non désactivé (vérifiez le journal de démarrage),
    • ACPI autres que processor à désactiver (sur PC : si vous percevez une variation du régime du ventilateur lors du lancement du bench, l'ACPI est probablement impliqué),
    • l'arrivée de NMI (cf. /proc/interrupts),
    • l'option idle=poll à passer sur la ligne de boot Lilo ou Grub ;
  • une mauvaise configuration directement au niveau du BIOS (Power management, SMI, ACPI encore et toujours, options Legacy*).

Si malgré cela, les mauvais résultats persistent, il faut investiguer avec I-pipe Tracer.

VI-H-3. Traquer les latences avec l'option I-pipe debugging

Si vous vous sentez un peu seul face à la question « qu'est-ce qui retarde ma tâche devant s'exécuter ? », ce débogueur va vous aider. Cela passe par deux choses :

  • l'instrumentation d'ADEOS, avec le traçage des interruptions et du temps passé dans leur traitement ;
  • l'instrumentation du code sous test, qui demande explicitement le gel du contexte conduisant au cas le plus défavorable.

On retourne dans notre configuration du noyau :

 
Sélectionnez
[root@localhost src]# cd /usr/src/linux-2.6.24
[root@localhost linux-2.6.24]#  make menuconfig

Puis dans le menu Kernel hacking, on active I-pipe debugging et son sous-menu Latency tracking.

Les options sont alors les suivantes :

I-pipe debugging

L'activation du débogage introduit une latence supplémentaire ;

Check for illicit cross-domain calls ;

Latency tracing

À activer pour notre investigation sur les temps de latence. Cette option peut être activée soit ici, soit via la commande echo 1 > /proc/ipipe/trace/enable ;

Enable tracing on boot ;

Instrument fonction entries ;

Trace IRQ-off times ;

Depth of trace log ;

Use vmalloc'ed trace buffer ;

Enable panic back traces.

Le détail des options, les fichiers de configuration et les fichiers produits se trouvent dans le manuel en ligne :http://www.xenomai.org/index.php/I-pipe:Tracer.

On conserve les choix par défaut puis on recompile (d'ailleurs, aviez-vous bien allégé le noyau ?) et on reboote :

 
Sélectionnez
[root@localhost linux-2.6.24]#  make && make modules_install install

On active le plus de traces possible :

 
Sélectionnez
[root@localhost bin]# echo 1 > /proc/ipipe/trace/enable
[root@localhost bin]# echo 1 > /proc/ipipe/trace/verbose

On agrandit la fenêtre de capture des évènements.

 
Sélectionnez
[root@localhost bin]# echo 128 > /proc/ipipe/trace/back_trace_points

On relance notre benchmark,avec l'option -f en plus (toujours en chargeant le système) :

 
Sélectionnez
[root@localhost bin]# /usr/xenomai/bin/latency -f
...
RTH|-----lat min|-----lat avg|-----lat max|-overrun|----lat best|---lat worst
RTD|       1.898|       3.099|       6.090|       3|       1.829|     202.798
RTD|       1.989|       3.133|     131.559|       4|       1.829|     202.798
RTD|       1.951|       3.105|       6.104|       4|       1.829|     202.798
RTD|       2.008|       3.197|       6.504|       4|       1.829|     202.798
RTD|       2.024|       3.091|       7.040|       4|       1.829|     202.798
RTD|       1.970|       3.136|       7.937|       4|       1.829|     202.798
RTD|       1.902|       3.117|       8.278|       4|       1.829|     202.798
RTD|       1.867|       3.091|       5.965|       4|       1.829|     202.798
RTD|       2.060|       3.082|       5.823|       4|       1.829|     202.798
RTD|       2.011|       3.094|       8.030|       4|       1.829|     202.798
RTD|       1.927|       3.099|       5.772|       4|       1.829|     202.798
RTD|       2.074|       3.133|       6.432|       4|       1.829|     202.798
RTD|       2.060|       3.132|     195.732|       5|       1.829|     202.798
RTD|       2.779|       3.112|       8.222|       5|       1.829|     202.798
RTD|       2.508|       3.072|       7.934|       5|       1.829|     202.798
RTD|       2.456|       3.124|       7.784|       5|       1.829|     202.798
RTD|       2.480|       3.117|       9.660|       5|       1.829|     202.798
RTD|       2.303|       3.049|       5.657|       5|       1.829|     202.798
---|------------|------------|------------|--------|-------------------------
RTS|       1.829|       3.086|     202.798|       5|    00:06:15/00:06:15

Il est normal que les résultats soient empirés par l'instrumentation.

Le résultat de la capture se trouve dans le fichier /proc/ipipe/trace/frozen :

 
Sélectionnez
I-pipe frozen back-tracing service on 2.6.24/ipipe-2.0-06
------------------------------------------------------------
CPU: 0, Freeze: 567619631513 cycles, Trace Points: 100 (+10)
Calibrated minimum trace-point overhead: 0.110 us

 +----- Hard IRQs ('|': locked)
 |+---- <unused>
 ||+--- <unused>
 |||+-- Xenomai
 ||||+- Linux ('*': domain stalled, '+': current, '#': current+stalled)
 |||||                        +---------- Delay flag ('+': > 1 us, '!': > 10 us)
 |||||                        |        +- NMI noise ('N')
 |||||                        |        |
      Type    User Val.   Time    Delay  Function (Parent)
:    +func                -221    0.105  do_sync_read+0x17 (vfs_read+0xed)
:    +func                -221    0.095  generic_file_aio_read+0x21 (do_sync_read+0xf2)
:    +func                -220    0.100  generic_segment_checks+0xe (generic_file_aio_read+0x4f)
:    +func                -220    0.105  do_generic_mapping_read+0x16 (generic_file_aio_read+0xf5)
:    +func                -220    0.095  cond_resched+0x9 (do_generic_mapping_read+0x79)
:    +func                -220    0.090  find_get_page+0x19 (do_generic_mapping_read+0x12b)
:    +func                -220    0.090  _read_lock_irq+0x9 (find_get_page+0x2f)
:    +func                -220    0.085  _read_lock_irqsave+0x16 (_read_lock_irq+0xe)
:    +func                -220    0.100  ipipe_check_context+0x19 (_read_lock_irqsave+0x25)
:    +func                -220    0.115  ipipe_check_context+0x19 (_read_lock_irqsave+0x41)
:    +func                -220    0.145  ipipe_check_context+0x19 (_read_lock_irqsave+0x71)
:    #func                -220    0.135  radix_tree_lookup+0x9 (find_get_page+0x3a)
:    #func                -219    0.105  _read_unlock_irq+0x9 (find_get_page+0x61)
:    #func                -219    0.100  __ipipe_unstall_root+0x9 (_read_unlock_irq+0x11)
:|   #begin   0x80000000  -219    0.095  __ipipe_unstall_root+0x5c (_read_unlock_irq+0x11)
:|   +end     0x80000000  -219    0.100  __ipipe_unstall_root+0x4b (_read_unlock_irq+0x11)
:    +func                -219    0.115  ipipe_check_context+0x19 (_read_unlock_irq+0x1d)
:    +func                -219    0.095  file_read_actor+0x21 (do_generic_mapping_read+0x2f2)
:    +func                -219    0.240  ipipe_check_context+0x19 (file_read_actor+0x125)
:    +func                -219    0.110  ipipe_check_context+0x19 (file_read_actor+0x192)
:    +func                -218    0.115  put_page+0x20 (do_generic_mapping_read+0x31d)
:    +func                -218    0.095  touch_atime+0xe (do_generic_mapping_read+0x386)
:    +func                -218    0.085  current_fs_time+0xe (touch_atime+0x98)
:    +func                -218    0.095  current_kernel_time+0xd (current_fs_time+0x16)
:    +func                -218    0.110  timespec_trunc+0xe (current_fs_time+0x27)
:    +func                -218    0.105  dnotify_parent+0x19 (vfs_read+0x12b)
:    +func                -218    0.105  _spin_lock+0xe (dnotify_parent+0x43)
:    +func                -218    0.120  ipipe_check_context+0x19 (_spin_lock+0x1d)
:    +func                -218    0.300  _spin_unlock+0x9 (dnotify_parent+0x83)
:|   +begin   0x00000081  -217    0.115  common_interrupt+0x6d (__ipipe_trace+0x1f7)
:|   +func                -217    0.170  __ipipe_handle_irq+0x21 (common_interrupt+0x75)
:|   +func                -217    0.155  __ipipe_set_irq_pending+0xa (__ipipe_handle_irq+0x22f)
:|   +func                -217    0.130  __ipipe_ack_irq+0x9 (__ipipe_handle_irq+0x24a)
:|   +func                -217    0.125  __ipipe_ack_fasteoi_irq+0x9 (__ipipe_ack_irq+0x20)
:|   +func                -217    0.120  ack_apic_level+0x9 (__ipipe_ack_fasteoi_irq+0x10)
:|   +func                -216    0.135  __mask_IO_APIC_irq+0xc (ack_apic_level+0x24)
:|   +func                -216+   1.534  io_apic_base+0x9 (__mask_IO_APIC_irq+0x6f)
:|   +func                -215    0.165  io_apic_base+0x9 (__mask_IO_APIC_irq+0x84)
:|   +func                -215+   1.499  io_apic_base+0x9 (__mask_IO_APIC_irq+0x91)
:|   +func                -213    0.155  __ipipe_walk_pipeline+0x10 (__ipipe_handle_irq+0x96)
:|   +func                -213    0.170  __ipipe_sync_stage+0x16 (__ipipe_walk_pipeline+0x118)
:|   #end     0x80000000  -213    0.165  __ipipe_sync_stage+0x31e (__ipipe_walk_pipeline+0x118)
:    #func                -213    0.140  __ipipe_get_irq_vector+0x9 (__ipipe_sync_stage+0x3a1)
:    #func                -213    0.140  do_IRQ+0x19 (__ipipe_sync_stage+0x3ee)
:    #func                -212    0.115  exit_idle+0x9 (do_IRQ+0x44)
:    #func                -212    0.095  irq_enter+0x9 (do_IRQ+0x49)
:    #func                -212    0.095  ipipe_check_context+0x19 (irq_enter+0x15)
:    #func                -212    0.125  idle_cpu+0x9 (irq_enter+0x35)
:    #func                -212    0.100  handle_fasteoi_irq+0x20 (do_IRQ+0x8a)
:    #func                -212    0.090  _spin_lock+0xe (handle_fasteoi_irq+0x3b)
:    #func                -212    0.125  ipipe_check_context+0x19 (_spin_lock+0x1d)
:    #func                -212    0.110  _spin_unlock+0x9 (handle_fasteoi_irq+0x8d)
:    #func                -212    0.110  ipipe_check_context+0x19 (_spin_unlock+0x1b)
:    #func                -211    0.105  handle_IRQ_event+0x10 (handle_fasteoi_irq+0x98)
:    #func                -211    0.145  usb_hcd_irq+0xe [usbcore] (handle_IRQ_event+0x39)
:    #func                -211+   1.288  uhci_irq+0x21 [uhci_hcd] (usb_hcd_irq+0x3d [usbcore])
:    #func                -210    0.095  ata_interrupt+0x16 (handle_IRQ_event+0x39)
:    #func                -210    0.095  _spin_lock_irqsave+0xc (ata_interrupt+0x23)
:    #func                -210    0.105  ipipe_check_context+0x19 (_spin_lock_irqsave+0x1b)
:    #func                -210    0.120  ipipe_check_context+0x19 (_spin_lock_irqsave+0x37)
:    #func                -209    0.220  ipipe_check_context+0x19 (_spin_lock_irqsave+0x67)
:    #func                -209    0.105  ata_bmdma_status+0x9 (ata_interrupt+0x1bf)
:    #func                -209+   1.062  ioread8+0x9 (ata_bmdma_status+0x19)
:    #func                -208    0.100  ata_bmdma_stop+0x16 (ata_interrupt+0x1de)
:    #func                -208+   1.057  ioread8+0x9 (ata_bmdma_stop+0x29)
:    #func                -207! 198.631  iowrite8+0x9 (ata_bmdma_stop+0x39)
:|   #begin   0x000000f7    -8    0.125  common_interrupt+0x6d (ata_bmdma_stop+0x3c)
:|   #func                  -8    0.140  __ipipe_handle_irq+0x21 (common_interrupt+0x75)
:|   #func                  -8    0.135  __ipipe_ack_apic+0x9 (__ipipe_handle_irq+0xe2)
:|   #func                  -8    0.135  __ipipe_dispatch_wired+0x20 (__ipipe_handle_irq+0x71)
:|  #*func                  -8    0.170  xnintr_clock_handler+0x12 (__ipipe_dispatch_wired+0x178)
:|  #*func                  -8    0.275  xntimer_tick_aperiodic+0x10 (xnintr_clock_handler+0x92)
:|  #*func                  -7    0.135  xnthread_periodic_handler+0x9 (xntimer_tick_aperiodic+0xb7)
:|  #*func                  -7    0.150  xnpod_resume_thread+0x16 (xnthread_periodic_handler+0x2f)
:|  #*[ 4445] samplin 99    -7    0.265  xnpod_resume_thread+0xd3 (xnthread_periodic_handler+0x2f)
:|  #*func                  -7    0.295  xntimer_next_local_shot+0x9 (xntimer_tick_aperiodic+0x184)
:|  #*func                  -6    0.265  xnpod_schedule+0x16 (xnintr_clock_handler+0x1a2)
:|  #*[ 4442] -<?>-   -1    -6    0.421  xnpod_schedule+0x1fb (xnintr_clock_handler+0x1a2)
:|  #*func                  -6    0.300  __phys_addr+0x9 (xnpod_schedule+0x550)
:|  #*func                  -5    0.340  __switch_to+0x16 (xnpod_schedule+0x5bf)
:|  #*[ 4445] samplin 99    -5    0.371  xnpod_schedule+0x613 (xnpod_suspend_thread+0x2e4)
:|  #*func                  -5    0.195  xntimer_get_overruns+0x9 (xnpod_wait_thread_period+0x127)
:|  #*func                  -5    0.140  __ipipe_restore_pipeline_head+0x16 (xnpod_wait_thread_period+0x17f)
:|  +*end     0x80000000    -4    0.315  __ipipe_restore_pipeline_head+0xc6 (xnpod_wait_thread_period+0x17f)
:|  +*begin   0x80000001    -4    0.215  __ipipe_dispatch_event+0x23f (__ipipe_syscall_root+0x62)
:|  +*end     0x80000001    -4    0.130  __ipipe_dispatch_event+0x203 (__ipipe_syscall_root+0x62)
:|  +*begin   0x80000000    -4    0.827  __ipipe_syscall_root+0xdb (__ipipe_syscall_root_thunk+0x35)
:   +*func                  -3    0.155  __ipipe_syscall_root+0xc (__ipipe_syscall_root_thunk+0x35)
:   +*func                  -3    0.110  __ipipe_dispatch_event+0x16 (__ipipe_syscall_root+0x62)
:|  +*begin   0x80000001    -3    0.115  __ipipe_dispatch_event+0x2a8 (__ipipe_syscall_root+0x62)
:|  +*end     0x80000001    -3    0.135  __ipipe_dispatch_event+0x24f (__ipipe_syscall_root+0x62)
:   +*func                  -2    0.396  hisyscall_event+0x21 (__ipipe_dispatch_event+0x12b)
:   +*func                  -2    0.315  xnshadow_sys_trace+0x16 (hisyscall_event+0x1bf)
:   +*func                  -2    0.220  ipipe_trace_frozen_reset+0x12 (xnshadow_sys_trace+0xe1)
:   +*func                  -1    0.195  __ipipe_global_path_lock+0x9 (ipipe_trace_frozen_reset+0x17)
:   +*func                  -1    0.110  __ipipe_spin_lock_irqsave+0xc (__ipipe_global_path_lock+0x15)
:|  +*begin   0x80000001    -1+   1.323  __ipipe_spin_lock_irqsave+0x8b (__ipipe_global_path_lock+0x15)
:|  #*func                   0    0.165  __ipipe_spin_unlock_irqcomplete+0xe (__ipipe_global_path_unlock+0x7b)
:|  +*end     0x80000001     0    0.165  __ipipe_spin_unlock_irqcomplete+0x64 (__ipipe_global_path_unlock+0x7b)
<   +*freeze  0x0002e643     0    0.185  xnshadow_sys_trace+0x49 (hisyscall_event+0x1bf)
 |  +*begin   0x80000001     0    0.155  __ipipe_dispatch_event+0x23f (__ipipe_syscall_root+0x62)
 |  +*end     0x80000001     0    0.150  __ipipe_dispatch_event+0x203 (__ipipe_syscall_root+0x62)
 |  +*begin   0x80000000     0    0.255  __ipipe_syscall_root+0xdb (__ipipe_syscall_root_thunk+0x35)
    +*func                   0    0.160  __ipipe_syscall_root+0xc (__ipipe_syscall_root_thunk+0x35)
    +*func                   0    0.135  __ipipe_dispatch_event+0x16 (__ipipe_syscall_root+0x62)
 |  +*begin   0x80000001     1    0.150  __ipipe_dispatch_event+0x2a8 (__ipipe_syscall_root+0x62)
 |  +*end     0x80000001     1    0.130  __ipipe_dispatch_event+0x24f (__ipipe_syscall_root+0x62)
    +*func                   1    0.180  hisyscall_event+0x21 (__ipipe_dispatch_event+0x12b)
    +*func                   1    0.145  __rt_task_wait_period+0x19 (hisyscall_event+0x1bf)
    +*func                   1    0.000N rt_task_wait_period+0x9 (__rt_task_wait_period+0x31)

Au premier abord, ce fichier n'est pas très facile à lire, voici quelques explications qui vous aideront à le décoder.

Tout d'abord, que cherche-t-on ? Des sections anormalement longues.

La colonne Time est le temps relatif de l'évènement par rapport à capture de la trace (appel à xntrace_user_freeze dans l'outil de benchmark). La colonne suivante, Delay, est la durée qu'a prise l'évènement. Pour nous aider un petit peu, I-Pipe Tracer nous indique avec + et !, les délais les plus longs.

[pid] :indique le scheduling d'un processus, son nom (samplin) et sa priorité (-1 pour les tâches schedulées par Linux).

common_interrupt indique l'arrivée d'une interruption, la ligne d'IRQ est 0x000000f7.

L'exploitation de ce fichier reste tout de même assez délicate car elle nécessite un très bonne connaissance de l'architecture matérielle utilisée.

Sur cette configuration, il s'agissait ici de l'absence du paramètre de noyau idle=poll lié à l'économie d'énergie, c'est une piste assez logique lorsque rien ne paraît dans la fonction justifier un long temps de traitement.

VI-I. Wiki d'I-Pipe Tracer

Toutes les clés pour exploiter le fichier de traces se trouvent à cette adresse : http://www.xenomai.org/index.php?title=I-pipe:Tracer.

VI-J. Traquer les interruptions parasites avec powertop

Moins il y a d'interruptions à traiter par ADEOS, meilleure sera la latence du système. L'idée consiste alors à distinguer les interruptions parasites de celles nécessaires, et de supprimer les premières.

Pas évident de faire ce tri me direz-vous. Eh bien non, bien au contraire, l'outil powertop, initialement destiné aux ordinateurs portables fait cela très simplement. Un bémol cependant, Powertop ne fonctionne que sur plate-forme Intel.

Auparavant, il faut activer l'option suivante lors de la configuration du noyau :

Kernel hacking/Kernel Debugging/Collect kernel timers statistics.

Après installation et lancement de powertop, il n'y a plus qu'à admirer le résultat :

Image non disponible

Dans cette exécution, ce sont les interruptions de la carte réseau (eth1) qui sont les plus nombreuses.

En lançant powertop -d, on obtient également des conseils sur la configuration de la machine. Attention ceux-ci ne sont pas forcément à prendre au pied de la lettre car ils sont édictés afin de consommer moins d'énergie, prudence donc.


précédentsommairesuivant
http://www.xenomai.org/index.php/FAQs.
Rappel : le processeur utilisé est un Dual Core, sur une autre architecture ces options peuvent légèrement varier.
Ces options se trouvent dans le fichier TROUBLESHOOTING du package d'installation.
Temps constatés par l'auteur sur d'autres PC et des posts sur la mailing list.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+