| 1 | {{{ |
| 2 | #!html |
| 3 | <h1>TP3: Déploiement de l'application MJPEG sur architecture multiprocesseur</h1> |
| 4 | }}} |
| 5 | [[PageOutline]] |
| 6 | |
| 7 | = 0. Objectif = |
| 8 | |
| 9 | Comme pour les précédents TP, vous aurez à fournir un certain nombre de sources et un rapport. |
| 10 | Il vous est conseillé de parcourir la documentation dans le trac, en partant de WikiStart. |
| 11 | Par ailleurs, vous êtes nombreux à faire des [wiki:StrangeThings erreurs connues]. |
| 12 | |
| 13 | La première partie de ce TP vise la description d'une architecture matérielle multiprocesseurs générique, |
| 14 | appelée !VgmnNoirqMulti. Cette architecture est générique dans le sens où on peut faire varier par un simple |
| 15 | paramètre le nombre de processeurs et le nombre de bancs mémoire, ainsi que les caractéristiques des caches |
| 16 | rattachés aux processeurs. |
| 17 | |
| 18 | La seconde partie de ce TP vise à déployer l'application MJPEG sur cette plateforme générique en faisant varier |
| 19 | les paramètres dont on dispose. Cette ''exploration architecturale'' est le but réel de l'outil DSX. |
| 20 | |
| 21 | = 1. Description de l'architecture générique !VgmnNoirqMulti = |
| 22 | |
| 23 | L'architecture !VgmnNoirqMono utilisée dans le TP2 était une architecture mono-processeur non-paramètrable. |
| 24 | On se propose de décrire maintenant avec DSX une architecture multi-processeur générique, dont les paramètres sont : |
| 25 | * Le nombre de processeurs : `nproc` |
| 26 | * Le nombre de bancs mémoire : `nram` |
| 27 | * Le nombre de lignes des caches : `icache_nline` et `dcache_nline` |
| 28 | * Le nombre de mots par ligne des caches : `icache_nword` et `dcache_nword` |
| 29 | |
| 30 | [[Image(VgmnNoirqMulti.png, align=right)]] |
| 31 | |
| 32 | Cette architecture comportera également un contrôleur de verrous et un contrôleur de terminaux (!MultiTty). |
| 33 | Pour faciliter le debug, le nombre de terminaux contrôlés par le composant !MultiTty sera systématiquement |
| 34 | égal au nombre de processeurs. Pour décrire |
| 35 | cette architecture générique, vous pourrez vous inspirer de l'architecture VgmnNoirqMono définie |
| 36 | dans le TP2, en n'hésitant pas à utiliser les constructions du langage Python permettant d'exprimer la généricité (tableaux, boucles, etc.). |
| 37 | Cette architecture générique !VgmnNoirqMulti sera décrite dans un fichier DSX séparé, pour faciliter sa réutilisation. |
| 38 | |
| 39 | Pour récupérer la valeur d'un paramètre (par exemple le nombre de processeurs à instancier : ''nproc''), |
| 40 | utilisez la construction: |
| 41 | {{{ |
| 42 | self.getParam("nproc") |
| 43 | }}} |
| 44 | |
| 45 | Pour instancier le !MultiTty vous aurez besoin de définir une liste de noms de TTYs, ce qui suppose un nombre variable d'arguments. |
| 46 | Vous aurez besoin d'utiliser une fonctionnalité du langage Python: le passage de nombre variable d'arguments issus d'une liste. Supposant que ''nproc'' est une variable contenant le nombre de tty (égal au nombre de processeurs) |
| 47 | * il faudra créer une liste avec les noms des tty: |
| 48 | {{{ |
| 49 | noms_ttys = ["tty%d"%i for i in range(nproc)] |
| 50 | }}} |
| 51 | * puis passer cette liste comme une liste d'arguments au constructeur du !MultiTty: |
| 52 | {{{ |
| 53 | tty_controller = MultiTty('tty', *noms_ttys) |
| 54 | }}} |
| 55 | Avec `nproc = 3`, ces deux lignes reviennent à: |
| 56 | {{{ |
| 57 | tty_controller = MultiTty('tty', "tty0", "tty1", "tty2") |
| 58 | }}} |
| 59 | |
| 60 | Il faudra de plus connecter les ''nproc'' lignes d'interruption du controlleur `MultiTty` à |
| 61 | chacun des port d'interruption IRQ0 des ''nproc'' processeurs. Une boucle suffit: |
| 62 | {{{ |
| 63 | for i in range(nproc): |
| 64 | tty_controller.irq[i] // self.processor[i].irq[0] |
| 65 | }}} |
| 66 | |
| 67 | Vous exporterez les membres suivants: |
| 68 | * `processor`: une liste contenant tous les processeurs crées. On accédera au processeur ''n'' par `archi.processor[n]` |
| 69 | * `cram`: une liste contenant tous les segments cachés crées |
| 70 | * `uram`: une liste contenant tous les segments non cachés crées |
| 71 | * `vgmn`: l'interconnect |
| 72 | * `locks`: le composant de verrous matériels |
| 73 | |
| 74 | Vous validerez cette architecture générique !VgmnNoirqMulti, en déployant l'application MJPEG sur |
| 75 | une instance particulière de cette architecture équivalente à celle utilisée dans le TP2 (c'est à dire un seul |
| 76 | processeur et deux bancs mémoire). On utilisera le système d'exploitation embarqué Mutek/S. |
| 77 | On utilisera deux bancs mémoire, et des caches de 64 lignes de 8 mots. |
| 78 | |
| 79 | On instanciera l'architecture avec la ligne: |
| 80 | {{{ |
| 81 | archi = VgmnNoirqMulti( nproc = 1, nram = 2, |
| 82 | icache_nline = 64, icache_nword = 8, |
| 83 | dcache_nline = 64, dcache_nword = 8 ) |
| 84 | }}} |
| 85 | |
| 86 | [[Image(MjpegCourse:q.gif)]] Q1: Combien faut-il de cycles pour décompresser 25 images? |
| 87 | |
| 88 | = 2. Exploration Architecturale = |
| 89 | |
| 90 | Dans cette seconde partie, on va déployer l'application MJPEG sur l'architecture MPSoC !VgmnNoirqMulti. |
| 91 | On va principalement faire varier le nombre de processeurs et la répartition des tâches logicielles sur les |
| 92 | processeurs. Les deux tâches d'entrée/sortie `tg` et `ramdac` sont toujours implantées sur des |
| 93 | coprocesseurs matériels spécialisés, et il ya donc 5 tâches "logicielles" à déployer sur un nombre de processeurs |
| 94 | qui reste à déterminer. |
| 95 | |
| 96 | == 2.1 Profilage de l'application == |
| 97 | |
| 98 | Pour guider la répartition des tâches sur les processeurs, on commence par effectuer un profilage |
| 99 | de l'application sur station de travail POSIX, en mesurant les temps passés dans les différentes tâches. |
| 100 | |
| 101 | La mise en oeuvre du profilage d'une application multithreadée en utilisant les outils actuellement installés sur le réseau |
| 102 | est non triviale. Comme elle ne représente pas un intérêt particulier pour le TP, on vous fournit un script pour |
| 103 | réaliser le profilage. Il s'utilise avec deux paramètres: le temps pendant lequel il faut lancer le programme, et le programme à lancer. |
| 104 | {{{ |
| 105 | $ ~pouillon/opt/bin/gprof-mt 15 ./exe.posix |
| 106 | }}} |
| 107 | |
| 108 | Dès qu'il parvient à obtenir les résultats, le script vous rend sur la première colonne le temps relatif |
| 109 | (en %) passé dans chacunes des 5 tâches `demux`, `vld`, `iqzz`, `idct` et `libu`. |
| 110 | |
| 111 | [[Image(MjpegCourse:q.gif)]] Q2: Donnez l'estimation des temps de calcul relatifs pour chacune des 5 tâches "logicielles" de l'application MJPEG. |
| 112 | Qu'en déduisez-vous sur les façons optimales de déployer MJPEG sur 2, 3, 4 et 5 processeurs ? |
| 113 | |
| 114 | == 2.2 Déploiement sur une architecture à 5 processeurs == |
| 115 | |
| 116 | Déployez l'architecture MJPEG sur une architecture !VgmnNoirqMultiPro comportant cinq processeurs, |
| 117 | (c'est à dire une tâche par processeur) et lancez la simulation. |
| 118 | |
| 119 | [[Image(MjpegCourse:q.gif)]] Q3: Combien faut-il de cycles pour décompresser 25 images? |
| 120 | |
| 121 | On cherche maintenant à estimer le taux d'utilisation de chacun des 5 processeurs. |
| 122 | |
| 123 | On va utiliser pour cela les informations fournies par l'ordonnanceur de tâches associé à chaque processeur. |
| 124 | Lorsqu'une tâche se bloque (par exemble en attente de données disponibles sur un canal MWMR d'entrée), |
| 125 | l'ordonnanceur essaie de lancer l'exécution d'une autre tâche. Dans un système où chaque processeur |
| 126 | n'exécute qu'une seule tâche, l'ordonnanceur va essayer de relancer l'exécution de la tâche bloquée |
| 127 | un grand nombre de fois, jusqu'à ce que la condition de blocage disparaisse. Le compteur ''idleness'' |
| 128 | - affiché par l'ordonnanceur - mesure le nombre total de tentatives de lancement d'une autre tâche. |
| 129 | Une valeur élevée pour ce compteur est donc un bon indicateur que le processeur est faiblement utilisé, |
| 130 | puisque que l'ordonnanceur essaye souvent de passer la main à d'autres tâches. |
| 131 | |
| 132 | [[Image(MjpegCourse:q.gif)]] Q4: Les valeurs des compteurs ''idleness'' sont-elles cohérentes avec les informations |
| 133 | de profilage obtenues sur station de travail? |
| 134 | |
| 135 | [[Image(MjpegCourse:q.gif)]] Q5: Quel est selon vous le processeur le plus chargé ? |
| 136 | |
| 137 | == 2.3 Déploiement sur des architectures à 4, 3 et 2 processeurs == |
| 138 | |
| 139 | Déployez l'application MJPEG sur des architectures matérielles comportant 4, puis 3, puis 2 processeurs, |
| 140 | en utilisant les informations de profilage et de taux d'utilisation obtenues dans les questions précédentes, |
| 141 | pour placer ''intelligemment'' les tâches de façon à obtenir les temps de décompression les plus courts possibles. |
| 142 | |
| 143 | [[Image(MjpegCourse:q.gif)]] Q6: Quel est le nombre de cycles minimal pour décompresser 25 images avec 4 processeurs ? |
| 144 | |
| 145 | [[Image(MjpegCourse:q.gif)]] Q7: Quel est le nombre de cycles minimal pour décompresser 25 images avec 3 processeurs ? |
| 146 | |
| 147 | [[Image(MjpegCourse:q.gif)]] Q8: Quel est le nombre de cycles minimal pour décompresser 25 images avec 2 processeurs ? |
| 148 | |
| 149 | == 2.4 Influence de la taille des caches == |
| 150 | |
| 151 | On souhaite maintenant évaluer l'influence de la taille des caches sur le temps de décompression. |
| 152 | |
| 153 | Pour faciliter l'exploration architecturale sans avoir à modifier le source de votre description à chaque fois |
| 154 | que vous voulez changer un paramètre, il serait judicieux d'utiliser la ligne de commande lors de |
| 155 | l'interprétation de la description. Dans ce but, on fournit un fichier attachment:cmdline_parser.py . |
| 156 | Une fois placé dans le répertoire de votre description DSX, il s'utilise de la manière suivante: |
| 157 | {{{ |
| 158 | from cmdline_parser import * |
| 159 | }}} |
| 160 | Il définit les variables suivantes: |
| 161 | * `dcache_lines`, nombre passé sur la ligne de commande après le flag `--dl`, à défaut, 1024. |
| 162 | * `icache_lines`, nombre passé sur la ligne de commande après le flag `--il`, à défaut, 1024. |
| 163 | Utilisez ces variables à l'instanciation de votre plateforme. |
| 164 | Pour créer une plateforme avec des caches avec 64 lignes de données, il suffira alors d'exécuter: |
| 165 | {{{ |
| 166 | $ ./mjpeg --dl 64 |
| 167 | }}} |
| 168 | |
| 169 | On se place dans l'hypothèse d'une architecture à 2 processseurs, en conservant le placement |
| 170 | des tâches optimal défini à la question précédente. On utilisera des lignes de cache de 8 mots, et on se contentera de |
| 171 | faire varier le nombre de lignes. |
| 172 | * Mesurez le temps de calcul pour décompresser 2 images, en utilisant deux "gros" |
| 173 | caches de 1024 lignes, pour les instructions comme pour les données. |
| 174 | * Refaites cette mesure en diminuant progressivement le nombre de lignes du |
| 175 | cache de données (256, puis 64, puis 16 puis 4 puis 1), en conservant une |
| 176 | capacité de 1024 lignes pour le cache d'instructions. |
| 177 | * Même question en diminuant progressivement le nombre de lignes du cache d'instructions |
| 178 | (256, puis 64, puis 16 puis 4 puis 1), en conservantune capacité de 1024 lignes pour le cache de données. |
| 179 | |
| 180 | [[Image(MjpegCourse:q.gif)]]Q9: Regroupez ces résultats dans deux tableaux de synthèse. |
| 181 | |
| 182 | [[Image(MjpegCourse:q.gif)]]Q10: Que choisiriez-vous comme capacité pour les caches, sachant |
| 183 | que la surface de la mémoire embarquée est un facteur important du coût de fabrication |
| 184 | (on comparera en particulier la capacité des caches à la capacité des bancs mémoire `ram0` et `ram1`). |
| 185 | |
| 186 | = 3. Compte-Rendu = |
| 187 | |
| 188 | Comme pour les TP précédents, vous rendrez une archive contenant: |
| 189 | {{{ |
| 190 | $ tar tzf binome0_binome1.tar.gz |
| 191 | tp3/ |
| 192 | tp3/rapport.pdf |
| 193 | tp3/vgmn_noirq_multi.py |
| 194 | tp3/mjpeg/ |
| 195 | tp3/mjpeg/mjpeg.py |
| 196 | tp3/mjpeg/src/ |
| 197 | tp3/mjpeg/src/iqzz.c |
| 198 | tp3/mjpeg/src/libu.c |
| 199 | }}} |
| 200 | |
| 201 | Le fichier `mjpeg.py` sera celui de la partie 2.4, avec la prise en compte des arguments sur la ligne |
| 202 | de commande. Les deux sources C sont ceux des deux derniers TP, éventuellement modifiés. |
| 203 | |
| 204 | Cette archive devra être livrée avant le mardi 27 février 2007, 18h00 à [MailAsim:nipo Nicolas Pouillon] |