Systèmes d`exploitation, gestion de processus (SGP)

publicité
Année scolaire 2016-2017
Isabelle Puaut
Systèmes d’exploitation, gestion
de processus (SGP)
Travaux dirigés
Préambule
Vous remarquerez que la plupart des périphériques utilisés lors des travaux
dirigés sont anciens tant au niveau de leur mode de fonctionnement que de leur
vitesse d’exécution. Les raisons motivant ce choix sont les suivantes :
Le mode de fonctionnement de ces périphériques est simple, ce qui permet de les
appréhender pendant la durée d’une séance de TD, ce qui serait quasiment
impossible avec des systèmes plus actuels
Les problèmes de synchronisation se posant avec ces périphériques simples sont
identiques à ceux qui se posent avec des systèmes plus complexes
La technologie évoluant très rapidement, il est illusoire d’avoir des informations
temporelles exactes
Merci de signaler lors des TD ou par mail à [email protected] toute erreur ou texte
confus dans les sujets de TD.
2
Petits exercices sur les
sémaphores
Objectifs
L'objectif de ce TD est d'acquérir une maîtrise de l'utilisation des sémaphores à
compteurs via la programmation de problèmes de synchronisation très simples,
mais néanmoins très courants.
Questions
1. Deux programmes P1 et P2 se partagent deux variables a et b.
Ecrire le code d’entrée et sortie de section critique permettant de
protéger ces deux variables. Quel est l’effet d’un P bloquant à
l’intérieur d’une des sections critiques ?
P1:
P2:
if (a >0) a = a-1;
b = a+4;
b = b*2;
2. Soient deux processus P1 et P2 dont le code est le suivant :
P1
P2
:
:
……….
……….
A1
A2
………….
………….
Ecrire le code de P1 et de P2 pour que P2 attende, au point A2,
que P1 soit au point A1, et uniquement quand c’est nécessaire.
3. En reprenant l'exemple précédent, écrire le code des processus P1
et P2 pour établir un rendez-vous entre P1 et P2 juste après
passage aux points A1 et A2 (attente mutuelle des deux
processus quand c’est nécessaire).
4. Ecrire le code pour maintenant réaliser un rendez-vous entre trois
processus P1, P2 et P3. Généraliser la solution pour un nombre n
de processus en utilisant un tableau de n sémaphores.
3
5. Donner une solution à la question précédente qui minimise le
nombre de sémaphores utilisés, par exemple en utilisant un
compteur de processus arrivés au rendez-vous.
6. Soit un parking à N places, initialement vide. Chaque voiture
désirant entrer dans le parking est représentée par un processus.
Ecrire le code de synchronisation bloquant les voitures quand le
parking est plein :
•
en n’utilisant pas d’attente active
•
en utilisant une variable partagée comptant le nombre de
places libres dans le parking
Processus voiture :
<entrer dans le parking, avec attente d’une place libre>
<rester dans le parking (durée quelconque inconnue a priori)>
<sortir du parking>
Est-il possible de réaliser ce problème de synchronisation sans
variable partagée, en utilisant exclusivement des sémaphores ? Si oui,
donner le code correspondant.
4
Utilisation de l'instruction
XCHG pour réaliser une
exclusion mutuelle
Objectif
L'objectif de ce TD est de bien comprendre les problèmes de réalisation de
l'exclusion mutuelle en système monoprocesseur et multiprocesseur.
Description du système
On se place dans le cadre d'un ordinateur monoprocesseur possédant une
instruction XCHG dont le fonctionnement est le suivant :
XCHG
-
reg,mem
Echange les contenus du registre reg et de la case mémoire
d'adresse mem
Ne positionne pas les codes condition du processeur
Comme toute instruction, non interruptible
Pas par défaut d’exclusivité d'accès au bus pendant l'exécution de
l'instruction
Questions
1. Programmer (en assembleur ou pseudo-code) le code d'entrée et
de sortie d'une section critique
2. Démontrer, en vous appuyant sur des diagrammes temporels
d’exécution, que :
5
•
Le code fonctionne toujours sur un monoprocesseur
•
Le code ne fonctionne pas sur un multiprocesseur
•
En supposant l'existence d'un préfixe d'instruction LOCK, de
syntaxe LOCK instruction, qui permet d'avoir un accès
exclusif au bus pendant toute la durée d'une instruction,
modifier les codes d'entrée et de sortie de section critique
pour que l'exclusion mutuelle soit respectée dans le cas
multiprocesseur et montrer que ce code fonctionne.
6
Application des sémaphores
à deux problèmes de type
général
Objectifs
L'objectif de ce TD est d'acquérir la maîtrise de deux problèmes de
synchronisation très courants.
Producteur-consommateur
Deux processus (le producteur et le consommateur) se partagent un tableau de N
éléments. Le producteur produit de nouveaux éléments dans le tableau, que le
consommateur est chargé de consommer. Le producteur produit les éléments un
par un. Le consommateur consomme les éléments également un par un.
L'échange d'informations entre producteur et consommateur suit le schéma
suivant, dans lequel les ??? représentent du code de synchronisation :
Producteur :
Consommateur :
while (1) {
while (1) {
< bâtir une information >
???
???
< recevoir une information >
< la communiquer au consommateur >
???
???
< exploiter l'information >
}
}
Le producteur produit les informations dans un tableau, géré de manière
circulaire. Le producteur utilise un indice de production nommé iplein (indice de
la dernière case remplie), tandis que le consommateur utilise un indice de
consommation nommé ivide (indice de la dernière case vidée).
1. Compléter le code des processus producteur et consommateur
(gestion des indices et synchronisations à l’aide de sémaphores).
2. Si les processus ne se trouvent pas dans les sections de code entre
les ???, on a e(splein) + e(svide) = N. Le démontrer en utilisant la
propriété des sémaphores e(s) = e0(s) + nb_V(s) - nb_P(s).
3. Si
l'on voulait avoir plusieurs producteurs et plusieurs
consommateurs, quelles modifications faudrait-il apporter au
7
schéma précédent ? On supposera que les producteurs produisent
pour n'importe quel consommateur.
4. On revient à un seul producteur et un seul consommateur. Si le
producteur est actif, il continue tant qu'il y a une case vide ; si le
producteur est bloqué, il n'est réveillé que s'il y a X cases vides
(X > 1). Ecrire les nouvelles synchronisations pour le producteur
et le consommateur.
Lecteur-rédacteur
Une donnée (par exemple un fichier) est partagée par deux types de processus :
-
Les processus qui la consultent (processus lecteurs)
Les processus qui la modifient (processus rédacteurs). Les
lectures et les écritures n’utilisent pas de temps processeur, donc
en l’absence de synchronisation s’exécutent en parallèle.
On veut assurer un maximum de parallélisme entre les différents processus tout
en assurant que les informations lues aient un sens et que les modifications se
fassent correctement. Pour que les informations lues aient un sens, on ne veut pas
avoir un lecteur et un écrivain en même temps, ou deux écrivains simultanément
sur la même donnée.
5. Donner le code des processus lecteur et rédacteur basé sur le
principe suivant :
-
Un processus rédacteur se bloque s'il existe un processus lecteur
ou écrivain en cours d'exécution
Un processus lecteur se bloque uniquement s'il existe un
processus écrivain en cours d'exécution
6. Que se passe t'il si on a les arrivées suivantes ? Dessiner le
chronogramme correspondant au code écrit dans la question
précédente, en supposant que les lectures peuvent s’effectuer en
parallèle car elles n’utilisent pas le processeur (ex : lecture sur un
périphérique).
Date d'arrivée
1
2
3
5
Nature
Lecteur 1
Rédacteur 2
Lecteur 2
Lecteur 3
Durée
3
2
3
3
7. Reprendre la première question en mettant une « priorité » égale
entre les processus lecteurs et rédacteurs. Dès qu'un processus
rédacteur arrive, tous les processus attendent, quelle que soit leur
catégorie.
8
Décomposition en processus
Objectif
L'objectif de cet exercice est de mettre en application votre connaissance de la
synchronisation par sémaphores (producteur-consommateur) sur un exemple
complet, tout en restant simple. L'exercice permettra aussi de se convaincre des
gains en performances que l'on peut obtenir en décomposant un système en
processus. Le système utilisé est volontairement générique (débarrassé de toute
considération de bas niveau).
Le système considéré
Dans le système on peut distinguer trois parties : entrée, calcul, sortie. Ces trois
parties échangent de l'information à travers deux types de tampons TE et TS. Les
tampons de même nature (TE, TS) sont chainés circulairement.
•
Entrée(TE) symbolise le remplissage du tampon TE. Cette partie dure 20
ms et se décompose en une phase d'initialisation d'1 ms, une phase
d'attente sur le périphérique d'entrée et une phase terminale qui utilise
également 1 ms de temps processeur. L’attente sur le périphérique
d’entrée est non active (i.e. le processus en attente est bloqué sur un
sémaphore pendant la durée de la lecture).
•
Calcul(TE,TS) utilise les informations contenues dans TE pour remplir le
tampon TS. Cette opération dure 21 ms et ne consomme que du temps
processeur.
•
Sortie(TS) symbolise le transfert sur le périphérique de sortie du contenu
du tampon TS. Cette partie dure 25 ms et se décompose en une phase
d'initialisation de 2 ms, une phase d'attente (non active) de 22 ms et une
phase terminale d'1 ms. Comme pour l’entrée, le processus qui attend la
fin de Sortie est bloqué sur un sémaphore pendant la durée de l’écriture.
On regroupe ces 3 parties dans une boucle :
while (1) {
entrée(TE);
calcul(TE,TS);
sortie(TS);
}
9
Questions
1. Evaluer la durée d'un cycle, ainsi que le taux d'occupation du
processeur.
Afin d'améliorer les performances, on envisage d'autres organisations. On
suppose que les entrées et les sorties se font sur des périphériques indépendants et
que l’ordonnançeur ne réalise la commutation de processus que sur l'appel à une
primitive P bloquante (pas de changement de processus lors d’un V).
Les schémas temporels mettront bien en évidence à chaque instant le processus
qui s’exécute sur le processeur.
On utilisera la notation x = suivant(x) pour effectuer un changement de tampon
dans un ensemble x de tampons gérés circulairement.
2. On met la partie entrée dans un processus et on regroupe calcul et
sortie dans un autre.
•
Combien de tampons TE et TS faudra-t-il déclarer pour avoir
un bon parallélisme ?
•
Donner le texte des deux processus avec leur synchronisation
par sémaphores.
•
Montrer sur un schéma temporel le fonctionnement de
l'ensemble et indiquer la durée du cycle lorsque le régime
permanent est atteint.
3. On regroupe maintenant entrée et calcul dans un processus,
tandis que sortie est mis dans un autre. Reprendre les trois points
de la question précédente avec cette nouvelle hypothèse.
4. On décompose le travail en trois processus : entrée, calcul,
sortie.
10
•
Quelle valeur de la durée du cycle espère-t-on ainsi atteindre
?
•
Donner le texte des trois processus.
•
Montrer sur le début d'un schéma temporel que
l’ordonnançeur va avoir à choisir entre plusieurs processus.
Quelle règle de choix proposez-vous (ordre de passage à prêt,
priorité, -) ?
•
Donner alors un schéma temporel complet.
Programmation
des
entrées/sorties caractère
Objectif
L'objectif de cet exercice est de programmer un pilote de périphérique caractère
par attente active puis demande d'interruptions. Le contrôleur de périphérique est
volontairement très simple pour se libérer des contraintes d'accès aux registres du
contrôleur.
Spécification du matériel
Une ligne série est utilisée pour communiquer entre deux ordinateurs. Le matériel
fonctionne en "full-duplex", ce qui signifie que l'envoi et la réception d'un
caractère sont deux opérations indépendantes pouvant se dérouler en parallèle.
Le contrôleur d'entrées/sorties comprend quatre registres internes :
-
Un registre d'entrée pour la réception d'un caractère
Un registre de sortie pour l'émission d'un caractère
Un registre d'état
Un registre de contrôle (commande)
Chaque voie du contrôleur (émission ou réception) peut être gérée en mode "test
d'état" (attente active), ou avec demande d'interruption.
On suppose disposer des primitives suivantes pour la programmation du
contrôleur :
-
-
11
void lire(char *c) : range dans c le contenu du registre d'entrée
void écrire(char c) : range c dans le registre de sortie
char état_sortie : rend vrai quand le registre de sortie est vide
char état_entrée : rend vrai quand le registre d'entrée est plein
void autoriser_it_s() : une interruption sur le niveau it_s est
postée par le contrôleur dès que le registre de sortie devient vide.
L'acquittement de cette interruption s'effectue en écrivant un
caractère dans le registre de sortie
void autoriser_it_e() : une interruption sur le niveau it_e est
postée par le contrôleur dès que le registre d'entrée devient plein.
L'acquittement de cette interruption s'effectue en lisant un
caractère.
-
void interdire_it_e() : le contrôleur ne poste pas d'interruption sur
le niveau it_e
- void interdire_it_s() : le contrôleur ne poste pas d'interruption sur
le niveau it_s
- void initialiser() : Initialise le contrôleur. Le contrôleur ne poste
pas d'interruption sur les niveaux it_e et it_s.
Les niveaux d'interruption it_e et it_s sont distincts ; le niveau it_e est plus
prioritaire que le niveau it_s.
Questions
Dans un premier temps, on suppose qu'un seul processus utilise la ligne série. On
souhaite réaliser les trois primitives suivantes :
-
void tty_init(void)
void tty_em_ligne (char *l); : émet la ligne de longueur lg située
dans le tableau l. Une ligne se termine par un zéro.
void tty_rec_ligne (int *lg ; char *l) : reçoit une ligne de
caractères terminée par 0 et retourne sa longueur dans lg.
1. Ecrire les trois opérations tty_init, tty_em_ligne et tty_rec_ligne,
le contrôleur étant programmé en mode test d'état (attente active).
L'émission et la réception sont des opérations synchrones.
2. Ecrire de nouveau les trois opérations en programmant
maintenant le contrôleur avec demande d'interruption en entrée et
en sortie. La voie de réception est gérée avec anticipation : les
caractères reçus sont mémorisés dans un tampon de réception
jusqu'à leur consommation (appel à tty_rec_ligne). Un tampon
est également affecté à la voie émission. Dès que la ligne à
émettre est recopiée dans le tampon émission, le processus
suppose que l'entrée/sortie est terminée. Vous écrirez également
les traitants d'interruption associés aux niveaux it_e et it_s.
3. Le partage de la ligne série entre plusieurs processus avec le code
des deux questions précédentes pose t'il des problèmes de
cohérence des lignes émises/reçues ? Si oui, modifier le code.
12
Entrées/sorties disque
Objectif
L'objectif de cet exercice est d'étudier la programmation de pilotes
d'entrées/sorties dans le cas où ces dernières sont prises en charge par un
processeur différent de celui sur lequel s'exécutent les programmes utilisateur
(par exemple, processeur intégré au contrôleur disque). On s'intéressera en
particulier à l'analyse des problèmes de synchronisation entre les processus
utilisateurs et l'interface matérielle d'entrées/sorties.
Le système considéré
A. Appel aux procédures d'entrée/sortie par les processus utilisateur
Un processus utilisateur qui désire lancer une entrée/sortie appelle une procédure
système d'entrée/sortie (read ou write selon le sens du transfert). Cette procédure
détermine le disque utilisé et construit un bloc d'entrée/sortie : IOCB (Input
Output Control Block).
IOCB
IOCB.sema
IOCB.posit
IOCB.transf
Zone réservée au chaînage
Sémaphore
privé
pour
synchronisation
Commande de positionnement
Commande de transfert
la
Ce bloc est ensuite chaîné dans une file d'attente exploitée par le processus driver.
On pourra utiliser les procédures indivisibles :
-
in_queue(f_a,IOCB) pour placer le bloc IOCB en queue de la file
d'attente f_a
out_queue(f_b,IOCB) pour extraire le premier bloc de la file
d'attente f_b et le recopier dans la zone locale IOCB.
B. Processeur embarqué dans le contrôleur disque
Le système peut comporter plusieurs disques, gérés par plusieurs contrôleurs
disque.
Les échanges entre la mémoire et les disques sont réalisés par un processeur
embarqué dans le contrôleur disque, que nous nommons par la suite unité
d'échange, ou UE, pour le différencier du processeur principal. Ce processeur
traite des mots de commande élémentaires (positionnement, transfert). Il ne sait
13
traiter qu'une commande à la fois (il est non multiplexé). On suppose écrite la
routine SIO(SIO a, b, @) (pour Start Input Output) qui transmet une commande à
l'UE :
où
a désigne le numéro de l'unité d'échange
b désigne le numéro du disque
@ désigne l'adresse du mot de commande
L'unité d'échange reconnaît deux commandes :
-
positionnement du bras sur la piste. Cette commande est
transmise au disque par l'UE et celle-ci redevient libre à la fin du
SIO
transfert. Cette commande est transmise au disque, mais l'UE ne
redevient libre qu'à la fin du transfert (c'est elle qui prend en
charge les transferts mémoire).
ex :
a = 0;
b = 1;
Par exemple, SIO(a, b, &IOCB.posit) transmet au disque 1 de l'unité d'échange 0
la commande de positionnement préparée dans le mot IOCB.posit
C. Le disque
Lorsqu'un disque a fini une opération (positionnement ou transfert), l’opération
V(sema(a,b)) est effectuée sur un sémaphore matériel. sema(a,b) est le sémaphore
associé au disque b de l'UE a. Ce sémaphore est connu du logiciel et du matériel.
Il est initialisé à 0 à la mise sous tension de la machine.
Caractéristiques du disque :
-
Temps moyen de positionnement du bras : 60 ms, temps de
rotation : 16ms
Nombre de secteurs par piste : 8, longueur d'un transfert : 1
secteur
Configuration machine ne comportant qu'un seul disque
1. Donner le squelette de la procédure d'entrée/sortie sans détailler
le remplissage de l'IOCB
2. Donner le squelette du processus driver disque associé, qui
exécute les SIO
3. Calculer la durée moyenne entre prise en compte d'une
commande d'entrée/sortie par le driver et son achèvement. En
déduire un pourcentage moyen d'occupation de l'unité d'échange.
14
Configuration machine à huit disques et une seule unité d'échange
Dans cette partie, une unité d'échange unique gère l'ensemble des disques.
4. Quel intérêt voyez vous à définir un processus driver par disque ?
5. Modifier la procédure d'entrée/sortie
6. Décrire l'un des processus driver disque
Configuration avec huit disques et deux unités d'échange
Dans cette partie, l'UE 0 gère les disques 0 à 3, alors que l'UE 1 gère les disques 4
à 7.
7. Quelles sont les modifications à apporter au code écrit avant pour
supporter cette nouvelle configuration ?
Configuration avec huit disques à double accès
On peut utiliser indifféremment l'une ou l'autre des unités d'échange pour
transmettre une commande au disque. Pour un même disque la commande de
positionnement et la commande de transfert ne sont pas obligées de transiter par
la même UE.
8. Quel(s) intérêt(s) voyez-vous à cette configuration par rapport à
la configuration précédente ?
9. On peut profiter de cette configuration pour spécialiser une UE
en positionnement et l'autre en transfert. Citer les avantages et
inconvénients d'une telle approche.
10. Si au contraire les deux UE ne sont pas spécialisées, modifier les
processus disques pour utiliser au mieux les unités d'échange.
15
Etude
d'un
d’impression
serveur
Objectif
Un serveur d’impression, autrefois appelé Spooler, de l'anglais SPOOL,
abréviation de Simultaneous Peripheral Operation On-Line, est un programme
qui se charge de récupérer les données envoyées vers un périphérique, qui les
met dans file d'attente servant aussi de tampon et ne les envoie que lorsque que le
périphérique est prêt. Cette technique est essentiellement utilisée pour les
imprimantes.
L'objectif de cet exercice est de réaliser un serveur d’impression, pour imprimer
le contenu d'un fichier en parallèle avec une autre utilisation du processeur. On
examinera aussi l'utilisation d'un DMA pour accélérer les transferts de données
vers l'imprimante.
L’imprimante utilisée (imprimante caractère que vous n’avez vue que dans le
grenier de vos parents) n’est pas là uniquement par pure nostalgie de son doux
crépitement, mais aussi parce que son temps variable d’impression d’un caractère
introduit des phénomènes intéressants d’un point de vue synchronisation.
Description du system
Caractéristiques du disque
-
temps de changement de piste :
30 ms
vitesse de rotation
: 160 ms/tour
32 secteurs par piste
128 octets par secteur
La primitive void lire_secteur(int nb; char *tampon,int *nblu) demande à
transférer le contenu de nb secteur(s) dans la zone tampon. En sortie, nblu indique
le nombre des secteurs qui ont effectivement été transférés. Cette primitive est
bloquante ; elle utilise 1 ms de temps processeur quel que soit le nombre de
tampons transférés.
A chaque appel de lire-secteur on suppose qu'il y a positionnement du bras car le
disque a pu être utilisé par d'autres processus.
Caractéristiques de l'imprimante
Pendant la phase de transfert d'une ligne vers l'imprimante, celle-ci impose un
délai de 200 micro-secondes pour mémoriser un caractère. La phase d'impression
16
proprement dite est déclenchée par le transfert du caractère '\n' et dure 300 ms (en
plus des 200 micro-secondes).
L'imprimante apparaît au processeur à travers trois registres : donnée, contrôle et
état.
Lorsque l'imprimante est prête à échanger un caractère, ceci est noté dans son
registre d'état et peut donner lieu à une interruption.
Lorsque la valeur "it-interdite" est placée dans le registre de contrôle,
l'imprimante n'émet aucune interruption. Si c'est par contre la valeur "it-permise",
l'imprimante maintient une demande d'IT tant qu'elle est dans l'état prêt.
Caractéristiques du fichier
Pour les applications numériques, on considérera que le serveur d’impressions
travaille sur un fichier de 50000 octets qui forment 1000 lignes. Une ligne est une
séquence de 0 à 127 caractères suivie du caractère '\n'.
Sauf indication contraire, les octets forment une chaîne continue qui ignore les
frontières de secteurs.
Le caractère '\0' servira à remplir les secteurs incomplets. Son transfert vers
l'imprimante occasionnera un délai de 200 micro-secondes comme les autres
caractères mais il sera ignoré lors de la phase d'impression.
Caractéristiques du processeur
La durée de la protection du contexte ou de sa restauration est de 30 microsecondes. Par contre, on considérera que dans la routine d'IT le temps des
instructions est négligeable, de même dans le serveur d’impression seule la
primitive lire-secteur consomme du temps processeur.
A) Version simple du serveur d’impression
On considère qu'il se compose d'une routine d'IT et d'un processus :
it-imprimante :
Processus serveur d’impression
donnée = *p;
while (1) {
compte = compte-1;
lire_secteur(1,tampon,&nblu);
if (compte == 0) {
if (nblu==0) break;
controle="it-interdite";
p=tampon;
V(sema);
compte = 128;
}
controle = "it-permise";
else p = p+1;
P(sema);
retour d'IT
}
Le pointeur p et la variable compte sont des variables globales partagées entre la
routine d'IT et le processus serveur d’impression.
1. Quelle doit être la valeur initiale de sema ? A quoi servent les
deux instructions modifiant le contenu du registre contrôle ?
17
2. Quel intervalle de temps sépare l'envoi sur l’imprimante de deux
caractères consécutifs d'une même ligne, stockés dans le même
secteur et déjà chargés en mémoire ?
3. Donner le schéma temporel moyen (ligne de taille "moyenne")
qui correspond à un tour de boucle du processus serveur
d’impression, et donner la durée totale du transfert.
4. Pour effectuer le transfert du fichier, quel est le temps
d'occupation du disque, de l'imprimante, du processeur ? Quel est
le temps total ? En déduire le taux d'occupation disque,
imprimante, processeur.
B) Modification de l'organisation disque
On décide de modifier les conventions du système de fichiers afin de ne mettre
qu'une ligne par secteur.
5. Modifier la routine it-imprimante pour tirer profit de cette
nouvelle convention.
6. Donner le nouveau schéma temporel
7. Reprendre la question 4 avec cette nouvelle convention.
C) Version rapide du serveur d’impression
Devant le volume disque impliqué par la convention du B) on revient à
l'organisation initiale.
8. Montrer par un schéma temporel que l'on peut quand même
conserver les performances de la partie B) à condition de prévoir
deux tampons.
9. Décrire la routine d'IT et le processus serveur d’impression
correspondant.
10. L'utilisation du disque par les autres processus peut provoquer
une attente supplémentaire dans la procédure lire-secteur.
Donner la valeur moyenne de l'attente qui peut être supportée
sans que l'imprimante en soit ralentie.
D) Augmentation des capacités d'impression
Afin de faire face au besoin d'impression, on décide de doter le système de deux
imprimantes connectées à travers un D.M.A. (Direct Memory Access) selon le
schéma suivant :
18
Imprimante
1
UC
Imprimante
2
DMA
Mémoire
Bus d'adresse
Bus de données
Le D.M.A. possède trois registres : adresse, nombre d'octets, état-dma. Lorsque
le mot de contrôle d'une imprimante est mis à "transfert avec dma", celle-ci
demande l'octet suivant au D.M.A. chaque fois qu'elle est prête ; par contre, elle
n'émet plus d'interruption. Lorsque le registre nombre d'octets du D.M.A. passe à
zéro, ceci est noté dans état-dma et génère simultanément une interruption. La
lecture de ce mot d'état supprime l'interruption et la marque de passage par zéro.
Les deux imprimantes et le D.M.A. sont connectés sur le même niveau
d'interruption.
11. Avec quelle valeur doit être chargé le registre nombre d'octets
pour aboutir à une bonne utilisation du D.M.A. ?
12. Quelles seront les valeurs successives mises dans le registre de
contrôle d'une imprimante ? Quelles seront les causes logiques de
ces modifications ?
13. Décrire la routine d'IT.
14. Décrire l'un des processus du serveur d’impression.
15. Comparer cette solution avec celle qui correspond à la
duplication de la solution de la partie C.
19
Sauvegarde d'un disque
Objectif
L'objectif dans cet exercice est de réaliser un système de gestion d'entrées/sorties
complexe : impliquant plusieurs périphériques, les contrôleurs associés étant
dotés de tampons internes, et les transferts vers ces tampons étant effectués par
DMA.
Architecture du système
Convention : Afin de simplifier les calculs et pour éviter toute ambiguïté, on
adopte les conventions suivantes, 1 Ko=1024 octets, 1 Mo= 1000 Ko et 1
Go=1000 Mo.
L'ordinateur utilisé possède la configuration ci-dessous.
Bande
disque
RAM
UC
adresse
e
compteur
fonction
Le DMA n'est pas multiplexé, c'est à dire qu'il ne peut prendre en charge qu'un
seul échange à la fois entre un périphérique et la RAM. Il apparaît à travers trois
registres : dma.adresse, dma.compteur, dma.fonction. Le contenu du registre
fonction comporte deux champs : {sens, périphérique}. Ainsi pour utiliser le
DMA lors d'une lecture sur la bande, écrira-t-on dma.fonction ={lecture, bande}.
Lorsque le compteur du DMA passe par 0, celui-ci émet une interruption et
devient disponible pour être affecté à un autre transfert.
Pour un fonctionnement correct, l'initialisation du DMA doit précéder celle du
périphérique mis en jeu dans l'échange.
Processus et ordonnancement
Les outils de synchronisation sont les sémaphores (sans message). Chaque
processus a sa priorité, et deux processus n'ont pas la même priorité. La
20
programmation de l’ordonnançeur, des primitives P et V, du retour d'IT, est faite
pour que ce soit toujours le processus prêt de plus haute priorité qui soit actif. Les
routines d'IT ne sont pas des processus, les IT utilisées sont au même niveau. il
n'y a pas d'interruption horloge.
Sauf indication contraire on négligera tous les temps de calcul sur le processeur.
Lors de l'opération de sauvegarde il n'y a pas d'autre utilisation de l'ordinateur.
Disque
Le disque comporte 8 faces, et donc 8 têtes de lecture. Chaque piste est formée de
192 secteurs de 512 octets, et il y a 5000 cylindres. Le disque tourne à 10000
tr/mn. Il contient également une mémoire interne de 512 Ko, appelée cache par la
suite.
Le contrôleur est suffisamment évolué pour qu'il n'y ait pas besoin de
programmer explicitement les déplacements du bras. Il apparaît à travers trois
registres :
-
disc.adresse : numéro du premier secteur à transférer,
disc.nbSecteur : nombre de secteurs consécutifs à transférer,
disc.fonction : lecture, écriture, ainsi qu'une autre fonction décrite
plus loin.
Une demande de transfert se fait en initialisant les registres adresse, nbSecteur et
fonction, dans cet ordre.
Le contrôleur décompose une fonction lecture en deux phases, il lit d'abord toute
l'information demandée sur le disque proprement dit et la met dans son cache,
puis il utilise le DMA pour transférer cette information du cache vers la RAM.
Au cours de l'exécution de cette fonction le contrôleur n'émet aucune IT.
Dans tout le problème on considérera que lors d'un transfert entre le disque et son
cache, il faut inclure un temps de positionnement en rotation, ou temps de
latence, égal à 1/2 tour, et si besoin un temps de déplacement du bras dont la
durée sera précisée dans la suite du texte. Le transfert à travers le DMA se fait à
20 Mo/s.
Lecteur de bande
Le lecteur de bande (nom classique même s'il sert aussi en écriture) est
architecturé autour d'un tampon de 1024 Ko géré circulairement. Son
fonctionnement peut se décomposer en deux activités indépendantes pouvant
s'exécuter en parallèle :
-
le transfert entre le tampon et la RAM au travers du DMA,
le transfert entre le tampon et la bande.
Le transfert à travers le DMA est limité à 4 Mo/s, mais il peut être plus lent. Le
transfert entre le tampon et la bande peut se faire selon trois vitesses : 600, 450 ou
300 Ko/s. La vitesse utilisée devra être définie au début de la sauvegarde.
21
Le contrôleur apparaît à travers deux registres :
-
bande.longueur : nombre d'octets à transférer à travers le DMA,
bande.fonction : écriture, lecture.
Une écriture sur bande s'initialise en chargeant le registre longueur puis la valeur
écriture dans le registre fonction. Ceci lance en parallèle une séquence
d'initialisation de la bande qui dure 1 s, et le remplissage du tampon du nombre
d'octets demandés. Le transfert entre le tampon et la bande ne débute qu'à la fin
de la séquence d'initialisation. Si les ordres d'écriture se succèdent assez
rapidement le tampon ne se vide pas complètement, la bande défile en continu et
donc la séquence d'initialisation n'a pas lieu. Si un ordre d'écriture arrive alors
que le tampon est presque plein, c'est le transfert à travers le DMA qui se ralentit,
pour s'adapter à la vitesse de libération du tampon par l'écriture sur la bande.
Par contre si les ordres d'écriture ne sont pas assez fréquents le tampon peut
devenir vide, dans ces conditions la bande s'arrête. Pour ce problème on
conviendra que la solution n'est pas acceptable quand la bande s'arrête au cours
de la sauvegarde.
Sauvegarde physique
Dans une première version on réalise une recopie systématique, piste par piste, de
tous les secteurs du disque.
1. Quelle est la capacité du disque ?
2. En détaillant votre calcul, indiquez le temps qui s'écoule entre
l'initialisation du disque et la disponibilité de l'information en
RAM lors du transfert d'une des pistes situées sous une tête de
lecture (pas de déplacement du bras) ? Pour les transferts piste
par piste, le déplacement du bras prend 1 ms, quel est le temps
nécessaire pour lire tout le contenu du disque mais sans effectuer
de sauvegarde ?
3. Quel est le temps minimum pour transférer dans le tampon du
lecteur de bande un volume équivalent à celui d'une piste, puis
pour le transférer sur la bande à 600 Ko/s ? En déduire la durée
du transfert sur la bande d'un volume équivalent à celui du disque
?
4. Donner
le code des deux procédures bloquantes
disc.lire(ad_mem,
ad_disque,
nb_secteurs)
et
bande.écrire(ad_mem, nb_octets) ainsi que la routine d'IT
associée. Les codes devront être suffisamment généraux pour
pouvoir être utilisés dans plusieurs processus.
Par la suite les échanges ne se feront qu'au travers de ces deux fonctions.
22
5. En justifiant votre réponse, indiquez si la sauvegarde peut se
programmer sous la forme d'un seul processus enchaînant la
lecture d'une piste puis l'écriture sur bande, ou s'il faut utiliser un
producteur-consommateur. Où se fera l'adaptation des vitesses ?
Sauvegarde logique
Afin de faciliter une restauration partielle du disque on envisage maintenant une
seconde version faisant la recopie fichier par fichier et non plus piste par piste. Le
système de fichier fait des allocations par granule, ensemble de secteurs
consécutifs.
Pour simplifier on ne se préoccupera pas de la gestion de la valeur de
adresse_disque dans les appels à disc.lire(). On peut alors symboliser la lecture
par :
char tamp[TAILLE_GRANULE] ;
/* tampon de la taille d'un granule */
for /* tous les fichiers */ {
for /* tous les granules */ {
disc.lire(& tamp, xxx, taille_granule);
}
}
Afin de pouvoir facilement comparer avec la version précédente on considérera
que le volume sauvegardé reste quand même celui de tout le disque. Cette
manière de faire implique des accès plus désordonnés que dans la version
précédente et le temps de positionnement moyen du bras sera celui fourni par le
constructeur, 8 ms.
6. Calculez le temps moyen de transfert par disc.lire() d'un granule
lorsque celui-ci fait 1 secteur et que tous les granules d'un fichier
sont répartis aléatoirement sur le disque. En déduire le temps de
lecture de tout le disque.
7. Calculez le temps de transfert d'un granule, puis celui de tout le
disque lorsque le granule fait 8 Ko.
8. Donnez le code de l'application sous la forme d'un producteur-
consommateur
bande.écrire().
utilisant
les
procédures
disc.lire()
et
9. En rapprochant la durée de la lecture du disque de celle de
l'écriture sur bande on décide d'utiliser la bande à 600 Ko/s et de
prendre deux tampons en mémoire. Montrez par un schéma
temporel que cette solution n'est pas satisfaisante. Pourquoi ?
23
10. En justifiant votre réponse, choisissez la vitesse de la bande, le
nombre de tampons en mémoire et la priorité des processus.
En lisant plus attentivement les caractéristiques du contrôleur du disque, on
s'aperçoit qu'il existe aussi la fonction préchargement qui se limite à transférer les
secteurs demandés dans le cache avec émission par le contrôleur d'une
interruption en fin de transfert. Lorsque par la suite, le contrôleur reçoit un ordre
de lecture portant sur des secteurs déjà dans le cache, il n'a plus qu'à réaliser le
transfert à travers le DMA.
11. Modifiez la procédure disc.lire(…, nb_secteurs) pour tirer partie
du préchargement de nb_secteurs et au besoin la routine d'IT.
12. En quoi cela modifie-t-il les choix faits dans la question 10.
Donnez un schéma temporel pour le début de la sauvegarde, puis
un autre quand le régime permanent est atteint.
Compression
Afin de pouvoir utiliser des cartouches de bande magnétique plus petites ou des
disques ayant un plus grand nombre de faces on envisage maintenant de
compresser les données lorsqu'elles sont en RAM, entre la lecture et l'écriture.
L'algorithme de compression s'adapte au contenu de chaque fichier et pour cela il
travaille en deux phases : il génère d'abord des statistiques sur tout le fichier
(supposé en mémoire), puis il le comprime bloc par bloc en fonction des
propriétés statistiques de ce fichier.
La procédure stat(ad_mem, nbOctets, tabStat) permet de remplir le tableau
tabStat en analysant la chaîne d'octets commençant en ad_mem. Cette procédure
prend 200 ms par Ko analysé. La procédure comprime(adSource, adCible,
tabStat) prend un bloc de 8 Ko et le comprime sous la forme d'un bloc de 4 Ko en
utilisant les statistiques contenues dans tabStat. Cette procédure prend 100 ms par
Ko produit.
Des mesures faites lors de l'utilisation de la version utilisant le préchargement ont
montré que le système de fichiers savait allouer les granules dans des cylindres
suffisamment proches pour que le temps moyen de déplacement du bras soit de 4
ms.
Pour rajouter la compression, on repart de la version avec préchargement. Il faut
donc décider de la place de chacune des procédures stat et comprime : dans le
processus de lecture, dans celui d'écriture, dans un processus indépendant. Il faut
également choisir la priorité des processus, la vitesse de la bande ainsi que les
caractéristiques des tampons en mémoire.
13. Commencez par faire ces choix en supposant que tous les fichiers
font 8 Ko,
14. Ces choix restent-ils valides lorsque les fichiers font tous 1 Mo ?
24
Téléchargement