• Aucun résultat trouvé

8.2 T HINK 4L : Une personnalité micro-noyau à base de composants

9.1.3 Mise au point de différentes versions du décodeur

Comme expliqué dans la sous-section précédente, la componentisation du décodeur H.264 nous a permis d’identifier trois composants principaux. L’architecture de ces trois composants est vue sous la forme d’un pipeline où le composant d’entrée et de sortie constituent respectivement la source et le puit, et le composant de traitement est un filtre qui implante un algorithme de transformation de flux vidéo. Cette sous section est dédiée à la présentation de différentes variations de ce pipeline vidéo qui sont mises en œuvre pour être exécutées sur différentes architectures de plates-formes embarquées.

9.1.3.1 Version séquentielle

La première version que nous avons crée adopte un modèle d’exécution séquentiel. Cette version s’exécute d’une manière identique à celle de la version originale : le composant de sortie demande le décodage d’une image au composant de traitement, le composant de traitement récupère une image encodée auprès du composant d’entrée, effectue l’opération de décodage et envoie l’image décodé au composant de sortie. Le décodage d’un flux s’effectue par itération sur l’ensemble de ces étapes.

Le but de cette première expérimentation était en particulier de concevoir un système d’exploitation minimale qui permet d’exécuter ce décodeur H.264 sur un processeur ST230. ST230 est un processeur de type traitement de signal conçu pour être utilisé dans des solutions de type système sur puce fournis par la société STMicroelectronics. Il s’agit d’un processeur de type very long instruction word (VLIW) qui permet d’exploiter un parallélisme au niveau instructions afin d’augmenter l’utilisation des ressources de calcul.

Afin de mettre au point l’instance du système d’exploitation décrit ci-dessus, nous avons d’abord configuré les composants d’entrée et de sortie pour obtenir une version du décodeur qui lit le flux en entrée à partir d’un fichier et qui affiche la sortie sur un écran. Par la suite, nous avons fait en sorte d’expliciter les services système requis par cette application. Pour ce faire, nous avons localisé les appels à des services système tels que l’ouverture et la lecture de fichiers ou l’allocation de mémoire. Ces appels ont été transformés en des appels à des interfaces clientes qui identifient explicitement les services systèmes requis pour le bon fonctionnement de l’application. À la fin de cette opération, nous avons constaté que trois blocs système étaient nécessaires pour exécuter le décodeur sur une machine nue. Il s’agit d’un gestionnaire dynamique de mémoire, d’un système de fichiers et d’un pilote de dispositif d’affichage graphique.

Une fois ces modules systèmes identifiés, nous avons utilisé la bibliothèque de composants du

ca-nevas THINK avec son portage sur le processeur ST230 pour assembler un système d’exploitation qui

fournit ces services. Cette opération d’assemblage a été effectuée uniquement en rédigeant des fichiers ADL. L’ensemble des fichiers ADL décrivant l’architecture du décodeur séquentiel et l’instance du sys-tème d’exploitation pour ce dernier contient 225 lignes1. Le noyau de système d’exploitation et

9.1. H.264 - Une expérimentation de mise en œuvre d’application multimédia

cation décodeur ont alors été assemblés et compilés par le compilateur ADL. Remarquons que, grâce

au niveau de modularité des composants système fournis dans la bibliothèque KORTEX, il a été possible

de construire un système d’exécution mono-thread, ce qui permet d’exécuter l’application de nature sé-quentielle sans aucun surcoût lié à un mécanisme d’ordonnancement.

9.1.3.2 Version parallèle mono-processeur

Après avoir réalisé un système permettant l’exécution séquentielle du décodeur H.264, nous nous sommes intéressés à la parallélisation des composants qui constituent l’architecture en pipeline de cette application. Dans ce cadre, notre stratégie de parallélisation a été de découpler le flot d’exécution des trois principaux composants du pipeline en les exécutant avec des threads différents. La parallélisation de ces blocs nécessite une gestion asynchrone de leurs interactions. Comme présenté précédemment, le modèle d’interaction de ces trois composants consiste à tirer des images d’un étage inférieur. Ce modèle est fortement synchrone étant donné que l’appelant reste bloqué jusqu’à ce que l’appelé lui fournisse une image. Le découplage de ces flots d’exécution n’est possible qu’en insérant des mémoires tampons entre les points d’interaction de ces étages de pipeline. Par ce biais, on peut faire en sorte d’exécuter séparément l’étage inférieur qui remplirait la mémoire tampon avec des images pendant que l’étage supérieur consomme ces dernières à sa vitesse.

