wiki:MultiCourseTP8

Cours "Architecture des Systèmes Multi-Processeurs"

TP8 : Contrôleur de disque & partage de périphériques

(franck.wajsburt@…)

A. Objectifs

Le premier objectif de ce TP est d'analyser le fonctionnement d'un nouveau contrôleur de périphérique: Le composant IOC (Input Output Controler) peut être utilisé pour effectuer des transferts de données entre la mémoire et un périphérique de stockage externe (disque magnétique, clé USB, etc...).

Le second objectif est d'analyser les problèmes posés par le partage des périphériques quand plusieurs programmes s'exécutent en parallèle sur plusieurs processeurs, et utilisent le même périphérique. L'architecture matérielle est donc l'architecture multi-processeurs générique, déjà utilisée dans les TP5, TP6, et TP7.

B. Contrôleur de disque

Le composant matériel PibusBlockDevice, permet d'accéder à un dispositif de stockage externe. A la différence de la mémoire vive (RAM) qui est volatile, ces dispositifs de stockage externe ont la propriété de conserver les informations stockées, même lorsque la machine est éteinte. Le prix à payer est en général des temps d'accès très grands (plusieurs millions de cycles pour un disque magnétique).

Dans l'espace de stockage externe, les données sont regroupées par blocs de 512 octets, et l'adresse externe (appelée Logical Block Address ou LBA) est un numéro de bloc, au lieu d'être un numéro d'octet comme dans l'espace d'adressage interne. Tous les transferts de données entre l'espace interne et l'espace externe se font donc par blocs de 512 octets.

Le contrôleur IOC permet donc à un programme s'exécutant sur le processeur MIPS32 de déclencher le transfert d'un ou plusieurs blocs de données entre un tampon mémoire et le périphérique de stockage externe.

