MEMOIRE DE STAGE

Couplage de codes dans une plateforme pour applications de simulation numérique

Pierre 'khorben' Pronchery



Remerciements

Je remercie Toan Nguyen, directeur de recherches à l'INRIA, de m'avoir permis d'effectuer ce stage.

Je remercie également Laurent Bonnaud, enseignant-chercheur à l'IUT2 de Grenoble, pour l'aide qu'il m'a apporté au cours de ce stage.

Table des matières
Introduction
1. Description du problème
1.1. Analyse de l'existant
1.1.1. Description de Cast
1.1.2. Les précédents développeurs
1.1.3. Fonctionnement de Cast
1.2. Définition du problème
1.2.1. Les limites de Cast
1.2.2. Migration de librairie graphique
2. Les différentes approches possibles
2.1. Recompilation avec wxGtk
2.2. Réécriture de l'interface avec Gtk
2.2.1. Réutilisation du code de Cast
2.2.2. Choix de librairie graphique
2.3. Approche du problème avec Dia
2.3.1. Présentation de Dia
2.3.2. Similarités avec Cast
2.3.3. Estimation de charge de développement
3. Réalisation du plug-in Dia
3.1. Prise en main du logiciel
3.2. Création des formes simples
3.2.1. Création de formes avec Dia
3.2.2. Création et modification manuelle des formes
3.2.3. Création du fichier de description
3.3. Écriture d'un plug-in élaboré
3.3.1. Les instructions nécessaires
3.3.2. Corps des fonctions
3.4. Plus loin dans la création des plug-ins
3.4.1. Un exemple concret
3.4.2. Compilation avec C++
Conclusion
Résumé et abstract
A. Manuel de l'utilisateur de Cast
B. Procédure d'installation de Cast
C. Fichiers de définition XML
Liste des tableaux
2-1. Librairies graphiques les plus répandues
3-1. Fonctions de chargement
3-2. Fonctions de sauvegarde
3-3. Fonctions de choix de trait
3-4. Fonctions de dessin
3-5. Corps proposés par Dia
Liste des illustrations
1-1. Calcul d'un profil d'aile d'avion
1-2. Interface de Cast
2-1. Fenêtre principale
2-2. Édition de diagrammes

Chapitre . Introduction

Présentation de l'INRIA

L'INRIA, Institut National de Recherche en Informatique et en Automatique, a été créé en 1967. C'est un établissement public à caractère scientifique et technologique (EPST), sous la tutelle du ministère de la recherche et du ministère de l'économie, des finances et de l'industrie. L'INRIA a ainsi été chargé de missions par l'État, dont la réalisation de systèmes expérimentaux, l'organisation d'échanges scientifiques, la diffusion des connaissances, la contribution à la normalisation. Pour cela l'INRIA crée des unités de recherche, prend des participations dans des entreprises et accueille des chercheurs de toute nationalité.

L'unité de recherche INRIA Rhône-Alpes est située à Montbonnot, regroupant 22 équipes de recherche. Les thèmes abordés sont les réseaux et systèmes informatiques, les interactions homme machine et la simulation de systèmes complexes, la moitié de ces projets étant en partenariat direct avec des acteurs de l'industrie et de l'enseignement.

Le projet Opale

Le projet Opale, ou "OPtimisation et contrôle, ALgorithmes numériquEs et intégration" (succédant au projet SINUS, "SImulation NUmérique dans les Sciences de l'ingénieur") consiste à faire progresser les méthodes de modélisation numérique. Le domaine couvert va de l'analyse des modèles à leur mise en oeuvre sur ordinateur, avec optimisation. Une des applications actuelles consiste par exemple à optimiser l'écoulement de l'air sur un profil d'aile d'avion. Ce type de calcul très exigeant est grandement accéléré grâce à l'utilisation de plusieurs grappes d'ordinateurs interconnectées par un réseau à haut débit.

Sujet du stage

Le stage devait initialement porter sur le développement de la plateforme d'intégration de logiciel, Cast, qui gère et fait communiquer les modèles et programmes numériques lors de leur exécution. Il s'agissait de mettre en oeuvre un couplage de code entre deux modèles numériques, et de les paralléliser pour une exécution sur grappe de PC.

