The ROme OpTimistic Simulator  2.0.0
A General-Purpose Multithreaded Parallel/Distributed Simulation Platform
init.c
Go to the documentation of this file.
1 
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <limits.h>
38 #include <sysexits.h>
39 #include <argp.h>
40 #include <errno.h>
41 
42 #include <ROOT-Sim.h>
43 #include <arch/thread.h>
45 #include <core/core.h>
46 #include <core/init.h>
47 #include <datatypes/bitmap.h>
48 #include <scheduler/process.h>
49 #include <gvt/gvt.h>
50 #include <gvt/ccgs.h>
51 #include <scheduler/scheduler.h>
52 #include <mm/state.h>
53 #include <mm/ecs.h>
54 #include <mm/mm.h>
55 #include <statistics/statistics.h>
56 #include <lib/numerical.h>
57 #include <lib/topology.h>
58 #include <lib/abm_layer.h>
59 #include <serial/serial.h>
60 #ifdef HAVE_MPI
61 #include <communication/mpi.h>
62 #endif
63 
64 
67  OPT_FIRST = 128,
69  // make sure these ones are mapped correctly to the external enum param_codes,
70  OPT_SCHEDULER = OPT_FIRST + PARAM_SCHEDULER,
71  OPT_CKTRM_MODE = OPT_FIRST + PARAM_CKTRM_MODE,
72  OPT_LPS_DISTRIBUTION = OPT_FIRST + PARAM_LPS_DISTRIBUTION,
73  OPT_VERBOSE = OPT_FIRST + PARAM_VERBOSE,
74  OPT_STATS = OPT_FIRST + PARAM_STATS,
75  OPT_STATE_SAVING = OPT_FIRST + PARAM_STATE_SAVING,
76  OPT_SNAPSHOT = OPT_FIRST + PARAM_SNAPSHOT,
77 
78  OPT_NP,
79  OPT_NPRC,
80  OPT_OUTPUT_DIR,
81  OPT_NPWD,
82  OPT_P,
83  OPT_FULL,
84  OPT_INC,
85  OPT_A,
86  OPT_GVT,
87  OPT_GVT_SNAPSHOT_CYCLES,
88  OPT_SIMULATION_TIME,
89  OPT_DETERMINISTIC_SEED,
90  OPT_SEED,
91  OPT_SERIAL,
92  OPT_NO_CORE_BINDING,
93 
94 #ifdef HAVE_PREEMPTION
95  OPT_PREEMPTION,
96 #endif
97  OPT_LAST
98 };
99 
100 // XXX we offset the first level with OPT_FIRST so remember about it when you index it!
101 const char * const param_to_text[][5] = {
102  [OPT_SCHEDULER - OPT_FIRST] = {
103  [SCHEDULER_INVALID] = "invalid scheduler",
104  [SCHEDULER_STF] = "stf",
105  },
106  [OPT_CKTRM_MODE - OPT_FIRST] = {
107  [CKTRM_INVALID] = "invalid termination checking",
108  [CKTRM_NORMAL] = "normal",
109  [CKTRM_INCREMENTAL] = "incremental",
110  [CKTRM_ACCURATE] = "accurate"
111  },
112  [OPT_LPS_DISTRIBUTION - OPT_FIRST] = {
113  [LP_DISTRIBUTION_INVALID] = "invalid LPs distribution",
114  [LP_DISTRIBUTION_BLOCK] = "block",
115  [LP_DISTRIBUTION_CIRCULAR] = "circular"
116  },
117  [OPT_VERBOSE - OPT_FIRST] = {
118  [VERBOSE_INVALID] = "invalid verbose specification",
119  [VERBOSE_INFO] = "info",
120  [VERBOSE_DEBUG] = "debug",
121  [VERBOSE_NO] = "no"
122  },
123  [OPT_STATS - OPT_FIRST] = {
124  [STATS_INVALID] = "invalid statistics specification",
125  [STATS_GLOBAL] = "global",
126  [STATS_PERF] = "performance",
127  [STATS_LP] = "lp",
128  [STATS_ALL] = "all"
129  },
130  [OPT_STATE_SAVING - OPT_FIRST] = {
131  [STATE_SAVING_INVALID] = "invalid checkpointing specification",
132  [STATE_SAVING_COPY] = "copy",
133  [STATE_SAVING_PERIODIC] = "periodic",
134  },
135  [OPT_SNAPSHOT - OPT_FIRST] = {
136  [SNAPSHOT_INVALID] = "invalid snapshot specification",
137  [SNAPSHOT_FULL] = "full",
138  }
139 };
140 
141 const char *argp_program_version = PACKAGE_STRING "\nCopyright (C) 2008-2019 HPDCS Group";
142 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
143 
144 // Directly from argp documentation:
145 // If non-zero, a string containing extra text to be printed before and after the options in a long help message,
146 // with the two sections separated by a vertical tab ('\v', '\013') character.
147 // By convention, the documentation before the options is just a short string explaining what the program does.
148 // Documentation printed after the options describe behavior in more detail.
149 static char doc[] = "ROOT-Sim - a fast distributed multithreaded Parallel Discrete Event Simulator \v For more information check the official wiki at https://github.com/HPDCS/ROOT-Sim/wiki";
150 
151 // this isn't needed (we haven't got non option arguments to document)
152 static char args_doc[] = "";
153 // the options recognized by argp
154 static const struct argp_option argp_options[] = {
155  {"wt", OPT_NP, "VALUE", 0, "Number of total cores being used by the simulation", 0},
156  {"lp", OPT_NPRC, "VALUE", 0, "Total number of Logical Processes being launched at simulation startup", 0},
157  {"output-dir", OPT_OUTPUT_DIR, "PATH", 0, "Path to a folder where execution statistics are stored. If not present, it is created", 0},
158  {"scheduler", OPT_SCHEDULER, "TYPE", 0, "LP Scheduling algorithm. Supported values are: stf", 0},
159  {"npwd", OPT_NPWD, 0, 0, "Non Piece-Wise-Deterministic simulation model. See manpage for accurate description", 0},
160  {"p", OPT_P, "VALUE", 0, "Checkpointing interval", 0},
161  {"full", OPT_FULL, 0, 0, "Take only full logs", 0},
162  {"inc", OPT_INC, 0, 0, "Take only incremental logs (still to be released)", 0},
163  {"A", OPT_A, 0, 0, "Autonomic subsystem: set checkpointing interval and log mode automatically at runtime (still to be released)", 0},
164  {"gvt", OPT_GVT, "VALUE", 0, "Time between two GVT reductions (in milliseconds)", 0},
165  {"cktrm-mode", OPT_CKTRM_MODE, "TYPE", 0, "Termination Detection mode. Supported values: normal, incremental, accurate", 0},
166  {"gvt-snapshot-cycles", OPT_GVT_SNAPSHOT_CYCLES, "VALUE", 0, "Termination detection is invoked after this number of GVT reductions", 0},
167  {"simulation-time", OPT_SIMULATION_TIME, "VALUE", 0, "Halt the simulation when all LPs reach this logical time. 0 means infinite", 0},
168  {"lps-distribution", OPT_LPS_DISTRIBUTION, "TYPE", 0, "LPs distributions over simulation kernels policies. Supported values: block, circular", 0},
169  {"deterministic-seed", OPT_DETERMINISTIC_SEED, 0, 0, "Do not change the initial random seed for LPs. Enforces different deterministic simulation runs", 0},
170  {"verbose", OPT_VERBOSE, "TYPE", 0, "Verbose execution", 0},
171  {"stats", OPT_STATS, "TYPE", 0, "Level of detail in the output statistics", 0},
172  {"seed", OPT_SEED, "VALUE", 0, "Manually specify the initial random seed", 0},
173  {"serial", OPT_SERIAL, 0, 0, "Run a serial simulation (using Calendar Queues)", 0},
174  {"sequential", OPT_SERIAL, 0, OPTION_ALIAS, NULL, 0},
175  {"no-core-binding", OPT_NO_CORE_BINDING, 0, 0, "Disable the binding of threads to specific physical processing cores", 0},
176 
177 #ifdef HAVE_PREEMPTION
178  {"no-preemption", OPT_PREEMPTION, 0, 0, "Disable Preemptive Time Warp", 0},
179 #endif
180  {0}
181 };
182 
183 #define malformed_option_failure() argp_error(state, "invalid value \"%s\" in %s option.\nAborting!", arg, state->argv[state->next -1 -(arg != NULL)])
184 
185 #define conflicting_option_failure(msg) argp_error(state, "the requested option %s with value \"%s\" is conflicting: " msg "\nAborting!", state->argv[state->next -1 -(arg != NULL)], arg)
186 
187 // this parses an string option leveraging the 2d array of strings specified earlier
188 // the weird iteration style skips the element 0, which we know is associated with an invalid value description
189 #define handle_string_option(label, var) \
190  case label: \
191  ({ \
192  unsigned __i = 1; \
193  while(1) { \
194  if(strcmp(arg, param_to_text[key - OPT_FIRST][__i]) == 0) { \
195  var = __i; \
196  break; \
197  } \
198  if(!param_to_text[key - OPT_FIRST][++__i]) \
199  malformed_option_failure(); \
200  } \
201  }); \
202  break
203 
204 
205 // the compound expression equivalent to __value >= low is needed in order to suppress a warning when low == 0
206 #define parse_ullong_limits(low, high) \
207  ({ \
208  unsigned long long int __value; \
209  char *__endptr; \
210  __value = strtoull(arg, &__endptr, 10); \
211  if(!(*arg != '\0' && *__endptr == '\0' && (__value > low || __value == low) && __value <= high)) { \
212  malformed_option_failure(); \
213  } \
214  __value; \
215  })
216 
217 static error_t parse_opt (int key, char *arg, struct argp_state *state)
218 {
219  // this is used in order to ensure that the user doesn't use duplicate options
220  static rootsim_bitmap scanned[bitmap_required_size(OPT_LAST - OPT_FIRST)];
221 
222  if(key >= OPT_FIRST && key < OPT_LAST){
223  if(bitmap_check(scanned, key - OPT_FIRST))
224  conflicting_option_failure("this option has already been specified");
225 
226  bitmap_set(scanned, key - OPT_FIRST);
227  }
228 
229  switch (key) {
230  case OPT_NP:
231  if(strcmp(arg, "auto") == 0){
232  n_cores = get_cores();
233  }else{
234  n_cores = parse_ullong_limits(1, UINT_MAX);
235  }
236  break;
237 
238  case OPT_NPRC:
239  n_prc_tot = parse_ullong_limits(1, UINT_MAX);
240  break;
241 
242  case OPT_OUTPUT_DIR:
244  break;
245 
246  handle_string_option(OPT_SCHEDULER, rootsim_config.scheduler);
247  handle_string_option(OPT_FULL, rootsim_config.snapshot);
248  handle_string_option(OPT_CKTRM_MODE, rootsim_config.check_termination_mode);
249  handle_string_option(OPT_VERBOSE, rootsim_config.verbose);
250  handle_string_option(OPT_STATS, rootsim_config.stats);
251  handle_string_option(OPT_LPS_DISTRIBUTION, rootsim_config.lps_distribution);
252 
253  case OPT_NPWD:
254  if (bitmap_check(scanned, OPT_P-OPT_FIRST)) {
255  conflicting_option_failure("I'm requested to run non piece-wise deterministically, but a checkpointing interval is set already.");
256  } else {
258  }
259  break;
260 
261  case OPT_P:
262  if(bitmap_check(scanned, OPT_NPWD-OPT_FIRST)) {
263  conflicting_option_failure("Copy State Saving is selected, but I'm requested to set a checkpointing interval.");
264  } else {
266  rootsim_config.ckpt_period = parse_ullong_limits(1, 40);
267  // This is a micro optimization that makes the LogState function to avoid checking the checkpointing interval and keeping track of the logs taken
268  if(rootsim_config.ckpt_period == 1)
270  }
271  break;
272 
273  case OPT_INC:
274  argp_failure(state, EXIT_FAILURE, ENOSYS, "incremental state saving is not supported in stable version yet...\nAborting");
275  break;
276 
277  case OPT_A:
278  argp_failure(state, EXIT_FAILURE, ENOSYS, "autonomic state saving is not supported in stable version yet...\nAborting");
279  break;
280 
281  case OPT_GVT:
282  rootsim_config.gvt_time_period = parse_ullong_limits(1, 10000);
283  break;
284 
285  case OPT_GVT_SNAPSHOT_CYCLES:
286  rootsim_config.gvt_snapshot_cycles = parse_ullong_limits(1, INT_MAX);
287  break;
288 
289  case OPT_SIMULATION_TIME:
290  rootsim_config.simulation_time = parse_ullong_limits(0, INT_MAX);
291  break;
292 
293  case OPT_DETERMINISTIC_SEED:
295  break;
296 
297  case OPT_SEED:
298  rootsim_config.set_seed = parse_ullong_limits(0, UINT64_MAX);
299  break;
300 
301  case OPT_SERIAL:
302  rootsim_config.serial = true;
303  break;
304 
305  case OPT_NO_CORE_BINDING:
307  break;
308 
309 #ifdef HAVE_PREEMPTION
310  case OPT_PREEMPTION:
312  break;
313 #endif
314 
315  case ARGP_KEY_INIT:
316 
317  memset(&rootsim_config, 0, sizeof(rootsim_config));
318  memset(scanned, 0, sizeof(scanned));
319  // Store the predefined values, before reading any overriding one
326  rootsim_config.snapshot = SNAPSHOT_FULL; // TODO: in the future, default to AUTONOMIC_
334  rootsim_config.serial = false;
336 
337 #ifdef HAVE_PREEMPTION
339 #endif
340  break;
341 
342  case ARGP_KEY_SUCCESS:
343 
344  // sanity checks
345  if(!rootsim_config.serial && !bitmap_check(scanned, OPT_NP - OPT_FIRST))
346  rootsim_error(true, "Number of cores was not provided \"--wt\"\n");
347 
348  if(!bitmap_check(scanned, OPT_NPRC - OPT_FIRST))
349  rootsim_error(true, "Number of LPs was not provided \"--lp\"\n");
350 
351  if(n_cores > get_cores())
352  rootsim_error(true, "Demanding %u cores, which are more than available (%d)\n", n_cores, get_cores());
353 
355  rootsim_error(true, "Too many threads, maximum supported number is %u\n", MAX_THREADS_PER_KERNEL);
356 
357  if(n_prc_tot > MAX_LPs)
358  rootsim_error(true, "Too many LPs, maximum supported number is %u\n", MAX_LPs);
359 
361  rootsim_error(true, "Requested a simulation run with %u LPs and %u worker threads: the mapping is not possible\n", n_prc_tot, n_cores);
362 
363  print_config();
364 
365  break;
366  /* these functionalities are not needed
367  case ARGP_KEY_ARGS:
368  case ARGP_KEY_NO_ARGS:
369  case ARGP_KEY_SUCCESS:
370  case ARGP_KEY_END:
371  case ARGP_KEY_ARG:
372  case ARGP_KEY_ERROR:
373  */
374  default:
375  return ARGP_ERR_UNKNOWN;
376  }
377  return 0;
378 }
379 
380 #undef parse_ullong_limits
381 #undef handle_string_option
382 #undef conflicting_option_failure
383 #undef malformed_option_failure
384 
385 static struct argp_child argp_child[2] = {
386  {0, 0, "Model specific options", 0},
387  {0}
388 };
389 
390 static struct argp argp = { argp_options, parse_opt, args_doc, doc, argp_child, 0, 0 };
391 
401 void SystemInit(int argc, char **argv)
402 {
403 #ifdef HAVE_MPI
404  mpi_init(&argc, &argv);
405 
406  if(n_ker > MAX_KERNELS){
407  rootsim_error(true, "Too many kernels, maximum supported number is %u\n", MAX_KERNELS);
408  }
409 #else
410  n_ker = 1;
411 #endif
412 
413  // Early initialization of ECS subsystem if needed
414 #ifdef HAVE_CROSS_STATE
415  ecs_init();
416 #endif
417 
418  // this retrieves the model's argp parser if declared by the developer
419  argp_child[0].argp = &model_argp;
420 
421  argp_parse (&argp, argc, argv, 0, NULL, NULL);
422 
423  // If we're going to run a serial simulation, configure the simulation to support it
424  if(rootsim_config.serial) {
425  ScheduleNewEvent = SerialScheduleNewEvent;
426  initialize_lps();
427  numerical_init();
428  statistics_init();
429  serial_init();
430  topology_init();
431  abm_layer_init();
432  return;
433  } else {
435  }
436 
437  // Initialize ROOT-Sim subsystems.
438  // All init routines are executed serially (there is no notion of threads in there)
439  // and the order of invocation can matter!
440  base_init();
441  segment_init();
442  initialize_lps();
443  remote_memory_init();
444  statistics_init();
445  scheduler_init();
447  gvt_init();
448  numerical_init();
449  topology_init();
450  abm_layer_init();
451 
452  // This call tells the simulation engine that the sequential initial simulation is complete
454 }
455 
456 
Communication Routines.
void abm_layer_init(void)
Definition: abm_layer.c:235
Initialization routines.
#define bitmap_set(bitmap, bit_index)
This sets the bit with index bit_index of the bitmap bitmap.
Definition: bitmap.h:116
seed_type set_seed
The master seed to be used in this run.
Definition: init.h:73
int check_termination_mode
Check termination strategy: standard or incremental.
Definition: init.h:68
char * output_dir
Destination Directory of output files.
Definition: init.h:58
int verbose
Kernel verbose.
Definition: init.h:70
Core ROOT-Sim functionalities.
void gvt_init(void)
Definition: gvt.c:132
void statistics_init(void)
Definition: statistics.c:660
ROOT-Sim header for model development.
unsigned int n_cores
Total number of cores required for simulation.
Definition: core.c:61
#define bitmap_required_size(requested_bits)
Computes the required size of a bitmap with requested_bits entries.
Definition: bitmap.h:92
int ckpt_period
Number of events to execute before taking a snapshot in PSS (ignored otherwise)
Definition: init.h:66
Definition: init.c:67
void initialization_complete(void)
Definition: core.c:316
int checkpointing
Type of checkpointing scheme (e.g., PSS, CSS, ...)
Definition: init.h:65
#define MAX_THREADS_PER_KERNEL
Definition: thread.h:137
void ParallelScheduleNewEvent(unsigned int gid_receiver, simtime_t timestamp, unsigned int event_type, void *event_content, unsigned int event_size)
Schedule a new message to some LP.
bool deterministic_seed
Does not change the seed value config file that will be read during the next runs.
Definition: init.h:69
#define DEFAULT_OUTPUT_DIR
This macro specified the default output directory, if nothing is passed as an option.
Definition: statistics.h:59
_opt_codes
This is the list of mnemonics for arguments.
Definition: init.c:66
Statistics module.
void base_init(void)
Definition: core.c:129
The ROOT-Sim scheduler main module header.
Generic thread management facilities.
Consistent and Committed Global State.
Numerical Library.
int scheduler
Which scheduler to be used.
Definition: init.h:59
simulation_configuration rootsim_config
This global variable holds the configuration for the current simulation.
Definition: core.c:70
void SystemInit(int argc, char **argv)
Definition: init.c:401
Memory Manager main header.
Serial scheduler.
int simulation_time
Wall-clock-time based termination predicate.
Definition: init.h:62
LP control blocks.
void mpi_init(int *argc, char ***argv)
Initialize MPI subsystem.
Definition: mpi.c:514
void(* ScheduleNewEvent)(unsigned int gid_receiver, simtime_t timestamp, unsigned int event_type, void *event_content, unsigned int event_size)
This is the function pointer to correctly set ScheduleNewEvent API version, depending if we&#39;re runnin...
Definition: communication.c:50
#define get_cores()
Macro to get the core count on the hosting machine.
Definition: thread.h:48
MPI Support Module.
LP state management.
#define bitmap_check(bitmap, bit_index)
This checks if the bit with index bit_index of the bitmap bitmap is set or unset. ...
Definition: bitmap.h:135
Bitmap data type.
#define MAX_KERNELS
Definition: thread.h:129
const char *const param_to_text[][5]
Definition: init.c:101
Global Virtual Time.
#define MAX_LPs
Maximum number of LPs the simulator will handle.
Definition: core.h:59
enum stats_levels stats
Produce performance statistic file (default STATS_ALL)
Definition: init.h:71
int lps_distribution
Policy for the LP to Kernel mapping.
Definition: init.h:63
int snapshot
Type of snapshot (e.g., full, incremental, autonomic, ...)
Definition: init.h:67
void communication_init(void)
Initialize the communication subsystem.
Definition: communication.c:59
bool core_binding
Bind threads to specific core (reduce context switches and cache misses)
Definition: init.h:74
Event & Cross State Synchornization.
unsigned int n_prc_tot
Total number of logical processes running in the simulation.
Definition: core.c:64
int gvt_time_period
Wall-Clock time to wait before executiong GVT operations.
Definition: init.h:60
bool serial
If the simulation must be run serially.
Definition: init.h:72
unsigned char rootsim_bitmap
This defines a generic bitmap.
Definition: bitmap.h:43
bool disable_preemption
If compiled for preemptive Time Warp, it can be disabled at runtime.
Definition: init.h:77
unsigned int n_ker
Total number of simulation kernel instances running.
Definition: core.c:58
int gvt_snapshot_cycles
GVT operations to be executed before rebuilding the state.
Definition: init.h:61