Line data Source code
1 1 : /**
2 : * @file core/core.c
3 : *
4 : * @brief Core ROOT-Sim functionalities
5 : *
6 : * Core ROOT-Sim functionalities
7 : *
8 : * @copyright
9 : * Copyright (C) 2008-2019 HPDCS Group
10 : * https://hpdcs.github.io
11 : *
12 : * This file is part of ROOT-Sim (ROme OpTimistic Simulator).
13 : *
14 : * ROOT-Sim is free software; you can redistribute it and/or modify it under the
15 : * terms of the GNU General Public License as published by the Free Software
16 : * Foundation; only version 3 of the License applies.
17 : *
18 : * ROOT-Sim is distributed in the hope that it will be useful, but WITHOUT ANY
19 : * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
20 : * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 : *
22 : * You should have received a copy of the GNU General Public License along with
23 : * ROOT-Sim; if not, write to the Free Software Foundation, Inc.,
24 : * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 : *
26 : * @author Francesco Quaglia
27 : * @author Alessandro Pellegrini
28 : * @author Roberto Vitali
29 : *
30 : * @date 3/18/2011
31 : */
32 :
33 : #include <stdlib.h>
34 : #include <stdio.h>
35 : #include <stdarg.h>
36 : #include <limits.h>
37 : #include <signal.h>
38 :
39 : #include <arch/thread.h>
40 : #include <core/core.h>
41 : #include <core/init.h>
42 : #include <scheduler/process.h>
43 : #include <scheduler/scheduler.h>
44 : #include <statistics/statistics.h>
45 : #include <gvt/gvt.h>
46 : #include <mm/mm.h>
47 :
48 : /// Barrier for all worker threads
49 1 : barrier_t all_thread_barrier;
50 :
51 : /// Mapping between kernel instances and logical processes
52 1 : unsigned int *kernel;
53 :
54 : /// Identifier of the local kernel
55 1 : unsigned int kid;
56 :
57 : /// Total number of simulation kernel instances running
58 1 : unsigned int n_ker;
59 :
60 : /// Total number of cores required for simulation
61 1 : unsigned int n_cores;
62 :
63 : /// Total number of logical processes running in the simulation
64 1 : unsigned int n_prc_tot;
65 :
66 : /// Number of logical processes hosted by the current kernel instance
67 1 : unsigned int n_prc;
68 :
69 : /// This global variable holds the configuration for the current simulation
70 1 : simulation_configuration rootsim_config;
71 :
72 : /// Flag to notify all workers that there was an error
73 1 : static bool sim_error = false;
74 :
75 : /// This flag tells whether we are exiting from the kernel of from userspace
76 1 : bool exit_silently_from_kernel = false;
77 :
78 : /// This flag is set when the initialization of the simulator is complete, with no errors
79 1 : static bool init_complete = false;
80 :
81 0 : bool user_exit_flag = false;
82 :
83 : /**
84 : * This function is used to terminate with not much pain the simulation
85 : * if the user model inadvertently calls exit(). It displays a warning
86 : * message, and then tries to silently shutdown.
87 : * The software enters this function using the standard atexit() API.
88 : *
89 : * @author Alessandro Pellegrini
90 : */
91 1 : void exit_from_simulation_model(void)
92 : {
93 :
94 : if (likely(!init_complete))
95 : return;
96 :
97 : if (unlikely(!exit_silently_from_kernel)) {
98 : exit_silently_from_kernel = true;
99 :
100 : printf("Warning: exit() has been called from the model.\n"
101 : "The simulation will now halt, but its unlikely what you really wanted...\n"
102 : "You should use OnGVT() instead. See the manpages for an explanation.\n");
103 :
104 : simulation_shutdown(EXIT_FAILURE);
105 : }
106 : }
107 :
108 0 : inline bool user_requested_exit(void)
109 : {
110 : return user_exit_flag;
111 : }
112 :
113 0 : static void handle_signal(int signum)
114 : {
115 : if (signum == SIGINT) {
116 : user_exit_flag = true;
117 : }
118 : }
119 :
120 : /**
121 : * This function initilizes basic functionalities within ROOT-Sim. In particular, it
122 : * creates a mapping between logical processes and kernel instances.
123 : *
124 : * @author Francesco Quaglia
125 : * @author Roberto Vitali
126 : * @author Alessandro Pellegrini
127 : *
128 : */
129 1 : void base_init(void)
130 : {
131 : struct sigaction new_act = { 0 };
132 :
133 : barrier_init(&all_thread_barrier, n_cores);
134 :
135 : // complete the sigaction struct init
136 : new_act.sa_handler = handle_signal;
137 : // we set the signal action so that it auto disarms itself after the first invocation
138 : new_act.sa_flags = SA_RESETHAND;
139 : // register the signal handler
140 : sigaction(SIGINT, &new_act, NULL);
141 : // register the exit function
142 : atexit(exit_from_simulation_model);
143 : }
144 :
145 : /**
146 : * This function finalizes the core structures of ROOT-Sim, just before terminating a simulation
147 : *
148 : * @author Roberto Vitali
149 : *
150 : */
151 1 : void base_fini(void)
152 : {
153 : }
154 :
155 : /**
156 : * Creates a mapping between logical processes and kernel instances
157 : *
158 : * @author Francesco Quaglia
159 : *
160 : * @param gid The logical process' global identifier
161 : * @return The id of the kernel currently hosting the logical process
162 : */
163 : __attribute__((pure))
164 1 : unsigned int find_kernel_by_gid(GID_t gid)
165 : {
166 : // restituisce il kernel su cui si trova il processo identificato da gid
167 : return kernel[gid.to_int];
168 : }
169 :
170 : /**
171 : * This function calls all the finalization functions exposed by subsystems and then
172 : * exits.
173 : *
174 : * @author Alessandro Pellegrini
175 : *
176 : * @param code The exit code to be returned by the process
177 : */
178 1 : void simulation_shutdown(int code)
179 : {
180 :
181 : exit_silently_from_kernel = true;
182 :
183 : statistics_stop(code);
184 :
185 : if (likely(rootsim_config.serial == false)) {
186 :
187 : thread_barrier(&all_thread_barrier);
188 :
189 : if (master_thread()) {
190 : statistics_fini();
191 : gvt_fini();
192 : communication_fini();
193 : scheduler_fini();
194 : base_fini();
195 : }
196 :
197 : thread_barrier(&all_thread_barrier);
198 : }
199 :
200 : exit(code);
201 : }
202 :
203 0 : inline bool simulation_error(void)
204 : {
205 : return sim_error;
206 : }
207 :
208 : /**
209 : * A variadic function which prints out error messages. If the errors are marked as fatal,
210 : * the simulation is correctly shut down.
211 : *
212 : * @author Alessandro Pellegrini
213 : *
214 : * @param fatal This flag marks an error as fatal (true) or not (false)
215 : * @param msg The error message to be printed out. This can be specified as in the printf()
216 : * format message, thus a matching number of extra parameters can be passed.
217 : *
218 : * @todo If a fatal error is received, write it on the log file as well!
219 : */
220 1 : void _rootsim_error(bool fatal, const char *msg, ...)
221 : {
222 : char buf[1024];
223 : va_list args;
224 :
225 : va_start(args, msg);
226 : vsnprintf(buf, 1024, msg, args);
227 : va_end(args);
228 :
229 : fprintf(stderr, (fatal ? "[FATAL ERROR] " : "[WARNING] "));
230 :
231 : fprintf(stderr, "%s", buf);
232 : fflush(stderr);
233 :
234 : if (fatal) {
235 : if (rootsim_config.serial) {
236 : exit(EXIT_FAILURE);
237 : } else {
238 :
239 : if (!init_complete) {
240 : exit(EXIT_FAILURE);
241 : }
242 :
243 : // Notify all KLT to shut down the simulation
244 : sim_error = true;
245 :
246 : // Bye bye main loop!
247 : longjmp(exit_jmp, 1);
248 : }
249 : }
250 : }
251 :
252 : /**
253 : * This function maps logical processes onto kernel instances
254 : *
255 : * @author Francesco Quaglia
256 : * @author Alessandro Pellegrini
257 : */
258 1 : void distribute_lps_on_kernels(void)
259 : {
260 : register unsigned int i = 0;
261 : unsigned int j;
262 : unsigned int buf1;
263 : int offset;
264 : int block_leftover;
265 :
266 : // Sanity check on number of LPs
267 : if (n_prc_tot < n_ker) {
268 : rootsim_error(true, "Unable to allocate %d logical processes on %d kernels: must have at least %d LPs\n", n_prc_tot, n_ker, n_ker);
269 : }
270 :
271 : kernel = (unsigned int *)rsalloc(sizeof(unsigned int) * n_prc_tot);
272 :
273 : switch (rootsim_config.lps_distribution) {
274 :
275 : case LP_DISTRIBUTION_BLOCK:
276 : buf1 = (n_prc_tot / n_ker);
277 : block_leftover = n_prc_tot - buf1 * n_ker;
278 :
279 : // It is a hack to bypass the first check that set offset to 0
280 : if (block_leftover > 0)
281 : buf1++;
282 :
283 : offset = 0;
284 : while (i < n_prc_tot) {
285 : j = 0;
286 : while (j < buf1) {
287 : kernel[i] = offset;
288 :
289 : if (kernel[i] == kid)
290 : n_prc++;
291 :
292 : i++;
293 : j++;
294 : }
295 : offset++;
296 : block_leftover--;
297 : if (block_leftover == 0)
298 : buf1--;
299 : }
300 : break;
301 :
302 : case LP_DISTRIBUTION_CIRCULAR:
303 : for (i = 0; i < n_prc_tot; i++) {
304 : kernel[i] = i % n_ker;
305 :
306 : if (kernel[i] == kid)
307 : n_prc++;
308 : }
309 : break;
310 : }
311 : }
312 :
313 : /**
314 : * This function records that the initialization is complete.
315 : */
316 1 : void initialization_complete(void)
317 : {
318 : init_complete = true;
319 : }
|