Limiter les surcharges via l`ordonnancement du seuil de préemption

Transcription

Limiter les surcharges via l`ordonnancement du seuil de préemption
Application  OS temps réel
Limiter les surcharges
via l’ordonnancement du seuil
de préemption
Dans un système embarqué temps réel les threads, ou tâches applicatives, exécutent leur
travail grâce à un système d'exploitation temps réel qui fait appel à un ordonnancement
préemptif afin de s'assurer que les threads critiques sont bien prioritaires. Mais, dans
certains cas, l'ordonnancement préemptif engendre des surcharges (overhead) liées
aux commutations de contexte. La technologie de l’ordonnancement du seuil
de préemption, peut néanmoins être utilisée pour réduire les overhead.
Auteur
John A.
Carbone,
Directeur
Marketing
Express Logic
A
vant d’aborder l’ordonnancement du seuil de
préemption, il est important de bien appréhender
les notions techniques de base des
systèmes d'exploitation temps réel.
Le « thread » est le premier terme à
expliciter, sachant que certains OS
temps réels utilisent parfois le terme
« tâche ». Dans la plupart des cas, ces
termes sont synonymes. Un thread
est une sorte de fonction au sein d’un
programme principal, qui s’exécute
jusqu'à son terme ou jusqu'à ce qu'il
soit interrompu. Parfois, les threads
peuvent se placer en pause dans l’attente d’un évènement particulier. Les
threads partagent un espace d'adressage et s'exécutent de façon pseudo-parallèle sur le même CPU. Dans
les systèmes multicœurs, les threads
peuvent réellement s'exécuter de
manière parallèle, un sur chaque
cœur, et partager par la suite ce cœur
avec d'autres threads. Les threads
sont utilisés afin de structurer un programme en parties modulaires, pour
une gestion plus simple de l’application et pour permettre à plusieurs
membres d'une équipe de participer
au développement.
Dans la pratique, les threads peuvent
se trouver dans les états suivants :
- PRET : le thread est prêt à s'exécuter, n’est pas en attente d'un événement, ne nécessite aucune intervention extérieure, mais il n'est pas en
train d'exécuter des instructions ;
- EN COURS :le thread exécute des
instructions ;
- EN PAUSE : le thread n'est pas prêt
à s'exécuter, parce qu'il est en attente
36 / L’EMBARQUÉ / N°1
d’un message dans la file d’attente,
d’un sémaphore, d’un compteur qui
doit se terminer, etc. ;
- TERMINE : le thread a terminé le
traitement qu’il devait effectuer et n'a
plus vocation à s'exécuter
A chaque thread est attribuée une
priorité qui indique son importance
relative et l’ordre dans lequel il aurait
accès au CPU au cas où tous les
threads seraient prêts à s'exécuter
simultanément. En général, les priorités sont représentées par un nombre
entier de 0 à N, avec le 0 soit en
haut, soit en bas de l'échelle des
priorités. Pour le système d'exploitation temps réel ThreadX, nous affectons le 0 au thread de plus haute
priorité, et les chiffres plus élevés
correspondent à des priorités moins
importantes. A chaque thread est
donc attribuée une priorité, et cette
priorité peut être modifiée de façon
dynamique. Plusieurs threads
peuvent se voir affecter la même
priorité, ou tous peuvent avoir une
priorité unique.
Lorsqu’un thread est en cours d'exécution et qu'un autre thread ayant
une priorité plus élevée est dans
l'état « PRET » à s'exécuter, le système d'exploitation temps réel interrompt ou préempte le thread en
cours et le remplace par le thread
ayant une priorité plus importante.
On appelle ce processus « la commutation de contexte » (tableau I).
Lors d’une commutation de contexte,
un So temps réel sauvegarde le
contexte du thread en cours sur sa
pile, récupère le contexte du nouveau thread depuis sa pile, et le
stocke dans les registres et le compteur ordinal du processeur. Ainsi il y
a eu commutation de contexte entre
les deux threads.
Le processus de commutation de
contexte s'avère assez complexe et
peut nécessiter de 50 à 500 cycles
d’horloge, selon le système d'exploitation temps réel et le processeur. Il
faut donc prendre soin d'optimiser
les opérations de commutation de
contexte dans un RTOS, et de minimiser le recours à de telles opérations. C’est l’objectif de l’ordonnancement du seuil de préemption.
Des ordonnanceurs
préemptifs
Les applications qui n’utilisent pas
de système d'exploitation temps réel
mais qui intègrent plusieurs opérations ou fonctions – des tâches ou des
threads la plupart du temps – doivent
inclure un mécanisme pour lancer la
fonction qui doit s'exécuter. Une
simple boucle séquentielle, voire des
boucles plus sophistiquées, peuvent
être utilisées afin de vérifier l'état
d’une fonction donnée, la lancer si
elle a un traitement à effectuer et
l’ignorer dans le cas contraire. Ces
boucles ressemblent à des ordonnanceurs, mais elles ont tendance à
manquer d'efficacité et de réactivité,
surtout quand le nombre de fonctions ou de threads augmente. Par
contre, un ordonnanceur de systèmes d'exploitation temps réel peut
surveiller l’ensemble et, à tout
moment, décider rapidement quelle
activité doit s’exécuter.
En général, les ordonnanceurs temps
L’intégration
anaLogique ?
Pas nécessairement
requis Par tous !
© 2013 Maxim Integrated Products, Inc. All rights reserved. Maxim Integrated and the Maxim
Integrated logo are trademarks of Maxim Integrated Products, Inc., in the United States and other
jurisdictions throughout the world.
Application  OS temps réel
I.- La commutation de contexte
Etape
Opération
Cycles
1
Sauvegarder le contexte du thread en cours
(les valeurs des registres GP et FP, et PC) sur la pile
20-100
2
Sauvegarder le pointeur de la pile en cours dans le blocde contrôle du thread
2-20
3
Commuter au pointeur de la pile du système
2-20
4
Retour à l'ordonnanceur
2-20
5
Trouver le thread ayant la priorité la plus haute qui est prêt à s'exécuter
2-50
6
Commuter à la pile du nouveau thread
2-50
7
Récupérer l'ancien PC du nouveau thread
20-100
8
Restaurer l'ancien PC du nouveau thread
2-40
9
Effectuer d'autres processus
0-100
Total
50-500
Une commutation de contexte est essentielle à la préemption, mais implique de nombreuses étapes
et des traitements importants, comme on le voit dans cet exemple d'un OS temps réel typique.
réel sont préemptifs c'est-à-dire
qu'ils s’assurent que le thread de plus
haute priorité prêt à s'exécuter est
bien celui dont ils autorisent le lancement, et que les autres patientent.
Les ordonnanceurs d'OS temps réel
peuvent aussi utiliser la méthode du
tourniquet (round-robin) qui est
assez similaire à celle de la boucle
séquentielle, ou faire appel à une
méthode de tourniquet plus sophistiquée où chaque thread, plutôt que
de s'exécuter jusqu'à son terme ou
jusqu'à une pause volontaire, se voit
allouer un certain pourcentage de
temps CPU. L’ordonnanceur de l'OS
temps réel exécute des commutations de contexte quand il le faut et
place les threads en sommeil, les
oblige à renoncer à leur temps CPU,
les force à se terminer et à disparaitre
du groupe de threads en attente de
l'accès au CPU.
Le terme « multithreading » (ou multitâche) indique que le CPU est partagé par plusieurs threads. Dans cette
configuration, si un thread rencontre
un blocage, plutôt que de vérifier les
conditions qui lui permettraient de
continuer, il cède l'accès au CPU
aux autres threads en attente prêts à
être exécutés. Ainsi cette méthode
1 Préemption d'un thread
Assigner un seuil de préemption plus élevé que la priorité du thread évite sa préemption
par des threads dont les priorités sont situées entre ces deux valeurs.
38 / L’EMBARQUÉ / N°1
assure une utilisation plus efficace
des cycles CPU qui, autrement,
seraient gaspillés. A titre d’exemple,
dans une configuration simple à
deux threads, thread_a et thread_b,
supposons que thread_a est en cours
d'exécution et lance une opération
d'E/S pouvant nécessiter des centaines de cycles pour s'achever. Au
lieu d'être placé en position d'attente
dans une boucle de scrutation active,
thread_a peut être mis en pause
jusqu'à ce que l’opération d'E/S soit
achevée et thread_b peut utiliser le
CPU entretemps. Ce processus
nécessite une commutation de
contexte, comme décrit ci-dessus.
Une fois l’opération d'E/S terminée,
thread_a peut reprendre son travail.
Par rapport au principe des boucles
séquentielles et aux autres approches
d’ordonnancement non-préemptives, le multitâche garantit une utilisation plus efficace des ressources
CPU.
La préemption consiste à arrêter
l'exécution d'un thread afin qu’une
autre action puisse s'exécuter. Ce
processus peut être dû à une interruption ou à une action du thread en
cours. Dans l’ordonnancement
préemptif, le système d'exploitation
temps réel exécute toujours le thread
à plus haute priorité qui est dans
l'état « PRET » à s'exécuter. En général, le contexte du thread en cours
d'exécution est sauvegardé, le
contexte d’un autre thread est stocké
à sa place, et le nouveau thread est
lancé. Les systèmes temps réel et les
OS temps réels en général utilisent
l’ordonnancement préemptif, car il
est le plus réactif aux évènements
externes, que ce soit lorsqu’un thread
doit s'exécuter dès l'occurrence d'un
tel évènement, ou qu’il doit s'exécuter avant une échéance particulière.
Bien que la réactivité soit optimisée,
la surcharge CPU est élevée puisqu'il
est nécessaire de lancer une commutation du contexte.
Il existe cependant certains problèmes liés à la préemption que le
développeur doit éviter ou gérer de
façon appropriée. Le premier est le
risque qu'un thread soit placé en
situation de « famine », c'est-à-dire
qu'il n’arrive jamais à s'exécuter car
un thread doté d'une priorité plus
élevée ne se termine jamais. Les
développeurs doivent éviter les situations où un thread de priorité élevée
se retrouve dans une boucle infinie
OS temps réel  Application
ou consomme trop de temps CPU,
empêchant les autres threads d'accéder au processeur.
Par ailleurs, en présence d'un très
grand nombre de commutations de
contexte, la surcharge CPU peut
s'avérer pénalisante. Dans l’exemple
ci-après, nous allons étudier ce type
de situation avec des outils qui vont
nous permettre d’observer et de
mesurer cette surcharge. Autre problème éventuel : l’inversion de priorité. L'inversion de priorité peut se
produire lorsqu'un thread à haute
priorité est en attente d'une ressource
partagée, alors que celle-ci est utilisée par un thread de faible priorité
qui ne peut pas en finaliser l’usage,
et ce en raison de la préemption d'un
thread doté d'une priorité intermédiaire.
2 Ordonnancement préemptif vs ordonnancement
du seuil de préemption
Le Cas-1, qui s'appuie sur un ordonnancement totalement préemptif, affiche quatre fois plus
de commutations de contexte que le Cas-2 qui utilise les mêmes threads, mais qui fait appel
à l'ordonnancement du seuil de préemption.
L'ordonnancement du seuil
de préemption
Nous allons maintenant présenter le
concept à la base de l’ordonnancement du seuil de préemption. Avec
cette méthode, on établit un niveau
de priorité qui doit être dépassé
avant qu’un thread puisse être
préempté. L'ordonnancement du
seuil de préemption empêche certaines préemptions et ainsi élimine
plusieurs commutations de contexte,
réduisant d’autant la surcharge.
Normalement, tout thread affecté
d'une priorité plus haute que celui
qui est en cours d'exécution peut le
préempter. Mais, avec l'ordonnancement du seuil de préemption, un
thread en cours ne peut être
préempté que si le thread est doté
d'une priorité plus élevée que le
3 Comptage des interruptions
La prise en compte d'un cycle complet permet de dénombrer le nombre total d'impulsions d'horloge, et de mesurer le temps réel
qu'il a fallu pour exécuter l'ensemble du cycle.
Cas-1 avec 1 801 impulsions d’horloge par cycle
Cas-2 avec 964 impulsions d’horloge par cycle
L’EMBARQUÉ / N°1 /
39
Application  OS temps réel
seuil de préemption du thread en
cours. Dans un système purement
préemptif, le seuil de préemption
serait égal à la priorité du thread. En
réglant un seuil de préemption à un
niveau plus élevé que la priorité du
thread, les threads dont les priorités
sont situées entre ces deux valeurs
ne pourront pas préempter.
Dans l’exemple suivant (voir figure 1
en page XX), un thread affecté d'une
priorité (faible) de 20 pourrait normalement être préempté par un thread
ayant une priorité de 19, 18, 17, 16,
etc. Mais, si le seuil de préemption
est fixé à 15, alors seuls les threads
dotés d'une priorité supérieure à 15
(dont la valeur réelle est inférieure à
15 donc), pourraient préempter le
thread. Partant, les threads intermédiaires – ceux affectés d'une priorité
de 19, 18, 17, 16 et 15 – ne peuvent
pas préempter, alors que les threads
dotés d'une priorité de 14 ou plus
(soit 14, 13, 12 et moins) le peuvent.
Le seuil de préemption est optionnel
et peut être spécifié pour un thread,
pour tous les threads, ou pour aucun
d’entre eux. S'il n'est pas spécifié, le
seuil de préemption d'un thread est
égal à son niveau de priorité. Mais
avec un seuil de préemption, un
thread peut empêcher sa préemption
par des threads affectés d'une priorité
plus élevée, ceci jusqu'à une certaine limite. Au-delà de cette limite,
la préemption sera autorisée.
Afin d’illustrer les bénéfices en
termes de performances que procure
un ordonnancement du seuil de
préemption, nous allons comparer
une approche intégralement préemptive avec une approche avec ordonnancement du seuil de préemption
et nous évaluerons les implications
de ces deux approches en termes de
commutation du contexte et de
débit. Pour mener à bien cette comparaison, nous utilisons une simple
application de type producteur/
consommateur, avec un thread qui
envoie les messages et 3 threads qui
les récupèrent dans des files d’attente. Nous allons enregistrer tous les
évènements pour bien visualiser les
actions effectuées. Ensuite, nous
pourrons observer les évènements
transcrits, décompter le nombre de
commutations de contexte, mesurer
les performances et en tirer nos
conclusions.
Afin de comparer les deux
approches, nous allons envisager
40 / L’EMBARQUÉ / N°1
deux cas (figures 2 et 3).
Le Cas-1 utilise l’approche totalement préemptive, avec attribution
des valeurs de priorité 1, 2, 3 et 4
au thread A, B, C et D respectivement.
Dans le Cas-2, nous ajoutons le
seuil de préemption pour voir comment il peut être utilisé pour
réduire le nombre de commutations de contexte. Pour ceci, nous
attribuons au thread_D un seuil de
préemption de 1, c'est-à-dire qu'il
ne peut être préempté que par un
thread ayant une priorité plus élevée que 1. Dans cette configuration, aucun thread n'a une priorité
plus haute que 1 (soit 0), donc
Thread_d ne sera préempté ni par
A, ni par B, ni par C.
neuf messages à envoyer. Le cycle est
alors terminé. Au cours du cycle, 9
messages ont été envoyés, 9 ont été
récupérés, et 18 commutations de
contexte ont été enregistrées.
Dans le Cas-2, le Thread_D ne sera
pas interrompu pendant qu’il envoie
ses messages. Ce Thread_D continue
d'envoyer ses messages jusqu'à ce
qu’une file d’attente soit pleine. A ce
moment là, il se met en pause
jusqu'à ce que l’une des files d’attente ne soit plus pleine. A noter
qu’une fois que le Thread_D se met
en pause, il ne pourra reprendre la
main que lorsque les Threads A, B et
C seront bloqués puisque ce
Thread_D a une priorité de valeur 4
et ne peut préempter aucun des
autres threads. Les résultats sont très
II.- Comparaison du nombre de commutations
de contexte et du débit
Cas
Messages
Commutations de contexte
Cas-1 : Priorités uniques
9
18
Cas-2 : Seuil de préemption
9
4
Mesures
Cas-1
(Priorités
Uniques)
Cas-2
(seuil
de préemption)
Ratio
(Cas-1 vs Cas-2)
Commutations de contexte
18
4
450 %
1 801 impulsions du timer
964 impulsions du timer
186 %
Messages envoyés
9
9
Pas de changement
Messages reçus
9
9
Pas de changement
Temps écoulé
Dans cet exemple, la comparaison des mesures en débit et en surcharge montre clairement
les avantages de l'ordonnancement du seuil de préemption
Dans le Cas-1, le Thread_D commence à envoyer ses messages vers
chaque file d'attente, mais dès qu'il
a envoyé le premier message, le
Thread_A prend la main pour le
récupérer. Pourquoi ? Parce que ce
Thread_A est affecté d'une priorité
plus haute que le Thread_D et que
le Thread_A est désormais prêt à
s'exécuter puisque la file d’attente
qu’il surveillait n’est plus vide. Une
fois que le Thread_A a lu son message, il se met en pause puisque sa
file d’attente est vide, et le
Thread_D reprend la main. Le
Thread_D envoie maintenant un
message au Thread_B, qui
préempte immédiatement le
Thread_D, et ainsi de suite pour les
différents de ceux obtenus dans le
Cas-1. En effet, ici, nous n’observons
que quatre commutations de
contexte, contre 18 pour le Cas-1.
Si l’on prend en compte un cycle
complet, nous pouvons décompter
le nombre d’impulsions d’horloge
qui se sont produites durant ce cycle.
Dans le Cas-1, on dénombre 1 801
interruptions, alors que le Cas-2 en
compte seulement 964.
Si l’application considérée était
un système émetteur de messages,
nous pourrions donc observer
une amélioration significative des
performances et du débit global
grâce à l’utilisation de l’ordon­
nancement du seuil de préemption
(tableau II). n
Windows Embedded 8 Standard
Windows Embedded 8 Standard réduit les cycles de développement et permet
aux fabricants de dispositifs de créer des produits différenciés et haut de gamme
Avantages clés
•
Exécutez vos applications métier Windows
existantes ou créez une nouvelle expérience
avec les applications Windows 8.
•
Proposez une expérience d'utilisation
immersive et naturelle avec l'interaction
tactile multipoint et Kinect pour Windows.
•
Améliorez la connectivité et la disponibilité
avec des technologies de réseau de
pointe et une meilleure gestion de
l'alimentation.
•
Créez une image personnalisée du
système d'exploitation pour fournir les
fonctionnalités nécessaires à l'appareil.
à leurs clients.
•
Fabriquez des appareils spécialisés à partir de
technologies de confiance
Utilisez les technologies de sécurité
renforcée pour protéger votre appareil,
vos données et votre réseau.
•
Contribuez à proposer une expérience
cohérente avec des capacités de
verrouillage améliorées.
•
Accédez aux systèmes informatiques
et au cloud pour des appareils toujours
connectés aux informations essentielles.
•
Gérez vos appareils avec Microsoft System
Center et Windows Embedded Device
Manager.
•
Améliorez le temps de mise sur le marché
grâce à des outils de développement
système de pointe.
qui enchanteront les clients et se démarqueront de la concurrence. Il permet de
proposer des solutions métier optimisées pour les systèmes intelligents, et donc
de transformer vos données en un avantage concurrentiel durable.
Pour en savoir plus, rendez-vous sur
www.windowsembedded.com/we8standard.
Créez des appareils différenciés
S'appuyant sur les dernières innovations de Microsoft, les fabricants peuvent
fournir une expérience d'utilisation plus immersive, naturelle et hautement
personnalisable afin de distinguer leurs appareils. Les fabricants d'appareils
peuvent offrir une expérience de marque unique à tous les niveaux du dispositif
et offrir ainsi une expérience d'utilisation exceptionnelle et très personnalisée
Windows Embedded 8 Standard vous apporte les dernières innovations
technologiques de Windows 8 pour vous aider à protéger les informations
sensibles de vos clients sur vos appareils spécialisés. En s'appuyant sur
Windows Embedded 8 Standard, les fabricants peuvent tirer parti de ses
fonctionnalités pour garantir la fiabilité de leurs appareils et permettre aux
utilisateurs de maîtriser la configuration en cours d’utilisation.
Activez vos outils d’analyse décisionnelle
En s'appuyant sur Windows Embedded 8 Standard, les fabricants peuvent
proposer des systèmes intelligents optimisés. Microsoft Active Directory simplifie
la gestion des identités et des accès au niveau de l'entreprise. Les appareils
spécialisés peuvent être gérés efficacement comme des PC Windows, et se
connecter à Windows Azure et Windows Server. Leurs données peuvent ainsi être
exploitées de manière optimale pour offrir un réel avantage concurrentiel.
10
ANS
Téléchargez Windows Embedded 8 Standard Release Preview sur le site :
www.windowsembedded.com/we8standard
Les produits Windows
Embedded bénéficient
d'un programme de
support leader de 10 ans
et restent disponibles
pendant 15 ans.

Documents pareils