L’actualité de l’OAMP
Entrées/Sorties
26/09/07

 

Entrées/Sorties

Plan

Généralités

Moniteur de gestion des E/S

   Pilote
   Contrôleur
   Méthode de commande
   DMA : Direct Memory Acces

Modes de traitement

   Mode programmé simple
   Mode programmé par interruption
      Déroulement d'une lecture gérée par interruption
   Mode canal
      Exemple
      Vol de cycle

Types d'échanges

   Types de retour
   Types d'arrêt

Entrées/Sorties tamponnées

   Lecture dans un fichier sur disque
   Exemple

Pilotes et contrôleurs

   Stratégie de l'ascenseur

Généralités

Les organes d'Entrée/Sortie sont des dispositifs mécaniques ou électroniques, couplés à la machine par des interfaces électroniques.

Ils sont très divers : claviers, écrans, imprimantes, disques souples ou durs, souris, mais aussi tout appareil que l'on souhaite piloter par ordinateur (systèmes temps réel).

Un rôle essentiel de l'interface d'entrée/sortie est d'assurer une compatibilité entre les vitesses très différentes de la machine et du périphérique. Pour synchroniser les deux, il faut échanger des signaux.

Enfin, le périphérique étant souvent beaucoup plus lent que l'U.C., il faut assurer une simultanéité entre calcul et échange, pour rentabiliser le processeur.

Historiquement, les E/S étaient traitées par des instructions qui testaient le périphérique tant que l'information n'avait pas été échangée.

Décomposition d'une E/S

L'acquisition d'un caractère à partir d'un périphérique est un problème très complexe, car il met en jeu le périphérique, l'interface de connexion du périphérique à l'ordinateur, et l'ordinateur lui-même. Ensuite, dans la machine elle-même, il utilise le processeur, et éventuellement un processeur spécialisé. La mémoire est concernée, lorsqu'on pratique la multiprogrammation : il faut la partager au mieux, et donc laisser la place aux autres lorsqu'on n'a pas un besoin impératif de place. Pour permettre le partage du processeur enfin, il faut éclater les opérations d'échange en plusieurs processus...

L'ensemble des programmes qui concourent à la réalisation d'un échange se décompose dans une hiérarchie indiquée ci-dessous :

Ce découpage :

- sépare les problèmes liés au matériel ;

- regroupe les commandes pour la présentation à l'utilisateur ;

- permet d'abstraire les numéros de périphériques en noms logiques ;

- assure la généralité des opérations d'E/S pour satisfaire toutes les demandes ;

- permet de gérer des unités par type (disque banal).

Moniteur de gestion des E/S

C'est la partie du système d'exploitation qui assure la communication entre l'utilisateur et le système ; Il propose un petit nombre de procédures générales, très indépendantes du matériel : écrire sur un écran ou dans un fichier se fait par la même fonction (l'appel du système de gestion de fichier est implicite). Il réalise donc une abstraction des opérations de lecture/écriture.

