Changes between Initial Version and Version 1 of MjpegCourse/Station


Ignore:
Timestamp:
Feb 26, 2007, 1:00:58 PM (18 years ago)
Author:
Nicolas Pouillon
Comment:

Nom hiérarchique

Legend:

Unmodified
Added
Removed
Modified
  • MjpegCourse/Station

    v1 v1  
     1{{{
     2#!html
     3<h1>TP1: Description d'application avec DSX, et exécution sur station de travail</h1>
     4}}}
     5[[PageOutline]]
     6
     7
     8= 0. Objectif =
     9
     10L'objectif de ce premier TP est de vous familiariser avec le langage de description DSX
     11(comme Design Space Explorer). Ce langage permet au concepteur de déployer une application
     12logicielle multi-tâches (écrite en C) sur une architecture matérielle multi-processeurs (MP-SoC),
     13modélisée avec les composants matériels fournis par la bibliothèque SoCLib.
     14
     15Le langage de description DSX est une API implémentée à l'aide du langage Python, et il permet au concepteur
     16de faire 3 choses:
     17 * Définir la structure de l'application logicielle multi-tâches, c'est à dire le Graphe des Tâches et des Communications.
     18   (aussi appelé TCG: Tasks&Communication Graph).
     19   On suppose que le parallélisme "gros grain" de l'application et le shéma des communication entre les
     20   tâches peuvent être statiquement définis par le concepteur, et n'évoluent pas en cours d'exécution.
     21 * Définir l'architecture matérielle, c'est à dire définir le nombre de processeurs, le nombre de bancs mémoires,
     22   la taille des caches, le type d'inerconnect utilisé, etc...
     23 * Contrôler le déploiement de l'application logicielle sur la plate-forme matérielle, c'est à dire le placement
     24   des tâches sur les processeurs et le placement des canaux de communication sur les bancs mémoire.
     25
     26L'exécution de cette description DSX permet générer trois choses:
     27 * Une version de l'application logicielle multi-tâches compatible POSIX, qui peut être
     28   compilée et exécutée sur n'importe quelle station de travail supportant l'API des threads POSIX.
     29   Cette première version permet de valider fonctionnellement l'application logicielle, indépendamment
     30   de toute architecture MP-SoC.
     31 * Un ensemble de fichiers de directives permettant de compiler l'application logicielle pour le(s)
     32   processeur(s) embarqué(s) sur le MP-SoC, d'effectuer l'édition de liens avec le système d'exploitation
     33   embarqué, et de générer le code binaire exécutable.
     34 * Un modèle SystemC complet de l'architecture matérielle, correctement configuré pour respecter
     35   l'organisation de l'espace adressable défini par le concepteur, permettant de générer un simulateur
     36   complet de cette architecture, capable d'exécuter en simulation le code embarqué.
     37 
     38Dans ce 1^er^ TP, on se limitera à décrire - en langage DSX - la structure de l'application logicielle MJPEG,
     39à écrire quelques unes des tâches de l'application MJPEG, et à valider cette application en l'exécutant sur
     40une station de travail GNU/Linux.
     41
     42Vous fournirez un rapport rédigé, en format Adobe Acrobat (PDF), ainsi que certaines sources. Tous les détails sont
     43à la fin dans la section 'Compte-Rendu'. Les points du présent sujet devant faire l'objet d'un écho dans votre rapport sont
     44en '''''gras oblique''''', préfixés de [[Image(MjpegCourse:q.gif)]].
     45
     46= 1. Prise en main =
     47 
     48== 1.1. Exécuter l'application SplitMsg ==
     49
     50Pour prendre en main l'outil DSX, on s'intéresse à une application parallèle
     51extrêmement simple comportant deux tâches et un seul canal de communication MWMR.
     52Cette application s'appelle !SplitMsg.
     53 * Importez l'environnement nécessaire dans le contexte de votre ''shell''
     54{{{
     55$ source /users/outil/dsx/dsx_env.sh
     56}}}
     57 * Créez un répertoire `SplitMsg` dans lequel vous mettrez les fichiers à recopier.
     58   * Pour les fichiers, voir la page SplitMsg
     59 * Si ce n'est pas déjà fait, rendez la description DSX exécutable
     60{{{
     61$ chmod +x fichier_de_description
     62}}}
     63 * Exécutez la description DSX
     64{{{
     65$ ./fichier_de_description
     66}}}
     67 * [[Image(MjpegCourse:q.gif)]] Q1: '''''Quels fichiers ou répertoires ont été créés?'''''
     68 * Lancez la compilation l'application logicielle générée par DSX, en utilisant le makefile également généré
     69   par DSX.
     70{{{
     71$ make
     72}}}
     73 * Lancez le programme multitâche généré qui porte le nom "exe.posix".
     74   Vous pourrez interrompre l'exécution à tout moment en pressant Ctrl-c.
     75{{{
     76$ ./exe.posix
     77}}}
     78 * [[Image(MjpegCourse:q.gif)]] Q2: '''''Comment interprêter ce que vous observez lors de l'exécution de cette application ?'''''
     79
     80== 1.2. Anatomie de la description DSX ==
     81
     82Dans DSX, on fait une distinction entre un modèle de tâche et une instance de tâche,
     83car un même modèle de tâche peut être instancié plusieurs fois dans une application.
     84 * Un modèle de tâche est défini par la directive `TaskModel`. Il spécifie
     85   pour une tâche ses ressources utilisées (canaux de communication, ...)
     86   ainsi que ses implémentations existantes. Pour l'instant, on ne s'intéressera
     87   qu'aux implémentations logicielles déclarées par `SwTask`. voir DsxTaskModel
     88 * Une instance de tâche est définie par la directive `Task`. Elle fait partie d'un
     89   TCG. Elle est connectée aux autres tâches par les ressources. voir DsxTasks
     90
     91Dans les applications décrites dans ce TP, chaque modèle de tâche ne sera utilisé qu'une fois.
     92
     93La description DSX de l'application SplitMsg est en trois parties.
     94
     95[[Image(MjpegCourse:q.gif)]] Q3: '''''A quoi sert chacune des parties ?'''''
     96
     97= 2. Application MJPEG =
     98
     99Dans tout le reste du TP, on s'intéressera à l'application MJpeg telle que décrite en cours.
     100On en rappelle le graphe de tâches:
     101
     102[[Image(MjpegCourse:mjpeg.png)]]
     103
     104Chaque tâche effectue un traitement élémentaire dans la décompression d'une image.
     105Dans ce TCG, on représente les tâches par des ronds et les canaux de communication
     106par des rectangles. Il s'agit donc d'un graphe bipartie.
     107
     108Notre animation MJPEG sera composée d'images faisant toutes la même taille.
     109Comme une compression JPEG découpe l'image en blocs de 8x8 pixels, chacune des
     110dimensions de l'image sera multiple de 8 (on ne gère qu'un nombre entier de blocs).
     111Nous allons utiliser les constantes suivantes:
     112 * WIDTH largeur de l'image en pixels
     113 * HEIGHT hauteur de l'image en pixels
     114A partir de ces deux constantes, d'autres constantes sont définies dans le fichier `jpeg.h`:
     115 * BLOCKS_W nombre de blocs en largeur
     116 * BLOCKS_H nombre de blocs en hauteur
     117 * NBLOCKS nombre de blocs par image (= BLOCKS_W*BLOCKS_H)
     118
     119== 2.1. Spécifier le TCG ==
     120
     121Il faut nommer chaque élément du TCG:
     122 * Les noms des tâches ont été définis en cours et sont imposés.
     123 * Vous pouvez choisir librement les noms des canaux de communication.
     124   Chaque canal de communication est attaché à au moins deux tâches par des ''ports''.
     125   On distingue le nom des canaux de communication et le nom des ports des tâches connectées à ces canaux.
     126
     127Pour déterminer les noms des ports des tâches, il est impératif de consulter
     128le code des tâches fourni dans le fichier attachment:mjpeg_tp1.tar.bz2,
     129recopiez ce fichier chez vous et décompressez-le.
     130{{{
     131$ tar xjvf mjpeg_tp1.tar.bz2
     132}}}
     133'''Note''': Même si le code sources des tâches {{{iqzz}}} et {{{libu}}}
     134n'est pas fourni, vous pouvez connaître les largeurs de
     135tous les canaux en vous référant au code des autres tâches, et le nom des
     136ports est fourni dans la description DSX, dans le fichier {{{mjpeg.py}}}
     137(à compléter).
     138
     139Dans le fichier de description DSX {{{mjpeg.py}}},
     140 * Pour chacun des modèles de tâches:
     141   * Reportez des noms pour chacun des ports d'entrée/sortie (cf DsxTasks).
     142   * Complétez la description des modèles de tâches
     143     Iqzz, et Libu ont une déclaration particulière à ne pas prendre en compte pour l'instant,
     144     car ces modèles tâches sont fournis sans les sources: vous les écrirez aux prochaines questions
     145 * Pour chaque canal de communication:
     146   * Choisissez un nom et instanciez le canal
     147     (Nous avons 8 fifos Mwmr, utiliser l'API décrite dans DsxResource, `tg_demux` est fournie en exemple)
     148   * Dimensionnez (profondeur et largeur) les canaux en fonction des contraintes imposées par le code des tâches.
     149 * Créez un Tcg
     150   * en instanciant une tâche de chaque modèle, voir DsxTcg
     151   * en connectant les canaux aux ports des tâches, en les désignant par leurs noms
     152
     153== 2.2. Exécution de l'application ==
     154
     155 * Exécutez la description
     156{{{
     157$ ./mjpeg.py
     158}}}
     159 * Lancez la compilation de l'application
     160{{{
     161$ make
     162}}}
     163 * Lancez l'exécution de l'application
     164{{{
     165$ ./exe.posix
     166}}}
     167 * [[Image(MjpegCourse:q.gif)]] Q4: '''''Décrivez brièvement ce que vous observez'''''
     168
     169== 2.3. Écriture en C de la tâche IQZZ ==
     170
     171IQZZ est une tâche faisant un double traitement, appliqué successivement à chaque bloc de 8x8 pixels de l'image.
     172
     173IQZZ nécessite un tableau de quantisation inverse T, venant de la tâche ''Demux'' par un canal de communication dédié.
     174
     175Cette table doit être lue '''une fois par image''', elle sert au traitement de '''tous''' les blocs
     176d'une image. Le nombre de blocs dans l'image est donné par la constante NBLOCKS, définie dans "jpeg.h".
     177
     178Un bloc entrant dans IQZZ est composé de 8x8=64 facteurs.
     179||F,,0,,||F,,1,,||F,,2,,||F,,3,,||F,,4,,||F,,5,,||F,,6,,||F,,7,,||
     180||F,,8,,||F,,9,,||F,,10,,||F,,11,,||F,,12,,||F,,13,,||F,,14,,||F,,15,,||
     181||F,,16,,||F,,17,,||F,,18,,||F,,19,,||F,,20,,||F,,21,,||F,,22,,||F,,23,,||
     182||F,,24,,||F,,25,,||F,,26,,||F,,27,,||F,,28,,||F,,29,,||F,,30,,||F,,31,,||
     183||F,,32,,||F,,33,,||F,,34,,||F,,35,,||F,,36,,||F,,37,,||F,,38,,||F,,39,,||
     184||F,,40,,||F,,41,,||F,,42,,||F,,43,,||F,,44,,||F,,45,,||F,,46,,||F,,47,,||
     185||F,,48,,||F,,49,,||F,,50,,||F,,51,,||F,,52,,||F,,53,,||F,,54,,||F,,55,,||
     186||F,,56,,||F,,57,,||F,,58,,||F,,59,,||F,,60,,||F,,61,,||F,,62,,||F,,63,,||
     187
     188On applique sur ce bloc deux traitement successifs:
     189
     190 * La quantisation inverse (IQ) est la multiplication de chaque élément d'entrée par un facteur
     191   de la table de 64 coefficients de quantisation inverse T,,n,,, globale pour l'image.
     192
     193F,,n,,' = F,,n,, * T,,n,,
     194
     195||F,,0,,'||F,,1,,'||F,,2,,'||F,,3,,'||F,,4,,'||F,,5,,'||F,,6,,'||F,,7,,'||
     196||F,,8,,'||F,,9,,'||F,,10,,'||F,,11,,'||F,,12,,'||F,,13,,'||F,,14,,'||F,,15,,'||
     197||F,,16,,'||F,,17,,'||F,,18,,'||F,,19,,'||F,,20,,'||F,,21,,'||F,,22,,'||F,,23,,'||
     198||F,,24,,'||F,,25,,'||F,,26,,'||F,,27,,'||F,,28,,'||F,,29,,'||F,,30,,'||F,,31,,'||
     199||F,,32,,'||F,,33,,'||F,,34,,'||F,,35,,'||F,,36,,'||F,,37,,'||F,,38,,'||F,,39,,'||
     200||F,,40,,'||F,,41,,'||F,,42,,'||F,,43,,'||F,,44,,'||F,,45,,'||F,,46,,'||F,,47,,'||
     201||F,,48,,'||F,,49,,'||F,,50,,'||F,,51,,'||F,,52,,'||F,,53,,'||F,,54,,'||F,,55,,'||
     202||F,,56,,'||F,,57,,'||F,,58,,'||F,,59,,'||F,,60,,'||F,,61,,'||F,,62,,'||F,,63,,'||
     203
     204 * Le !ZigZag (ZZ) est un réordonnancement des pixels d'un bloc en diagonale. Il permet d'améliorer la compression.
     205
     206Après le réordonnancement, l'ordre des facteurs en sortie doit être:
     207
     208||F,,0,,'||F,,1,,'||F,,5,,'||F,,6,,'||F,,14,,'||F,,15,,'||F,,27,,'||F,,28,,'||
     209||F,,2,,'||F,,4,,'||F,,7,,'||F,,13,,'||F,,16,,'||F,,26,,'||F,,29,,'||F,,42,,'||
     210||F,,3,,'||F,,8,,'||F,,12,,'||F,,17,,'||F,,25,,'||F,,30,,'||F,,41,,'||F,,43,,'||
     211||F,,9,,'||F,,11,,'||F,,18,,'||F,,24,,'||F,,31,,'||F,,40,,'||F,,44,,'||F,,53,,'||
     212||F,,10,,'||F,,19,,'||F,,23,,'||F,,32,,'||F,,39,,'||F,,45,,'||F,,52,,'||F,,54,,'||
     213||F,,20,,'||F,,22,,'||F,,33,,'||F,,38,,'||F,,46,,'||F,,51,,'||F,,55,,'||F,,60,,'||
     214||F,,21,,'||F,,34,,'||F,,37,,'||F,,47,,'||F,,50,,'||F,,56,,'||F,,59,,'||F,,61,,'||
     215||F,,35,,'||F,,36,,'||F,,48,,'||F,,49,,'||F,,57,,'||F,,58,,'||F,,62,,'||F,,63,,'||
     216
     217Notes d'implémentation:
     218 * Pour implémenter ZZ, un tableau statique commençant par les
     219   valeurs ZZ![0]=0, ZZ![1]=1, ZZ![2]=8, ZZ![3]=16, ZZ![4]=9, ...
     220   vous sera probablement utile.
     221 * Les transformations IQ et ZZ doivent être implémentées dans
     222   la même boucle.
     223 * Les types des données sont:
     224   * T: Table de quantisation inverse (IQ): entiers non signés 8 bits
     225   * F,,n,,: Blocs en entrée: entiers 16 bits signés
     226   * F,,n,,': Blocs en sortie: entiers 32 bits signés (car 8bits*16bits nécessite au plus 24 bits...)
     227 * Votre code '''doit''' être portable quelle que soit l'endianness du processeur sous-jacent
     228   (si vous ne faites pas de transtypages hasardeux sur les pointeurs, ça devrait bien se passer)
     229 * Votre code '''doit''' gérer toutes les tailles d'images (tant qu'elles sont multiples de 8x8).
     230   Toutes les boucles doivent utiliser les tailles issues des defines (WIDTH, HEIGHT, BLOCKS_W, BLOCKS_H)
     231
     232Instructions:
     233 * Écrivez en C le code de la tâche IQZZ à l'aide de l'API logicielle définie dans SrlApi
     234 * Réécrivez la définition de la tâche IQZZ dans la description DSX
     235{{{
     236# On avait:
     237LlvmBlob('iqzz', stack_size = 1024, blob = 'src/iqzz_48x48.bc')
     238
     239# On peut alors déclarer iqzz comme une tâche logicielle en C.
     240SwTask( ... )
     241}}}
     242Inspirez-vous des autres déclarations, n'oubliez pas les `defines` si vous voulez un code portable.
     243
     244En fonction de la définition d'{{{iqzz}}} que vous utilisez (celle de `LlvmBlob` ou la vôtre),
     245et en recompilant, vous observerez les résultats l'implémentation de référence ou de la vôtre.
     246
     247 * Affinez votre fonction. Si besoin, lancez l'application {{{exe.posix}}} dans un débugger.
     248   La fonction implémentant {{{iqzz}}} portera probablement le nom {{{iqzz_func_iqzz}}}.
     249
     250== 2.4. Écriture en C de la tâche LIBU ==
     251
     252Un Ramdac est une RAM couplée à un DAC (Digital to Analog Converter). Le contenu de la ram est
     253converti en signal analogique pour être envoyé sur un écran. Notre Ramdac a un accès particulier:
     254Il a un comportement Fifo. Il faut écrire les pixels dans l'ordre où ils vont être affichés :
     255tous les pixels d'une ligne, puis toutes les lignes d'une image.
     256
     257Il se trouve que les blocs issus de la décompression JPEG font 8x8 pixels. Ils ne font pas la
     258largeur de l'image, il faut donc construire des lignes d'image à partir des blocs issus de la décompression.
     259C'est le but de la tâche Libu (Line Builder).
     260
     261Libu prend BLOCKS_W blocs de 8x8 pixels et en construit 8 lignes de WIDTH pixels de large
     262(rappel: BLOCKS_W*8 = WIDTH). Il peut alors envoyer successivement ces lignes au Ramdac.
     263
     264En pseudo-code, le traitement de Libu est:
     265{{{
     266bloc : 8x8 pixels
     267buffer : WIDTH*8 pixels
     268
     269Pour chaque 0 .. BLOCKS_H:
     270    Pour chaque 0 .. BLOCKS_W:
     271        Lire un bloc
     272        Pour chaque ligne du bloc
     273            Copier les 8 pixels en les mettant à leur place dans buffer
     274    Pour chacune des 8 lignes du buffer:
     275        Envoyer la ligne
     276}}}
     277 * Implémentez cette tâche en C à l'aide de l'API logicielle définie dans SrlApi
     278 * Modifiez la description de l'application DSX pour prendre en compte votre source
     279 * Testez l'application nouvellement compilée
     280
     281= 3. Compte-Rendu =
     282
     283Vous devrez créer une archive `tar.gz`, contenant un seul répertoire nommé `tp1`. Dans ce répertoire vous devrez mettre:
     284 * Un fichier `__init__.py` vide
     285 * Un fichier `rendu.py` contenant:
     286{{{
     287
     288from dsx import *
     289
     290iqzz = TaskModel( # le reste de la définition de votre modèle iqzz
     291                     )
     292libu = TaskModel( # le reste de la définition de votre modèle libu
     293                     )
     294}}}
     295   Et rien d'autre, en particulier rien à propos des autres tâches ou du TCG.
     296 * Le code des tâches iqzz et libu que vous avez écrites dans un sous-répertoire `src/`.
     297 * Votre rapport (une page maximum) en format PDF (et aucun autre) dans `tp1/rapport.pdf`.
     298
     299Le nom de fichier de l'archive doit contenir les nom des deux auteurs, séparés par un ''underscore'' (_),
     300par exemple: `dupond_dupont.tar.gz`.
     301
     302Faites particulièrement attention à cette archive. elle fera l'objet d'une correction automatique pour la
     303validation des sources, d'où le format strict.
     304
     305Pour être surs de vous, le listing du contenu de l'archive doit donner cette liste avec ces noms,
     306et rien de plus (l'ordre des fichiers n'importe pas):
     307{{{
     308$ tar tzf nombinome0_nombinome1.tar.gz
     309tp1/
     310tp1/__init__.py
     311tp1/src/
     312tp1/src/iqzz.c
     313tp1/src/libu.c
     314tp1/rapport.pdf
     315tp1/rendu.py
     316$
     317}}}
     318
     319Envoyez cette archive avant le 13/02/2007, 18h00 à [MailAsim:nipo Nicolas Pouillon].