Grâce à l’approche à base de composants, nous avons pu implanter la parallélisation uniquement en agissant au niveau architectural, sans modifier l’implantation des composants fonctionnels. La figure 9.4 illustre la modification architecturale que nous avons implantée pour paralléliser les trois composants du décodeur H.264. Ces modifications peuvent être résumées en deux parties :

Données de sortie Données d'entrée flux de contrôle flux de données thread Décodeur Entrée Afficheur contrôleur d'exécution (a) Données d'entrée Données de sortie Données d'entrée Buffer circulaire Buffer circulaire contrôleur d'entrée Entrée Stub contrôleur de décodeur Décodeur Stub Stub contrôleur d'affichage Stub Afficheur Données de sortie (b)

FIG. 9.4 – Modification de l’architecture du décodeur H.264 pour passer d’un mode d’exécution

séquen-tiel à un mode d’exécution parallèle.

– Des connecteurs spéciaux ont été insérés au niveau des liaisons de ces trois composants. Ces connecteurs permettent d’insérer une mémoire tampon entre les paires de composants afin de dé-coupler leurs interactions. Une implantation de type buffer circulaire a été adopté au niveau des tampons afin d’assurer les échanges de données en minimisant le nombre de copies effectuées. Des composants stub/skeleton ont permis d’adapter les interfaces des composants fonctionnels au composant de mémoire tampon. Par ce biais, les liaisons entre les composants ont été assurés via une mémoire tampon sans modifier leur code d’implantation.

– Des contrôleurs d’exécution ont été insérés au niveau de chaque composant parallèle. En effet, dans le modèle séquentiel, le contrôle du flot d’exécution était assuré par l’étage qui se trouvait au

plus haut du pipeline. Pour exécuter chaque étage séparément, des composants spéciaux ont été placés. Ces composants ont pour fonction d’appeler les composants fonctionnels de chaque étage pour faire en sorte que les mémoires tampons soient remplies.

Pour exécuter cette version parallèle du décodeur, un système d’exécution multi-threads est requis. Pour répondre à ce besoin, nous avons modifié le système d’exploitation initial afin d’y rajouter les méca-nismes nécessaires. La figure 9.5 illustre l’architecture de l’ensemble contenant le décodeur parallèle et le système d’exploitation multi-threads. Remarquons que ce schéma est simplifié. Par exemple, le compo-sant scheduler illustré en un compocompo-sant est en fait constitué de plusieurs sous-compocompo-sants pour la gestion des contextes du processeur, la gestion des interruptions, la gestion de politique d’ordonnancement, etc.

Configuration Multi-Thread Mono-Processeur

Noyau Buffer Circulaire Contrôleur décodeur Contrôleur de sortie Entrée Contrôleur d'entrée Ordonnan-ceur Système de fichier Allocateur mémoire Binding Circular Buffer Sortie Stub Stub Décodeur Stub Stub Afficheur Thread 1 Thread 2 Thread 3

FIG. 9.5 – Architecture de l’ensemble contenant le décodeur parallèle est le système d’exploitation sous-jacent.

Comme nous disposions au préalable des composants de système d’exploitations adéquats, le passage vers cette version parallèle a nécessité uniquement l’écriture des connecteurs de mémoire et des contrô-leurs d’exécution décrits ci-dessus. Le reste des modifications a été effectué au niveau des descriptions d’architecture. L’ensemble du décodeur et son système d’exploitation pour l’exécuter sur un processeur

ST230 ont été décrits en 310 lignes de THINKADL. À partir de ces descriptions, le compilateur ADL

nous a permis d’assembler une image binaire qui permet d’exécuter cette architecture sur la plate-forme visée.

9.1.3.3 Version parallèle multiprocesseurs