Il assure les contrôles indispensables pour vérifier la cohérence du traitement demandé (prise en charge des défauts périphérique, gestion de la mémoire utilisée pour les échanges, rentabilisation du processeur par traitement simultané d'autres programmes...).

Il réalise le partage des périphériques (accès exclusif pour une imprimante, accès simultané pour un disque) et la protection des données.

Ce moniteur est constitué d'un ensemble de tâches distinctes ; sa conception est modulaire.

Pilote

Le pilote est un programme de plus bas niveau ; Il est responsable de la gestion d'un type particulier de périphérique, et il est adapté aux signaux que ce type de périphérique émet ou reçoit. C'est en général un programme réentrant, partagé entre les différents utilisateurs.

Il prend en charge l'optimisation des traitements (par exemple, l'algorithme de l'ascenseur pour les accès disques...)

Une procédure est réentrante si plusieurs processus peuvent l'appeller simultanément.

Une procédure qui n'utilise que les registres du processeur est réentrante.

Une procédure qui utilise des variables en mémoire doit impérativement les placer
dans la pile de récursivité, puisque chaque processus appellant lui passera sa propre pile.

Contrôleur

C'est le dernier des programmes de gestion d'un périphérique ; il envoie les commandes à l'interface, et analyse ses compte-rendus.

Interface

C'est une carte électronique de liaison entre le périphérique et l'ordinateur. L'interface est commandée par des signaux électriques.

L'interface contient des tampons de faible capacité pour adapter les vitesses souvent très différentes entre l'ordinateur et le périphérique, et des registres de commande.

Méthodes de commande

- Par cartographie mémoire

Les tampons et registres de commande sont accessibles comme des mémoires ordinaires, placées à des adresses particulières. L'exécution d'une sortie par exemple, consiste à transférer les données dans le tampon (instruction MOVE par exemple), puis à écrire dans un registre de commande l'ordre de transfert ; cette méthode a été utilisée sur les premiers microprocesseurs ;

Attente active de la fin d'échange par test d'un registre, ou bien arrêt de la tâche pour reprise après interruption.

- Par instructions spéciales

Les données sont prises n'importe où en mémoire ; les ordres sont envoyés au coupleur par une instruction SIO (Start Input Output).

DMA (Direct Memory Acces)

Le mode DMA est un mode de réalisation des E/S dans lequel l'interface du périphérique est directement connecté à la mémoire. L'interface doit être un processeur à part entière, bien que spécialisé.

Canal

On utilise une interface spéciale nommée canal, connectée directement au bus mémoire. Un canal en mode DMA est capable de transférer des données du périphérique à la mémoire sans passer par le processeur. Ce genre de coupleurs permet donc de traiter les E/S et le calcul vraiment en parallèle. Toutefois, il n'est pas possible d'accéder à deux cellule de mémoire simultanément (c'est pour cela, ou à cause de cela qu'il y a un bus). Si le processeur et le canal veulent accéder à la mémoire en même temps, l'un passera avant l'autre par attribution successive du bus mémoire. De ce fait, le canal ralentira un peu le processeur par vol de cycles.

Un canal est un processeur spécialisé pour les E/S ; il réalise en particulier l'accès direct mémoire. Il est partageable entre plusieurs périphériques qu'il gère simultanément.

 

Modes de traitement

Mode programmé simple

C'est le mode le plus simple, dans lequel l'UC gère la totalité de l'échange ; c'est le premier mode utilisé par les ordinateurs anciens. Il nécessite l'attente active (le processeur ne fait rien d'autre pendant la durée de l'échange).

Le déroulement d'une opération d'E/S, tel qu'il est représenté sur la figure ci-dessus, se compose de :

- instruction SIO de lecture du mot d'état périphérique (pour s'assurer que le périphérique soit sous tension, et non en défaut) ;

- instruction SIO d'initialisation, répétée jusqu'à ce que le périphérique soit prêt ;

- si c'est une sortie, SIO transférant la donnée au coupleur ;

- si c'est une entrée, dans une boucle, instructions SIO de lecture de donnée, répétée jusqu'à ce que le coupleur indique que l'information est valide.

Le chronograme ci-dessus montre que le processeur est occupé en permanence par le programme, soit pour son calcul avant et après l'E/S, soit pour l'E/S elle-même.

Mode programmé géré par interruptions

Ce second mode est plus élaboré que le précédent, car il libère le processeur entre deux caractères. Il est bien sûr plus complexe.

l'UC gère l'échange, mais n'interroge plus le périphérique pour connaître son état, c'est le périphérique qui la prévient . La boucle d'attente disparaît, le changement d'état du périphérique est transmis par une interruption.

Les interruptions sont :

- appel au moment de la libération en sortie : le périphérique est prêt à recevoir le caractère suivant ;

- appel de validation au moment où un caractère est présent sur le coupleur ; le registre de données contient alors une information valide.

Programmation

- une SIO permet de placer le coupleur dans le bon mode d'échange (mode par interruptions, entrée ou sortie...) ;

- une SIO d'échange demande le transfert au périphérique ; la tâche doit alors se mettre en sommeil en attendant l'IT de fin d'échange ;

