From ba8a9c5fbc92dc95fc99d8078b3474fd2fd5a043 Mon Sep 17 00:00:00 2001 From: Arnaud Giersch Date: Wed, 15 Dec 2010 18:10:07 +0100 Subject: [PATCH] Add load balancing algorithm selection facility. Plus... * add named_object_list templates * first tests with MSG_set_function in MY_launch_application * some preliminary work for topology selection * rename loba_least_loaded -> loba_simple * some minor cleanups --- Makefile | 9 +- TODO | 8 +- deployment.cpp | 24 +++- hostdata.cpp | 1 + loba_least_loaded.h | 19 --- loba_least_loaded.cpp => loba_simple.cpp | 4 +- loba_simple.h | 19 +++ main.cpp | 9 +- named_object_list.h | 154 +++++++++++++++++++++++ options.cpp | 98 +++++++++++---- options.h | 36 ++++-- process.cpp | 2 + 12 files changed, 311 insertions(+), 72 deletions(-) delete mode 100644 loba_least_loaded.h rename loba_least_loaded.cpp => loba_simple.cpp (91%) create mode 100644 loba_simple.h create mode 100644 named_object_list.h diff --git a/Makefile b/Makefile index f2d206c..2ab9e7b 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,10 @@ CPPFLAGS += -I $(SIMGRID_INSTALL_DIR)/include CPPFLAGS += $(CHECK_FLAGS) CFLAGS += -std=c99 -CFLAGS += -fgnu89-inline # workaround simgrid bug +#CFLAGS += -fgnu89-inline # workaround simgrid bug CFLAGS += $(OPTIM_FLAGS) $(DEBUG_FLAGS) +#CXXFLAGS += -std=c++0x CXXFLAGS += $(OPTIM_FLAGS) $(DEBUG_FLAGS) LDFLAGS += -L $(SIMGRID_INSTALL_DIR)/lib @@ -52,7 +53,7 @@ TARGETS := loba simple_async $(shell $(SETLOCALVERSION)) -.PHONY: all depend clean +.PHONY: all clean realclean all: $(TARGETS) @@ -71,7 +72,11 @@ realclean: clean version.o: $(patsubst %.cpp,%.o,$(filter-out version.cpp, $(SRC.loba))) +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(MAKECMDGOALS),realclean) -include $(DEP) +endif +endif .SECONDEXPANSION: $(TARGETS): $$(patsubst %.cpp,%.o,$$(SRC.$$@)) diff --git a/TODO b/TODO index 07ec631..1b4de13 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ * implement loba_* algorithms (start with some trivial one) -* add loba algorithm selection (-a number ?) * fix process::run when load is 0 -> wait for a message... @@ -8,10 +7,5 @@ * implement automatic process topology (line, ring, star, btree, clique, hypercube, etc..) - use MSG_process_create_with_arguments - name function name (is duped...) - code use MSG_get_registered_function - data NULL - argc - argv argv[0] = process_name +* add synchronized mode diff --git a/deployment.cpp b/deployment.cpp index db02f0d..a0fad27 100644 --- a/deployment.cpp +++ b/deployment.cpp @@ -1,9 +1,29 @@ #include "deployment.h" -namespace { +#include +#include +#include +#include +#include "hostdata.h" -} void MY_launch_application() { + xbt_assert(hostdata::size() >= 2); + + const char* func = "simulation_main"; + xbt_dynar_t p0_args = xbt_dynar_new(sizeof(const char*), NULL); + xbt_dynar_t p1_args = xbt_dynar_new(sizeof(const char*), NULL); + + xbt_dynar_push_as(p0_args, const char*, "33"); + xbt_dynar_push_as(p0_args, const char*, hostdata::at(1).get_name()); + + xbt_dynar_push_as(p1_args, const char*, "42"); + xbt_dynar_push_as(p1_args, const char*, hostdata::at(0).get_name()); + + MSG_set_function(hostdata::at(0).get_name(), func, p0_args); + MSG_set_function(hostdata::at(1).get_name(), func, p1_args); + + xbt_dynar_free(&p0_args); + xbt_dynar_free(&p1_args); } diff --git a/hostdata.cpp b/hostdata.cpp index a92527e..c15c0ee 100644 --- a/hostdata.cpp +++ b/hostdata.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "misc.h" XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(main); diff --git a/loba_least_loaded.h b/loba_least_loaded.h deleted file mode 100644 index 893a48a..0000000 --- a/loba_least_loaded.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef LOBA_LEAST_LOADED -#define LOBA_LEAST_LOADED - -#include "process.h" - -class loba_least_loaded: public process { -public: - loba_least_loaded(int argc, char* argv[]): process(argc, argv) { } - ~loba_least_loaded() { } - -private: - double load_balance(double my_load); -}; - -#endif //!LOBA_LEAST_LOADED - -// Local variables: -// mode: c++ -// End: diff --git a/loba_least_loaded.cpp b/loba_simple.cpp similarity index 91% rename from loba_least_loaded.cpp rename to loba_simple.cpp index 9927fd9..7d4937c 100644 --- a/loba_least_loaded.cpp +++ b/loba_simple.cpp @@ -1,4 +1,4 @@ -#include "loba_least_loaded.h" +#include "loba_simple.h" #include @@ -8,7 +8,7 @@ XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(loba); * load balance with a least-loaded neighbor, * without breaking the ping-pong condition */ -double loba_least_loaded::load_balance(double my_load) +double loba_simple::load_balance(double my_load) { int imin = -1; int imax = -1; diff --git a/loba_simple.h b/loba_simple.h new file mode 100644 index 0000000..1a2fd73 --- /dev/null +++ b/loba_simple.h @@ -0,0 +1,19 @@ +#ifndef LOBA_SIMPLE +#define LOBA_SIMPLE + +#include "process.h" + +class loba_simple: public process { +public: + loba_simple(int argc, char* argv[]): process(argc, argv) { } + ~loba_simple() { } + +private: + double load_balance(double my_load); +}; + +#endif //!LOBA_SIMPLE + +// Local variables: +// mode: c++ +// End: diff --git a/main.cpp b/main.cpp index 8c1965a..1b462c2 100644 --- a/main.cpp +++ b/main.cpp @@ -29,13 +29,13 @@ enum { EXIT_FAILURE_CLEAN = 0x08, // error at cleanup }; -#include "loba_least_loaded.h" +#include "loba_simple.h" int simulation_main(int argc, char* argv[]) { int result; process* proc; try { - proc = new loba_least_loaded(argc, argv); + proc = opt::loba_algorithms.new_instance(opt::loba_algo, argc, argv); result = proc->run(); delete proc; } @@ -84,8 +84,9 @@ int main(int argc, char* argv[]) TRY { exit_status = EXIT_FAILURE_INIT; // ===== - // Register the main function of an agent in a global table. - MSG_function_register("simulation_main", simulation_main); + // Register the default function of an agent + // MSG_function_register("simulation_main", simulation_main); + MSG_function_register_default(simulation_main); // Create the platform and the application. MSG_create_environment(opt::platform_file.c_str()); diff --git a/named_object_list.h b/named_object_list.h new file mode 100644 index 0000000..d3fb20c --- /dev/null +++ b/named_object_list.h @@ -0,0 +1,154 @@ +#ifndef NAMED_OBJECT_LIST_H +#define NAMED_OBJECT_LIST_H + +#include +#include + +//===== arity 0 ===== + +template +class named_object_list { +protected: + struct creator_base { + std::string description; + creator_base(const std::string& descr): description(descr) { } + creator_base(const char* descr): description(descr) { } + virtual Base* operator()() const = 0; + }; + + template + struct creator: public creator_base { + creator(const std::string& descr): creator_base(descr) { } + creator(const char* descr): creator_base(descr) { } + Base* operator()() const { return new Derived(); } + }; + + typedef std::map map_type; + + map_type assoc; + + void insert(const std::string& name, const creator_base* creat) + { + assoc.insert(std::make_pair(name, creat)); + } + + void insert(const char* name, const creator_base* creat) + { + assoc.insert(std::make_pair(std::string(name), creat)); + } + +public: + typedef typename map_type::const_iterator iterator; + + named_object_list() { }; + ~named_object_list() + { + for (iterator it = begin(); it != end(); ++it) + delete it->second; + } + + Base* new_instance(const std::string& name) const + { + iterator it = assoc.find(name); + if (it != assoc.end()) + return (*it->second)(); + else + return NULL; + } + + Base* new_instance(const char* name) const + { + return new_instance(std::string(name)); + } + + const std::string& get_name(iterator& it) const { return it->first; } + const std::string& get_descr(iterator& it) const + { return it->second->description; } + + size_t size() const { return assoc.size(); } + iterator begin() const { return assoc.begin(); } + iterator end() const { return assoc.end(); } + +}; + +//===== arity 2 ===== + +#include +#include + +template +class named_object_list2 { +protected: + struct creator_base { + std::string description; + creator_base(const std::string& descr): description(descr) { } + creator_base(const char* descr): description(descr) { } + virtual Base* operator()(Arg1, Arg2) const = 0; + }; + + template + struct creator: public creator_base { + creator(const std::string& descr): creator_base(descr) { } + creator(const char* descr): creator_base(descr) { } + Base* operator()(Arg1 arg1, Arg2 arg2) const + { return new Derived(arg1, arg2); } + }; + + typedef std::map map_type; + + map_type assoc; + + void insert(const std::string& name, const creator_base* creat) + { + assoc.insert(std::make_pair(name, creat)); + } + + void insert(const char* name, const creator_base* creat) + { + assoc.insert(std::make_pair(std::string(name), creat)); + } + +public: + typedef typename map_type::const_iterator iterator; + + named_object_list2() { }; + ~named_object_list2() + { + for (iterator it = begin(); it != end(); ++it) + delete it->second; + } + + Base* new_instance(const std::string& name, Arg1 arg1, Arg2 arg2) const + { + iterator it = assoc.find(name); + if (it != assoc.end()) + return (*it->second)(arg1, arg2); + else + return NULL; + } + + Base* new_instance(const char* name, Arg1 arg1, Arg2 arg2) const + { + return new_instance(std::string(name), arg1, arg2); + } + + const std::string& get_name(iterator& it) const { return it->first; } + const std::string& get_descr(iterator& it) const + { return it->second->description; } + + bool exists(const std::string& name) const + { return assoc.find(name) != assoc.end(); } + iterator begin() const { return assoc.begin(); } + iterator end() const { return assoc.end(); } + +}; + +//=================== + +#define THIS_INSERT(name, descr, class) insert(name, new creator(descr)) + +#endif // !NAMED_OBJECT_LIST_H + +// Local variables: +// mode: c++ +// End: diff --git a/options.cpp b/options.cpp index 243ad59..0a9fb5c 100644 --- a/options.cpp +++ b/options.cpp @@ -5,22 +5,25 @@ #include #include // getopt #include -#include "misc.h" +#include "loba_simple.h" XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(main); namespace opt { + // Global options std::string program_name; - - std::string platform_file; - std::string deployment_file; - int help_requested = 0; bool version_requested = false; + // Simulation parameters unsigned log_rate = 1; + // Platform and deployment + std::string platform_file; + std::string deployment_file; + + // Automatic deployment namespace auto_depl { bool enabled = false; std::string topology; @@ -28,13 +31,34 @@ namespace opt { double load = 0.0; } - unsigned maxiter = 4; // fixme - bool exit_on_close = false; - + // Load balancing algorithm + std::string loba_algo("none"); bool bookkeeping = false; + // Application parameters cost_func comp_cost("1e9, 0"); // fixme: find better defaults cost_func comm_cost("1, 0"); // fixme: find better defaults + unsigned maxiter = 4; // fixme + bool exit_on_close = false; + + // Named parameters lists + loba_algorithms_type loba_algorithms; + loba_algorithms_type::loba_algorithms_type() + { + THIS_INSERT("none", "no load-balancing", process); + THIS_INSERT("simple", "balance with least loaded neighbor", + loba_simple); + } + +#if 0 + topologies_type topologies; + topologies_type::topologies_type() + { + THIS_INSERT("none", "no load-balancing", process); + THIS_INSERT("simple", "balance with least loaded neighbor", + loba_simple); + } +#endif } // namespace opt @@ -56,8 +80,11 @@ int opt::parse_args(int* argc, char* argv[]) int c; opterr = 0; - while ((c = getopt(*argc, argv, "bc:C:ehi:l:L:N:T:V")) != -1) { + while ((c = getopt(*argc, argv, "a:bc:C:ehi:l:L:N:T:V")) != -1) { switch (c) { + case 'a': + opt::loba_algo = optarg; + break; case 'b': opt::bookkeeping = true; break; @@ -148,9 +175,19 @@ void opt::print() void opt::usage() { + // option(...) #define o(opt) " " << std::setw(14) \ << std::left << (opt) << std::right << " " -#define so(subopt) std::setw(10) << (subopt) << ": " + // sub-option(...) +#define so(subopt) std::setw(18) << (subopt) << " : " + // sub-option list +#define so_list(name) do { \ + name ## _type::iterator it; \ + for (it = name.begin() ; it != name.end() ; ++it) \ + std::clog << so(name.get_name(it)) \ + << name.get_descr(it) << "\n"; \ + } while (0) + std::clog << "Usage: " << opt::program_name << " [options] \n"; @@ -171,6 +208,29 @@ void opt::usage() << "print current load every n-th iterations, 0 to disable" << " (" << opt::log_rate << ")\n"; + std::clog << "\nAutomatic deployment options\n"; + std::clog << o("-T name") + << "enable automatic deployment with selected topology\n"; + if (opt::help_requested > 1) +#if 0 + so_list(opt::topologies); +#else + std::clog << so("name") << "FIXME\n"; // fixme +#endif + std::clog << o("-L value") + << "total load with auto deployment, 0 for number of hosts" + << " (" << opt::auto_depl::load << ")\n"; + std::clog << o("-N value") + << "number of hosts to use with auto deployment," + << " 0 for max. (" << opt::auto_depl::nhosts << ")\n"; + + std::clog << "\nLoad balancing algorithm\n"; + std::clog << o("-a name") << "load balancing algorithm" + << " (" << opt::loba_algo << ")\n"; + if (opt::help_requested > 1) + so_list(opt::loba_algorithms); + std::clog << o("-b") << "enable bookkeeping\n"; + std::clog << "\nApplication parameters\n"; std::clog << o("-c [fn,...]f0") << "polynomial factors for computation cost" @@ -183,23 +243,7 @@ void opt::usage() << "maximum number of iterations, 0 for infinity" << " (" << opt::maxiter << ")\n"; - std::clog << "\nLoad balancing algorithm\n"; - std::clog << o("-b") << "enable bookkeeping\n"; - - std::clog << "\nAutomatic deployment options\n"; - std::clog << o("-T type") - << "enable automatic deployment with selected topology\n"; - if (opt::help_requested > 1) { - std::clog << so(1) << "pipo\n"; - std::clog << so(42) << "atchoum\n"; - } - std::clog << o("-L value") - << "total load with auto deployment, 0 for number of hosts" - << " (" << opt::auto_depl::load << ")\n"; - std::clog << o("-N value") - << "number of hosts to use with auto deployment," - << " 0 for max. (" << opt::auto_depl::nhosts << ")\n"; - +#undef so_list #undef so #undef o } diff --git a/options.h b/options.h index 8d89808..4e352c6 100644 --- a/options.h +++ b/options.h @@ -3,20 +3,25 @@ #include #include "cost_func.h" +#include "named_object_list.h" +#include "process.h" // Global parameters, shared by all the processes namespace opt { + // Global options extern std::string program_name; - - extern std::string platform_file; - extern std::string deployment_file; - extern int help_requested; extern bool version_requested; + // Simulation parameters extern unsigned log_rate; + // Platform and deployment + extern std::string platform_file; + extern std::string deployment_file; + + // Automatic deployment namespace auto_depl { extern bool enabled; extern std::string topology; @@ -24,17 +29,30 @@ namespace opt { extern double load; } - extern std::string topology; - extern double init_load; + // Load balancing algorithm + extern std::string loba_algo; + extern bool bookkeeping; + // Application parameters + extern cost_func comp_cost; + extern cost_func comm_cost; extern unsigned maxiter; extern bool exit_on_close; - extern bool bookkeeping; + // Named parameters lists + extern struct loba_algorithms_type: + public named_object_list2 { + loba_algorithms_type(); + } loba_algorithms; - extern cost_func comp_cost; - extern cost_func comm_cost; +#if 0 + extern struct topologies_type: + public named_object_list { + topologies_type(); + } topologies; +#endif + // Utility functions int parse_args(int* argc, char* argv[]); void print(); void usage(); diff --git a/process.cpp b/process.cpp index 3b37123..ed7be05 100644 --- a/process.cpp +++ b/process.cpp @@ -129,6 +129,8 @@ double process::sum_of_to_send() const double process::load_balance(double /*my_load*/) { + if (iter == 1) + WARN0("process::load_balance is a no-op!"); return 0.0; } -- 2.39.5