Pour des raisons techniques, le sujet du stage a évolué: il s'agit de reprendre l'interface graphique de Cast, afin de rendre celui-ci utilisable sur un maximum de systèmes possibles.


Chapitre 1. Description du problème

1.1. Analyse de l'existant

1.1.1. Description de Cast

Fonctionnalités offertes

Cast[1] est une plateforme d'intégration de logiciels. Elle permet de définir une succession dynamique d'applications, ou tâches, à l'aide d'opérateurs de choix, itération, séquence par exemple. Ceci est proposé sous une forme graphique, permettant une définition intuitive des tâches et de leur déroulement. L'objectif est de synchroniser et répartir l'exécution de code, tout en le faisant communiquer.

Ainsi Cast est aujourd'hui capable de faire de la simulation numérique distribuée, en utilisant autant de grappes d'ordinateurs que disponibles. Interconnectées, Cast peut y exécuter des applications réparties de calcul parallèle, dépassant les performances de certains calculateurs plus coûteux. Dans le calcul de l'exemple suivant, l'optimisation du profil d'une aile d'avion, il a fallu 4h30 de travail pour une station de travail, et 3 minutes pour une grappe de 40 ordinateurs (à gauche se trouve le profil initial, à droite l'optimisé).

Modèle mathématique manipulé

La représentation empruntée correspond en fait au modèle de l'algèbre SCCS de Milner. Ce modèle permet de définir une suite algébrique de données suivant leurs caractéristiques temporelles: par exemple le produit de deux données marque leur simultanéité, la somme leur exclusion mutuelle.

Aspects techniques

CORBA[2] est une infrastructure et architecture logicielle, indépendante du matériel et logiciel utilisés. Elle permet l'exécution et la communication d'applications à travers n'importe quel type de réseau. Ce standard est défini par l'OMG[3], et il est actuellement utilisable sur la quasi-totalité des matériels existants, depuis les systèmes embarqués jusqu'aux super-calculateurs.

Cast est exclusivement programmé en C++. Il utilise diverses librairies pour son fonctionnement:

  • une implémentation de CORBA gérant les objets parallèles, PACO, développée par l'INRIA en extension à l'implémentation CORBA MICO.

  • une librairie graphique, wxMotif, issue du projet wxWindows, permettant la compilation d'une interface graphique sur de multiples plateformes différentes


1.1.2. Les précédents développeurs

Cast a été développé successivement par plusieurs personnes depuis 1995. Il a été adapté à PACO en 1999. Des scripts d'autoconfiguration ont ensuite été rajoutés afin de permettre la compilation sur la plupart des Unix existants: ils génèrent dynamiquement le fichier Makefile, en étudiant la disponibilité et l'emplacement des librairies nécessaires.

Le projet a ensuite été placé sur l'hébergeur Sourceforge, qui permet le développement par CVS[4]. Il s'agit en fait d'un serveur, accessible exclusivement par réseau, qui contient l'ensemble des sources du projet. Il conserve de manière appropriée chaque modification, par personne et date, ce qui le rend capable de régénérer d'anciennes versions du projet sans avoir à les garder séparément. Son interrogation, soumise à autorisation, permet le téléchargement des sources, et aux développeurs la mise à jour du serveur. De cette manière le développement en groupe d'un logiciel est rendu complètement transparent, les opérations courantes étant réduites à une simple commande (téléchargement, mise à jour d'un téléchargement, mise à jour du serveur, administration, historique, ...).

Les derniers développements ont été réalisés en Août 2001, avec le travail de Mickaël Marchand. Un module a été rajouté à Cast, appelé "Observator". Celui-ci, exécuté sur un serveur chargé d'une tâche de Cast, est capable de suivre son déroulement et la charge du système, et de les reporter à Cast: l'utilisateur peut alors mettre en pause, reprendre et arrêter l'exécution d'un calcul à tout moment.

Cast est mis gratuitement à disposition de tous par l'INRIA, sur autorisation écrite. Ses sources le sont de la même manière.


1.2. Définition du problème


Chapitre 2. Les différentes approches possibles


2.2. Réécriture de l'interface avec Gtk

Par suite il m'a semblé plus adéquat de procéder à la réécriture de l'interface de Cast. Avec l'approbation de Mr Nguyen, je me suis penché sur cette possibilité.


2.2.2. Choix de librairie graphique

  1. Environnement complet, comprenant un bureau, un navigateur et une suite d'applications

  2. Projet similaire à Gnome

Ici intervient le problème de licence. En effet la plupart des librairies graphiques multi-plateformes et gratuites sont protégées par des licences dites "libres". Leur code source est disponible pour tous, mais leur utilisation soumise parfois à des obligations. La GPL[5], créée par la FSF[6], oblige tout logiciel utilisant du code sous cette licence à être aussi soumis à la GPL, et donc à diffuser le code source. En contrepartie, le logiciel reste la propriété de son auteur, et tout travail effectué dessus sera disponible avec son code source. La LGPL[7] autorise quant à elle les travaux propriétaires à utiliser une librairie sous son régime, sans aucune obligation. La licence BSD[8] enfin, autorise toute réutilisation de code sous son régime.

Pour résumer les conséquences des licences, Cast en utilisant une librairie sous licence GPL, devra également être en GPL (et donc, de code source ouvert), tandis que la LGPL et la BSD lui autorisent n'importe quel régime. Ceci a une grande importance dans un tel choix, mais le code source de Cast étant déjà disponible assez facilement, son passage en GPL ne pourrait que le protéger.

Les possibilités des différentes librairies sont généralement équivalentes, étant toutes disponibles au moins en version finale stable. La difficulté majeure dans l'interface de Cast est la reproduction de l'aire de travail. Mais en utilisant par exemple Gtk+ ou Gtk--, interfaces respectives C et C++ de Gtk, cette opération me semblait faisable, pour les raisons suivantes:

  • Gtk est multi-plateforme

  • sa licence en autorise une utilisation peu restreinte

  • l'intégration d'objets Gnome est immédiate, en particulier le GnomeCanvas qui permettrait de réaliser à moindre coût l'aire de travail

  • très utilisé, Gtk dispose d'une documentation importante

  • enfin, j'avais déjà des connaissances sur la programmation avec Gtk+

Néanmoins, pour me lancer dans cette opération je devais acquérir plus de connaissances sur la création et la manipulation d'objets graphiques. C'est pourquoi Je me suis penché sur un logiciel, Dia, que j'utilise régulièrement.


2.3. Approche du problème avec Dia

2.3.1. Présentation de Dia

Dia est un éditeur de diagrammes, en cours de développement (version 0.90rc3). Il comprend déjà de nombreuses possibilités de création de diagrammes: diagrammes de flux, UML, Sybase par exemple, qui peuvent être étendues grâce à un système de plug-ins.

Son principal intérêt réside dans son interface, comportant une aire de travail multi-documents complète. Elle est composée d'une fenêtre principale, comportant un accès direct aux formes standard, et à celles du plug-in sélectionné, ainsi que d'une fenêtre de diagramme par diagramme ouvert.

Dia est donc capable d'utiliser des formes simples: texte, polygones, ellipses, lignes droites, courbes, flèches et même des images. Plus précisément, un diagramme est constitué de formes rectangulaires (pouvant être transparentes), reliées par des flèches. Il est ensuite possible de rajouter des plug-ins, pouvant produire des entités complexes, les déplacer, redimensionner, relier, dupliquer grâce à de simples clics de souris.

La construction de diagrammes est assez intuitive, et ressemble à celle de Cast. Les différentes formes disponibles sont regroupées par thème, et une fenêtre de propriétés s'ouvre après un double clic sur une forme. De plus les diagrammes peuvent être imprimés ou sauvegardés sous divers formats.

D'un point de vue plus technique, Dia présente d'autres propriétés très intéressantes. Dia est réalisé en Gtk, et complètement compilable sur plusieurs plateformes (dont Unix et Windows). Il est déjà traduit dans une trentaine de langues. Son système de plug-in accepte le C, le C++ et le Python.


2.3.3. Estimation de charge de développement

Différents choix techniques sont alors possibles, en voici une estimation, dans un ordre croissant de temps de développement:

En m'inspirant de plug-ins simples, fournis dans Dia, je me suis donc penché sur la réalisation de l'interface de Cast, sous la forme d'un plug-in pour Dia. De plus les diagrammes générés par Dia sont exportables assez facilement, car au format XML. Ce format présente des données textuelles sous forme structurée: ceci en permet une lecture humaine comme informatique facile et sans ambiguités. Ainsi, dans le pire des cas les diagrammes générés seraient exportables dans Cast et directement exécutables. Par ailleurs, un fichier de données au format XML répond à un besoin particulier, qui doit être défini informatiquement. Ces définitions sont appelées DTD, et peuvent valider la conformité d'un fichier concerné (bon nommage et bonne succession des entités par exemple) Les différentes DTD correspondant aux fichiers XML rencontrés sont situées en Annexe C.


Chapitre 3. Réalisation du plug-in Dia

3.1. Prise en main du logiciel

Pour commencer, il faut télécharger le logiciel. À la mi-Avril, il y avait deux possibilités: la version stable, 0.88.1, sortie en Mai 2001, et la version CVS "0.89". Le développement de Dia est très actif, donc la version CVS avait beaucoup évolué. La dernière version stable étant de surcroît âgée, la réalisation a été effectuée en utilisant la version CVS.

Dia faisant partie du projet Gnome, il est hébergé sur leur serveur CVS. Il faut donc s'identifier (une fois suffit) sur le serveur CVS anonyme:

$ cvs -d:pserver:anonymous@anoncvs.gnome.org:/cvs/gnome login
et enfin, le télécharger:
$ cvs -z3 -d:pserver:anonymous@anoncvs.gnome.org:/cvs/gnome co dia
pour appliquer les changements du CVS à sa copie, la commande est la suivante:
$ cvs -z3 -d:pserver:anonymous@anoncvs.gnome.org:/cvs/gnome update -PAd
en se plaçant bien dans la racine du projet.

De plus une liste de diffusion (système d'échange par mail) est mise à disposition de tous, elle aussi hébergée par le projet Gnome. Après inscription, on se rend rapidement compte qu'elle est très active, utilisée autant pour les questions venant des utilisateurs, les rapports de bugs et les prises de décisions pour les orientations du projet. Ainsi j'ai pu entrer directement en contact avec les développeurs, et rester informé des mises à jour de la version CVS.

Ayant informé les développeurs de mon intention de réaliser un document sur l'écriture de plug-ins pour leur logiciel, la suite de ce chapitre devrait être intégrée au projet Dia. En effet ceci répond à plusieurs demandes formulées sur la mailing-liste, et il n'existait pas encore de document sur ce sujet dans le projet.


3.2. Création des formes simples


3.3. Écriture d'un plug-in élaboré


3.3.1. Les instructions nécessaires

Un plug-in est un fichier, plus précisément une librairie, qui peut être chargé par le programme pour lequel il a été prévu. Pour ce faire le programme cherche des points d'ancrage spécifiques dans le plug-in, conformément à sa structure de données. C'est pourquoi le plug-in doit nécessairement comporter les instructions suivantes:

Déclaration du plug-in Dia. Ceci est accompli ainsi:

DIA_PLUGIN_CHECK_INIT

PluginInitResult dia_plugin_init(PluginInfo *info)
{
    /* vérifier l'initialisation */
    if(!dia_plugin_info_init(info, "Plug-in",
            "The description of the plug-in",
            NULL, NULL))
	return DIA_PLUGIN_INIT_ERROR;

    /* suite: déclaration des formes, etc. */

    return DIA_PLUGIN_INIT_OK;
}

Inclusion du fichier image. Il en faut un par forme:

#include "shape.xpm"

Déclaration de l'"ObjectType" de la forme. Il s'agit habituellement d'une structure renommée, dont les attributs peuvent être des types C quelconques. Néanmoins, Dia propose une liste renommée de ces types afin d'être multi-plateforme, il vaut mieux donc les utiliser (comme DiaFont, Color, la liste est conséquente mais malheureusement éparpillée). La structure comporte au moins les champs suivants:

typedef struct _Shape Shape;
struct _Shape
{
    Element element;
    /* contient le type d'objet, sa position, zone affichée, handles,
    * ses connections, ainsi que le coin supérieur gauche,
    * largeur et hauteur */

    /* autres attributs */
};

Déclaration des fonctions... chargées de:

Les fonctions sont accompagnées de leur prototype.

ObjectTypeOps shape_type_ops =
{
/* un exemple complet:
(CreateFunc)    shape_create,
(LoadFunc)      shape_load,
(SaveFunc)      shape_save
*/
};

Déclaration des fonctions... chargées de:

Les fonctions sont accompagnées de leur prototype.

ObjectOps shape_ops =
{

(DestroyFunc)

Retirer une tâche de la mémoire:

void shape_destroy(Shape *shape)

(DrawFunc)

Dessiner une tâche dans l'aire de travail:

void shape_draw(Shape *shape, Renderer *renderer)

(DistanceFunc)

Renvoyer la distance depuis un point à la forme:

real shape_distance_from(Shape *shape, Point *point)

(SelectFunc)

Mettre à jour l'affichage lors de la sélection:

void shape_select(Shape *shape, Point *clicked,
	Renderer *interactive_renderer)

(CopyFunc)

Copier une forme en mémoire:

Object* shape_copy(Shape *shape)

(MoveFunc)

Mettre à jour la structure de données de la forme lorsqu'elle est déplacée:

void shape_move(Shape *shape, Point *to)

(MoveHandleFunc)

Mettre à jour l'affichage de la forme lorsqu'elle est déplacée:

void shape_move_handle(Shape *shape, Handle *handle,
	Point *to, HandleMoveReason reason, ModifierKeys modifiers)

(GetPropertiesFunc)

Renvoyer la boîte de dialogue des propriétés (sans les boutons "OK, "Apply" et "Close", gérés par Dia):

GtkWidget* shape_get_properties(Shape *shape,
	Property *props, guint nprops)

(ApplyPropertiesFunc)

Appliquer les nouvelles propriétés depuis la boîte de dialogue des propriétés:

ObjectChange* shape_apply_props(Shape *shape)

(ObjectMenuFunc)

Afficher le menu contextuel d'objet (invoqué à l'aide du bouton du milieu):

DiaMenu* shape_object_menu(Shape *shape, Point *clicked)

(DescribePropsFunc)

Pas encore implémenté dans mon plug-in:

PropDescription* shape_describe_props(Shape *shape)

(GetPropsFunc)

Non plus:

void shape_get_props(Shape *shape, GPtrArray *props)

(SetPropsFunc)

Non plus:

void shape_set_props(Shape *shape, GPtrArray *props)

/* un exemple raccourci:
(CopyFunc)      shape_copy,
*/
};

Déclaration de la forme:

ObjectType shape_type =
{
    "Plug-in - Shape",    /* name */
    0,                    /* version */
    (char **) shape_xpm   /* pixmap */
    &shape_type_ops       /* ops */
};

3.3.2. Corps des fonctions

Dia propose au programmeur diverses fonctions, qui lui facilitent la tâche et permettent d'uniformiser les plug-ins. Certaines permettent de remplacer tout le corps d'une fonction, Dia reconnaissant ce qu'il a à faire. Dans d'autres cas, ce n'est pas possible ou suffisant. Dans la liste suivante, seules les premières fonctions sont décrites, et celles que Dia est capable d'effectuer mentionnées. En effet le code de Dia est bien commenté, et il est assez aisé d'écrire les corps des fonctions à partir des en-têtes ou des plug-ins existants (sous-répertoires "lib" et "objects" du projet).

Object* shape_create(Point *startpoint, void *user_data,
                Handle **handle1,
                Handle **handle2)
{
    Shape *shape;
    Element *elem;
    Object *obj;
    int i;

    /* allocation de l'espace nécessaire */
    shape = g_malloc0(sizeof(Shape));
    /* pour alléger l'écriture par la suite */
    elem = &shape->element;
    obj = &elem->object;

    obj->type = &shape_type;
    obj->ops = &elem->object;

    elem->corner = *startpoint;
    /* bien sûr il faut définir les valeurs au préalable */
    elem->width = SHAPE_DEFAULT_WIDTH;
    elem->height = SHAPE_DEFAULT_HEIGHT;

    /* changer 8 au nombre de points de connection */
    element_init(elem, 8, 8);
    for(i = 0; i < 8; i++)
    {
        obj->connections[i] = &shape->connections[i];
        shape->connections[i].object = obj;
        shape->connections[i].connected = NULL;
    }

    /* initialiser les autres attributs */

    shape_update_data(shape);

    /* changer 8 au nombre de points de connection */
    for(i = 0; i < 8; i++)
        obj->handles[i]->type = HANDLE_NON_MOVABLE;

    *handle1 = NULL;
    *handle2 = obj->handles[0];
    return &shape->element.object;
}

Dessin d'une forme. Le dessin d'une forme est effectué en invoquant le "renderer". On distingue les fonctions de choix de trait, de celles qui dessinent effectivement. Les fonctions sont disponibles en les préfixant par:

renderer->ops->
Illustration par l'exemple:
Point ul_corner, lr_corner;

/* mettre à jour les coordonnées des points */

renderer->ops->set_fillstyle(renderer, FILLSTYLE_SOLID);
renderer->ops->fill_rect(renderer, &ul_corner, &lr_corner, &shape->inner_color);
renderer->ops->draw_rect(renderer, &ul_corner, &lr_corner, &shape->border_color);


3.4. Plus loin dans la création des plug-ins


Conclusion

Avec du recul les choix techniques effectués m'ont semblé un temps moins évidents. En particulier, à certaines étapes de la réalisation où j'ai pû être confronté à des blocages. En fait ceux-ci une fois franchis marquent les progrès réalisés, ces expériences ont été très enrichissantes et me serviront pleinement à l'avenir.

Je regretterais de n'avoir eu plus de pratique préalable en programmation, surtout en applications graphiques C/C++, si les bases acquises en algorithmie, modèles relationnels et conception orientée objet n'avaient pas été suffisantes pour finalement l'appréhender sans trop de difficultés.

Au-delà des simples notions de programmation, j'ai redécouvert le monde du travail, sous un nouvel angle. En effet j'ai pu me rendre compte du temps et des investissements nécessaires à l'élaboration d'un projet informatique, ce dans une grande autonomie grâce à la confiance de Mr Nguyen que je remercie particulièrement. D'autre part la prise de contact m'a été facilitée par les documents réalisés par les précédents "intermittents", ceci ajoute positivement la nécessité de maintenir une documentation au projet, tant à destination interne qu'externe.

Ces différents éléments combinés à l'enjeu du stage m'ont motivé à m'y investir, et je suis ravi d'avoir pu apprendre et partager cette nouvelle expérience, tout en contribuant à faire avancer le projet.


Résumé et abstract

Cast est un logiciel facilitant la mise en oeuvre de calculs sur grappes de PC, typiquement de modélisation numérique. Développé par l'INRIA depuis 1995, le logiciel est complètement fonctionnel, mais son interface graphique est difficile à compiler, car la librairie utilisée est rarement rencontrée sur les systèmes actuels.

Le choix d'une nouvelle librairie graphique a ainsi été fait suivant sa popularité, mais aussi selon ses possibilités en termes de temps de développement, réutilisation du maximum de code de Cast, et droit d'utilisation par exemple. Ce choix s'est finalement porté sur l'écriture d'un plug-in à un logiciel existant, Dia, dont l'interface est similaire à celle de Cast.

Ce mémoire présente donc la démarche ayant amené à faire ce choix, puis détaille les différentes manières de réaliser un plug-in au logiciel Dia.

The software Cast aims to ease the implementation of calculations on PC clusters, typically of numeric modelisation. Developped by the INRIA since 1995, it is fully functional, but its graphic interface library is rarely found on current systems and so it's hard to compile.

The choice of a new graphic library has been determined by its popularity, but also in terms of development time, licensing, and ability to reuse most original Cast code for example. It was finally decided to write a plug-in to an existing software, called Dia, because its interface is very close to Cast's.

Therefore this report deals with the steps which led to this choice, and then explains how to develop different kinds of plug-ins for Dia.


Annexe A. Manuel de l'utilisateur de Cast


Annexe B. Procédure d'installation de Cast


Annexe C. Fichiers de définition XML

Notes

[1]

Collaborative Applications Specification Tool, http://www.inrialpes.fr/sinus/cast

[2]

Common Object Request Broker Architecture, http://www.corba.org

[3]

Object Management Group, http://www.omg.org

[4]

Concurrent Version System, http://www.cvshome.org

[5]

General Public License, http://www.gnu.org/licenses/licenses.html

[6]

Free Software Foundation, http://www.gnu.org

[7]

Lesser General Public License, idem GPL

[8]

Berkeley Software Distribution, système Unix de l'université de Berkeley (Californie), http://www.freebsd.org/copyright/index.html