Pour simplifier le simulateur, on utilise directement comme capacité de stockage externe un fichier stocké sur le disque de la station de travail qui exécute la simulation. Le disque de la plate-forme simulée est donc représenté par un unique fichier situé sur le disque de la station de travail. Un périphérique de ce type est vu comme une séquence de blocs de 512 octets. Pour la machine simulée, le fichier représentant le disque (et le nombre de blocs qu'il contient) sont des caractéristiques matérielles qui ne peuvent évidemment pas être modifiés par le logiciel. L'image disque qui vous est fournie pour ce TP est contenue dans le fichier images.raw. Il contient une séquence de 21 images. Chaque image contient 128 lignes de 128 pixels, et chaque pixel est codé sur un octet (256 niveaux de gris).

Le scénario de communication entre le programme utilisateur et le contrôleur de disque est le suivant:

  1. Le programme utilisateur, qui s'exécute sur le processeur MIPS32 utilise un appel système qui configure le contrôleur IOC et lance le transfert en écrivant dans différents registres « mappés en mémoire ». Cet appel système écrit dans quatre registres pour:
    • définir le sens du transfert (lecture ou écriture sur le disque),
    • définir l'adresse de base du tampon en mémoire,
    • définir le nombre de blocs à transférer,
    • définir le numéro du premier bloc sur le disque (LBA),
  2. Le coprocesseur IOC effectue le transfert bloc par bloc (une transaction rafale par bloc). Si le transfert est une écriture sur disque, les transactions sont des lectures sur le pibus, et inversement. 0n parle de coprocesseur d'entrées/sorties, car le contrôleur I/O et le processeur principal travaillent en parallèle durant ce transfert.
  3. La durée du transfert est encore plus imprédictible que dans le cas du contrôleur DMA, car elle dépend non seulement de la charge du bus, mais également de la position (mécanique) de la tête de lecture du disque. Lorsque le transfert est terminé, le contrôleur IOC active une interruption, pour signaler la fin du transfert au système d'exploitation, qui peut alors débloquer l'application ayant demandé le transfert.

Lisez la spécification fonctionnelle du composant PibusBlockDevice que vous trouverez dans l'en-tête du fichier pibus_block_device.h pour répondre aux questions suivantes:

Question B1 : Quelle est la signification des argument block_size et latency du constructeur du composant matériel PibusBlockDevice ?

Question B2 : Combien de blocs une image occupe-t-elle sur le disque, pour des blocs de 512 octets ?

Question B3 : Quels sont les registres adressables du contrôleur de disque, et quel effet a une écriture ou une lecture dans chacun de ces registres ?

Question B4 : Quels sont les différentes valeurs de l'état interne du contrôleur de disque qui peuvent être lues par le logiciel, et quelle est la signification de chacun de ces états ?

C. Architecture matérielle

L'archive attachment:multi_tp8.tgz contient les fichiers dont vous aurez besoin. Créez un répertoire de travail tp8, et copiez les deux fichiers tp5_top.cpp, et tp5.desc dans ce répertoire. Décompressez l'archive. Vous trouverez comme d'habitude le logiciel embarqué dans le répertoire soft, que vous recopierz dans tp8. On utilisera dans ce TP une architecture à 4 coeurs.

Attention : Il faut éditer le fichier tp5_top.cpp pour modifier la valeur d'un paramètre du constructeur du composant PibusSegBcu. Le paramètre timeout définit la durée maximale d'une transaction. Si la durée d'une transaction dépasse cette valeur, le contrôleur du bus interrompt la transaction. C'est l'utilisation du composant PibusBlockDevice qui rend cette modification nécessaire.

Question C1 : Pourquoi l'utilisation du composant PibusBlockDevice impose-t-elle d'augmenter la valeur du timeout du composant PibusSegBcu ? Quelle valeur faut-il donner au paramètre timeout du constructeur du composant PibusSegBcu ?

Pour le composant Frame Buffer, on choisira une hauteur et une largeur correspondant aux images qui se trouvent sur le disque (images de 128 lignes de 128 pixels).

En analysant le contenu du fichier tp5_top.cpp, répondez aux questions suivantes:

Question C2 : Quelles sont les valeurs de l'adresse de base et de la longueur du segment associé au contrôleur de disque (IOC). Compte-tenu du nombre variable de processeurs dans cette architecture, quelle sont les longueurs des segments associés aux composants ICU, TTY et TIMER ?

Question C3 : Combien y a-t-il de composants maitres dans cette architecture ? Combien de composants cibles ?

Question C4 : Sachant que l'architecture générique utilisée dans cette architecture permet de faire varier le nombre de coeurs, analysez le fichier tp5_top.cpp pour déterminer combien le composant ICU reçoit de lignes d'interruption entrantes, en provenance des 4 périphériques TTY, TIMER, DMA et IOC ? Combien possède-t-il de lignes d'interruptions sortantes ? Comment les IRQs provenant des périphériques sont-elles connectées sur les ports IRQ_IN[i] du composant ICU ?

Vérifiez et/ou modifiez les valeurs par défaut des paramètres matériels pour donner à la plate-forme matérielle les caractéristiques ci-dessus, et générez le simulateur.

D. Code de boot

Placez-vous dans le répertoire soft.

Le fichier reset.s contient le code de boot chargé d'initialiser le vecteur d'interruption et le périphérique ICU, ainsi que les pointeurs de pile des différents processeurs.

Question D1 : Rappelez pourquoi l'initialisation du pointeur de pile dépend du numéro de processeur.

Question D2 : Rappelez le mécanisme général qui permet au système d'exploitation de router - par logiciel - les différentes lignes d'interruption entrantes sur le composant ICU vers différents processeurs.

Question D3 : Dans le cas d'une architecture à 4 processeurs, quelles sont les valeurs à stocker dans les 4 registres de masque de l'ICU si on veut réaliser le routage suivant:

  • IRQ_TIMER[0], IRQ_TTY[0] IRQ_DMA et IRQ_IOC vers le processeur 0
  • IRQ_TIMER[1], IRQ_TTY[1] vers le processeur 1
  • IRQ_TIMER[2], IRQ_TTY[2] vers le processeur 2
  • IRQ_TIMER[3], IRQ_TTY[3] vers le processeur 3

Complétez le fichier reset.s pour initialiser le pointeur de pile des 4 processeurs (64 Koctets par processeur), et pour réaliser le routage des interruptions défini ci-dessus. Le périphérique TIMER n'est pas utilisé dans ce TP et n'a pas besoin d'être initialisé.

E. Application logicielle de traitement d'image

Le fichier main_image.c contient un programme de traitement d'image. Ce programme a été conçu pour permettre une exécution parallèle sur une architecture comportant 1, 2 ou 4 processeurs.

On commence par une exécution séquentielle sur une architecture comportant un seul processeur.

A chaque itération de la boucle principale, le programme effectue sucessivement les trois opérations suivantes:

  1. lecture d'une image sur le disque, et copie de cette image dans un tampon mémoire buf_in, au moyen de l'appel système ioc_read(), puis attente que le transfert soit terminé, avec l'appel système ioc_completed().
  2. Traitement de cette image pixel par pixel, consistant à appliquer un seuil sur l'image. L'image modifiée est copiée dans un second tampon mémoire buf_out.
  3. affichage sur le terminal graphique de l'image modifiée contenue dans le tampon mémoire buf_out, en utilisant l'appel système fb_sync_write(), qui n'utilise pas le le contrôleur DMA.

Question E1 : Quels sont les arguments de l'appel système ioc_read() ? Que fait cet appel système ? La réponse se trouve dans les fichiers stdio.c et drivers.c. Cet appel système attend-il que le transfert soit terminé pour rendre la main ? Dans quel cas cet appel système est-il bloquant ?

Question E2 : Que fait l'appel système ioc_completed() ? Quels sont ses arguments ? Cet appel système est-il bloquant ?

Complétez le fichier main_image.c pour définir les arguments manquants des appels système.

Dans le fichier de configuration config.h, vérifiez que l'argument NB_PROCS a la valeur 1, et que l'argument NO_HARD_CC a la valeur 0.

Utilisez le Makefile pour générer le code binaire.

Retournez dans le répertoire tp8 et lancez l'exécution sur une architecture mono-processeur, en définissant sur la ligne de commande le chemin vers le fichier contenant l'image disque, et en utilisant de gros caches :

$ ./simul.x -DISK images.raw -ISETS 1024 -IWAYS 4 -DSETS 1024 -DWAYS 4 -NPROCS 1

Il s'agit d'une application interactive : la boucle principale se termine par un appel système tty_getc() permettant de lire un caractère tapé au clavier. Puisque cet appel système est bloquant, il faut appuyer sur une touche du clavier (n'importe laquelle) pour autoriser le chargement et l'affichage de l'image suivante.

Question E3 : Quel problème observez-vous lors de l'affichage des images suivantes ? Expliquez précisément quelle est la cause de ce dysfonctionnement. Indication : la cause du problème est liée au fonctionnement du cache de données.

Modifiez - sur la ligne de commande - la valeur du paramètre SNOOP, qui permet d'activer le mécanisme d'espionnage du bus du composant PibusMip32Xcache... et vérifiez que le dysfonctionnement observé disparait.

En analysant le contenu du fichier pibus_mips32_xcache.cpp, et plus particulièrement le comportement de l'automate SNOOP_FSM, répondez aux questions suivantes:

Question E4 : Quelles conditions font-elles sortir l'automate SNOOP_FSM de l'état IDLE ? La stratégie mise en oeuvre en cas de hit externe est-elle une mise à jour ou une invalidation ?

Question E5 : Pourquoi la détection de plusieurs hit externes consécutifs pose-t-elle un problème particulier ? Comment ce problème est-il résolu ?

Modifiez dans le fichier tp5_top.cpp la valeur par défaut du paramètre SNOOP, de façon à ce que le SNOOP soit toujours activé.

Question E6 : Mesurez, pour les 4 premières images, les durées d'exécution de chacune des trois étapes du programme (chargement, seuillage, affichage) et reportez ces mesures dans un tableau.

F. Exécution sur architecture multi-processeurs

On veut maintenant exécuter l'application de traitement d'images sur une architecture comportant 4 processeurs. L'idée de base est d'accélérer le traitement en partageant le travail entre plusieurs processeurs travaillant en parallèle. Le principe de la parallélisation consiste à découper l'image en bandes horizontales, de sorte que chaque processeur est responsable du traitement d'une bande. Pour une image de 128 lignes, chaque processeur traite 32 lignes, représentant 1/4 de l'image.

Question F1 : Sur les trois phases de traitement (chargement, filtrage, affichage), lesquelles vont effectivement pouvoir être parallélisées ?

Au début du traitement d'une image, chaque processeur cherche à utiliser le contrôleur de disque pour charger en mémoire la partie de l'image qui le concerne.

Question F2 : Le contrôleur IOC ne pouvrant effectuer qu'un seul transfert à la fois, décrivez le mécanisme général qui permet de séquentialiser les 4 transferts demandés par les 4 processeurs.

C'est le fonction système _ioc_get_lock() (elle-même appelée par l'appel système ioc_read()), qui permet au système d'exploitation de prendre le verrou permettant l'accès exclusif au contrôleur IOC. Cette fonction utilise deux instructions assembleur particulières LL et SC pour réaliser un accès read_then_write atomique :

  • instructions LL(X) (linked load) : c'est une lecture d'un mot de 32 bits à une adresse mémoire X, avec prise de réservation sur la case mémoire X. Toute écriture à l'adresse X (par un autre processeur) annule la réservation.
  • instruction SC(X) (store conditional) : c'est une écriture conditionnelle d'un mot de 32 bits à l'adresse X. Si il n'y a pas eu d'autre accès en écriture à l'adresse X depuis la réservation réalisée par LL(X), c'est un succès, l'écriture est effectuée, et la réservation est annulée. Sinon, c'est un échec et l'écriture n'est pas effectuée. Cette instruction SC(X) est bloquante comme une lecture, puisqu'elle retourne une valeur : 1 en cas de succès, et 0 en cas d'échec.

Dans le cas (fréquent) où plusieurs programmes effectuent une réservation (instruction LL) sur la même adresse X, c'est donc le premier programme qui exécute l'instruction SC qui gagne.

Question F3 : Analysez en détail le code de la fonction _ioc_get_lock() que vous trouverez dans le fichier drivers.c, et expliquez ce que fait ce code.

Question F4 : Quelle est la fonction système qui libère le verrou protégeant l'accès exclusif au composant IOC. Pourquoi n'est-il pas nécessaire d'utiliser une instruction particulière pour libérer le verrou ?

Recompilez l'application de traitement d'image dans le répertoire soft pour une architecture à 4 processeurs en précisant le nombre de processeurs dans le fichier config.h. Lancez l'exécution.

$ ./simul.x -DISK images.raw -ISETS 1024 -IWAYS 4 -DSETS 1024 -DWAYS 4 -NPROCS 4

G. Réalisation matérielle du LL/SC

Le mécanisme (LL/SC) permet d'utiliser n'importe quelle adresse mémoire X comme verrou d'accès exclusif, et l'association entre une adresse X et une ressource protégée est une convention qui est définie soit par le système d'exploitation (pour les verrous utilisés par le système), soit par les applications (pour les verrous directement gérés par le code applicatif). Les instructions LL et SC ne sont donc pas des instructions protégées, réservées au système d'exploitation. Pour donner toute liberté au logiciel sur le choix des adresses de verrous, le matériel doit donc être capable d'enregistrer la prise de réservation effectuée par l'instruction LL(X) sur n'importe quelle adresse X.

En pratique, dans les architectures à base de bus, les registres permettant d'enregistrer cette prise de réservation sont généralement situés dans le contrôleur de cache et non dans le contrôleur mémoire.

Question G1 : Pour quelle raison réalise-t-on cet enregistrement du côté du processeur plutôt que du côté de la mémoire ?

Cet enregistrement du côté du processeur pose évidemment un problème: pour garantir l'accès exclusif, une réservation sur l'adresse X effectuée par une instruction LL(X) exécutée sur le processeur P0 doit être annulée si un autre processeur P1 exécute le premier une instruction SC(X) sur la même adresse.

Question G2 : Dans le scénario décrit ci-dessus, comment le processeur P0 est-il informé de l'écriture effectuée par P1 ?

Question G3 : Pour vérifier votre hypothèse, exécutez l'application de traitement d'image en désactivant le mécanisme de snoop, grâce à l'argument (-SNOOP 0) sur la ligne de commande. Comment expliquez-vous ce que vous observez ?

Question G4 : Résumez en une phrase les deux utilisations du mécanisme de snoop qui on été mis en évidence dans ce TP.

H. Compte-rendu

Les réponses aux questions ci-dessus doivent être rédigées sous éditeur de texte et ce compte-rendu doit être rendu au début de la séance de TP suivante. De même, le simulateur, fera l'objet d'un contrôle (par binôme) au début de la séance de TP de la semaine suivante.

Last modified 13 months ago Last modified on Apr 7, 2023, 1:41:00 PM

Attachments (2)

Download all attachments as: .zip