| | 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] |