La dernière expérimentation réalisée avec le décodeur H.264 à base de composants concerne la répar-tition de ses trois composants principaux sur une architecture multiprocesseurs. L’architecture matérielle que nous avons considéré pour effectuer cette expérimentation est la plate-forme ST230-SMP. Cette plate-forme, destinée à la mise au point d’un système multiprocesseurs sur puce, est réifié à ce jour par un simulateur qui permet d’intégrer un nombre configurable de processeurs de type ST230 au sein d’une architecture à mémoire partagée.

La configuration parallèle de l’application ayant déjà été obtenue dans la version précédente, cette expérimentation a touché uniquement à l’adaptation de cette dernière à une architecture matérielle diffé-rente. Puisque les composants fonctionnels de l’application sont indifférents par rapport à la plate-forme d’exécution, seuls les connecteurs mémoire ont dû être adaptés. En pratique, ces composants ont été remplacés par d’autres qui implantent le même type de tampon circulaire mais avec des mécanismes de synchronisation de bas niveau, fournis par la plate-forme ST230-SMP.

Dans le cadre de la répartition du décodeur sur plusieurs processeurs, une autre amélioration a été effectuée au niveau du système d’exploitation. En effet, nous avons conçu des instances de système

d’ex-9.1. H.264 - Une expérimentation de mise en œuvre d’application multimédia

ploitation différentes pour chaque nœud de la plate-forme. Ces instances sont spécialisés en fonction du composant logiciel qu’elles accueillent. La figure 9.6 illustre l’architecture de cette nouvelle configura-tion. Nous voyons que le système d’exploitation qui accueille le composant d’entrée fournit un système de fichiers et un gestionnaire de mémoire. Le système conçu pour le composant de traitement est réduit à un simple support d’exécution (runtime) qui fournit des opération d’allocation dynamique de mémoire. Enfin, le système qui accueil le composant de sortie ne fournit qu’un pilote pour gérer l’affichage gra-phique.

Configuration Multi-Thread Multi-Processeur

Processeur 1 Noyau Processeur 2 Processeur 3 Noyau Noyau Stub Système fichier Allocateur mémoire Allocateur mémoire Afficheur Sortie Décodeur Stub Stub Entrée Stub Mémoire partagée Mémoire partagée

FIG. 9.6 – Architecture de la version multiprocesseurs du décodeur H.264.

9.1.4 Évaluation

Nous avons présenté les trois questions qui ont motivé notre expérimentation au début de cette sec-tion. Nous répondons maintenant à ces questions en deux volets pour distinguer les aspects qualitatifs et les aspects quantitatifs.

9.1.4.1 Évaluation qualitative

La première question concernait la viabilité de la transformation d’une application monolithique écrite en C en une application à base de composants. Nos résultats ont montré qu’il faut répondre à cette question sous deux angles. D’un point de vue faisabilité, nous avons vu qu’il était tout a fait possible d’effectuer une telle transformation. Nous avons montré qu’une méthodologie de componentisation a été mis en place, et a été appliqué aisément pour transformer une application de taille considérable. De plus, cette méthodologie étant incrémentale, il nous a été possible de tester l’application au fur et à mesure du processus de transformation. Nous avons ainsi obtenu une version à base de composants d’un décodeur multimédia avec un effort tout à fait acceptable. Cependant, d’un point de vue architectural, le processus de transformation n’a pas amélioré l’architecture inhérente à l’application monolithique. En effet, nous avons vu qu’en suivant une stratégie de componentisation qui consiste à encapsuler dans des composants les fichiers (qui sont les unités de modularité du langage C) nous avons obtenu une structure très complexe. De plus,il nous a semblé très difficile d’en dériver une architecture propre. Nous avons conclu qu’une procédure de développement à base de composants devrait être appliquée dés la conception d’un projet de développement pour obtenir une architecture propre et modulaire.

La deuxième question qualitative qui nous préoccupait concerne les avantages d’un processus de développement basé sur l’architecture logicielle pour les applications multimédia, et en particulier à des-tination des plates-formes multiprocesseurs sur puce. Nous avons vu au travers nos cas d’études qu’une fois que l’architecture d’un logiciel est rendue modulaire, il était possible d’en dériver plusieurs ver-sions différentes en effectuant des manipulations au niveau de l’ADL. Nous avons en particulier montré

