From b78d5563826957045678f4c3bcfdcef6c9bfc48d Mon Sep 17 00:00:00 2001 From: Arnaud Giersch Date: Thu, 16 Dec 2010 18:51:41 +0100 Subject: [PATCH] Add more documentation. --- README | 101 ++++++++++++++++++++++++++++++++++++++++---- TODO | 2 + communicator.h | 24 ++++++++--- cost_func.h | 3 ++ deployment.h | 2 + hostdata.cpp | 7 +-- hostdata.h | 3 ++ loba_simple.cpp | 6 +-- named_object_list.h | 12 ++++++ neighbor.h | 14 ++++-- process.cpp | 2 - process.h | 47 +++++++++++++++------ simgrid_features.h | 6 ++- 13 files changed, 190 insertions(+), 39 deletions(-) diff --git a/README b/README index db47b28..d34cb4b 100644 --- a/README +++ b/README @@ -1,3 +1,14 @@ +Contenu +======= +* Compilation de SimGrid +* Compilation... +* Utilisation +* Communications +* Pour ajouter un nouvel algorithme d'équilibrage +* Pour ajouter une nouvelle option au programme +* Liste des fichiers +---------------------------------------------------------------------- + Compilation de SimGrid ====================== @@ -15,18 +26,92 @@ d'installation de SimGrid (par ex. /usr/local). Utilisation =========== -Pour avoir l'aide en ligne : -$ ./loba -hhh +Idée générale : on dispose d'une plate-forme (décrite dans le fichier +XML qui va bien), et on déploie dessus une application. La notion de +voisinage entre les processus est *liée à l'application*. Il faut +évidemment que la plate-forme sous-jacente autorise les communications +entre voisins... + +Pour avoir l'aide en ligne sur les différents paramètres : + $ ./loba -h (ou -hh, ou -hhh, pour plus de détails) Pour changer le niveau de détail des affichages : --log=category.thres:level avec category : simu, main, depl, comm, proc, loba et - level : trace, debug, verbose, info, warning, error, critical + level : trace, debug, verbose, info, warning, error, critical + +Pour plus de détail sur les options de logging : + http://simgrid.gforge.inria.fr/doc/group__XBT__log.html#log_use + +Communications +============== + +Pour communiquer, chaque processus écoute sur 2 mailboxes (sortes de +ports) : + - une pour les message de contrôle ; + - une pour les transferts de charge. + +Ceci afin d'éviter de bloquer les échanges d'information pendant un +transfert de charge. + +À la fin, chaque processus envoie un message "CLOSE" à tous ses +voisins (sur chaque mailbox), et attends d'avoir reçu deux messages par +voisin (un sur chaque mailbox). + +Ceci permet de synchroniser les processus à la terminaison (ça, à la +rigueur, on s'en fout un peu), et surtout de s'assurer qu'il n'y a +plus de communication qui « traîne » dans les canaux. + +Cela permet aussi de ne pas réarmer les communications non bloquantes +qu'on ne sait pas annuler proprement (un manque dans SimGrid). + +Il ne faut bien sûr plus envoyer de message après avoir envoyé un +"CLOSE". + +Attention : lors du déploiement de l'application, il faut s'assurer que +la relation de voisinage est symétrique ! +*Ce n'est pas vérifié par le programme.* + +Pour ajouter un nouvel algorithme d'équilibrage +=============================================== + +1. Imiter ce qui est fait pour loba_simple : + - définir une nouvelle classe dérivant de process + - attention, il faut construire le process explicitement + - redéfinir la méthode load_balance qui : + - reçoit en paramètre la charge à prendre en compte ; + - peut utiliser et éventuellement réordonner le tableau process::pneigh ; + - peut récupérer l'information de charge d'un voisin avec + pneigh[i]->get_load() ; + - définit la charge à envoyer avec + pneigh[i]->set_to_send(quantité) ; + - retourne la somme des quantités définies avec set_to_send, + éventuellement à l'aide de la méthode process::sum_of_to_send() + qui clacule cette somme. + +2. Ajouter l'algorithme dans la liste des options. Dans options.cpp : + - faire le #include adéquat ; + - ajouter une ligne NOL_INSERT(...) dans la liste existante + (dans loba_algorithms_type::loba_algorithms_type()). + +Pour ajouter une nouvelle option au programme +============================================= + +1. Ajouter une variable, déclarée dans options.h et définie dans options.cpp + (classement plus ou moins thématique). + +2. Toujours dans options.cpp, il faut : + - compléter la fonction opt::parse_args(), normalement le 3e paramètre à + getopt() et le switch..case qui suit (garder l'ordre alphabétique) ; + - compléter la fonction opt::print() (avec le même ordre que en 1.) ; + - compléter la fonction opt::usage() (avec le même ordre que en 1.). + +3. Utiliser la nouvelle variable au(x) bon(s) endroit(s) ! -Fichiers -======== +Liste de fichiers +================= * fichiers de description de plates-formes @@ -53,8 +138,8 @@ Fichiers hostdata.h gestion des boites de réception, par hôte hostdata.cpp - loba_simple.h load-balancing simple (à copier pour ajouter - loba_simple.cpp d'autres algorithmes) + loba_simple.h équilibrage simple + loba_simple.cpp (à imiter pour ajouter d'autres algorithmes) main.cpp le programme principal @@ -62,7 +147,7 @@ Fichiers misc.cpp named_object_list.h gestion d'une table de constructeurs - avec des noms et des descritpions + avec des noms et des descriptions neighbor.h un voisin pour un processus neighbor.cpp diff --git a/TODO b/TODO index 39591ca..99b97e0 100644 --- a/TODO +++ b/TODO @@ -8,3 +8,5 @@ -> implement some random initial distribution of load * add synchronized mode + +* translate README file ? diff --git a/communicator.h b/communicator.h index fb06d34..465d0cf 100644 --- a/communicator.h +++ b/communicator.h @@ -29,12 +29,23 @@ public: communicator(); ~communicator(); + // Start to listen for incoming messages void listen(); + // Send a message to the "dest" mailbox void send(const char* dest, message* msg); + + // Try to receive a message. Returns true on success. + // If "wait" is true, blocks until success or error. bool recv(message*& msg, m_host_t& from, bool wait); + + // Try to flush pending sending communications. + // If "wait" is true, blocks until success. void flush(bool wait); + // Advertise that the next "close" message is the last one, and + // that we do not await any message after that, either on the + // control or the data channel. void next_close_on_ctrl_is_last(); void next_close_on_data_is_last(); @@ -48,18 +59,19 @@ private: int send_counter; // Control channel for receiving - m_task_t ctrl_task; - msg_comm_t ctrl_comm; - bool ctrl_close_is_last; + m_task_t ctrl_task; // receive buffer + msg_comm_t ctrl_comm; // receive communication + bool ctrl_close_is_last; // do not rearm comm after next close // Data channel for receiving - m_task_t data_task; - msg_comm_t data_comm; - bool data_close_is_last; + m_task_t data_task; // receive buffer + msg_comm_t data_comm; // receive communication + bool data_close_is_last; // do not rearm comm after next close const char* get_ctrl_mbox() const { return host->get_ctrl_mbox(); } const char* get_data_mbox() const { return host->get_data_mbox(); } + // Used to test if a communication is over, and to destroy it if it is. static bool comm_test_n_destroy(msg_comm_t comm); }; diff --git a/cost_func.h b/cost_func.h index ed97dcf..d7310d2 100644 --- a/cost_func.h +++ b/cost_func.h @@ -4,6 +4,9 @@ #include #include +// Define a polynomial function +// The factors are given at construction time, in a C-style string, +// separated by commas (eg. "1, 2, 3" for x^2 + 2x +3). class cost_func { public: cost_func(const char* param); diff --git a/deployment.h b/deployment.h index cba191b..3e71df5 100644 --- a/deployment.h +++ b/deployment.h @@ -3,8 +3,10 @@ #include +// Deploy an application automatically, according to the global parameters void MY_launch_application(); +// Base class for deployment generators... class deployment_generator { public: deployment_generator(); diff --git a/hostdata.cpp b/hostdata.cpp index c15c0ee..3ac7b0b 100644 --- a/hostdata.cpp +++ b/hostdata.cpp @@ -6,6 +6,7 @@ #include #include #include "misc.h" +#include "options.h" XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(main); @@ -25,9 +26,9 @@ void hostdata::create() { int nhosts = MSG_get_host_number(); m_host_t* host_list = MSG_get_host_table(); - // fixme: only sort hosts for automatically created deployment - // fixme: add an option to disable sorting - std::sort(host_list, host_list + nhosts, m_host_less()); + // only sort hosts for automatically created deployment + if (opt::auto_depl::enabled) + std::sort(host_list, host_list + nhosts, m_host_less()); hosts.assign(host_list, host_list + nhosts); xbt_free(host_list); diff --git a/hostdata.h b/hostdata.h index 59ca35d..703b7a1 100644 --- a/hostdata.h +++ b/hostdata.h @@ -5,6 +5,9 @@ #include #include +// Helper class that associates instances of itself with each host. +// Facilitate global operations on hosts, and retreiving of host name +// and mailboxes. class hostdata { public: static void create(); diff --git a/loba_simple.cpp b/loba_simple.cpp index 7d4937c..2cf613f 100644 --- a/loba_simple.cpp +++ b/loba_simple.cpp @@ -14,8 +14,8 @@ double loba_simple::load_balance(double my_load) int imax = -1; double min = my_load; double max = -1.0; - for (unsigned i = 0 ; i < neigh.size() ; ++i) { - double l = neigh[i].get_load(); + for (unsigned i = 0 ; i < pneigh.size() ; ++i) { + double l = pneigh[i]->get_load(); if (l >= my_load) continue; if (l < min) { @@ -31,7 +31,7 @@ double loba_simple::load_balance(double my_load) // found someone double balance = (my_load - max) / 2; DEBUG6("%d:%g %d:%g %g %g", imin, min, imax, max, my_load, balance); - neigh[imin].set_to_send(balance); + pneigh[imin]->set_to_send(balance); return balance; } else { return 0.0; diff --git a/named_object_list.h b/named_object_list.h index 2c91263..929a0db 100644 --- a/named_object_list.h +++ b/named_object_list.h @@ -4,6 +4,17 @@ #include #include +// Define an associative container that maps a name with a class and a +// description. All classes must be derived from a same base class. +// +// We can then use the name to create an object of the associated +// class, and to retrieve a pointer to this object. +// +// Furthermore, it is possible to iterate over the elements to get +// their name and their description. + +// I am too lazy to comment the code, which should be obvious... + //===== arity 0 ===== template @@ -143,6 +154,7 @@ public: //=================== +// "NOL" like in Named_Object_List.... #define NOL_INSERT(name, descr, class) insert(name, new creator(descr)) #endif // !NAMED_OBJECT_LIST_H diff --git a/neighbor.h b/neighbor.h index 7700cb3..9607c07 100644 --- a/neighbor.h +++ b/neighbor.h @@ -9,26 +9,32 @@ public: neighbor(const char* hostname); ~neighbor(); + // returns name, ctrl or data mbox const char* get_name() const { return host->get_name(); } const char* get_ctrl_mbox() const { return host->get_ctrl_mbox(); } const char* get_data_mbox() const { return host->get_data_mbox(); } + // Getter and setter for load double get_load() const { return load; } void set_load(double amount) { load = amount; } + // Getter and setter for debt double get_debt() const { return debt; } void set_debt(double amount) { debt = amount; } + // Getter and setter for to_send double get_to_send() const { return to_send; } void set_to_send(double amount) { to_send = amount; } private: - const hostdata* host; + const hostdata* host; // pointer to this neighbor's hostdata - double load; - double debt; + double load; // the load information we know for it + double debt; // the load we had to send to it, but + // that we have not currently sent + // (in bookkeeping mode) - double to_send; + double to_send; // the load we have to send to it }; #endif // !NEIGHBOR_H diff --git a/process.cpp b/process.cpp index ed7be05..b0d7026 100644 --- a/process.cpp +++ b/process.cpp @@ -188,7 +188,6 @@ void process::send() using namespace std::tr1; using namespace std::tr1::placeholders; - // fixme: shall we send data at all iterations? if (opt::bookkeeping) { std::for_each(neigh.begin(), neigh.end(), bind(&process::send1_bookkeeping, this, _1)); @@ -200,7 +199,6 @@ void process::send() } } -// Returns false if a CLOSE message was received. bool process::receive(recv_wait_mode wait) { bool result = true; diff --git a/process.h b/process.h index 607a6af..268fac9 100644 --- a/process.h +++ b/process.h @@ -26,35 +26,58 @@ protected: typedef std::vector neigh_type; typedef std::vector pneigh_type; - neigh_type neigh; - pneigh_type pneigh; + pneigh_type pneigh; // list of pointers to neighbors that + // we are free to reorder + + // Returns the sum of "to_send" for all neighbors. + double sum_of_to_send() const; private: typedef MAP_TEMPLATE rev_neigh_type; - enum recv_wait_mode { NO_WAIT = 0, WAIT, WAIT_FOR_CLOSE }; - rev_neigh_type rev_neigh; + neigh_type neigh; // list of neighbors (do not alter + // after construction!) + rev_neigh_type rev_neigh; // map m_host_t -> neighbor - communicator comm; - int ctrl_close_pending; - int data_close_pending; + communicator comm; // communicator for this process + int ctrl_close_pending; // number of "close" messages to wait + // on ctrl channel + int data_close_pending; // number of "close" messages to wait + // on data channel - unsigned iter; + unsigned iter; // counter of iterations - double prev_load_broadcast; - double load; - double expected_load; + double prev_load_broadcast; // used to ensure that we do not send + // a same information messages + double load; // current load + double expected_load; // expected load in bookkeeping mode - double sum_of_to_send() const; + // The load balancing algorithm comes here... + // Parameter "my_load" is the load to take into account for myself + // (may be load or expected load). + // Returns the total load sent to neighbors. virtual double load_balance(double my_load); + // Virtually do some computation void compute(); + + // Send procedures, with helpers for bookkeeping mode or not void send1_no_bookkeeping(neighbor& nb); void send1_bookkeeping(neighbor& nb); void send(); + + // Receive procedure: wait (or not) for a message to come. + // Returns false if some "close" message was received, returns true + // otherwise. + enum recv_wait_mode { NO_WAIT = 0, WAIT, WAIT_FOR_CLOSE }; bool receive(recv_wait_mode wait); + + // Finalize sends a "close" message to each neighbor and wait for + // all of them to answer. void finalize1(neighbor& nb); void finalize(); + + // Print with given priority what we know about our neighbors' loads void print_loads(e_xbt_log_priority_t logp = xbt_log_priority_info); }; diff --git a/simgrid_features.h b/simgrid_features.h index 8fa8d56..8aef329 100644 --- a/simgrid_features.h +++ b/simgrid_features.h @@ -1,7 +1,11 @@ #ifndef SIMGRID_FEATURES_H #define SIMGRID_FEATURES_H -// fixme: dirty hack +// Try to guess if MSG_wait destroys communications or not, because it +// changed after SimGrid 3.5. +// +// Use some define introduced after that. fixme: dirty hack +// #if defined(XBT_RUNNING_CTX_INITIALIZER) # define MSG_WAIT_DESTROYS_COMMS 0 #else -- 2.39.5