|
|
Entrées-sorties
Exercice 1 : Nombre d'octets à écrire et
performances
Préparation
Se placer dans un répertoire de travail
tar xvfz perfW.tgz
cd PerfW
Question 1
Compléter toutes les sections "/* A vous de compléter */"
du fichier pw.c
make
Question 2
Ca y est : "pw.c compile" !
/usr/bin/time pw 16
Puis 32, 64 et toutes les puissances de 2 jusqu'à 8192. Pour
automatiser ce traitement, on peut s'appuyer sur les capacités
de bash:
- for i in 16 32 64 128 256 512 1024 2048 4096 8192; do echo $i; /usr/bin/time pw $i; done
- ou bien
for ((i=16; i<= 8192; i*=2)); do echo $i; /usr/bin/time pw $i; done
Qu'en concluez-vous ?
Question 3
Rajouter l'option O_SYNC à votre fonction open()
/usr/bin/time pw 512
/usr/bin/time pw 8192
Qu'en pensez-vous ?
Question 4
Recopier pw.c en pwWritev.c
Modifier pwWritev.c en :
- Retirant l'option O_SYNC de la fonction open(),
- Ecrivant le fichier à l'aide de la fonction writev (au lieu
de write). writev devra être appelé avec, en paramètre,
8192/param_appel_a_pwWritev structures
iovec pointant sur des zones de param_appel_a_pwWritev octets.
Compiler pwWritev
Comparer les performances de pw 16, pw 8192, pwWritev 16, et pwWritev 8192
Exercice 2 : Comment écrire par blocs de 8192 octets
alors que l'application écrit par blocs de 16 octets et ce qu'on
y gagne
Préparation
Se placer dans un répertoire de travail
tar xvfz cmpW.tgz
cd CmpW
Question 1
Dans cw.c, comparer ecritMethode1() et ecritMethode2().
Pourquoi à la fin de ecritMethode2() doit-on appeler flushBuf() ?
Question 2
On souhaite comparer ces 2 méthodes d'écriture. Pour ce
faire, on va "instrumenter" (faire un "profiling", si on utilise la
terminologie anglaise) le programme cw.
Taper
make cw
Que fait cette instruction ?
Noter que :
- L'option -pg qui demande l'instrumentation
Taper
make run
Que fait cette instruction ?
Noter que:
- "/usr/bin/time cw" exécute le programme et
génère un fichier contenant les résultats du
"profiling" : gmon.out
- "gprof cw > resultat.txt" génère une
version compréhensible par un humain du fichier gmon.out,
génération qu'on redirige vers le fichier resultat.txt
Voici un exemple commenté du fichier resultat.txt
(les commentaires sont signalés par des "//"). Consulter le pour
voir le type d'informations qu'on peut exploiter avec ce profiling.
Analyser (rapidement) votre propre fichier resultat.txt.
Question 3
Mêmes manipulations qu'à la question 2 en ajoutant O_SYNC
au moment du open des fichiers *et* en diminuant
d'au moins un
facteur 50 la taille des fichiers tests générés.
Exercice 3 : Calcul du nombre de lignes
- Écrire un programme qui lit un fichier et affiche
le nombre de lignes de ce fichier.
- Compléter ce programme pour que le nom du fichier
soit
passé en argument.
- Ajouter un test sur la nature de cet argument : s'il
s'agit d'un fichier, compter et afficher son nombre de lignes, sinon,
afficher seulement son type : répertoire ou fichier
spécial.
- Compléter ce programme de la façon suivante
: quand l'argument est un répertoire, il faut alors se
déplacer sous ce répertoire, et afficher le nombre de
lignes de tous les fichiers ordinaires qu'il contient et seulement le
nom pour les autres entrées.
Remarque : il faut penser à tester l'exécution des
fonctions (par exemple si le répertoire est inaccessible, la
fonction chdir échoue).
Exercice 4 : Informations SGF
- Écrire un programme qui sera exécuté
avec en argument un nom de fichier ou de répertoire. Ce
programme affichera alors le nombre de blocs total, le nombre de blocs
libres, le nombre d'inodes total et le nombre d'inodes libres du
système de fichiers auquel appartient cet argument.
Les résultats de ce programme pourront être
vérifiés avec les résultats de la commande df.
(attention : selon les versions, df utilise des
blocs de 512 ou
de 1K octets).
Exercice 5 : Méthode pour trouver
"instantanément" la i-è ligne d'un fichier texte
On se propose de développer un programme gl.c
(pour GotoLigne) permettant de trouver "instantanément" la ième
ligne d'un fichier texte dont les lignes ont des longueurs
différentes (inférieures à 1024 caractères,
caractère de nouvelle ligne inclus).
Le principe de la solution retenue est le suivant pour trouver la iè
ligne du fichier mEtMme.txt
:
- Avant l'utilisation de
gl.c ,
on construit
(à l'aide du programme d'initialisation gli )
un
fichier mEtMme.txt.idx tel que :
- Les 4 premiers octets du fichier
mEtMme.txt.idx
contiennent le décalage écrit en binaire de la 1ère ligne de mEtMme.txt
(par rapport au début de mEtMme.txt), i.e. 0x00000000 (zéro).
- Les 4 suivants contiennent le décalage de la 2ème
ligne de
mEtMme.txt , i.e. longueur de la 1ère
ligne. Par exemple, 0x07000000 (et non 0x00000007 , car le processeur Intel est Little Endian ; NB: vous n'aurez rien de spécial à faire dans votre programme pour prendre en compte le Little Endian) si la 1ère
ligne
de mEtMme.txt contient "Coucou\n".
- Les 4 suivants contiennent le décalage de la 3ème
ligne de
mEtMme.txt , i.e. longueur de la 1ère
ligne + longueur de la 2ème. Par exemple, 0x0d000000 ,
si la 2ème ligne contient "Hello\n".
- Au moment de l'exécution de
gl.c
:
- On ouvre le fichier
mEtMme.txt.idx
- Grâce à
lseek on se décale pour se placer au niveau des octets
correspondant au décalage du numéro de ligne
cherchée
- On lit, dans un entier, les 4 octets correspondant
au
numéro de ligne cherchée
- On lit également les 4 octets correspondant au
numéro de ligne recherché + 1 (on connaît ainsi la
longueur de la ligne cherchée)
- On ouvre le fichier
mEtMme.txt
- On se décale de la valeur des 4 octets
correspondant à la ligne cherchée
- On lit le fichier pour récupérer toute la
ligne
Question 1
Écrire le programme d'initialisation "gli" (à l'aide des
fonctions de la bibliothèque C d'entrées-sorties). Ce
programme lit sur la ligne de commande le nom du fichier pour lequel il
faut générer le fichier d'index (le nom du fichier
d'index est le nom du fichier original concaténé avec
".idx").
Question 2
Écrire le programme "gl" (à l'aide des fonctions de la
bibliothèque C d'entrées-sorties). Ce programme lit sur
la
ligne de commande le nom du fichier et le numéro de ligne. Il
affiche
la ligne.
Question 3
Écrire une nouvelle version de "gl" (glMmap) qui utilise mmap
pour permettre la lecture des octets du fichier d'index sans utiliser
fread ou read.
Exercice 6 : Accès concurrents et NFS
Question 1
Écrire un programme "nfs" qui :
- Lit sur la ligne de commande :
- le nom du fichier à ouvrir
- une chaîne de caractère(s).
- Ouvre le fichier en mode écriture seulement,
création si n'existe pas et mode "ajout" (droits
lecture/écriture pour l'utilisateur seulement).
- Écrit 10.000.000 de fois la chaîne de
caractères dans le fichier.
Question 2
Lancer la commande "nfs /var/tmp/ficTest a" sur 2 terminaux
différents en parallèle. Faire "ls -l /var/tmp/ficTest".
Que pensez-vous de la taille du fichier obtenu ? Effacer le fichier
/var/tmp/ficTest
Question 3
Même opération avec le fichier ~/ficTest avec:
- les 2 terminaux étant sur la même machine (ne
pas
oublier d'effacer le fichier obtenu) : pourquoi a-t-on le même
comportement qu'à la question 1 ?
- les 2 terminaux sur une machien différente :
pourquoi perd-on des écritures ?
Exercice 7 : Gestion d'une banque
Préparation
Se placer dans un répertoire de travail
tar xvfz banque.tgz
cd Banque
RecommandationDans cette exercice, vous allez écrire du
code. Et ce code, vous allez le tester pour le vérifier. Il est
recommandé d'effecturer ces tests avec un numéro de
compte autre que le compte numéro 0 (zéro) pour
éviter de passer à côté de certaines erreurs
(impossibles à voir avec le compte numéro 0).Question 0
On souhaite écrire un programme pour la gestion d'une banque. Ce
programme manipule un fichier de données ("banque.dat") contenant
NBCOMPTES comptes en banque. Chaque compte est identifié par un
numéro correspondant au rang du compte dans le fichier (par
exemple, le compte numéro 0 apparaît en premier dans le fichier) et est
représenté dans le fichier par un nombre décimal (éventuellement
négatif) correspondant au solde du compte.
Dans cette question, on suppose que NBCOMPTES vaut 4 et que
les 4 comptes ont respectivement pour solde : -10,02 euros, 1235,43
euros, 150000,43 euros et 9999999,99 euros.
On considère les trois implémentations suivantes du fichier :
- Implémentation 1 :
-10.02[caractère(s)
de renvoi à la ligne]
1235.43[caractère(s)
de renvoi à la ligne]
150000.43[caractère(s)
de renvoi à la ligne]
9999999.99[caractère(s)
de renvoi à la ligne]
- Implémentation 2 :
-10.02[caractère(s) de renvoi à la ligne]
1235.43[caractère(s) de renvoi à la ligne]
150000.43[caractère(s)
de renvoi à la ligne]
9999999.99[caractère(s)
de renvoi à la ligne]
- Implémentation 3 :
XXXXXXXXYYYYYYYYZZZZZZZZTTTTTTTT
où X (respectivement Y, Z et T) représente 1 octet, XXXXXXXX
(respectivement YYYYYYYY, ZZZZZZZZ et TTTTTTTT) correspondant à la
valeur binaire du double contenant le solde du compte numéro 0
(respectivement 1, 2 et 3).
Dans le fichier reponses.txt, calculez (en justifiant brièvement) pour chacune de ces implémentations :
- Le nombre d'octets requis pour stocker les 4 comptes
(pour les implémentations 1 et 2, on distinguera le cas Unix et le cas
Windows)
- Le nombre d'octets qui doivent être lus sur disque
pour disposer en mémoire du solde du compte numéro 3 (traiter uniquement le cas Unix).
Dans les questions suivantes, on décide de privilégier l'implémentation
3 qui minimise le nombre d'octets et le nombre de lectures de fichier
requises. Vous pouvez réaliser cette implémentation soit avec les
fonctions système d'accès aux fichiers (read, write...), soit avec les
fonctions de la librairie C (fread, fwrite..). Mais dans le cas des
fonctions de la librairie C, veillez à inhiber le tampon d'écriture des
fichiers (avec setvbuf) sous peine d'avoir des anomalies de
fonctionnement.
Question 1
Compléter le fichier banque.c de manière à ce
qu'il implémente l'algorithme suivant :
Lecture des
paramètres d'appel du programme
Ouverture fichier "banque.dat"
Lecture du solde stocké dans le fichier
Affichage de ce solde
sleep(5)
si (typeOp == 'L') alors
Lecture du solde stocké dans le fichier
Affichage du solde
sinon
Calcul
du
nouveau solde
Ecriture de ce nouveau solde dans le fichier
finsi
Fermeture du fichier
NB : si le fichier "banque.dat" n'existe pas, il
faut le
créer en l'initialisant avec NBCOMPTES valeurs de type double,
chacune étant initialisées à 0 et correspondant au
solde de chacun des comptes gérés par la banque.
Vérifier le
fonctionnement correct de l'application.
Question 2
Ouvrir une deuxième fenêtre et placez-vous
également dans le répertoire Banque de votre
répertoire de travail
Taper "banque 0 L" ("L" comme "Lecture") dans la première
fenêtre (sans taper return)
Taper "banque 0 M -5" ("M" comme "Modification" ou "Mise-à-jour"
dans la deuxième fenêtre et appuyer sur return
Revenir dans la première fenêtre et appuyer sur return
Pourquoi "banque 0 L" affiche 2 soldes différents au cours de
son exécution ? Ce comportement est-il acceptable par un client
? Pour ces 2 questions, vous veillerez à répondre dans le
fichier reponses.txt.
Question 3
Taper "banque 0 M -10" dans la première fenêtre (sans
taper return)
Taper "banque 0 M -5" dans la deuxième fenêtre et appuyer
sur return
Revenir dans la première fenêtre et appuyer sur return
Attendre la fin de l'exécution de ces 2 programmes, puis
exécuter "banque 0 L".
Commenter le résultat. Ce comportement est-il acceptable par un
client ? Vous veillerez à répondre dans le fichier reponses.txt.
Question 4
On souhaite corriger les dysfonctionnements observés aux
questions 2 et 3. Pour ce faire, on souhaite tester une solution
consistant en la pose du verrou le plus adapté aux
circonstances. L'algorithme envisagé est le suivant :
Lecture
des
paramètres d'appel du programme
Ouverture
fichier
"banque.dat"
Pose verrou en lecture // Nouveau par rapport a la question 1
Lecture du solde stocké dans le fichier
Affichage de ce solde
sleep(5)
si (typeOp == 'L') alors
Lecture du solde stocké dans le fichier
Affichage du solde
sinon
Pose verrou en écriture // Nouveau par rapport a la question 1
Calcul du
nouveau solde
Ecriture de ce nouveau solde dans le fichier
finsi
Relâchement verrou //
Nouveau par rapport a la
question 1
Fermeture du
fichier
Faire la commande cp banque.c banqueQ4.c
Implémenter l'algorithme ci-dessus dans la banqueQ4.c
Vérifier que les manipulations de la question 2
n'entraînent plus de dysfonctionnement.
Constater qu'en revanche, les manipulations de la question 3 donnent
lieu à une erreur. Expliquer, dans le fichier reponses.txt, le message d'erreur.
Question 5
On souhaite corriger le dysfonctionnement observé à la
question 4. Une personne propose l'algorithme suivant :
Lecture
des
paramètres d'appel du programme
Ouverture
fichier
"banque.dat"
Pose verrou en lecture
Lecture du solde stocké dans le fichier
Affichage de ce solde
sleep(5)
si (typeOp == 'L') alors
Lecture du solde stocké dans le fichier
Affichage du solde
sinon
Relâchement verrou //
Nouveau par rapport a la question 4
Pose verrou en
écriture
Calcul du nouveau solde
Ecriture de ce nouveau solde dans le fichier
finsi
Relâchement verrou
Fermeture du
fichier
Indiquez dans le fichier reponses.txt ce que vous pensez de cette proposition. NB : il n'est pas demandé
d'écrire un programme banqueQ5.c, même si ça peut
aider.
Question 6
Pour corriger tous les dysfonctionnements, une personne propose
l'algorithme suivant (consistant à poser dès le
début le verrou le plus fort dont on aura besoin) :
Lecture
des
paramètres d'appel du programme
Ouverture
fichier
"banque.dat"
si
(typeOp == 'L')
alors // Nouveau par rapport a la
question 4
Pose
verrou en lecture // Nouveau par rapport a la
question 4
sinon
// Nouveau par rapport a la
question 4
Pose
verrou en
écriture// Nouveau par rapport a la
question 4
finsi
//
Nouveau par
rapport a la question 4
Lecture du solde stocké dans le fichier
Affichage de ce solde
sleep(5)
si (typeOp == 'L') alors
Lecture du solde stocké dans le fichier
Affichage du solde
sinon
// Nouveau par rapport a la
question 4
(plus de "Pose
verrou en
écriture")
Calcul du nouveau solde
Ecriture de ce nouveau solde dans le fichier
finsi
Relâchement verrou
Fermeture du
fichier
Faire la commande cp banque.c banqueQ6.c
Implémenter l'algorithme ci-dessus dans la banqueQ6.c
Vérifier qu'il n'y a plus de dysfonctionnement.
Question 7
banqueQ7 a en fait encore un dysfonctionnement !
Ouvrir une troisième fenêtre :
- Taper "banque 0 M -10" dans la première
fenêtre (sans taper return)
- Taper "banque 0 L" dans la deuxième fenêtre
(sans taper return)
- Taper "banque 0 L" dans la troisième fenêtre
et appuyez sur return
- Aller dans la première fenêtre et appuyer sur
return
- Aller dans la deuxième fenêtre et appuyer sur
return
- Dès que "banque 0 L" a fini dans la troisième
fenêtre, relancer le.
- Dès que "banque 0 L" a fini dans la deuxième
fenêtre, relancer le.
- On observe que "banque 0 M -10" n'arrive jamais à
s'exécuter !
Ce dysfonctionnement ne pourra être corrigé que lors de
l'exercice CommInterProcessus/7
|