4 /* Copyright (c) 2002,2003,2004 Arnaud Legrand. All rights reserved. */
6 /* This program is free software; you can redistribute it and/or modify it
7 * under the terms of the license (GNU LGPL) which comes with this package. */
10 #include "xbt/sysdep.h"
12 #include "xbt/ex.h" /* ex_backtrace_display */
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_kernel, msg,
14 "Logging specific to MSG (kernel)");
16 int __stop_at_time = -1.0 ;
18 MSG_Global_t msg_global = NULL;
20 /* static void MarkAsFailed(m_task_t t, TBX_HashTable_t failedProcessList); */
21 /* static xbt_fifo_t MSG_buildFailedHostList(double a, double b); */
23 /** \defgroup msg_simulation MSG simulation Functions
24 * \brief This section describes the functions you need to know to
25 * set up a simulation. You should have a look at \ref MSG_examples
26 * to have an overview of their usage.
29 /** \addtogroup msg_simulation
30 * \htmlonly <!-- DOXYGEN_NAVBAR_LABEL="Simulation functions" --> \endhtmlonly
33 /********************************* MSG **************************************/
35 /** \ingroup msg_simulation
36 * \brief Initialize some MSG internal data.
38 void MSG_global_init_args(int *argc, char **argv)
40 MSG_global_init(argc,argv);
43 /** \ingroup msg_simulation
44 * \brief Initialize some MSG internal data.
46 void MSG_global_init(int *argc, char **argv)
49 surf_init(argc, argv); /* Initialize some common structures. Warning, it sets msg_global=NULL */
51 msg_global = xbt_new0(s_MSG_Global_t,1);
53 msg_global->host = xbt_fifo_new();
54 msg_global->process_to_run = xbt_fifo_new();
55 msg_global->process_list = xbt_fifo_new();
56 msg_global->max_channel = 0;
57 msg_global->current_process = NULL;
58 msg_global->registered_functions = xbt_dict_new();
60 msg_global->task_mallocator = xbt_mallocator_new(256,
61 (pvoid_f_void_t*) task_mallocator_new_f,
62 (void_f_pvoid_t*) task_mallocator_free_f,
63 (void_f_pvoid_t*) task_mallocator_reset_f);
67 /** \ingroup msg_easier_life
68 * \brief Traces MSG events in the Paje format.
70 void MSG_paje_output(const char *filename)
73 const char *paje_preembule=
74 "%EventDef PajeDefineContainerType 1\n"
76 "% ContainerType string\n"
79 "%EventDef PajeDefineStateType 3\n"
81 "% ContainerType string\n"
84 "%EventDef PajeDefineLinkType 5\n"
86 "% ContainerType string\n"
87 "% SourceContainerType string\n"
88 "% DestContainerType string\n"
91 "%EventDef PajeDefineEntityValue 6\n"
93 "% EntityType string\n"
96 "%EventDef PajeCreateContainer 7\n"
98 "% NewContainer string\n"
99 "% NewContainerType string\n"
100 "% Container string\n"
103 "%EventDef PajeDestroyContainer 8\n"
108 "%EventDef PajeSetState 10\n"
110 "% EntityType string\n"
111 "% Container string\n"
114 "%EventDef PajePushState 11\n"
116 "% EntityType string\n"
117 "% Container string\n"
119 "% TaskName string\n"
121 "%EventDef PajePopState 12\n"
123 "% EntityType string\n"
124 "% Container string\n"
126 "%EventDef PajeStartLink 16\n"
128 "% EntityType string\n"
129 "% Container string\n"
131 "% SourceContainer string\n"
134 "%EventDef PajeEndLink 17\n"
136 "% EntityType string\n"
137 "% Container string\n"
139 "% DestContainer string\n"
143 const char *type_definitions = "1 Sim_t 0 Simulation_t\n"
144 "1 H_t Sim_t m_host_t\n"
145 "1 P_t H_t m_process_t\n"
146 "3 S_t P_t \"Process State\"\n"
147 "6 E S_t Executing\n"
149 "6 C S_t Communicating\n"
150 "5 Comm Sim_t P_t P_t Communication_t\n";
152 const char *ext = ".trace";
153 int ext_len = strlen(ext);
157 xbt_fifo_item_t item = NULL;
159 xbt_assert0(msg_global, "Initialize MSG first\n");
160 xbt_assert0(!msg_global->paje_output, "Paje output already defined\n");
161 xbt_assert0(filename, "Need a real file name\n");
163 len = strlen(filename);
164 if((len<ext_len) || (strncmp(filename+len-ext_len,ext,ext_len))) {
165 CRITICAL2("The name of the Paje trace file \"%s\" does not end by \"%s\". Paje will cause difficulties to read it.\n",
169 msg_global->paje_output=fopen(filename,"w");
170 xbt_assert1(msg_global->paje_output, "Failed to open %s \n",filename);
172 fprintf(msg_global->paje_output,"%s",paje_preembule);
173 fprintf(msg_global->paje_output,"%s",type_definitions);
176 for(i=0; i<msg_global->max_channel; i++) {
177 fprintf(msg_global->paje_output, "6 COMM_%d Comm \"Channel %d\"\n" ,i,i);
179 fprintf(msg_global->paje_output,
180 "7 0.0 CUR Sim_t 0 \"MSG simulation\"\n");
183 xbt_fifo_foreach(msg_global->host,item,host,m_host_t) {
188 xbt_fifo_foreach(msg_global->process_list,item,process,m_process_t) {
189 PAJE_PROCESS_NEW(process);
193 /** \defgroup m_channel_management Understanding channels
194 * \brief This section briefly describes the channel notion of MSG
198 /** \addtogroup m_channel_management
199 * \htmlonly <!-- DOXYGEN_NAVBAR_LABEL="Channels" --> \endhtmlonly
201 * For convenience, the simulator provides the notion of channel
202 * that is close to the tag notion in MPI. A channel is not a
203 * socket. It doesn't need to be opened neither closed. It rather
204 * corresponds to the ports opened on the different machines.
208 /** \ingroup m_channel_management
209 * \brief Set the number of channel in the simulation.
211 * This function has to be called to fix the number of channel in the
212 simulation before creating any host. Indeed, each channel is
213 represented by a different mailbox on each #m_host_t. This
214 function can then be called only once. This function takes only one
216 * \param number the number of channel in the simulation. It has to be >0
218 MSG_error_t MSG_set_channel_number(int number)
220 xbt_assert0((msg_global) && (msg_global->max_channel == 0), "Channel number already set!");
222 msg_global->max_channel = number;
227 /** \ingroup m_channel_management
228 * \brief Return the number of channel in the simulation.
230 * This function has to be called once the number of channel is fixed. I can't
231 figure out a reason why anyone would like to call this function but nevermind.
232 * \return the number of channel in the simulation.
234 int MSG_get_channel_number(void)
236 xbt_assert0((msg_global)&&(msg_global->max_channel != 0), "Channel number not set yet!");
238 return msg_global->max_channel;
241 void __MSG_display_process_status(void)
243 m_process_t process = NULL;
244 xbt_fifo_item_t item = NULL;
246 int nbprocess=xbt_fifo_size(msg_global->process_list);
248 INFO1("MSG: %d processes are still running, waiting for something.",
250 /* List the process and their state */
251 INFO0("MSG: <process>(<pid>) on <host>: <status>.");
252 xbt_fifo_foreach(msg_global->process_list,item,process,m_process_t) {
253 simdata_process_t p_simdata = (simdata_process_t) process->simdata;
254 simdata_host_t h_simdata=(simdata_host_t)p_simdata->host->simdata;
257 asprintf(&who,"MSG: %s(%d) on %s: %s",
258 process->name,p_simdata->PID,
259 p_simdata->host->name,
260 (process->simdata->blocked)?"[blocked] "
261 :((process->simdata->suspended)?"[suspended] ":""));
263 for (i=0; i<msg_global->max_channel; i++) {
264 if (h_simdata->sleeping[i] == process) {
265 INFO2("%s\tListening on channel %d",who,i);
269 if (i==msg_global->max_channel) {
270 if(p_simdata->waiting_task) {
271 if(p_simdata->waiting_task->simdata->compute) {
272 if(p_simdata->put_host) {
273 INFO4("%s\tTrying to send the task '%s' to Host %s, channel %d.",
274 who, p_simdata->waiting_task->name,p_simdata->put_host->name, p_simdata->put_channel);
276 INFO2("%s\tWaiting for %s to finish.",who,p_simdata->waiting_task->name);
278 } else if (p_simdata->waiting_task->simdata->comm) {
279 INFO2("%s\tWaiting for %s to be finished transfered.",
280 who,p_simdata->waiting_task->name);
282 INFO1("%s\tUNKNOWN STATUS. Please report this bug.",who);
284 /* The following would display the trace of where the maestro thread is,
285 since this is the thread calling this. I'd like to get the other threads to
286 run this to see where they were blocked, but I'm not sure of how to do this */
287 /* xbt_backtrace_display(); */
288 } else { /* Must be trying to put a task somewhere */
289 INFO1("%s\tUNKNOWN STATUS. Please report this bug.",who);
296 /* FIXME: Yeah, I'll do it in a portable maner one day [Mt] */
299 static void _XBT_CALL inthandler(int ignored)
301 INFO0("CTRL-C pressed. Displaying status and bailing out");
302 __MSG_display_process_status();
306 /** \ingroup msg_simulation
307 * \brief Launch the MSG simulation
309 MSG_error_t MSG_main(void)
311 m_process_t process = NULL;
313 double elapsed_time = 0.0;
314 int state_modifications = 1;
316 /* Prepare to display some more info when dying on Ctrl-C pressing */
317 signal(SIGINT,inthandler);
319 /* Clean IO before the run */
323 surf_solve(); /* Takes traces into account. Returns 0.0 */
324 /* xbt_fifo_size(msg_global->process_to_run) */
326 xbt_context_empty_trash();
327 if(xbt_fifo_size(msg_global->process_to_run) && (elapsed_time>0)) {
328 DEBUG0("**************************************************");
330 if((__stop_at_time>0) && (MSG_get_clock() >= __stop_at_time)) {
331 DEBUG0("Let's stop here!");
334 while ((process = xbt_fifo_pop(msg_global->process_to_run))) {
335 DEBUG3("Scheduling %s(%d) on %s",
336 process->name,process->simdata->PID,
337 process->simdata->host->name);
338 msg_global->current_process = process;
340 xbt_context_schedule(process->simdata->context);
341 msg_global->current_process = NULL;
345 surf_action_t action = NULL;
346 surf_resource_t resource = NULL;
347 m_task_t task = NULL;
352 xbt_dynar_foreach(resource_list, i, resource) {
353 if(xbt_swag_size(resource->common_public->states.failed_action_set) ||
354 xbt_swag_size(resource->common_public->states.done_action_set))
355 state_modifications = 1;
358 if(!state_modifications) {
359 DEBUG1("%f : Calling surf_solve",MSG_get_clock());
360 elapsed_time = surf_solve();
361 DEBUG1("Elapsed_time %f",elapsed_time);
363 if (elapsed_time<0.0) {
364 /* fprintf(stderr, "We're done %g\n",elapsed_time); */
369 while (surf_timer_resource->extension_public->get(&fun,(void*)&arg)) {
370 DEBUG2("got %p %p", fun, arg);
371 if(fun==MSG_process_create_with_arguments) {
372 process_arg_t args = arg;
373 DEBUG2("Launching %s on %s", args->name, args->host->name);
374 process = MSG_process_create_with_arguments(args->name, args->code,
375 args->data, args->host,
376 args->argc,args->argv);
377 if(args->kill_time > MSG_get_clock()) {
378 surf_timer_resource->extension_public->set(args->kill_time,
379 (void*) &MSG_process_kill,
384 if(fun==MSG_process_kill) {
386 DEBUG3("Killing %s(%d) on %s", process->name, process->simdata->PID,
387 process->simdata->host->name);
388 MSG_process_kill(process);
392 xbt_dynar_foreach(resource_list, i, resource) {
394 xbt_swag_extract(resource->common_public->states.
395 failed_action_set))) {
399 DEBUG1("** %s failed **",task->name);
400 xbt_dynar_foreach(task->simdata->sleeping,_cursor,process) {
401 DEBUG3("\t preparing to wake up %s(%d) on %s",
402 process->name,process->simdata->PID,
403 process->simdata->host->name);
404 xbt_fifo_unshift(msg_global->process_to_run, process);
410 xbt_swag_extract(resource->common_public->states.
415 DEBUG1("** %s done **",task->name);
416 xbt_dynar_foreach(task->simdata->sleeping,_cursor,process) {
417 DEBUG3("\t preparing to wake up %s(%d) on %s",
418 process->name,process->simdata->PID,
419 process->simdata->host->name);
420 xbt_fifo_unshift(msg_global->process_to_run, process);
427 state_modifications = 0;
430 if (xbt_fifo_size(msg_global->process_list) == 0) {
431 /* INFO0("Congratulations ! Simulation terminated : all processes are over"); */
434 INFO0("Oops ! Deadlock or code not perfectly clean.");
435 __MSG_display_process_status();
436 if(XBT_LOG_ISENABLED(msg, xbt_log_priority_debug) ||
437 XBT_LOG_ISENABLED(msg_kernel, xbt_log_priority_debug)) {
442 INFO0("Return a Warning.");
447 /** \ingroup msg_simulation
448 * \brief Kill all running process
450 * \param reset_PIDs should we reset the PID numbers. A negative
451 * number means no reset and a positive number will be used to set the PID
452 * of the next newly created process.
454 int MSG_process_killall(int reset_PIDs)
456 m_process_t p = NULL;
457 m_process_t self = MSG_process_self();
459 while((p=xbt_fifo_pop(msg_global->process_list))) {
460 if(p!=self) MSG_process_kill(p);
464 msg_global->PID = reset_PIDs;
465 msg_global->session++;
468 xbt_context_empty_trash();
474 return msg_global->PID;
477 /** \ingroup msg_simulation
478 * \brief Clean the MSG simulation
480 MSG_error_t MSG_clean(void)
482 xbt_fifo_item_t i = NULL;
484 m_process_t p = NULL;
487 while((p=xbt_fifo_pop(msg_global->process_list))) {
491 xbt_fifo_foreach(msg_global->host,i,h,m_host_t) {
492 __MSG_host_destroy(h);
494 xbt_fifo_free(msg_global->host);
495 xbt_fifo_free(msg_global->process_to_run);
496 xbt_fifo_free(msg_global->process_list);
497 xbt_dict_free(&(msg_global->registered_functions));
498 xbt_mallocator_free(msg_global->task_mallocator);
500 if(msg_global->paje_output) {
501 fclose(msg_global->paje_output);
502 msg_global->paje_output = NULL;
504 msg_config_finalize();
513 /** \ingroup msg_easier_life
514 * \brief A clock (in second).
516 double MSG_get_clock(void) {
517 return surf_get_clock();