Répartition de charge dynamique dans un syst`eme

Transcription

Répartition de charge dynamique dans un syst`eme
Rapport de TER
Répartition de charge dynamique dans
un système distribuée
Tuteur :
Stephane Mancini
Benjamin Petit
Grenoble INP - Ensimag
Mai 2010
Table des matières
1 Introduction
4
1.1
Contexte pratique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
1.2
Contexte scientifique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
1.3
Mon travail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
2 La répartition de charge
5
2.1
Quelques notions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.2
Clefs de la répartition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2.3
Algorithmes de répartitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.3.1
Répartition statique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.3.2
Répartition dynamique
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.3.3
Problème de cohérence dans un modèle distribué . . . . . . . . . . . . . .
9
3 Simulation
11
3.1
But de la simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
3.2
Structure d’une tâche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
3.3
Structure d’un message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
3.4
Structure d’un noeud . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
3.4.1
L’unité de calcul . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
3.4.2
Liste de tâche en attente . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
3.4.3
Le routeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
3.4.4
Le gestionnaire de charge . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
Résultats et limites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
3.5
4 Bilan
16
5 Références
17
2
Remerciements
Je remercie Stephane Mancini et le laboratoire GISPA-lab pour m’avoir accueilli durant ce
TER. Je remercie égalemment le personnel enseignant de l’Ensimag qui a permis de mettre en
place ce module.
3
1
1.1
Introduction
Contexte pratique
J’ai effectué ce Travail d’Études et de Recherche au sein du laboratoire Grenoble Images
Parole Signal Automatique (GIPSA-lab).
Le GIPSA-lab s’investit dans la recherche fondamentale sur le traitement du signal, la commande et le diagnostic des systèmes, sur la parole et la cognition.
J’ai été affecté au le département Images et Signal et dans l’équipe Géométrie, Perception,
Images, Gestes sous la responsabilité de Stéphane Mancini.
1.2
Contexte scientifique
Pour augmenter les performances des processeurs, dans un premier temps, les fondeurs ont
sans cesse cherché à augmenter la fréquence de fonctionnement de leurs puces. Cependant, il
semblerait qu’aujourd’hui nous soyons arrivé à des fréquence qu’il va être difficile de dépasser.
Pour augmenter les performances, les fabricants s’efforcent désormais de produire des puces
dotées de plusieurs unités de calcul.
De nos jours, nous utilisons de plus en plus des machines de type multi-processeurs ou multicoeurs. Afin de répartir le travail de manière intelligente sur toutes ces unités disponibles, il est
nécessaire d’utiliser un système dit de répartition de charge ou load balancing en anglais.
Beaucoup de ces systèmes multi-processeurs sont dit homogènes, c’est à dire que les différentes
unités de calcul sont les mêmes : elles tournent à la même fréquence et ont des capacités de calcul
similaires. Ce modèle présente tout de même des limites : la production de processeur possédant
des coeurs de plus en plus nombreux coûtent de plus en plus cher aux fondeurs, du fait de la
complexité des architectures.
Dans les systèmes actuels, c’est le rôle du système d’exploitation de répartir correctement la
charge sur les différents processeurs disponibles.
1.3
Mon travail
Ici je vais traiter des systèmes hétérogènes, c’est à dire des systèmes qui possèdent des unités
parfois très différentes les unes des autres ; on peut imaginer par exemple que le système possède
des processeurs génériques ainsi que des accélérateurs matériels, très spécialisés, mais très performants pour une tâche donnée.
De plus, je vais me concentrer essentiellement sur la répartition de charge dite distribuée,
contrairement à la répartition de charge où la décision est centralisée en un point.
4
2
La répartition de charge
2.1
Quelques notions
On suppose que le programme qui s’exécute peut être découpé dans des tâches bien connues,
sur un ensemble d’unités de calculs aussi appelées noeuds. Un noeud exécute une tâche à la fois,
et peut avoir une liste de tâches a exécuter dans une liste d’attente.
Figure 1 – Grille de calcul 4x4 composée de 16 noeuds
Les noeuds ne sont pas forcement interconnectés comme dans la figure 1 : on peut imaginer
d’autres topologies possible pour une grille de calcul.
Chaque tâche peut, après avoir été calculée, démarrer d’autres sous-tâches. On néglige ici les
arguments et les retour de résultats des différentes sous-tâches.
C’est pour cela qu’on étudie principalement la répartition de charge distribuée : chaque noeud
choisira à qui envoyer sa ou ses sous-tâches.
Chaque programme peut donc être représenté par un arbre comme celui-ci :
Figure 2 – Représentation d’un programme en arbre de tâches
Chacune des tâches nécessite une puissance de calcul qui peut être prédite à l’avance. De
même, pour chaque noeud, on connait leur capacité de traiter telle ou telle tâche.
La figure 2 montre bien que plusieurs tâches peuvent être exécutées en parallèle ; et comme
tous les noeuds n’ont pas les mêmes capacités de calcul, il faut choisir soigneusement le noeud
qui s’occupera d’une tâche donnée : l’efficacité de l’algorithme de répartition de charge est donc
primordiale.
5
2.2
Clefs de la répartition
Dans un système homogène, il est relativement aisé de distribuer les tâches de manière efficace ; comme tous les noeuds de calculs ont les même capacités, il suffit de donner du travail aux
noeuds les moins chargés.
Dans un système hétérogène, c’est plus complexe. Tous les noeuds n’ayant pas les mêmes
capacités de calcul il faut choisir soigneusement quel noeud on va utiliser pour telle tâche. On
ne prend pas forcement le noeud le plus rapide, car il est peut-être déjà très chargé, tout comme
on n’utilise pas forcement le noeud le moins occupé parce que trop lent pour la tâche.
Prenons par exemple une grille de calcul, dont l’état est le suivant :
Noeud
Disponible dans
1
5ms
2
11ms
3
8ms
Capacités
Tâche A 10ms
Tâche B
8ms
Tâche C 20ms
Tâche A 6ms
Tâche B 8ms
Tâche C 5ms
Si la prochaine tâche à traiter est une tâche de type A :
– Noeud 1 : fin estimée de la tâche A : 5ms + 10ms = 15ms
– Noeud 2 : fin estimée de la tâche A : 11ms + 6ms = 17ms
– Noeud 3 : impossible d’effectuer cette tâche
Dans cette exemple, si on a une tâche A a traité, il vaut mieux l’envoyer sur le noeud 1,
même si il est moins rapide que le noeud 2 pour cette tâche. On voit aussi ici que l’algorithme de
répartition de charge doit être très rapide : plus la prise de décision est longue, plus la décision
pourra être fausse.
Bien sûr dans cette exemple, on estime que le coût de la transmission de charge est gratuite , c’est à dire que la transmission de messages entre les noeuds est instantanée et que le lien
ne peut être saturé. Cependant, dans le cas des Network On Chip (NoC), ce facteur peut être
très limitant.
D’autres facteurs peuvent rentrer en compte : la topologie du réseau, la fragmentation des
noeuds exécutés, des impératifs de consommations. . .
Pour prendre des décisions efficaces dans un système hétérogène, il faut donc connaı̂tre la
charge des différents modules, ainsi que de leurs capacités de calcul respectives. Mais comment
garantir une cohérence de la vision de la charge des noeuds dans le système entier ?
6
2.3
Algorithmes de répartitions
Il existe deux grands types d’algorithmes de répartitions : les algorithmes de répartitions de
charges dit statiques, que l’on peut définir à la compilation, et les algorithmes dit dynamiques,
calculé pendant l’exécution du programme.
Les algorithmes dit statiques sont certainement les plus efficaces, mais ne peuvent être mis
en place que si le programme n’est pas interactif. De même, pour un programme distribué en
binaire, il n’est pas forcement possible de savoir sur quel type d’architecture va être exécuté le
programme. Dans tous ces cas il faut utiliser des algorithmes dynamiques.
Cependant, même en utilisant un algorithme dynamique, il peut être intéressant d’utiliser un
algorithme pseudo-statique pour le mappage initial des tâches, comme nous allons le voir dans
le point suivant.
2.3.1
Répartition statique
La répartition statique peut être calculé au moment de la compilation ; si le programme n’est
pas interactif, c’est avec cette méthode qu’on obtiendra les meilleurs temps de calculs, du fait
qu’il n’y aura pas d’algorithme à exécuter pour choisir le noeud qui exécutera une tâche donnée.
Mais comme soulevé dans [1], même dans le cas de programme dynamique, il est utile de faire
appel à une stratégie de placement statique. Voyons un exemple dans une grille de calcul 4x4.
Figure 3 – Mauvais placement
Figure 4 – Bon placement
Dans la figure 3, la tâche initiale est située sur le noeud le plus foncé. On voit que si elle se
divise en deux sous-tâches, les communications avec les autres noeuds seront plus compliqués,
du fait que pour transmettre d’autres tâches ou des résultats, les chemins seront plus longs et
nécessiteront des sauts.
Au contraire, la situation dans la figure 4 est meilleure ; le noeud contenant la tâche initiale
a moins de chance d’être isolé.
On voit donc bien que même dans le cadre d’algorithme dynamique, le mappage initial des
tâches (et donc par extension, la mise en place d’une grille de calcul) est très important.
Cette stratégie de mappage initiale doit être implémentée dans la grille de calcul elle-même,
non pas à la compilation si l’on veut que le code soit portable.
7
2.3.2
Répartition dynamique
Pour palier au manque des algorithmes de répartitions statiques, des chercheurs ont expérimentés
plusieurs types de répartitions dynamique. Le choix du meilleur noeud étant plus ou moins facile
suivant les données qui influenceront la prise de décision (cf la partie 2.2), la plupart des travaux
se concentrent sur l’optimisation des communications entre noeuds, notemment éviter la congestion réseau.
Ces algorithmes visent à choisir entre deux noeuds qui pourraient accueillir une même tâche,
dans des délais équivalents. Bien que dans mon travail, je n’ai pas traité de la partie pénalité
dûe au réseau , je pense qu’il est important d’en citer quelques un.
Les trois algorithmes suivant sous tirés de [1]. On y trouve aussi d’autres stratégies, mais j’en
ai retenues trois :
1. First Fee (FF)
Cette algorithme est le plus simple ; il n’est jamais utilisé en pratique, mais on l’utilise pour
comparer plusieurs méthodes différents. Il consiste simplement à prendre le premier noeud
disponible le plus proche, en parcourant le réseau colonne à colonne.
Cette algorithme n’a pas de coût d’évaluation.
2. Nearest Neighbor (NN)
Cette algorithme ressemble à la stratégie précédente ; elle n’a pas de coût d’évaluation.
Cette stratégie consiste à chercher le noeud le plus proche en testant tous les voisins à une
distance n, n variant de 1 au nombre de noeuds disponible dans la grille.
3. Path Load (PL)
Le troisième algorithme est le plus compliqué. Les algorithmes précédent ne tiennent pas
compte de la bande passante disponible entre les noeuds de la grille : cette dernière stratégie
tente de diminuer la congestion réseau en prenant compte de cette donnée.
Cet algorithme calcul le coût des transmissions entre chaque noeud à l’aide de l’équation
suivante :
costk =
X
ratec(i,j) +
X
ratec(i,j)
Où ratec(i,j) et ratec(j,i) correspondent à la vitesse de transmission entre deux noeuds, du
sens i → j et du sens j → i (les communications ne sont pas nécessairement symétriques)
La stratégie PL est certainement la plus complète. Cependant, les expériences [1] ont montré
que les résultats obtenus avec cette méthode sont très proches de ceux obtenus avec la stratégie
NN. Celà est sans doute dû au calcul qui est nécessaire pour la stratégie PL.
Bien que l’on peut difficilement dire quel est l’algorithme le meilleur (cela dépend essentiellement de la nature de la grille de calcul ainsi que du programme à faire tourner), cette expérience
montre bien que l’algorithme de répartition de charge, pour être efficace, doit être très rapide et
simple à exécuter.
8
2.3.3
Problème de cohérence dans un modèle distribué
Dans un système classique centralisée, les décisions de délégation de tâches dont prises en
un point. Ce point maı̂tre connait avec exactitude l’état des noeuds de calcul, car lui et lui seul
envoie des tâches.
Dans un système distribuée, les décisions sont prises par chacun des noeuds : or, comment
garantir que l’état des noeuds est correct en chacun des points de la grille ?
On appelera état réel l’état dans lequel le noeud est à l’instant t, et état supposé l’état d’un
noeud vu par un autre noeud à l’instant t.
Noeud
Disponible dans
1
5ms
2
11ms
3
8ms
États supposés des
Noeud 2
Noeud 3
Noeud 1
Noeud 3
Noeud 1
Noeud 2
autres noeuds
2ms
8ms
10ms
8ms
5ms
11ms
Figure 5 – États réels des noeuds et états supposés
Dans la figure 5, on voit un exemple d’incohérence : l’état supposé du noeud 2 par le noeud
1 est fausse (2ns contre 11ms en réalité).
Le challenge majeur pour une répartition dynamique est donc de réduire au maximum l’écart
entre état réel et état supposé. Pour cela, plusieurs solutions sont possibles :
Avertir tous les noeuds qu’une tâche a été affecté
En théorie, probablement une des stratégies les meilleures. Cependant, son application en
pratique pose d’évident problème de communication dans la grille de calcul : si des milliers
de tâches sont exécutées sur une grille, le réseau va très vite être saturé.
Envoyer aux autres noeuds son état de manière régulière
Cette stratégie consiste à envoyer toutes les période t son état aux autres noeuds.
Pour éviter une congestion du réseau, il vaut mieux éviter que plusieurs broadcast de l’état
de noeuds aient lieu en même temps.
Cette valeur peut être différente selon chaque noeud.
De plus, elle dépend énormément de la durée du traitement des tâches, et de la nature de
la grille de calcul, et doit être déterminée au cas par cas.
Avertir les autres noeuds que son état a changé de manière significative
Cela rejoint un peu l’idée précédente : on envoie à tous les autres noeuds son état actuel,
lorsque qu’il a changé de manière significative. Le problème est de quantifier le delta qui
déterminera quand envoyer une mise à jour d’état.
Ici aussi le paramètre de cette stratégie est très dépendent de la durée des calculs et de la
nature de la grille de calcul.
Avertir les autres noeuds qu’une décision en lui convient pas
Cette fois ci, un noeud enverra son nouveau statut lorsqu’une tâche lui aura été envoyé,
alors que, selon lui, cette tâche devrait être exécutée sous un autre noeud. Bien sûr, on
peut le combiner avec la stratégie précédente, ce qui veut dire qu’il tolèrera une certaine
marge d’erreur.
9
Noeud
si exécution sur noeud courant)
1
14ms
si exécution sur autre noeud
Noeud 2
2ms
Noeud 3 19ms
Figure 6 – Décision litigieuse
La figure 6 montre que le noeud 1 a reçu une tâche, qu’il aura finie de calculer dans 14ms.
Or, il lui semble, selon sa vision de la grille, qu’il serait plus judicieux de l’envoyer sur le noeud
2. Il prend quand même la tâche qui lui a été envoyée, mais il envoie son statut à jour aux autres
noeuds.
Cette dernière stratégie semble celle qui a le moins d’inconvénients, par rapport aux autres.
Cependant, elle n’est pas parfaite, et des erreurs de décisions peuvent être prises.
On peut ainsi compléter cette solution avec une boucle d’auto-correction comme cela est
proposé dans [2]
Le principe de cette boucle est simple : à intervalle régulier, on recalcule la politique de
répartition de charge pour chacune des tâches présentes dans la file d’attente du noeud. Mais le
problème est de bien choisir la durée de ces intervalles.
10
3
Simulation
Dans cette partie je vais parler du petit simulateur en C que j’ai développé afin de tester
divers algorithmes de répartition de charge.
3.1
But de la simulation
Le simulateur doit donc simuler le fonctionnement d’une grille de calcul, dans laquelle se
trouve des noeuds de calculs.
On devra exécuter des programmes comme celui de la figure 2. On néglige la question de
passage de paramètre ou de gestion de résultat.
Nous ne prenons pas en compte la topologie de la grille et les performances du réseau ; pour
simplifier, on estime que tous les noeuds sont reliés ensemble et qu’il n’y a aucun problème de
communication dans le réseau.
Enfin, le code doit être le plus modulaire possible afin de pouvoir changer des modules, que
je détaille par la suite, afin de pouvoir changer le comportement de ces derniers, afin d’améliorer
le simulateur.
3.2
Structure d’une tâche
Initialement, chaque tâche devait exécuter des fonctions C, compilées avec des options différentes
selon les noeuds, afin de simuler une différence de rapidité de traitements entre ces derniers.
Par manque de temps, une tâche ne contient qu’un temps incompressible de calcul. On peut
facilement changer le contenu de cette structure (via le fichier task.h ainsi que le traitement de
celle-ci dans la fonction traite task (dans node.c).
3.3
Structure d’un message
Divers messages peuvent être échangé dans la grille de calcul entre noeuds. Ces messages
peuvent être du type :
– STATUS : un noeud envoie un message de ce type afin d’envoyer son état réel aux autres
noeuds du système.
– TASK : un noeud envoie une tâche à un autre grâce à ce message.
– TASK IN : utilisé pour l’envoie d’une tâche en interne (dans le cadre d’une création d’une
sous-tâche - voir le point sur l’unité de calcul).
On pourrait imaginer d’autres types de messages : des messages d’erreur, pour signaler qu’un
noeud est H.S., des messages de recalibration, pour mettre à jour les capacités de chaque noeud. . .
On peut ajouter des types de messages différents dans le fichier msg.h
11
3.4
Structure d’un noeud
Chaque noeud de la grille est lancé par un thread qui lui est propre, pour simuler l’exécution
parallèle de plusieurs noeuds.
Figure 7 – Composition d’un noeud
Pour cette simulation, on considère qu’un noeud (voir figure 7) est composé de :
– une unité de calcul
– une liste de tâches en attente
– un gestionnaire de charge
– un routeur
3.4.1
L’unité de calcul
Figure 8 – Traitements réalisés dans l’unité de calcul
L’unité de calcul simule le calcul, en attendant le temps spécifié par la tâche qu’il doit traiter.
En plus de ce temps, il ajoute une pénalité, qui dépend de sa capacité à traiter la tâche : ceci
permet de simuler des différences de performances dans le traitement des tâches.
Si une des tâches qu’il traite nécessite de lancer une ou plusieurs sous-tâche, il les envoie au
gestionnaire de charge.
12
Lorsque la tâche courante a fini d’être calculée (c’est à dire que le délai d’attente est écoulé),
elle va chercher la première tâche située dans la liste de tâche en attente.
L’unité de calcul s’exécute dans un thread qui lui ai propre.
3.4.2
Liste de tâche en attente
La liste des tâches en attente est tout simplement une liste FIFO qui contient la liste des
tâches à passer à l’unité de calcul.
Dans le simulateur elle est implémenté avec un pipe entre le gestionnaire de charge et l’unité
de calcul.
3.4.3
Le routeur
Le routeur se charge des communications entre les différents noeuds de la grille.
C’est lui qui forgera les paquets à envoyer aux autres noeuds selon la nature du message.
C’est également lui qui traitera les paquets reçus et qui les enverra ensuite au gestionnaire de
charge.
Dans le simulateur, les liaisons entre les noeuds sont implémenté avec des pipe. On peut
facilement changer l’implémentation du routeur sans toucher au reste du code, par exemple pour
simuler plus précisément les problèmes de communications qui peuvent avoir lieu.
Tout comme l’unité de calcul, le routeur s’exécute dans un thread à part.
3.4.4
Le gestionnaire de charge
Le gestionnaire de charge est l’élément central de la simulation. C’est lui qui intègre l’algorithme de répartition de charge ainsi que la boucle correctrice, exécutée à intervalle régulier.
Lorsque le gestionnaire de charge reçoit une tâche provenant du module réseau, il regarde
d’abord dans un premier temps si selon lui, il est acceptable d’exécuter cette tâche. Si oui, il
l’envoie directement à la liste des tâches à traiter. Sinon il demande au module réseau d’envoyer
un message de mise à jour de son statut réel aux autres noeuds.
Pour éviter une partie de ping-pong entre plusieurs noeuds, on accepte de prendre la tâche,
même si le noeud courant est très chargé.
C’est le rôle de la boucle de correction de palier à ce problème : évaluée à un bon intervalle,
elle doit limiter le nombre d’erreurs.
Le gestionnaire de charge reçoit également des tâches provenant du module de calcul, lorsque
ce dernier demande à exécuter une ou plusieurs sous-tâches. Il choisit alors où cette ou ces
dernières doivent s’exécuter, soit localement, soit sur un autre noeud.
Il est a noter que lors d’un envoie de tâche à un autre noeud, il met à jour l’état supposé de
celui-ci, afin d’éviter de le surcharger en lui envoyant une dizaine de tâche dans un délai court.
Les fonctions utilisées par le gestionnaire doivent être très efficace, pour que la prise de
décision soit rapide. Ainsi, les erreurs de jugement sont limités.
Tout comme l’unité de calcul et le module réseau, pour la simulation, le gestionnaire de charge
s’exécute dans un thread à part.
13
Figure 9 – Traitements réalisés dans le gestionnaire de charge
Le nombre de threads pour simuler un noeud est donc de trois. Malheureusement, les machines
utilisées pour faire tourner le simulateur ne dispose pas d’un nombre de processeur illimité. Pour
limiter le nombre de thread, on fait tourner le module réseau et le gestionnaire de charge dans
le même thread.
Cela a théoriquement peu d’impact dans la simulation actuelle, du fait de la grande rapidité
des méthodes utilisées dans le gestionnaire de charge et que le module réseau n’a aucun traitement
complexe à réaliser.
14
3.5
Résultats et limites
Dans les expérimentations, les résultats obtenus avec le simulateur se sont révélés très proches
des meilleurs résultats possibles. Mais j’ai utilisé des stubs assez grossier pour simuler les temps
de calcul (l’unité de calcul se contentait de faire des sleep de quelques secondes).
L’utilisation de la boucle de correction n’a eu que très peu d’impact sur le résultat. Cependant,
en augmentant les niveaux de tolérance qui régissent l’envoi d’une mise à jour de statut, afin de
réduire les échanges au sein de la grille, cette boucle permet de limiter les erreurs de répartition.
De même, en augmentant de manière artificielle le temps d’exécution de l’algorithme de
répartition de charge, on note une très forte augmentation d’erreurs de choix de répartitions, ce
qui souligne l’importance d’avoir des algorithmes simple si les tâches a exécuter sont rapides.
Pour simuler d’une manière plus exhaustive une grille de calcul, il faudrait prendre en compte
le réseau qui relie tous les noeuds, ainsi que la transmission des arguments et des résultats produits
par les tâches.
15
4
Bilan
J’ai effectué mon stage de fin de DUT dans le laboratoire LIMSI, Laboratoire d’Informatique
pour la Mécanique et les Sciences de l’Ingénieur, à Orsay (Paris XI). J’avais donc déjà une petite
idée de la recherche publique. Cependant, j’ai eu surtout un rôle de développeur pendant ce
stage.
C’est pour cela que j’ai eu envie de faire un TER. Celui-ci m’a permis de m’initier réellement
à la recherche. J’ai appris à chercher des articles sur des sites spécialisées ainsi qu’à lire de long
documents universitaires.
Ce fût une expérience enrichissante, qui en plus de m’avoir fait découvrir le monde de la
recherche, m’a permis de travailler sur un domaine que je n’aurai probablement pas eu l’occasion
de traiter dans les cours classiques, la répartition de charge distribuée.
16
5
Références
[1] Carvalho, E. ; Calazabs, M. ; Moraes,F. ; Heuristic for Dynamic Task Mapping in Noc-based
Heterogenous MPSoCs.
[2] Mancini S. ; Architecture materielle pour la synthèse d’image par lancer de rayon. 2000
[3] Bertozzi S. ; Acquaviva A. ; Bertozzi D. ; Poggiali A. ; Supporting Task Migration in MuliProcessor Systems-on-chip : A Feasibility Study
17