IRL : Simulation distribuée pour les systèmes embarqués Yassine El Khadiri, 2 ème année Ensimag, Grenoble INP Matthieu Moy, Verimag Denis Becker, Verimag 19 mai 2015 1
Table des matières 1 MPI et la sérialisation de données 4 1.1 Présentation de l outil MPI................... 4 1.2 Principe de sérialisation de données............... 5 2 Implémentation 5 2.1 Adaptation de l architecture existante............. 5 2.2 Ajout d un nouveau type dans la bibliothèque......... 6 3 Suite du travail 6 4 Conclusion 6 2
Introduction SystemC est une bibliothèque C++ qui permet une description du comportement matériel non seulement au niveau RTL comme Verilog et VHDL mais aussi au niveau comportementale ou TLM. Cette modélisation permet de simuler des systèmes assez rapidement et très tôt dans leurs cycles de développement. Ceci offre ainsi la possibilité de développer en parallèle l implémentation matérielle et la couche logicielle associée. SC_MODULE(Memory) { ensitlm::target_socket<memory> target; SC_HAS_PROCESS(Memory); Memory(sc_core::sc_module_name name, unsigned int size); ~Memory(); tlm::tlm_response_status read(ensitlm::addr_t a, ensitlm::data_t& d); tlm::tlm_response_status write(ensitlm::addr_t a, ensitlm::data_t d); ensitlm::data_t* storage; private: unsigned int m_size; }; Program 1: Un simple composant mémoire Un problème de SystemC est que la description des modules suit une logique de conception parallèle alors que la simulation est exécutée de manière séquentielle. On ne profite pas de la puissance de calcul parallèle disponible sur des machines multi-cœur. La bibliothèque Sc-during [2] créée par Matthieu Moy tente de résoudre ce problème en offrant à l utilisateur plusieurs outils pour simplifier l exécution de tâches parallèles tout en distinguant le temps d exécution de la simulation et le temps simulé par l avancement des opérations sur le modèle. La fonction principale qui permet d appliquer ce principe est la fonction during( t, f) à laquelle on passe en argument la méthode à exécuter et 3
la durée t que cette opération est censée prendre. On peut choisir entre plusieurs stratégies pour during : Appel séquentiel de la tâche pour valider qu une exécution séquentielle Création d un processus système léger pour chaque tâche à exécuter Création d un processus léger en le gardant pour une utilisation ultérieur Pré-allocation d un nombre de processus légers fixe et choix des tâches à associer à chacun suivant une FIFO Création de plusieurs processus sur plusieurs machines en réseaux Cette dernière stratégie à été implémentée par Amaury Graillat en se basant sur un modèle de communication type maître-esclave. Nous avons décidé d ajouter la possibilité de passer des arguments aux fonctions distantes. Ceci nécessite de connaitre le nombre et les types de ces arguments pour pourvoir ensuite les envoyer sur le réseau et garantir l exécution correcte de la fonction. En assembleur il aurait suffit d empiler les paramètres qu on recevrait du réseau petit à petit et ensuite sauter à l adresse d exécution de la fonction qui dépilerait d elle même ces arguments au fur et à mesure qu elle les utiliserait. Malheureusement, il est difficile de dupliquer un tel comportement sur un langage de haut niveau tel que le C++. Surtout qu étant sur du distribué, on ne peut pas avoir d à priori sur l architecture des machines sur lesquelles les simulations vont s exécuter. Ainsi il a fallu mettre en place un mécanisme qui permettrait de donner au fonctions distribués une signature unique tout en gardant une flexibilité par rapport au nombre d arguments et leurs types du point de vue de l utilisateur. 1 MPI et la sérialisation de données 1.1 Présentation de l outil MPI MPI [1] est une norme définissant une bibliothèque de fonctions utiles pour la programmation distribué. Celle ci permettent l envoie et la réception de messages suivant différents modes de communication. 4
Nous utilisons le mode point-à-point qui permet la communication entre processus à l aide des fonctions MPI_Send et MPI_Recv. MPI permet de d envoyer et recevoir plusieurs types de base ( int, float, char... ) mais aussi de créer des structures plus complexes. Nous avons choisit par contre de ne pas exposer la couche MPI à l utilisateur pour des raisons de modularité. 1.2 Principe de sérialisation de données La sérialisation [3] est un processus visant à transformer une donnée en une suite de données plus petites. Ceci pose un certain nombre de problèmes liée à la gestion des références entre objets et le parcourt des graphes d objets (détection des cycles...). C est une problématique qu on retrouve souvent lors de l implémentation de ramasse-miettes par exemple. Ainsi nous avons décidé de ne gérer que les types de base. Nous verrons ensuite comment ajouter de nouveaux types dans le code source de la bibliothèque. 2 Implémentation 2.1 Adaptation de l architecture existante La fonction during distribuée ne prend en paramètre que le numéro de la fonction à appeler. Ainsi pour permettre à l utilisateur d appeler une fonction avec des paramètres, elle a été surchargé pour prendre en argument un objet de type ArgList qui contiendra une liste d objets de type Arg. Les fonctions distribuées ont ainsi toutes la même signature : farglist. Ceci permet ainsi de simplifier l envoie et le traitement des arguments sur le réseau car il suffit de reconstruire un objet de type f(arglist) sur la machine distante pour pouvoir le passer en paramètre à la fonction et ainsi l exécuter. Ainsi une fonction : void f( float f, int i, char c) { cout << f << ", " << i << ", " << c << endl ; } 5
devient en version distribuée : void f( ArgList args ) { float f = args. get (0). float_value (); int i = args. get (1). int_value (); char c = args. get (2). char_value (); } cout << f << ", " << i << ", " << c << endl ; 2.2 Ajout d un nouveau type dans la bibliothèque Pour ajouter un nouveau type, il faut : L ajouter à la liste des types supportés par la classe Arg : Ajouter une énumération lui correspondant dans Arg::arg_t Ajouter la variable du type dans l union Surcharger le constructeur et ajouter un accesseur correspondant Ajouter un case dans during pour le transformer en message MPI Ajouter un case dans dist_slave::polling pour le reconstruire Ainsi on peut gérer simplement des types plus complexes en les sérialisant dans during. 3 Suite du travail Une suite possible du travail serait de proposer à l utilisateur d enregistrer ses propres types et de gérer le retour asynchrone des résultats des calculs. 4 Conclusion Nous avons redéfinit la fonction during pour supporter le passage d arguments et avons imposé une signature uniforme que toutes fonctions distribuées doit respecter. 6
Références [1] Open mpi : Open source high performance computing. http://www. open-mpi.org/, 2015. [2] Matthieu Moy. Parallel programming with systemc for loosely timed models : A non-intrusive approach, 2012. [3] Wikipedia. Serialisation. http://en.wikipedia.org/wiki/ Serialisation, Avril 2015. 7