comment le pipeline du décodeur pouvait être adapté à des modèles d’exécution variés, sans effectuer la moindre modification au niveau des composants fonctionnels. En effet, la présence d’un compilateur ADL qui assemble une configuration à base de composants à partir des description d’architecture nous a permis d’assembler des couples de décodeurs et de systèmes d’exploitation spécialisés avec un effort minimal. Néanmoins, remarquons que notre expérimentation concernait uniquement la parallélisation de composants à gros grain avec des interactions faiblement couplées. La parallélisation sans modifica-tion de code foncmodifica-tionnel des composants à grain plus fin nous a semblé impossible car cela nécessiterait l’emploi de protocoles d’interaction complexes qui seront introduits avec le parallélisme.

9.1.4.2 Evaluation quantitative

La dernière interrogation ayant motivé cette expérimentation était quantitative. Il s’agit d’évaluer l’impact de la componentisation en termes de performances. Nous préférons encore répondre à cette question sous deux angles.

Le premier aspect est le coût de la technologie à composants utilisée. Dans le cadre de nos expéri-mentations, nous avons utilisé le canevas THINK. Afin d’évaluer le coût de cette technologie, nous avons comparé le temps d’exécution et la taille en mémoire de la version originale de l’application à la version à base de composants s’exécutant en mode séquentiel. Nous avons choisi d’effectuer cette comparaison sur plate-forme matérielle standard. Nous avons alors considéré l’architecture Intel x86 associée à un noyau Linux 2.6. Nous avons exécuté le décodeur assez longtemps (pour 500 images qcif) afin de relativiser les impactes non déterministes de type cache. Nous avons observé un surcoût de 1.5% en ce qui concerne le temps d’exécution du décodeur à base de composants par rapport à la version monolithique. Ce coût est principalement dû aux indirections mémoire qui sont effectuées au niveau des appels aux interfaces de composants. Ce surcoût nous semble tout à fait acceptable étant donné qu’il s’agit d’une version très modulaire, constituée de 35 composants. De plus, il est tout à fait possible d’améliorer ces chiffres en intégrant certaines stratégies d’optimisation au niveau du compilateur ADL utilisé pour la génération de code. Quant au surcoût en taille mémoire, il est de 7%. Cela est principalement dû au caractère réflexif des composant THINK. Il est tout à fait envisageable d’améliorer l’implantation actuelle du compilateur ADL pour éliminer les informations tissées au niveau de chaque composant lorsque la réflexivité n’est pas utilisée par l’application.

Le deuxième aspect est le coût impliqué par la modification de l’architecture du logiciel. Dans le cadre de nos expérimentations, nous n’avons pas effectué de telles modifications au niveau du décodeur. Notre sentiment est qu’il est difficile de déterminer a priori un éventuel gain ou surcoût lié à l’architec-ture. Bien qu’en général une architecture modulaire est moins performante qu’une architecture monoli-thique, la modularité peut servir pour la mise au point des versions spécialisées d’une application et peut s’avérer bénéfique au niveau des performances. Nous avons par exemple vu que la modularité fournie par

la bibliothèque KORTEXnous a permis de construire des instances de systèmes d’exploitation adaptées

aux fonctions de l’application accueillie. 9.2 Comment aller plus loin ?

L’expérimentation sur la mise en œuvre du décodeur H.264 nous a permis d’identifier un certain nombre de perspectives pour améliorer la programmation des applications de streaming à destination de systèmes multiprocesseurs sur puce. Nous essayons, dans cette section, de décrire comment le processus de développement de telles application pourrait être amélioré. Nous commençons par préciser nos objec-tifs. Ensuite, nous dressons un état de l’art pour mieux connaître les différentes approches proposées dans le passé pour la programmation des applications de streaming. Nous présentons enfin notre proposition qui vise à améliorer notre compilateur ADL afin de mettre en place un modèle de programmation et un support d’exécution pour développer des composants aisément parallélisables.