- au moment où l'IT se produit, il faut soit exécuter une nouvelle SIO d'échange, soit (lorsque l'échange est terminé) exécuter une SIO de mise hors tension du périphérique.

Les trous dans le chronogramme représentent le temps récupéré par l'UC pour traiter une autre tâche. Pour la lisibilité du chronogramme, les crénaux d'échange ont été élargis. Sur un clavier, le temps de récupération d'un caractère est de l'ordre de 100 microsecondes, alors que l'intervalle entre deux caracètres successifs est plutôt de l'ordre de la 1/2 seconde. Le créneau de calcul est donc 5.000 fois plus long que le créneau de récupération.

En l'absence de canal, ce mode d'échange apporte donc une amélioration considérable à la gestion du processeur, puisque pratiquement tout le temps de l'E/S est récupéré pour exécuter un autre processus.

Les échanges de contexte sont nombreux (deux par caractère) et font perdre une petite partie du bénéfice.

Déroulement d'une E/S gérée par interruptions

Le schéma qui suit représente une opération de lecture au clavier, exécutée à la demande du processus utilisateur 12. Voici des explications sur les opérations qui sont successivement exécutées :

  1. Le processus, qui s'exécute en mode esclave (donc avec accès mémoire à sa seule partition), exécute une séquence de préparation des paramètres de l'opération dans le bloc mémoire nommé IOCB (Input Output Control Bloc).
  2. Ensuite, il place dans un registre l'adresse du bloc de paramètres, par l'instruction LAD (Load ADdress), puis il appelle le moniteur d'entrée/sortie, nommé ici IOCS (Input Output Control System), grâce à l'instruction SVC. Celle-ci est une instruction d'appel de sous-programme, qui empile l'adresse de retour, et place dans le registre pointeur d'instruction l'adresse de la routine à exécuter. Mais en plus de ce comportement normal, elle change le mode d'exécution du programme, qui passe en mode maître (s'il n'y est déjà). La routine appellée pourra donc accéder à toute la mémoire.
  3. Au début de son exécution, la routine IOCS recopie le bloc de paramètres (dont elle trouve l'adresse dans le registre) dans une zone appartenant à l'espace adressable du système. A partir de cet instant, le bloc de données de l'utilisateur n'est plus utile.
  4. Ensuite, la routine alloue, toujours dans la zone système, un tampon dans lequel elle réalisera réellement l'échange : les caractères lus y seront placés successivement. Ce tampon permet de ne pas utiliser la variable de l'utilisateur pendant la durée de l'échange. Ainsi, tout l'échange pourra se faire sans jamais utiliser la partition de l'utilisateur. Ceci permet au système, si besoin est, d'envoyer cette partition sur disque (Va-et-Vient ou Pagination) pour faire de la place en mémoire à un autre programme utlisateur.
  5. Il est temps maintenant de lancer l'échange, ce qui se fait par une instruction SIO (Start IO) qui réalise les initialisations nécessaires du périphérique. Après cela, la tâche 12 se met en attente jusqu'à la fin de l'échange.
  6. On voit sur la partie droite du schéma que la tâche n° 2, appartenant au système, est la tâche de traitement des interruption d'E/S, en attente d'une interruption. Lorsque celle-ci se produit, sa prise en compte provoque automatiquement un échange de contexte entre la tâche en cours (non figurée sur le schéma), et la tâche 2. Celle-ci exécute une instruction ACQ (ACQuit) qui acquitte l'interruption en la remettant à zéro, et en récupérant ses caractéristiques.
  7. L'interruption indique quel caractère a été tapé, et la tâche 2 le range dans le tampon système (auquel est associé un index). La dernière instruction de cette tâche est un JUMP, qui la renvoie au début, où elle se remet en attente du caractère suivant. Si le caractère récupéré est un retout-charriot, il marque la fin de l'échange. Le tampon est donc complet, et il convient de réactiver la tâche utilisateur. Pour cela, la tâche 2 exécute une instruction d'activation ARM (ARMer, qui active une tâche), qui marque la tâche 12 comme activable, et lance l'ordonnanceur.
  8. L'ordonnanceur examine l'état de la tâche utilsateur 12. Si celle-ci est restée en mémoire (elle est prête), on continue à la ligne 11 ci-dessous.
  9. Si la tâche utilisateur 12 a été rejetée sur disque par le Va-et-Vient (non prête), il est impossible de la relancer. On doit d'abord la recharger. Pour cela, il faut activer le chargeur (tâche 0 sur le schéma), et ce sera fait tout simplement en remplaçant le numéro de la tâche utilisateur (12) par le numéro de la tâche chargeur. Ainsi, c'est le chargeur qui est simplement activé à la place de la tâche à relancer.
  10. Le chargeur recherche une partition libre (il en vide une éventuellement), puis lit la partition de la tâche 12 sur disque, marque la tâche comme prête, et se remet en attente.
  11. La tâche est prête (en mémoire), et la donnée lue présente dans le tampon système. Lorsque l'ordonnanceur l'active, la tâche doit d'abord recopier ce tampon dans la variable de l'utilisateur, contenue dans la partition. Une fois cette recopie effectuée, elle place dans le bloc de paramètres IOCB de la partition le compte-rendu de l'échange, puis retourne au programme utlisateur par l'instruction RSV (Return from SuperVisor), qui est complémentaire de SVC : c'est un retour de sous-programme normal, avec en plus passage en mode esclave.
  12. Le processeur va maintenant exécuter l'instruction qui suit l'appel à IOCS. La donnée lue est présente dans la variable utilisateur, et peut être utilisée immédiatement. Le compte-rendu d'échange de l'IOCB lui indique si l'échange s'est bien déroulé (avec un code d'erreur négatif par exemple), ou alors le nombre de caractères échangés (lus).

Le flèches courbes à droite du schéma indiquent que les deux tâches 2 et 0 bouclent indéfiniment. Elles sont donc toujours prêtes à prendre en compte une nouvelle activation.

Résumé :

Du point de vue de l'utilisateur, l'E/S est constituée d'un simple appel de sous-programme superviseur, qui semble se charger de tout.

En réalité, elle est réalisée entièrement en mode maître, et trois tâches participent à sa réalisation :

Dans ce dernier cas, elle est rechargée avant de lui donner le contrôle, et par conséquent le tampon utilisateur est assurément présent au moment de la recopie.

Mode canal

Le mode canal est utilisable à la condition que la machine possède un canal, c'est-à-dire un processeur spécialisé dans les entrées/sorties, et connecté au bus mémoire en mode DMA. Le canal effectuera toute la boucle d'acquisition des caractères composant la donnée (ou de sortie ; ici, le fonctionnement est illustré encore sur une lecture).

On constate que la tâche utilsateur 12 est très semblable à celle que nous avions étudiée pour le mode programmé avec interruptions. Mais ici, l'instruction SIO lance le canal, au lieu d'activer la tâche de récupération de caractères. Le canal va effectuer la totalité de l'échange, comme s'il s'agissait d'un seul caractère, et sans utiliser le processeur général.

Le canal récupère les caractères un par un, les analyse, et détermine la fin de l'échange lorsqu'il récupère le dernier caractère demandé. Alors, sa boucle s'achève, et il provoque une interruption de fin d'échange, puis se rendort en attendant une prochaine demande d'échange.

Par conséquent, la tâche 2, qui dans l'exemple précédent était activée à chaque caractère, ne sera activée qu'à la fin de l'échange par cette interruption. Elle acquitte l'interruption, et trouve dans le tampon système la donnée prête. Comme dans le mode programmé avec interruptions, il faut recopier le tampon système dans la variable de l'utilisateur, noter le compte-rendu d'échange dans l'IOCB, puis relancer la tâche utilisateur.

Si la tâche utilisateur 12 n'est pas prête, comme précédement, elle sera rechargée par la tâche 0.

Vous pouvez constater que le principe de réalisation de l'échange est le même que précédement, à la différence que la boucle d'acquisition est faite par le canal au lieu d'être faite par la tâche 2.

Exemple d'Entrée

L'acquisition des données est maintenant faite par le canal, l'UC se contente de lui envoyer un ordre d'échange, puis attend l'IT de fin d'échange, en traitant d'autres tâches.

La structure des programmes est la même qu'en mode programmé avec interruptions : en effet l'IT de fin d'échange envoyée par le canal joue le même rôle que la dernière des IT (celle qui trouve le RC) en mode programmé ; elle résume l'échange.

Vol de cycle

Il ne s'agit pas de vélos...

Le canal et l'UC sont en accès direct mémoire ; à chaque instant, les deux processeurs sont suceptibles de demander un accès mémoire.

Pour que ce branchement soit possible, il faut que la machine comporte un circuit d'attribution mémoire, qui donne la priorité à l'un des processeurs demandeur en cas de conflit.

L'UC travaille à son rythme ; toutefois, le canal lui volera des accès mémoire pour assurer ses échanges.

Dans le schéma, les cycles volés sont représentés par les traits verticaux ; ils hachent le trait horizontal qui représente le traitement de l'UC.

Types d'échanges

Type de retour

Dans les langages de programmation, on distingue 2 types de retour :

- Retour en fin d'échange

C'est le plus courant. Le programme demandeur lance l'opération d'E/S au moment où il en a besoin ; il n'a rien d'autre à faire en attendant la fin du transfert. Il peut donc rendre le processeur à un autre programme pendant la durée de l'échange. Le processeur est bien rentabilisé par la multiprogrammation, mais le programme demandeur doit attendre. Pour lui, l'échange est du temps perdu.

C'est le fonctionnement que nous avons vu plus haut.

- Retour en fin d'initialisation

Il y a des cas où le demandeur ne souhaite pas perdre la main, pour ne pas perdre de temps : il gère mieux ses échanges, au prix d'un travail supplémentaire.

On distingue les deux cas d'entrée et de sortie.

• Si le programme effectue une sortie, il est facile de concevoir qu'il peut continuer son calcul pendant que la donnée est envoyée vers le périphérique, à la condition toutefois qu'elle soit d'abord recopiée dans un tampon système (c'est d'ailleurs ce que nous avons fait plus haut, afin de pouvoir disposer de la place en mémoire occupée par le programme). Attention, si nous voulons effectuer une seconde sortie sur le même périphérique, il faudra s'assurer que la première est bien terminée.

• Si le programme demande une entrée, dans l'esprit habituel du programmeur, il a besoin de la donnée tout de suite. Il doit donc attendre... Mais une autre façon de penser la programmation est possible : elle consiste à remonter, dans le texte du programme, la demande de lecture à un endroit où on n'en a pas encore besoin. Il faut prévoir ! Si c'est possible, on demande la lecture et le moniteur doit rendre la main tout de suite. On peut continuer le calcul, tant qu'on n'a pas besoin de la donnée. Lorsqu'on veut l'utiliser, il faut s'assurer qu'elle est présente, et ceci doit se faire par un nouvel appel de confirmation au moniteur. Si la donnée n'est pas encore prête, cet appel est bloquant.

Types d'arrêt

On distingue la lecture d'un bloc de données (secteur du disque, de taille fixe) de la lecture d'un flot (saisie au clavier, le nombre d'octets n'est pas prédéfini). Cette distinction se reflète naturellement dans le système de gestion des E/S. On définit donc deux types d'arrêts d'une E/S :

Arrêt sur compte d'octets

On fournit au système le nombre d'octets à lire ou à écrire ; si l'opération ne s'effectue pas en totalité, le système retourne le nombre d'octets effectivement échangés ; ce n'est pas forcément une erreur, le programmeur doit tester ce nombre et agir en conséquence. Dans les exemples donnés plus haut, on peut obtenir l'arrêt sur compte d'octets en remplaçant dans la tâche 2 le test du retour-charriot par un test sur le nombre de caractères déjà échangés.

Arrêt sur code

C'est le cas de la lecture de caractères sur un clavier, ou une bande magnétique... à chaque caractère reçu, le système doit comparer avec le caractère de fin de ligne et terminer l'échange en cas d'égalité. Il faut prévoir l'absence de ce caractère, et arrêter l'échange après réception d'un nombre de caractères maximum (qui correspondra à la taille du tampon système). C'est ce type d'arrêt que nous avons utilisé dans les exemples plus haut.

E/S tamponnées

Lecture dans un fichier sur disque

La caractéristique d'un disque est sa très grande capacité. Il contient des dizaines de milliards d'octets. D'autre part, sa constitution est particulière : pour accéder à un octet particulier, il faut déplacer les têtes de lecture/écriture au-dessus de la piste qui contient l'octet, puis attendre que celui-ci passe juste en-dessous pour être lisible. Le déplacement des têtes prend du temps, l'arrivée du caractère sous les têtes aussi. L'ensemble des deux attentes peut atteindre plusieurs dizaines de millisecondes, alors que la lecture du caractère se fait en quelques microsecondes !

Dans ces conditions, il ne serait vraiment pas raisonnable d'écrire ou de lire un seul octet à la fois. La place sur disque est allouée en blocs, dont la taille dépendra de la capacité du disque : plus le disque est gros, plus les blocs sont gros, afin de n'avoir pas un trop grand nombre de blocs. Les échanges se font aussi bloc par bloc.

Lorsqu'un programme demande un octet, le moniteur d'E/S va donc lire le bloc le contenant en totalité (c'est une lecture avec arrêt sur compte d'octets). Le bloc va donc être rangé dans un tampon système. Là, le moniteur va rechercher le caractère demandé, et le passer au programme demandeur. Tout le reste du contenu du tampon est pour l'instant inutile. Mais si le caractère provient d'un fichier de texte, il y a de fortes chances que le programme utilisateur demande rapidement le caractère suivant, qui se trouve déjà dans le tampon.

On en vient alors à modifier un peu ce que nous avons dit plus haut : dans les deux exemples, nous avons envisagé d'allouer un tampon système dont la taille est égale à celle de la variable utilisateur, nous avons effectué la lecture dans ce tampon, puis nous l'avons recopié en totalité dans la variable utilisateur, et enfin nous avons libéré le tampon. Ce qu'il convient de faire maintenant, c'est de modifier la politique d'allocation du tampon. On va l'allouer au moment où on ouvre le fichier, et le conserver jusqu'à sa fermeture. Par conséquent, le tampon sera associé à un fichier et non plus à un échange.

De ce fait, il va falloir modifier le moniteur. Lorsqu'un caractère, ou un groupe de caractères, est demandé en provenance d'un fichier, le moniteur va tout d'abord examiner le tampon associé au fichier :

On peut considérer que la partition de l'utilisateur est recopiée sur disque entre le début et la fin de sa demande. Dans ce cas, le moniteur ne doit pas recopier directement dans la zone utilisateur, mais dans un autre tampon, correspondant à la demande d'échange de l'utilisateur, et qui n'est alloué que pour cette durée.

Une lecture dans un fichier sur disque réalise donc rarementun véritable échange physique...

Exemple

Dans le premier dessin ci-dessous, aucune lecture n'a encore été faite. La flèche 1 indique la lecture du premier secteur du fichier. Le tampon est alors plein. La première partie du tampon est recopiée (flèche 2) dans le tampon utilisateur (ou dans un tampon système intermédiaire).

La demande suivante de l'utilisateur concerne des données qui sont déjà dans le tampon : aucune lecture disque n'est nécessaire, et la donnée demandée est recopiée dens la tampon utilisateur (flèche 3).

 

On parle de lecture anticipée. Les sorties sont également tamponées, c'est l'écriture retardée. Dans ce cas, si votre programme est interrompu (défaut de fonctionnement), les informations qui restent dans le tampon sont perdues. Pour éviter cela, on peut utiliser une méthode nommée flush(), qui force la recopie du tampon sur disque. Comprenez bien qu'en l'utilisant, vous améliorez la sécurité de vos données, en pénalisant la rapidité de votre programme (qui provoquera bien plus d'échanges disque).

Pilotes et Contrôleurs

Ces deux types de programmes ne sont pas toujours distingués ; le contrôleur est le module qui gère directement un périphérique (échange des données selon le format du périphérique, traitement des signaux...) ; le pilote est à un niveau d'abstraction au-dessus (optimisation en particulier), mais ce niveau n'existe pas toujours.

Exemple : statégie de l'ascenseur

C'est un algorithme de gestion efficace des E/S disque dans un système multiprogrammé. Il s'applique à un disque à têtes mobiles (contrairement à la stratégie SATF)

Le système ordonne les demandes d'échange en fonction de leurs numéros de piste ; lorsqu'il est prêt à traiter un échange, il choisit celui qui se trouve sur la piste la plus proche afin de minimiser les déplacements.

Cette stratégie est efficace pour minimaliser le total des temps de transfeert, puisqu'elle limite pour chacun le temps de déplacement des têtes de lecture. Mais elle peut amener une famine : si deux programmes font sans cesse des demandes concernant deux pistes proches, le système alternera les lectures sur ces deux pistes, ignorant totalement une demande concernant une piste beaucoup plus éloignée. Le programme demandeur sera différé indéfiniment.

Pour éviter la famine, on modifie le principe de base en imposant de plus que le sens de déplacement du bras soit conservé tant qu'il y a des demandes en attente au-dessus (ou au-dessous). Les têtes de lecture/écriture font donc des aller-retours sur le disque, ce qui évoque le mouvement d'un ascenseur, d'où le nom de la stratégie.