Line data Source code
1 1 : /**
2 : * @file serial/serial.c
3 : *
4 : * @brief Sequential simlation engine
5 : *
6 : * SPDX-FileCopyrightText: 2008-2021 HPDCS Group <rootsim@googlegroups.com>
7 : * SPDX-License-Identifier: GPL-3.0-only
8 : */
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 :
22 : /// The LP context for the serial runtime
23 1 : struct s_lp_ctx {
24 : /// The context for the model development libraries
25 : struct lib_ctx lib_ctx;
26 : #if LOG_DEBUG >= LOG_LEVEL
27 : /// The logical time of the last processed event by this LP
28 1 : simtime_t last_evt_time;
29 : #endif
30 : /// The last evaluation of the termination predicate for this LP
31 1 : bool terminating;
32 : };
33 :
34 : /// The array of all the simulation LP contexts
35 1 : static struct s_lp_ctx *s_lps;
36 : /// The context of the currently processed LP
37 1 : static struct s_lp_ctx *s_current_lp;
38 : /// The messages queue of the serial runtime
39 1 : static binary_heap(struct lp_msg *) queue;
40 : #if LOG_DEBUG >= LOG_LEVEL
41 : /// Used for debugging possibly inconsistent models
42 : 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;
49 : s_lps = s_current_lp - n_lps;
50 :
51 : lib_lp_init();
52 : ProcessEvent(0, 0, MODEL_INIT, NULL, 0, NULL);
53 : lib_lp_fini();
54 : }
55 :
56 : /**
57 : * @brief Initializes the serial simulation environment
58 : */
59 1 : static void serial_simulation_init(void)
60 : {
61 : stats_global_init();
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 :
81 : /**
82 : * @brief Finalizes the serial simulation environment
83 : */
84 1 : 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();
103 : stats_global_fini();
104 : }
105 :
106 : /**
107 : * @brief Runs the serial simulation
108 : */
109 1 : 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 >=
161 : global_config.termination_time))
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 0 : 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 :
185 : /**
186 : * @brief Handles a full serial simulation runs
187 : */
188 1 : void serial_simulation(void)
189 : {
190 : log_log(LOG_INFO, "Initializing serial simulation");
191 : serial_simulation_init();
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");
196 : serial_simulation_run();
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");
201 : serial_simulation_fini();
202 : }
203 :
204 0 : lp_id_t lp_id_get(void)
205 : {
206 : return s_current_lp - s_lps;
207 : }
208 :
209 0 : struct lib_ctx *lib_ctx_get(void)
210 : {
211 : return &s_current_lp->lib_ctx;
212 : }
|