]> AND Private Git Repository - loba.git/blob - main.cpp
Logo AND Algorithmique Numérique Distribuée

Private GIT Repository
478d1e870fec04d34ae80e461275d400e8aa0e46
[loba.git] / main.cpp
1 #include <cerrno>
2 #include <cmath>
3 #include <csignal>
4 #include <cstring>              // strchr
5 #include <iostream>
6 #include <stdexcept>
7 #include <msg/msg.h>
8 #include <xbt/log.h>
9
10 // Creates log categories
11 XBT_LOG_NEW_CATEGORY(simu, "Root of simulation messages");
12 XBT_LOG_NEW_SUBCATEGORY(main, simu, "Messages from global infrastructure");
13 XBT_LOG_NEW_SUBCATEGORY(depl, main, "Messages from auto deployment");
14 XBT_LOG_NEW_SUBCATEGORY(comm, simu, "Messages from asynchronous pipes");
15 XBT_LOG_NEW_SUBCATEGORY(proc, simu, "Messages from base process class");
16 XBT_LOG_NEW_SUBCATEGORY(loba, simu, "Messages from load-balancer");
17 XBT_LOG_NEW_SUBCATEGORY(thrd, simu, "Messages from thread wrapper class");
18
19 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(main);
20
21 #include "deployment.h"
22 #include "hostdata.h"
23 #include "misc.h"
24 #include "options.h"
25 #include "process.h"
26 #include "statistics.h"
27 #include "synchro.h"
28 #include "timer.h"
29 #include "tracing.h"
30 #include "version.h"
31
32 #define DATA_DESCR_WIDTH 37
33
34 namespace {
35     // Failure exit status
36     enum {
37         EXIT_NO_FAILURE    = 0x00,  // no error
38         EXIT_FAILURE_ARGS  = 0x01,  // bad arguments
39         EXIT_FAILURE_INIT  = 0x02,  // failed to initialize simulator
40         EXIT_FAILURE_SIMU  = 0x04,  // simulation failed
41         EXIT_FAILURE_CLEAN = 0x08,  // error at cleanup
42         EXIT_FAILURE_INTR  = 0x10,  // interrupted by user
43         EXIT_FAILURE_LOAD  = 0x20,  // lost load on exit
44         EXIT_FAILURE_OTHER = 0x40,  // other error
45     };
46
47     // Cannot be globally initialized...
48     mutex_t* proc_mutex;
49     condition_t* proc_cond;
50     unsigned proc_counter = 0;
51
52     statistics loads;
53     statistics comps;
54     statistics data_send_amount;
55     statistics data_recv_amount;
56     statistics data_send_count;
57     statistics data_recv_count;
58     statistics ctrl_send_amount;
59     statistics ctrl_recv_amount;
60     statistics ctrl_send_count;
61     statistics ctrl_recv_count;
62
63 }
64
65 static int simulation_main(int argc, char* argv[])
66 {
67     int result;
68     process* proc;
69     try {
70         proc = opt::loba_algorithms.new_instance(opt::loba_algo, argc, argv);
71
72         proc_mutex->acquire();
73         ++proc_counter;
74         proc_mutex->release();
75
76         result = proc->run();
77
78         proc_mutex->acquire();
79         loads.push(proc->get_real_load());
80         comps.push(proc->get_comp_amount());
81         data_send_amount.push(proc->get_data_send_amount());
82         data_recv_amount.push(proc->get_data_recv_amount());
83         data_send_count.push(proc->get_data_send_count());
84         data_recv_count.push(proc->get_data_recv_count());
85         ctrl_send_amount.push(proc->get_ctrl_send_amount());
86         ctrl_recv_amount.push(proc->get_ctrl_recv_amount());
87         ctrl_send_count.push(proc->get_ctrl_send_count());
88         ctrl_recv_count.push(proc->get_ctrl_recv_count());
89
90         // Synchronization barrier...
91         // The goal is to circumvent a limitation in SimGrid (at least
92         // in version 3.5): a process must be alive when another one
93         // destroys a communication they had together.
94
95         --proc_counter;
96         proc_cond->broadcast();
97         while (proc_counter > 0)
98             proc_cond->wait(*proc_mutex);
99         proc_mutex->release();
100
101         delete proc;
102     }
103     catch (const std::invalid_argument& e) {
104         THROWF(arg_error, 0, "%s", e.what());
105     }
106     catch (const std::exception& e) {
107         THROWF(0, 0, "%s", e.what());
108     }
109     return result;
110 }
111
112 static bool check_for_lost_load()
113 {
114     bool res = true;
115     double total_init = process::get_total_load_init();
116     double total_exit = process::get_total_load_exit();
117     double lost = total_init - total_exit;
118     double lost_ratio = 100.0 * lost / total_init;
119     if (lost_ratio < -opt::load_ratio_threshold) {
120         XBT_ERROR("Gained load at exit! %g (%g%%) <============",
121                   -lost, -lost_ratio);
122         res = false;
123     } else if (lost_ratio > opt::load_ratio_threshold) {
124         XBT_ERROR("Lost load at exit! %g (%g%%) <============",
125                   lost, lost_ratio);
126         res = false;
127     } else
128         XBT_VERB("Total load at exit looks good: %g (%g%%)", lost, lost_ratio);
129
130     double total_running = process::get_total_load_running();
131     double running_ratio = 100.0 * total_running / total_init;
132     if (running_ratio < -opt::load_ratio_threshold) {
133         XBT_ERROR("Negative running load at exit! %g (%g%%) <============",
134                   total_running, running_ratio);
135         res = false;
136     } else if (running_ratio > opt::load_ratio_threshold) {
137         XBT_ERROR("Remaining running load at exit! %g (%g%%) <============",
138                   total_running, running_ratio);
139         res = false;
140     } else
141         XBT_VERB("Running load at exit looks good: %g (%g%%)",
142                  total_running, running_ratio);
143     return res;
144 }
145
146 static void signal_handler(int /*sig*/)
147 {
148     if (!opt::exit_request) {
149         XBT_CRITICAL(">>>>>>>>>>"
150                      " caught CTRL-C: global exit requested "
151                      "<<<<<<<<<<");
152         opt::exit_request = 1;
153     } else {
154         XBT_CRITICAL(">>>>>>>>>>"
155                      " caught CTRL-C for the 2nd time: exit immediately "
156                      "<<<<<<<<<<");
157         exit(EXIT_FAILURE_INTR);
158     }
159 }
160
161 static void install_signal_handler()
162 {
163     struct sigaction action;
164     action.sa_handler = signal_handler;
165     sigemptyset(&action.sa_mask);
166     action.sa_flags = SA_RESTART;
167     if (sigaction(SIGINT, &action, NULL) == -1) {
168         std::cerr << "sigaction: " << strerror(errno) << "\n";
169         exit(EXIT_FAILURE_OTHER);
170     }
171 }
172
173 #define PR_STATS(descr, st)                                             \
174     XBT_INFO("| %.*s: %g / %g / %g", DATA_DESCR_WIDTH,                  \
175              descr " (total/avg./stddev)................................", \
176              st.get_sum(), st.get_mean(), st.get_stddev())
177
178 int main(int argc, char* argv[])
179 {
180     // Note: variables used after THROW must be declared as volatile.
181     volatile int exit_status = 0;   // global exit status
182     volatile double simulated_time = -1.0;
183     timestamp elapsed_time(timestamp::wallclock_time);
184     timestamp simulation_time(timestamp::cpu_time);
185     xbt_ex_t ex;
186     MSG_error_t res;
187
188     elapsed_time.start();
189     simulation_time.start();
190
191     // Set default logging parameters
192     bool do_log_control_set = true;
193     for (int i = 1 ; do_log_control_set && i < argc ; i++)
194         do_log_control_set = !(argv[i][0] == '-' && argv[i][1] != '-' &&
195                                strchr(argv[i] + 1, 'v'));
196     if (do_log_control_set) {
197         // xbt_log_control_set("simu.thres:verbose");
198         xbt_log_control_set("simu.fmt:'[%h %r] [%c/%p] %m%n'");
199         xbt_log_control_set("main.fmt:'[%c/%p] %m%n'");
200     }
201
202     // Initialize some MSG internal data.
203     // Note: MSG_global_init() may throw an exception, but it seems
204     // impossible to catch it correctly :-(
205     MSG_global_init(&argc, argv);
206     install_signal_handler();
207
208     // Parse global parameters
209     bool parse_res = opt::parse_args(&argc, argv);
210     if (!parse_res
211         || opt::version_requested || opt::help_requested) {
212         if (opt::version_requested)
213             std::clog << version::name << " (" << opt::program_name << ")"
214                       << " version " << version::num << "\n"
215                       << version::copyright << "\n"
216                 "Compiled on " << version::date << "\n\n";
217         if (!parse_res || opt::help_requested)
218             opt::usage();
219         MSG_clean();
220         exit(parse_res ? EXIT_NO_FAILURE : EXIT_FAILURE_ARGS);
221     }
222     XBT_INFO("%s v%s (%s)", opt::program_name.c_str(), version::num.c_str(),
223           version::date.c_str());
224     opt::print();
225
226     TRY {
227         exit_status = EXIT_FAILURE_INIT; // =====
228
229         // Register the default function of an agent
230         // MSG_function_register("simulation_main", simulation_main);
231         MSG_function_register_default(simulation_main);
232
233         // Create the platform and the application.
234         XBT_DEBUG("Loading platform file...");
235         MSG_create_environment(opt::platform_file.c_str());
236         XBT_DEBUG("Creating hostdata...");
237         hostdata::create();
238         XBT_INFO("Loaded description of %zd hosts.", hostdata::size());
239         XBT_DEBUG("Deploying processes...");
240         if (opt::auto_depl::enabled) {
241             if (!opt::auto_depl::nhosts)
242                 opt::auto_depl::nhosts = hostdata::size();
243             if (opt::auto_depl::nhosts > hostdata::size()) {
244                 XBT_WARN("%u hosts is too much: limiting to %zu",
245                          opt::auto_depl::nhosts, hostdata::size());
246                 opt::auto_depl::nhosts = hostdata::size();
247             }
248             if (opt::auto_depl::load == 0.0) {
249                 XBT_WARN("Initial load is zero!  "
250                          "Falling back on old behaviour (load = nhosts).");
251                 opt::auto_depl::load = opt::auto_depl::nhosts;
252             } else if (opt::auto_depl::load < 0.0)
253                 opt::auto_depl::load =
254                     -opt::auto_depl::load * opt::auto_depl::nhosts;
255             double iload = std::trunc(opt::auto_depl::load);
256             if (opt::integer_transfer && opt::auto_depl::load != iload) {
257                 XBT_WARN("Total load %g is not an integer.  Truncate it.",
258                          opt::auto_depl::load);
259                 opt::auto_depl::load = iload;
260             }
261             MY_launch_application(); // it is already opt::* aware...
262         } else {
263             MSG_launch_application(opt::deployment_file.c_str());
264         }
265
266         // Register tracing categories
267         TRACE_category_with_color(TRACE_CAT_COMP, TRACE_COLOR_COMP);
268         TRACE_category_with_color(TRACE_CAT_CTRL, TRACE_COLOR_CTRL);
269         TRACE_category_with_color(TRACE_CAT_DATA, TRACE_COLOR_DATA);
270
271         exit_status = EXIT_FAILURE_SIMU; // =====
272
273         proc_mutex = new mutex_t();
274         proc_cond = new condition_t();
275
276         // Launch the MSG simulation.
277         XBT_INFO("Starting simulation at %f...", MSG_get_clock());
278         res = MSG_main();
279         simulated_time = MSG_get_clock();
280         XBT_INFO("Simulation ended at %f.", simulated_time);
281
282         delete proc_cond;
283         delete proc_mutex;
284
285         if (res != MSG_OK)
286             THROWF(0, 0, "MSG_main() failed with status %#x", res);
287
288         exit_status = EXIT_NO_FAILURE; // =====
289     }
290     CATCH (ex) {
291         int len = strlen(ex.msg);
292         if (len > 0 && ex.msg[len - 1] == '\n')
293             ex.msg[len - 1] = '\0'; // strip the ending '\n'
294         XBT_ERROR("%s", ex.msg);
295         XBT_DEBUG("Error from %s() in %s:%d", ex.func, ex.file, ex.line);
296         xbt_ex_free(ex);
297     }
298
299     // Clean the MSG simulation.
300     hostdata::destroy();
301     res = MSG_clean();
302     if (res != MSG_OK) {
303         XBT_ERROR("MSG_clean() failed with status %#x", res);
304         exit_status |= EXIT_FAILURE_CLEAN;
305     }
306
307     // Report final simulation status.
308     if (simulated_time >= 0.0) {
309         simulation_time.stop();
310         elapsed_time.stop();
311         if (!check_for_lost_load())
312             exit_status |= EXIT_FAILURE_LOAD;
313         XBT_INFO(",----[ Results ]");
314         PR_STATS("Load", loads);
315         PR_STATS("Computation", comps);
316         PR_STATS("Data send amount", data_send_amount);
317         PR_STATS("Data recv amount", data_recv_amount);
318         PR_STATS("Data send count", data_send_count);
319         PR_STATS("Data recv count", data_recv_count);
320         PR_STATS("Ctrl send amount", ctrl_send_amount);
321         PR_STATS("Ctrl recv amount", ctrl_recv_amount);
322         PR_STATS("Ctrl send count", ctrl_send_count);
323         PR_STATS("Ctrl recv count", ctrl_recv_count);
324         XBT_INFO("| %.*s: %g", DATA_DESCR_WIDTH,
325                  "Total simulated time..................................",
326                  simulated_time);
327         XBT_INFO("| %.*s: %g", DATA_DESCR_WIDTH,
328                  "Total simulation time.................................",
329                  simulation_time.duration());
330         XBT_INFO("| %.*s: %g", DATA_DESCR_WIDTH,
331                  "Elapsed (wall clock) time.............................",
332                  elapsed_time.duration());
333         XBT_INFO("`----");
334     }
335     if (exit_status)
336         XBT_ERROR("Simulation failed (%#x).", exit_status);
337     else
338         XBT_INFO("Simulation succeeded.");
339
340     return exit_status;
341 }
342
343 // Local variables:
344 // mode: c++
345 // End: