The ROme OpTimistic Simulator  3.0.0
A General-Purpose Multithreaded Parallel/Distributed Simulation Platform
serial.c
Go to the documentation of this file.
1 
9 #include <serial/serial.h>
10 
11 #include <arch/timer.h>
12 #include <core/core.h>
13 #include <core/init.h>
14 #include <datatypes/heap.h>
15 #include <lib/lib.h>
16 #include <log/stats.h>
17 #include <lp/msg.h>
18 #include <mm/msg_allocator.h>
19 
20 #include <stdlib.h>
21 
23 struct s_lp_ctx {
25  struct lib_ctx lib_ctx;
26 #if LOG_DEBUG >= LOG_LEVEL
29 #endif
30  bool terminating;
32 };
33 
35 static struct s_lp_ctx *s_lps;
37 static struct s_lp_ctx *s_current_lp;
39 static binary_heap(struct lp_msg *) queue;
40 #if LOG_DEBUG >= LOG_LEVEL
41 static simtime_t current_evt_time;
43 #endif
44 
45 void serial_model_init(void)
46 {
47  struct s_lp_ctx tmp_lp = {0};
48  s_current_lp = &tmp_lp;
50 
51  lib_lp_init();
52  ProcessEvent(0, 0, MODEL_INIT, NULL, 0, NULL);
53  lib_lp_fini();
54 }
55 
59 static void serial_simulation_init(void)
60 {
62  stats_init();
63  msg_allocator_init();
64  heap_init(queue);
65  lib_global_init();
66  serial_model_init();
67 
68  s_lps = mm_alloc(sizeof(*s_lps) * n_lps);
69  memset(s_lps, 0, sizeof(*s_lps) * n_lps);
70 
71  for (uint64_t i = 0; i < n_lps; ++i) {
72  s_current_lp = &s_lps[i];
73  lib_lp_init();
74 #if LOG_DEBUG >= LOG_LEVEL
75  s_lps[i].last_evt_time = -1;
76 #endif
77  ProcessEvent(i, 0, LP_INIT, NULL, 0, s_lps[i].lib_ctx.state_s);
78  }
79 }
80 
84 static void serial_simulation_fini(void)
85 {
86  for (uint64_t i = 0; i < n_lps; ++i) {
87  s_current_lp = &s_lps[i];
88  ProcessEvent(i, 0, LP_FINI, NULL, 0, s_lps[i].lib_ctx.state_s);
89  lib_lp_fini();
90  }
91 
92  ProcessEvent(0, 0, MODEL_FINI, NULL, 0, NULL);
93 
94  for (array_count_t i = 0; i < array_count(queue); ++i) {
95  msg_allocator_free(array_get_at(queue, i));
96  }
97 
98  mm_free(s_lps);
99 
100  lib_global_fini();
101  heap_fini(queue);
102  msg_allocator_fini();
104 }
105 
109 static void serial_simulation_run(void)
110 {
111  timer_uint last_vt = timer_new();
112  uint64_t to_terminate = n_lps;
113 
114  while (likely(!heap_is_empty(queue))) {
115  const struct lp_msg *cur_msg = heap_min(queue);
116  struct s_lp_ctx *this_lp = &s_lps[cur_msg->dest];
117  s_current_lp = this_lp;
118 
119 #if LOG_DEBUG >= LOG_LEVEL
120  if (log_can_log(LOG_DEBUG)) {
121  if(cur_msg->dest_t == s_current_lp->last_evt_time)
122  log_log(
123  LOG_DEBUG,
124  "LP %u got two consecutive events with same timestamp %lf",
125  cur_msg->dest,
126  cur_msg->dest_t
127  );
128  s_current_lp->last_evt_time = cur_msg->dest_t;
129  }
130  current_evt_time = cur_msg->dest_t;
131 #endif
132 
133  stats_time_start(STATS_MSG_PROCESSED);
134 
135  ProcessEvent(
136  cur_msg->dest,
137  cur_msg->dest_t,
138  cur_msg->m_type,
139  cur_msg->pl,
140  cur_msg->pl_size,
141  s_current_lp->lib_ctx.state_s
142  );
143 
144  stats_time_take(STATS_MSG_PROCESSED);
145 
146  bool can_end = CanEnd(cur_msg->dest, s_current_lp->lib_ctx.state_s);
147 
148  if (can_end != s_current_lp->terminating) {
149  s_current_lp->terminating = can_end;
150  to_terminate += 1 - ((int)can_end * 2);
151 
152  if (unlikely(!to_terminate)) {
153  stats_on_gvt(cur_msg->dest_t);
154  break;
155  }
156  }
157 
158  if (global_config.gvt_period <= timer_value(last_vt)) {
159  stats_on_gvt(cur_msg->dest_t);
160  if (unlikely(cur_msg->dest_t >=
162  break;
163  last_vt = timer_new();
164  }
165 
166  msg_allocator_free(heap_extract(queue, msg_is_before));
167  }
168 
169  stats_dump();
170 }
171 
172 void ScheduleNewEvent(lp_id_t receiver, simtime_t timestamp,
173  unsigned event_type, const void *payload, unsigned payload_size)
174 {
175 #if LOG_DEBUG >= LOG_LEVEL
176  if (log_can_log(LOG_DEBUG) && current_evt_time > timestamp)
177  log_log(LOG_DEBUG, "Sending a message in the PAST!");
178 #endif
179 
180  struct lp_msg *msg = msg_allocator_pack(
181  receiver, timestamp, event_type, payload, payload_size);
182  heap_insert(queue, msg_is_before, msg);
183 }
184 
189 {
190  log_log(LOG_INFO, "Initializing serial simulation");
192  stats_global_time_take(STATS_GLOBAL_INIT_END);
193 
194  stats_global_time_take(STATS_GLOBAL_EVENTS_START);
195  log_log(LOG_INFO, "Starting simulation");
197  stats_global_time_take(STATS_GLOBAL_EVENTS_END);
198 
199  stats_global_time_take(STATS_GLOBAL_FINI_START);
200  log_log(LOG_INFO, "Finalizing simulation");
202 }
203 
204 lp_id_t lp_id_get(void)
205 {
206  return s_current_lp - s_lps;
207 }
208 
209 struct lib_ctx *lib_ctx_get(void)
210 {
211  return &s_current_lp->lib_ctx;
212 }
stats_init
void stats_init(void)
Initializes the stats subsystem in the current thread.
Definition: stats.c:179
simtime_t
double simtime_t
The type used to represent logical time in the simulation.
Definition: core.h:62
heap_fini
#define heap_fini(self)
Finalizes an heap.
Definition: heap.h:32
lib.h
Model library main header.
LOG_DEBUG
#define LOG_DEBUG
The logging level reserved to useful debug messages.
Definition: log.h:27
s_current_lp
static struct s_lp_ctx * s_current_lp
The context of the currently processed LP.
Definition: serial.c:37
lp_msg::m_type
uint_fast32_t m_type
The message type, a user controlled field.
Definition: msg.h:40
s_lps
static struct s_lp_ctx * s_lps
The array of all the simulation LP contexts.
Definition: serial.c:35
s_lp_ctx::terminating
bool terminating
The last evaluation of the termination predicate for this LP.
Definition: serial.c:31
n_lps
lp_id_t n_lps
The total number of LPs in the simulation.
Definition: core.c:13
s_lp_ctx::last_evt_time
simtime_t last_evt_time
The logical time of the last processed event by this LP.
Definition: serial.c:28
binary_heap
static binary_heap(struct lp_msg *)
The messages queue of the serial runtime.
Definition: serial.c:39
mm_alloc
void * mm_alloc(size_t mem_size)
A version of the stdlib malloc() used internally.
Definition: mm.h:26
simulation_configuration::termination_time
simtime_t termination_time
The target termination logical time.
Definition: init.h:22
stats_global_fini
void stats_global_fini(void)
Finalizes the stats subsystem in the node.
Definition: stats.c:273
lp_msg
A model simulation message.
Definition: msg.h:34
simulation_configuration::gvt_period
unsigned gvt_period
The gvt period expressed in microseconds.
Definition: init.h:24
ProcessEvent
void ProcessEvent(lp_id_t me, simtime_t now, unsigned event_type, const void *content, unsigned size, void *state)
The total number of threads running in the node.
Definition: application.c:21
msg_allocator.h
Memory management functions for messages.
msg.h
Message management functions.
lp_msg::dest
lp_id_t dest
The id of the recipient LP.
Definition: msg.h:36
serial_simulation
void serial_simulation(void)
Handles a full serial simulation runs.
Definition: serial.c:188
timer_uint
uint_fast64_t timer_uint
Definition: timer.h:20
heap_insert
#define heap_insert(self, cmp_f, elem)
Inserts an element into the heap.
Definition: heap.h:47
stats.h
Statistics module.
s_lp_ctx
The LP context for the serial runtime.
Definition: serial.c:23
init.h
Initialization routines.
log_log
#define log_log(lvl,...)
Produces a log.
Definition: log.h:49
s_lp_ctx::lib_ctx
struct lib_ctx lib_ctx
The context for the model development libraries.
Definition: serial.c:25
timer.h
Timers.
serial_simulation_init
static void serial_simulation_init(void)
Initializes the serial simulation environment.
Definition: serial.c:59
array_count_t
uint_fast32_t array_count_t
The type used to handle dynamic arrays count of elements and capacity.
Definition: array.h:21
serial_simulation_run
static void serial_simulation_run(void)
Runs the serial simulation.
Definition: serial.c:109
serial_simulation_fini
static void serial_simulation_fini(void)
Finalizes the serial simulation environment.
Definition: serial.c:84
mm_free
void mm_free(void *ptr)
A version of the stdlib free() used internally.
Definition: mm.h:61
LOG_INFO
#define LOG_INFO
The logging level reserved to useful runtime messages.
Definition: log.h:29
serial.h
Sequential simlation engine.
likely
#define likely(exp)
Optimize the branch as likely taken.
Definition: core.h:57
lib_ctx
Definition: lib.h:17
lp_msg::pl
unsigned char pl[48]
The initial part of the payload.
Definition: msg.h:54
array_count
#define array_count(self)
Gets the count of contained element in a dynamic array.
Definition: array.h:47
lp_id_t
uint64_t lp_id_t
Used to uniquely identify LPs in the simulation.
Definition: core.h:75
core.h
Core ROOT-Sim functionalities.
lp_msg::pl_size
uint_fast32_t pl_size
The message payload size.
Definition: msg.h:46
heap_extract
#define heap_extract(self, cmp_f)
Extracts an element from the heap.
Definition: heap.h:72
unlikely
#define unlikely(exp)
Optimize the branch as likely not taken.
Definition: core.h:59
global_config
struct simulation_configuration global_config
The configuration filled in by init_args_parse()
Definition: init.c:27
stats_global_init
void stats_global_init(void)
Initializes the stats subsystem in the node.
Definition: stats.c:162
timer_value
timer_uint timer_value(timer_uint start)
Computes a time interval measure using a previous timer_uint value.
heap_init
#define heap_init(self)
Initializes an empty heap.
Definition: heap.h:24
stats_global_time_take
void stats_global_time_take(enum stats_global_time this_stat)
Initializes the internal timer used to take accurate measurements.
Definition: stats.c:154
lp_msg::dest_t
simtime_t dest_t
The intended destination logical time of this message.
Definition: msg.h:38
log_can_log
#define log_can_log(lvl)
Checks if a logging level is being processed.
Definition: log.h:42
heap.h
Heap datatype.
timer_new
timer_uint timer_new(void)
Gets a new starting point for an time interval measure.