ALMO TP n°8 - Périphériques orientés blocs
Préambule
L'objectif de ce TP est d'analyser le comportement d'une application logicielle de manipulation d'image s'exécutant sur la plateforme matérielle rappelée ci-dessous.
Les différentes lignes d'interruptions sont connectées comme suit :
- L'interruption du Contrôleur I/O est connectée à l'entrée
IRQ[0]
de l'ICU. - L'interruption du
TIMER
est connectée à l'entréeIRQ[1]
de l'ICU. - L'interruption du Contrôleur
DMA
est connectée à l'entréeIRQ[2]
de l'ICU. - L'interruption du contrôleur TTY est connectée à l'entrée
IRQ[3]
de l' ICU.
On cherche essentiellement à mesurer le temps moyen de traitement d'une image, en nombre de cycles du processeur. Le traitement d'une image se décompose en trois étapes, comme expliqué dans le TD associé :
- phase Load : chargement de l'image depuis un fichier sur disque vers un premier tampon mémoire appelé
buf_in
. - phase Modif : modification de cette image et recopie de l'image modifiée dans un second tampon mémoire appelé
buf_out
. - phase Display : affichage de l'image modifiée par copie du tampon
buf_out
vers la mémoire vidéo.
Comme d'habitude, commencez par recopier dans votre répertoire de travail les fichiers sources spécifiques à ce TP :
$ cp -r /Infos/lmd/2019/licence/ue/LU3IN004-2019oct/sesi-almo/soft/tp08/sujet ./tp08
$ cd tp08
Les images à afficher sont stockées dans le fichier images.raw
, qui contient une séquence de 20 images. Pour réduire les temps de simulation, les images sont de petites tailles : 128 lignes de 128 pixels. Chaque pixel est codé sur un octet en 256 niveaux de gris.
Le simulateur utilisé est toujours simul_almo_generic
.
1. Application séquentielle sans DMA
Dans un premier temps, on va déterminer les temps d'exécution de chacune des trois phases de traitement grâce à une application logicielle séquentielle qui exécute successivement les trois phases pour chaque image : chargement, modification et affichage, en affichant sur un terminal TTY la date de terminaison de chaque phase.
Les segments associés aux trois nouveaux périphériques (DMA, IOC et FBF) sont implantés aux adresses suivantes dans la zone protégée de l'espace adressable :
seg_ioc_base
se situe à l'adresse0x92000000
.seg_dma_base
se situe à l'adresse0x93000000
.seg_fb_base
se situe à l'adresse0x96000000
.
- Complétez le fichier de script
ld
nomméseg.ld
pour y définir les adresses de base de ces 3 nouveaux segments.
- Ouvrez maintenant le fichier
reset.s
et complétez le de façon à installer dans le vecteur d'interruption les 4 ISR correspondant aux quatre périphériques présents dans la plateforme matérielle. Vous devez regarder le fichierirq_handler.c
pour déterminer les noms de ces 4 ISR. Il faut également configurer le composant ICU pour qu'il laisse passer ces 4 lignes d'interruption.
- Complétez le fichier
main.c
qui contient la fonction principalemain()
, en précisant les valeurs des arguments des différents appels systèmes. Vous devez regarder les fichiersstdio.[ch]
pour vérifier le type et la signification des arguments. N'oubliez pas qu'il faut lire une nouvelle image dans le fichier à chaque itération dans la boucle.- En quoi consiste la modification de l'image réalisée par cette application avant affichage ?
- Compilez le système logiciel en utilisant le
Makefile
qui vous est fourni, puis lancez l'exécution de la simulation avec la commande donnée ci-dessous.- L'option
-IOCFILE
informe le simulateur que la plateforme contient un contrôleur I/O sur disque, et que le fichier représentant le disque estimages.raw
. - L'option
-FBFSIZE
informe le simulateur que la plateforme contient un contrôleur graphique et que le tampon qui lui est associé a une capacité de 128 lignes de 128 pixels. - Les deux options
-NICACHE
et-NDCACHE
permettent d'augmenter la capacité des caches L1.
- L'option
$ simul_almo_generic -SYS sys.bin -APP app.bin -IOCFILE images.raw -FBFSIZE 128 -NICACHE 512 -NDCACHE 512
- Relevez les dates correspondant aux événements significatifs. Les durées observées se comptant en centaines de milliers de cycles, on arrondira les dates à des multiples de 1000 cycles et on utilisera comme unité le Kcycle (1 Kcycle = 1000 cycles).
- Construisez un tableau contenant, pour chacune des 5 images, la durée de la phase de chargement, la durée de la phase de traitement, et la durée de la phase d'affichage.
2. Application séquentielle avec DMA
L'appel système bloquant fb_sync_write()
utilisé dans la première partie du TP effectue le transfert de la phase Display par une technique purement logicielle de type memcpy : chaque octet est successivement lu dans le tampon buf_out
, puis écrit dans le tampon vidéo. Cette technique n'est pas très efficace pour deux raisons : d'une part, elle génère beaucoup de transactions sur le bus (deux transactions pour transférer un seul octet), et d'autre part, le processeur ne peut être utilisé pour faire d'autres calculs puisque c'est lui qui déplace les données en exécutant des instructions de lecture et d'écriture en mémoire. On va donc utiliser le contrôleur DMA disponible dans la plateforme pour accélérer le transfert dans la phase Display.
- Sauvez le fichier
main.c
sous un autre nom, puis éditez-le et modifiez l'application pour que la phase Display utilise dorénavant l'appel système non-bloquantfb_write()
, qui configure et démarre le contrôleur DMA pour que celui-ci effectue le transfert du tamponbuf_out
vers le tampon vidéo par rafales de 32 mots (128 octets). Notez que l'application logicielle doit maintenant utiliser l'appel système bloquantfb_completed()
pour s'assurer que le transfert est terminé avant de passer à l'image suivante.
- Recompilez l'application, puis relancez l'exécution. Relevez les dates correspondant aux événements significatifs, et reconstruisez un tableau similaire à celui de la partie précente. Qu'observez-vous ?
3. Application pipe-line
Il est possible de réduire encore la durée moyenne de traitement d'une image, en remarquant que durant la phase Load (chargement d'une image depuis le disque vers le tampon buf_in
), ainsi que pendant la phase Display, le processeur ne fait aucun traitement utile.
On va donc essayer de paralléliser les trois phases Load, Modif et Display, en écrivant une application qui traite jusqu'à trois images à la fois, en utilisant le fait qu'on possède 3 processeurs ou coprocesseurs : le contrôleur I/O, le processeur MIPS32
et le contrôleur DMA
. Le schéma (presque) périodique de fonctionnement pipe-line est décrit ci-dessous.
Il faut maintenant deux tampons mémoire d'entrée, buf_in_0
et buf_in_1
, que l'on utilise alternativement pour stocker les images paires et impaires venant du disque, ainsi que deux tampons mémoire de sortie, buf_out_0
et buf_out_1
, pour stocker les images modifiées paires et impaires.
Période 0 | Période 1 | Période 2 | Période 3 | Période 4 | Période 5 | Période 6 | |
---|---|---|---|---|---|---|---|
IOC | Load[0] | Load[1] | Load[2] | Load[3] | Load[4] | ||
MIPS32 | Modif[0] | Modif[1] | Modif[2] | Modif[3] | Modif[4] | ||
DMA | Display[0] | Display[1] | Display[2] | Display[3] | Display[4] |
Le fonctionnement général est le suivant :
- Durant les périodes paires :
- Chargement de l'image (2 * i) dans
buf_in_0
, - Modification de l'image (2 * i - 1) stockée dans
buf_in_1
et écriture dansbuf_out_1
, - Transfert de l'image (2 * i - 2) stockée dans
buf_out_0
vers la mémoire vidéo.
- Chargement de l'image (2 * i) dans
- Durant les périodes impaires :
- Chargement de l'image (2 * i + 1) dans
buf_in_1
, - Modification de l'image (2 * i) stockée dans
buf_in_0
et écriture dansbuf_out_0
, - Transfert de l'image (2 * i - 1) stockée dans
buf_out_1
vers la mémoire vidéo.
- Chargement de l'image (2 * i + 1) dans
Grâce à l'utilisation alternative des tampons mémoires pairs et impairs, à aucun moment on ne lit et on n'écrit simultanément dans le même tampon.
- Sauvez le fichier
main.c
sous un autre nom, puis éditez-le et modifiez l'application pour qu'elle respecte le 7 périodes décrites ci-dessus. Pour simplifier, on se limitera à une séquence de 5 images et on n'utilisera pas de boucle.
Attention : il faut s'assurer que les traitements parallèles exécutés dans la période
(n)
sont terminés quand on passe de la période(n)
à la période(n + 1)
. On introduira dans le programme l'affichage des dates permettant de déterminer les durées d'exécutions des 7 périodes.
- Recompilez, relancez l'exécution, et relevez les dates permettant de déterminer les durées d'exécution. Quel est le temps de traitement d'une image quand on est en régime établi (périodes 2, 3 et 4) ?
- Améliorez l'application pour qu'elle puisse traiter une séquence d'images de longueur quelconque. Cette application doit comporter 3 parties :
- un prologue correspondant au remplissage initial du pipe-line (ce prologue correspond aux périodes 0 et 1 de l'application en 7 périodes)
- une boucle permettant de traiter un nombre quelconque d'images en régime établi (ceci correspond aux périodes 2, 3 et 4 de l'application en 7 périodes)
- un épilogue permettant de vider le pipe-line (cet épilogue correspond aux périodes 5 et 6 de l'application en 7 périodes)