The ROme OpTimistic Simulator  2.0.0
A General-Purpose Multithreaded Parallel/Distributed Simulation Platform
topology.c
1 /*
2  * topology_custom.c
3  *
4  * Created on: 24 mag 2018
5  * Author: andrea
6  */
7 
8 #include <ROOT-Sim.h>
9 #include <lib/topology.h>
10 
11 #include <math.h>
12 
13 #include <scheduler/scheduler.h>
14 #include <lib/jsmn_helper.h>
15 #include <lib/numerical.h>
16 #include <datatypes/bitmap.h>
17 #include <datatypes/array.h>
18 #include <datatypes/heap.h>
19 #include <scheduler/process.h>
20 #include <core/init.h>
21 #include <serial/serial.h>
22 
23 struct _topology_global_t topology_global;
24 
25 //used internally (also in abm_layer module) to schedule our reserved events TODO: move in a more system-like module
26 void UncheckedScheduleNewEvent(unsigned int gid_receiver, simtime_t timestamp, unsigned int event_type, void *event_content, unsigned int event_size){
27 
28  msg_t *event;
29  GID_t receiver;
30 
32  SerialScheduleNewEvent(gid_receiver, timestamp, event_type, event_content, event_size);
33  return;
34  }
35 
36  // Internally to the platform, the receiver is a GID, while models
37  // have no difference across GIDs and LIDs. We convert here the passed
38  // id to a GID.
39  set_gid(receiver, gid_receiver);
40 
41  // In Silent execution, we do not send again already sent messages
42  if(current->state == LP_STATE_SILENT_EXEC) {
43  return;
44  }
45 
46 #ifndef NDEBUG
47  // Check whether the destination LP is out of range
48  if(receiver.to_int >= n_prc_tot) { // It's unsigned, so no need to check whether it's < 0
49  rootsim_error(true, "Warning: the destination LP %u %lf %u is out of range. The event has been ignored\n", receiver.to_int, timestamp, event_type);
50  return;
51  }
52 
53  // Check if the associated timestamp is negative
54  if(timestamp < lvt(current)) {
55  rootsim_error(true, "LP %u is trying to generate an event (type %d) to %u in the past! (Current LVT = %f, generated event's timestamp = %f) Aborting...\n", current, event_type, receiver.to_int, lvt(current), timestamp);
56  }
57 #endif
58 
59  // Copy all the information into the event structure
60  pack_msg(&event, current->gid, receiver, event_type, timestamp, lvt(current), event_size, event_content);
61  event->mark = generate_mark(current);
62 
63  insert_outgoing_msg(event);
64 }
65 
70 static unsigned directions_count(void) {
71  switch (topology_global.geometry) {
72  case TOPOLOGY_GRAPH:
73  return topology_global.lp_cnt - 1;
74  case TOPOLOGY_HEXAGON:
75  return 6;
76  case TOPOLOGY_TORUS:
77  case TOPOLOGY_SQUARE:
78  return 4;
79  case TOPOLOGY_STAR:
80  return 2;
81  case TOPOLOGY_RING:
82  return 1;
83  case TOPOLOGY_BIDRING:
84  return 2;
85  }
86  return UINT_MAX;
87 }
88 
98 static void *load_topology_file(const char *file_name) {
99  char *json_base;
100  jsmntok_t *root_token;
101  c_jsmntok_t *t;
102 
103  unsigned lp_cnt;
104  enum _topology_type_t t_type;
106 
107  void *ret = NULL;
108 
109  // load and parse the file with given file_name
110  if(load_and_parse_json_file(file_name, &json_base, &root_token) < 0)
111  rootsim_error(true, "The specified topology file at \"%s\" is either non accessible, non existing, or is not a properly formed JSON file", file_name);
112  // parse the regions count and check its validity
113  if(parse_unsigned_by_key(root_token, json_base, root_token, "regions_count", &lp_cnt) < 0)
114  rootsim_error(true, "Invalid or missing json value with key \"regions_count\" (must be an unsigned integer)");
115  // sanity checks on the number of instantiated LPs
116  if(lp_cnt + topology_settings.out_of_topology > n_prc_tot)
117  rootsim_error(true, "This topology needs an higher number of available LPs (%lu versus %lu available LPs)", lp_cnt, n_prc_tot);
118  if(lp_cnt + topology_settings.out_of_topology < n_prc_tot)
119  rootsim_error(true, "The requested regions are fewer than the available LPs (%lu versus %lu available LPs)", lp_cnt, n_prc_tot);
120 
121  // look for the topology type
122  const char *type_choices[] = {
123  [TOPOLOGY_COSTS] = "costs",
124  [TOPOLOGY_OBSTACLES] = "obstacles",
125  [TOPOLOGY_PROBABILITIES] = "probabilities"
126  };
127  // look for the type key and retrieve its value
128  t = get_value_token_by_key(root_token, json_base, root_token, "type");
129  // parse the choice from the expected string value
130  if((t_type = parse_string_choice(root_token, json_base, t, sizeof(type_choices)/sizeof(const char *), type_choices)) == UINT_MAX)
131  rootsim_error(true, "Invalid or missing json value with key \"type\" (must be a recognizable string)");
132  // sanity check between the topology type requested by the model and what we found
133  if(t_type != topology_settings.type){
134  rootsim_error(true, "The specified topology has a different type from the one requested by the model");
135  }
136 
137  // look for the topology type
138  const char *geometry_choices[] = {
142  [TOPOLOGY_STAR - TOPOLOGY_GEOMETRY_OFFSET] = "star",
146  };
147  // look for the geometry key and retrieve its value
148  t = get_value_token_by_key(root_token, json_base, root_token, "geometry");
149  // parse the choice from the expected string value
150  if((geometry = parse_string_choice(root_token, json_base, t, sizeof(geometry_choices)/sizeof(const char *), geometry_choices)) == UINT_MAX)
151  rootsim_error(true, "Invalid or missing json value with key \"geometry\" (must be a recognizable string)");
152  // we sum the offset of the enum to obtain a valid geometry number
153  geometry += TOPOLOGY_GEOMETRY_OFFSET;
154  // we set the known fields of the global struct
155  topology_global.geometry = geometry;
156  topology_global.lp_cnt = lp_cnt;
157  topology_global.directions = directions_count();
158  // we give control to the right specific parser
159  switch (t_type) {
161  ret = load_topology_file_probabilities(root_token, json_base);
162  break;
163 
164  case TOPOLOGY_COSTS:
165  ret = load_topology_file_costs(root_token, json_base);
166  break;
167 
168  case TOPOLOGY_OBSTACLES:
169  ret = load_topology_file_obstacles(root_token, json_base);
170  break;
171  }
172  // cleanup
173  rsfree(root_token);
174  rsfree(json_base);
175  // return the topology specific data
176  return ret;
177 }
178 
183 static void compute_edge(void){
184  unsigned edge;
185  const unsigned lp_cnt = topology_global.lp_cnt;
186  switch (topology_global.geometry) {
187  case TOPOLOGY_SQUARE:
188  case TOPOLOGY_HEXAGON:
189  case TOPOLOGY_TORUS:
190  edge = sqrt(lp_cnt);
191  // we make sure there are no "lonely" LPs
192  if(edge * edge != lp_cnt)
193  rootsim_error(true, "Invalid number of regions for this topology geometry (must be a square number)");
194  break;
195  default:
196  // the edge value is actually unused
197  edge = 0;
198  break;
199  }
200  // set the edge value
201  topology_global.edge = edge;
202 }
203 
208 void topology_init(void) {
209  if(!&topology_settings)
210  // the weak symbol isn't defined: we aren't needed
211  return;
212 
213  // this is the data extracted from the topology file
214  void *t_data = NULL;
215  // basic sanity check
216  if(topology_settings.out_of_topology >= n_prc_tot)
217  rootsim_error(true, "Not enough LPs to run even a default topology with %u control LPs", topology_settings.out_of_topology);
218  // set default values
219  topology_global.lp_cnt = n_prc_tot - topology_settings.out_of_topology;
220  topology_global.geometry = topology_settings.default_geometry;
221  topology_global.directions = directions_count();
222  // load settings from file if specified
223  if(topology_settings.topology_path)
224  t_data = load_topology_file(topology_settings.topology_path);
225  // compute the edge value for topologies it makes sense for
226  compute_edge();
227  // compute the topology struct size (used also for check-pointing)
228  switch(topology_settings.type){
229  case TOPOLOGY_COSTS:
230  topology_global.chkp_size = size_checkpoint_costs();
231  break;
233  topology_global.chkp_size = size_checkpoint_probabilities();
234  break;
235  case TOPOLOGY_OBSTACLES:
236  topology_global.chkp_size = size_checkpoint_obstacles();
237  break;
238  }
239  // initialize the topology struct
240  foreach_lp(lp){
241  if(lp->gid.to_int >= topology_global.lp_cnt){
242  // this LP isn't part of the underlying topology
243  lp->topology = NULL;
244  }
245  switch(topology_settings.type){
246  case TOPOLOGY_COSTS:
247  lp->topology = topology_costs_init(lp->gid.to_int, t_data);
248  break;
249  case TOPOLOGY_OBSTACLES:
250  lp->topology = topology_obstacles_init(lp->gid.to_int, t_data);
251  break;
253  lp->topology = topology_probabilities_init(lp->gid.to_int, t_data);
254  break;
255  }
256  }
257  // free the topology data read from file
258  rsfree(t_data);
259 }
260 
261 void SetValueTopology(unsigned from, unsigned to, double value) {
262  switch_to_platform_mode();
263  const unsigned lp_cnt = topology_global.lp_cnt;
264 
265  if(unlikely(!topology_settings.write_enabled))
266  rootsim_error(true, "SetValueTopology(): called with write_enable false");
267 
268  if(unlikely(from >= lp_cnt || to >= lp_cnt))
269  rootsim_error(true, "SetValueTopology(): from % u, to %u when lp_cnt is %u", from, to, lp_cnt);
270 
271  if(unlikely(value < 0))
272  rootsim_error(true, "SetValueTopology(): negative values are not supported", value);
273 
274  switch (topology_settings.type) {
275  case TOPOLOGY_COSTS:
276  set_value_topology_costs(from, to, value);
277  break;
279  set_value_topology_probabilities(from, to, value);
280  break;
281  case TOPOLOGY_OBSTACLES:
282  set_value_topology_obstacles(from, to, value);
283  break;
284  }
285  switch_to_application_mode();
286 }
287 
288 double GetValueTopology(unsigned from, unsigned to) {
289  switch_to_platform_mode();
290  const unsigned lp_cnt = topology_global.lp_cnt;
291 
292  double ret = -1;
293 
294  if(from >= lp_cnt || to >= lp_cnt)
295  rootsim_error(true, "SetValueTopology(): from % u, to %u when lp_cnt is %u", from, to, lp_cnt);
296 
297  switch (topology_settings.type) {
298  case TOPOLOGY_COSTS:
299  ret = get_value_topology_costs(from, to);
300  break;
302  ret = get_value_topology_probabilities(from, to);
303  break;
304  case TOPOLOGY_OBSTACLES:
305  ret = get_value_topology_obstacles(from, to);
306  break;
307  }
308  switch_to_application_mode();
309  return ret;
310 }
311 
312 void ProcessEventTopology(void){
313  switch(current_evt->type){
314  case TOPOLOGY_UPDATE:
315  switch (topology_settings.type) {
316  case TOPOLOGY_COSTS:
317  update_topology_costs();
318  break;
320  update_topology_probabilities();
321  break;
322  case TOPOLOGY_OBSTACLES:
323  update_topology_obstacles();
324  break;
325  default:
326  rootsim_error(true, "This shouldn't happen. Contact the maintainer");
327  }
328  break;
329  default:
330  switch_to_application_mode();
332  switch_to_platform_mode();
333  }
334 }
335 
336 unsigned int RegionsCount(void) {
337  return topology_global.lp_cnt;
338 }
339 
340 unsigned int DirectionsCount(void) {
341  return topology_global.directions;
342 }
343 
344 static bool is_reachable(unsigned int to){
345  bool result = false;
346  switch (topology_settings.type) {
348  result = is_reachable_probabilities(to);
349  break;
350  case TOPOLOGY_OBSTACLES:
351  result = is_reachable_obstacles(to);
352  break;
353  case TOPOLOGY_COSTS:
354  result = is_reachable_costs(to);
355  break;
356  }
357  return result;
358 }
359 
360 unsigned int NeighboursCount(unsigned region){
361  switch_to_platform_mode();
362  unsigned i = topology_global.directions;
363  unsigned res = 0;
364  unsigned lp_id;
365  while(i--){
366  if((lp_id = get_raw_receiver(region, i)) != DIRECTION_INVALID)
367  res++;
368  }
369  switch_to_application_mode();
370  return res;
371 }
372 
380 unsigned int get_raw_receiver(unsigned int from, direction_t direction) {
381  unsigned int x, y;
382  unsigned receiver;
383  // const so we don't accidentally modify it
384  const unsigned sender = from;
385  // the pre-computed edge length for geometries which require it
386  const unsigned edge = topology_global.edge;
387  // without modifications we would fail
388  receiver = DIRECTION_INVALID;
389 
390  switch (topology_global.geometry) {
391 
392  case TOPOLOGY_HEXAGON:
393  // Convert linear coords to square coords
394  y = sender / edge;
395  x = sender - y * edge;
396 
397  switch (direction) {
398  case DIRECTION_NW:
399  x += (y & 1U) - 1;
400  y -= 1;
401  break;
402  case DIRECTION_NE:
403  x += (y & 1U);
404  y -= 1;
405  break;
406  case DIRECTION_SW:
407  x += (y & 1U) - 1;
408  y += 1;
409  break;
410  case DIRECTION_SE:
411  x += (y & 1U);
412  y += 1;
413  break;
414  case DIRECTION_E:
415  x += 1;
416  break;
417  case DIRECTION_W:
418  x -= 1;
419  break;
420  default:
421  goto out;
422  }
423 
424  if(likely(x < edge && y < edge))
425  receiver = y * edge + x;
426 
427  break;
428 
429  case TOPOLOGY_SQUARE:
430  // Convert linear coords to square coords
431  y = sender / edge;
432  x = sender - y * edge;
433 
434  switch (direction) {
435  case DIRECTION_N:
436  y -= 1;
437  break;
438  case DIRECTION_S:
439  y += 1;
440  break;
441  case DIRECTION_E:
442  x += 1;
443  break;
444  case DIRECTION_W:
445  x -= 1;
446  break;
447  default:
448  goto out;
449  }
450 
451  if(likely(x < edge && y < edge))
452  receiver = y * edge + x;
453 
454  break;
455 
456  case TOPOLOGY_TORUS:
457  // Convert linear coords to square coords
458  y = sender / edge;
459  x = sender - y * edge;
460 
461  switch (direction) {
462  case DIRECTION_N:
463  y -= 1;
464  if(unlikely(y >= edge)){
465  y = edge - 1;
466  }
467  break;
468  case DIRECTION_S:
469  y += 1;
470  if(unlikely(y >= edge)){
471  y = 0;
472  }
473  break;
474  case DIRECTION_E:
475  x += 1;
476  if(unlikely(x >= edge)){
477  x = 0;
478  }
479  break;
480  case DIRECTION_W:
481  x -= 1;
482  if(unlikely(x >= edge)){
483  x = edge - 1;
484  }
485  break;
486  default:
487  goto out;
488  }
489 
490  // Convert back to linear coordinates
491  receiver = y * edge + x;
492 
493  break;
494 
495  case TOPOLOGY_GRAPH:
496  if(likely(direction < topology_global.lp_cnt))
497  receiver = direction;
498  break;
499 
500  case TOPOLOGY_BIDRING:
501  if(direction == DIRECTION_W) {
502  if(sender == 0) {
503  receiver = topology_global.lp_cnt - 1;
504  } else {
505  receiver =sender - 1;
506  }
507  } else if(likely(direction == DIRECTION_E)) {
508  if(sender + 1 == topology_global.lp_cnt)
509  receiver = 0;
510  else
511  receiver = sender + 1;
512  }
513 
514  break;
515 
516  case TOPOLOGY_RING:
517  if(likely(direction == DIRECTION_E)) {
518  receiver = sender + 1;
519 
520  if(receiver == topology_global.lp_cnt) {
521  receiver = 0;
522  }
523  }
524 
525  break;
526 
527  case TOPOLOGY_STAR:
528  if(sender) {
529  if(direction)
530  goto out;
531  receiver = 0;
532  } else {
533  if(direction + 1 >= topology_global.lp_cnt)
534  goto out;
535  receiver = direction + 1;
536  }
537 
538  break;
539 
540  default:
541  rootsim_error(true, "This shouldn't happen. Aborting...");
542  }
543 
544  out:
545  return receiver;
546 }
547 
548 unsigned int GetReceiver(unsigned int from, direction_t direction, bool reachable) {
549  unsigned receiver;
550  switch_to_platform_mode();
551  // sanity check
552  if(unlikely(topology_global.lp_cnt <= from))
553  rootsim_error(true, "GetReceiver(): region argument not included in topology!");
554 
555  receiver = get_raw_receiver(from, direction);
556  if(reachable && !is_reachable(receiver))
557  receiver = UINT_MAX;
558  switch_to_application_mode();
559  return receiver;
560 }
561 
562 bool IsReachable(unsigned int to){
563  bool result;
564  switch_to_platform_mode();
565  result = is_reachable(to);
566  switch_to_application_mode();
567  return result;
568 }
569 
570 unsigned int FindReceiver(void) {
571  switch_to_platform_mode();
572 
573  const unsigned lp_cnt = topology_global.lp_cnt;
574  unsigned receiver = DIRECTION_INVALID;
575 
576  if(unlikely(lp_cnt <= current->gid.to_int))
577  rootsim_error(true, "FindReceiver(): source region %u when topology includes %u regions", current->gid.to_int, lp_cnt);
578 
579  switch (topology_settings.type) {
581  receiver = find_receiver_probabilities();
582  break;
583  case TOPOLOGY_OBSTACLES:
584  receiver = find_receiver_obstacles();
585  break;
586  default:
587  rootsim_error(true, "FindReceiver(): topology type not supported!");
588  }
589 
590  switch_to_application_mode();
591  return receiver;
592 }
593 
594 unsigned int FindReceiverToward(unsigned int to) {
595  switch_to_platform_mode();
596 
597  const unsigned lp_cnt = topology_global.lp_cnt;
598  // fail by default
599  unsigned receiver = DIRECTION_INVALID;
600  // sanity checks
601  if(unlikely(to >= lp_cnt || current->gid.to_int >= lp_cnt))
602  rootsim_error(true, "Calling FindReceiverToward() from or toward a region not included in the topology");
603 
604  switch (topology_settings.type) {
605  case TOPOLOGY_COSTS:
606  receiver = find_receiver_toward_costs(to);
607  break;
608  case TOPOLOGY_OBSTACLES:
609  receiver = find_receiver_toward_obstacles(to);
610  break;
611  default:
612  rootsim_error(true, "FindReceiverToward(): unsupported topology type");
613  }
614  switch_to_application_mode();
615  return receiver;
616 }
617 
629 unsigned build_path(unsigned lp_cnt, unsigned result[lp_cnt], const unsigned int previous[lp_cnt], unsigned source, unsigned dest) {
630  unsigned mid_cell;
631  unsigned *res_aux;
632 
633  if(previous[dest] == UINT_MAX) {
634  // the wished destination is unreachable
635  return 0;
636  }
637  // we point to the latest element (we still don't know how long is the path)
638  res_aux = result + lp_cnt - 1;
639  // we fill in the obvious last hop
640  *res_aux = dest;
641 
642  unsigned hops = 1;
643 
644  mid_cell = previous[dest];
645  // while the previous hop is not the actual source
646  while (mid_cell != source) {
647  // we go further behind
648  res_aux--;
649  // we fill in the intermediate step
650  *res_aux = mid_cell;
651  // go behind you too!
652  mid_cell = previous[mid_cell];
653  // one more hop
654  ++hops;
655  }
656  // we move back the computed path
657  memmove(result, res_aux, ((result + lp_cnt) - res_aux) * sizeof(unsigned));
658  return hops;
659 }
660 
661 double ComputeMinTour(unsigned int source, unsigned int dest, unsigned int result[RegionsCount()]) {
662  switch_to_platform_mode();
663 
664  const unsigned lp_cnt = topology_global.lp_cnt;
665  double ret = -1.0;
666 
667  if(unlikely(source >= lp_cnt)) {
668  rootsim_error(true, "Invalid source passed to ComputeMinTour(): %u.\n", source);
669  return UINT_MAX;
670  }
671  if(unlikely(dest >= lp_cnt)) {
672  rootsim_error(true, "Invalid destination passed to ComputeMinTour(): %u.\n", dest);
673  return UINT_MAX;
674  }
675  if(unlikely(source == dest)) {
676  rootsim_error(true, "Asking ComputeMinTour() to find a path from a source equal to the destination\n");
677  return UINT_MAX;
678  }
679 
680  switch (topology_settings.type) {
681  case TOPOLOGY_COSTS:
682  ret = compute_min_tour_costs(source, dest, result);
683  break;
684  case TOPOLOGY_OBSTACLES:
685  ret = compute_min_tour_obstacles(source, dest, result);
686  break;
687  default:
688  rootsim_error(true, "ComputeMinTour(): unsupported topology type %u", topology_settings.type);
689  }
690  switch_to_application_mode();
691  return ret;
692 }
all crossing costs and probabilities are set to 1, but there can be not crossable regions ...
Definition: ROOT-Sim.h:126
Definition: jsmn.h:43
#define lvt(lp)
Definition: process.h:168
unsigned long long generate_mark(struct lp_struct *lp)
Definition: queues.c:270
#define likely(exp)
Optimize the branch as likely taken.
Definition: core.h:72
Initialization routines.
DIRECTION_W.
Definition: ROOT-Sim.h:112
enum _topology_geometry_t geometry
Definition: topology.h:22
A generic invalid direction.
Definition: ROOT-Sim.h:122
DIRECTION_SE.
Definition: ROOT-Sim.h:120
DIRECTION_E.
Definition: ROOT-Sim.h:111
DIRECTION_N.
Definition: ROOT-Sim.h:114
square grid topology
Definition: ROOT-Sim.h:91
ROOT-Sim header for model development.
unsigned chkp_size
Definition: topology.h:18
DIRECTION_NW.
Definition: ROOT-Sim.h:119
unsigned int to_int
The GID numerical value.
Definition: core.h:133
unsigned lp_cnt
Definition: topology.h:21
The ROOT-Sim scheduler main module header.
double GetValueTopology(unsigned from, unsigned to)
Definition: topology.c:288
This is the implementation of a dynamic array, used for managing various data structures.
_topology_geometry_t
Definition: ROOT-Sim.h:88
a torus shaped grid topology (a wrapping around square topology)
Definition: ROOT-Sim.h:94
__thread struct lp_struct * current
This is a per-thread variable pointing to the block state of the LP currently scheduled.
Definition: scheduler.c:72
Numerical Library.
DIRECTION_S.
Definition: ROOT-Sim.h:115
hexagonal grid topology
Definition: ROOT-Sim.h:90
double simtime_t
This defines the type with whom timestamps are represented.
Definition: ROOT-Sim.h:55
void SetValueTopology(unsigned from, unsigned to, double value)
Definition: topology.c:261
simulation_configuration rootsim_config
This global variable holds the configuration for the current simulation.
Definition: core.c:70
__thread msg_t * current_evt
Definition: scheduler.c:83
decisions are taken at random but are weighted on the palatability of neighbours
Definition: ROOT-Sim.h:128
Message Type definition.
Definition: core.h:164
unsigned int size
Unique identifier of the message, used for rendez-vous events.
Definition: core.h:189
Serial scheduler.
enum _direction_t direction_t
void insert_outgoing_msg(msg_t *msg)
Place a message in the temporary LP outgoing buffer.
unsigned edge
Definition: topology.h:20
unsigned directions
Definition: topology.h:19
LP control blocks.
void pack_msg(msg_t **msg, GID_t sender, GID_t receiver, int type, simtime_t timestamp, simtime_t send_time, size_t size, void *payload)
Pack a message in a platform-level data structure.
an arbitrary shaped topology
Definition: ROOT-Sim.h:96
Definition of a GID.
Definition: core.h:132
a ring shaped topology direction
Definition: ROOT-Sim.h:93
GID_t gid
Global ID of the LP.
Definition: process.h:82
short unsigned int state
Current execution state of the LP.
Definition: process.h:88
arbitrary offset used to distinguish during debug different enums
Definition: ROOT-Sim.h:89
Bitmap data type.
DIRECTION_SW.
Definition: ROOT-Sim.h:118
decisions on next hops are taken based on the costs undertaken to cross the boundaries ...
Definition: ROOT-Sim.h:127
void(* ProcessEvent)(unsigned int me, simtime_t now, int event_type, void *event_content, unsigned int size, void *state)
Definition: process.h:136
a ring shaped topology walkable in a single direction
Definition: ROOT-Sim.h:92
this is used to store the common characteristics of the topology
Definition: topology.h:17
_topology_type_t
Definition: ROOT-Sim.h:125
unsigned int n_prc_tot
Total number of logical processes running in the simulation.
Definition: core.c:64
bool serial
If the simulation must be run serially.
Definition: init.h:72
void * current_base_pointer
The current state base pointer (updated by SetState())
Definition: process.h:100
#define unlikely(exp)
Optimize the branch as likely not taken.
Definition: core.h:74
DIRECTION_NE.
Definition: ROOT-Sim.h:117