3 /* Copyright (c) 2002,2003,2004 Arnaud Legrand. All rights reserved. */
5 /* This program is free software; you can redistribute it and/or modify it
6 * under the terms of the license (GNU LGPL) which comes with this package. */
9 #include "xbt/sysdep.h"
11 #include "xbt/ex.h" /* ex_backtrace_display */
12 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_kernel, msg,
13 "Logging specific to MSG (kernel)");
15 int __stop_at_time = -1.0 ;
17 MSG_Global_t msg_global = NULL;
19 /* static void MarkAsFailed(m_task_t t, TBX_HashTable_t failedProcessList); */
20 /* static xbt_fifo_t MSG_buildFailedHostList(double a, double b); */
22 /** \defgroup msg_simulation MSG simulation Functions
23 * \brief This section describes the functions you need to know to
24 * set up a simulation. You should have a look at \ref MSG_examples
25 * to have an overview of their usage.
26 * \htmlonly <!-- DOXYGEN_NAVBAR_LABEL="Simulation functions" --> \endhtmlonly
29 /********************************* MSG **************************************/
31 /** \ingroup msg_simulation
32 * \brief Initialize some MSG internal data.
34 void MSG_global_init_args(int *argc, char **argv)
36 MSG_global_init(argc,argv);
39 /** \ingroup msg_simulation
40 * \brief Initialize some MSG internal data.
42 void MSG_global_init(int *argc, char **argv)
45 surf_init(argc, argv); /* Initialize some common structures. Warning, it sets msg_global=NULL */
47 msg_global = xbt_new0(s_MSG_Global_t,1);
50 msg_global->host = xbt_fifo_new();
51 msg_global->process_to_run = xbt_fifo_new();
52 msg_global->process_list = xbt_fifo_new();
53 msg_global->max_channel = 0;
54 msg_global->current_process = NULL;
55 msg_global->registered_functions = xbt_dict_new();
60 /** \ingroup msg_easier_life
61 * \brief Traces MSG events in the Paje format.
63 void MSG_paje_output(const char *filename)
66 const char *paje_preembule="%EventDef SetLimits 0\n"
70 "%EventDef PajeDefineContainerType 1\n"
72 "% ContainerType string\n"
75 "%EventDef PajeDefineEventType 2\n"
77 "% ContainerType string\n"
80 "%EventDef PajeDefineStateType 3\n"
82 "% ContainerType string\n"
85 "%EventDef PajeDefineVariableType 4\n"
87 "% ContainerType string\n"
90 "%EventDef PajeDefineLinkType 5\n"
92 "% ContainerType string\n"
93 "% SourceContainerType string\n"
94 "% DestContainerType string\n"
97 "%EventDef PajeDefineEntityValue 6\n"
99 "% EntityType string\n"
102 "%EventDef PajeCreateContainer 7\n"
104 "% NewContainer string\n"
105 "% NewContainerType string\n"
106 "% Container string\n"
109 "%EventDef PajeDestroyContainer 8\n"
114 "%EventDef PajeNewEvent 9\n"
116 "% EntityType string\n"
117 "% Container string\n"
120 "%EventDef PajeSetState 10\n"
122 "% EntityType string\n"
123 "% Container string\n"
126 "%EventDef PajeSetState 101\n"
128 "% EntityType string\n"
129 "% Container string\n"
131 "% FileName string\n"
134 "%EventDef PajePushState 111\n"
136 "% EntityType string\n"
137 "% Container string\n"
139 "% FileName string\n"
142 "%EventDef PajePushState 11\n"
144 "% EntityType string\n"
145 "% Container string\n"
147 "% TaskName string\n"
149 "%EventDef PajePopState 12\n"
151 "% EntityType string\n"
152 "% Container string\n"
154 "%EventDef PajeSetVariable 13\n"
156 "% EntityType string\n"
157 "% Container string\n"
160 "%EventDef PajeAddVariable 14\n"
162 "% EntityType string\n"
163 "% Container string\n"
166 "%EventDef PajeSubVariable 15\n"
168 "% EntityType string\n"
169 "% Container string\n"
172 "%EventDef PajeStartLink 16\n"
174 "% EntityType string\n"
175 "% Container string\n"
177 "% SourceContainer string\n"
180 "%EventDef PajeEndLink 17\n"
182 "% EntityType string\n"
183 "% Container string\n"
185 "% DestContainer string\n"
189 const char *type_definitions = "1 Sim_t 0 Simulation_t\n"
190 "1 H_t Sim_t m_host_t\n"
191 "1 P_t H_t m_process_t\n"
192 "3 S_t P_t \"Process State\"\n"
193 "6 E S_t Executing\n"
195 "6 C S_t Communicating\n"
196 "5 Comm Sim_t P_t P_t Communication_t\n";
198 const char *ext = ".trace";
199 int ext_len = strlen(ext);
203 xbt_fifo_item_t item = NULL;
205 xbt_assert0(msg_global, "Initialize MSG first\n");
206 xbt_assert0(!msg_global->paje_output, "Paje output already defined\n");
207 xbt_assert0(filename, "Need a real file name\n");
209 len = strlen(filename);
210 if((len<ext_len) || (strncmp(filename+len-ext_len,ext,ext_len))) {
211 CRITICAL2("The name of the Paje trace file \"%s\" does not end by \"%s\". Paje will cause difficulties to read it.\n",
215 msg_global->paje_output=fopen(filename,"w");
216 xbt_assert1(msg_global->paje_output, "Failed to open %s \n",filename);
218 fprintf(msg_global->paje_output,"%s",paje_preembule);
219 fprintf(msg_global->paje_output,"%s",type_definitions);
222 for(i=0; i<msg_global->max_channel; i++) {
223 fprintf(msg_global->paje_output, "6 COMM_%d Comm \"Channel %d\"\n" ,i,i);
225 fprintf(msg_global->paje_output,
226 "7 0.0 CUR Sim_t 0 \"MSG simulation\"\n");
229 xbt_fifo_foreach(msg_global->host,item,host,m_host_t) {
234 xbt_fifo_foreach(msg_global->process_list,item,process,m_process_t) {
235 PAJE_PROCESS_NEW(process);
239 /** \defgroup m_channel_management Understanding channels
240 * \brief This section briefly describes the channel notion of MSG
242 * \htmlonly <!-- DOXYGEN_NAVBAR_LABEL="Channels" --> \endhtmlonly
245 * For convenience, the simulator provides the notion of channel
246 * that is close to the tag notion in MPI. A channel is not a
247 * socket. It doesn't need to be opened neither closed. It rather
248 * corresponds to the ports opened on the different machines.
252 /** \ingroup m_channel_management
253 * \brief Set the number of channel in the simulation.
255 * This function has to be called to fix the number of channel in the
256 simulation before creating any host. Indeed, each channel is
257 represented by a different mailbox on each #m_host_t. This
258 function can then be called only once. This function takes only one
260 * \param number the number of channel in the simulation. It has to be >0
262 MSG_error_t MSG_set_channel_number(int number)
264 xbt_assert0((msg_global) && (msg_global->max_channel == 0), "Channel number already set!");
266 msg_global->max_channel = number;
271 /** \ingroup m_channel_management
272 * \brief Return the number of channel in the simulation.
274 * This function has to be called once the number of channel is fixed. I can't
275 figure out a reason why anyone would like to call this function but nevermind.
276 * \return the number of channel in the simulation.
278 int MSG_get_channel_number(void)
280 xbt_assert0((msg_global)&&(msg_global->max_channel != 0), "Channel number not set yet!");
282 return msg_global->max_channel;
285 void __MSG_display_process_status(void)
287 m_process_t process = NULL;
288 xbt_fifo_item_t item = NULL;
290 int nbprocess=xbt_fifo_size(msg_global->process_list);
292 INFO1("MSG: %d processes are still running, waiting for something.",
294 /* List the process and their state */
295 INFO0("MSG: <process>(<pid>) on <host>: <status>.");
296 xbt_fifo_foreach(msg_global->process_list,item,process,m_process_t) {
297 simdata_process_t p_simdata = (simdata_process_t) process->simdata;
298 simdata_host_t h_simdata=(simdata_host_t)p_simdata->host->simdata;
301 asprintf(&who,"MSG: %s(%d) on %s: %s",
302 process->name,p_simdata->PID,
303 p_simdata->host->name,
304 (process->simdata->blocked)?"[blocked] "
305 :((process->simdata->suspended)?"[suspended] ":""));
307 for (i=0; i<msg_global->max_channel; i++) {
308 if (h_simdata->sleeping[i] == process) {
309 INFO2("%s\tListening on channel %d",who,i);
313 if (i==msg_global->max_channel) {
314 if(p_simdata->waiting_task) {
315 if(p_simdata->waiting_task->simdata->compute) {
316 if(p_simdata->put_host) {
317 INFO4("%s\tTrying to send the task '%s' to Host %s, channel %d.",
318 who, p_simdata->waiting_task->name,p_simdata->put_host->name, p_simdata->put_channel);
320 INFO2("%s\tWaiting for %s to finish.",who,p_simdata->waiting_task->name);
322 } else if (p_simdata->waiting_task->simdata->comm) {
323 INFO2("%s\tWaiting for %s to be finished transfered.",
324 who,p_simdata->waiting_task->name);
326 INFO1("%s\tUNKNOWN STATUS. Please report this bug.",who);
328 /* The following would display the trace of where the maestro thread is,
329 since this is the thread calling this. I'd like to get the other threads to
330 run this to see where they were blocked, but I'm not sure of how to do this */
331 /* xbt_backtrace_display(); */
332 } else { /* Must be trying to put a task somewhere */
333 INFO1("%s\tUNKNOWN STATUS. Please report this bug.",who);
340 /* FIXME: Yeah, I'll do it in a portable maner one day [Mt] */
343 static void inthandler(int ignored)
345 INFO0("CTRL-C pressed. Displaying status and bailing out");
346 __MSG_display_process_status();
350 /** \ingroup msg_simulation
351 * \brief Launch the MSG simulation
353 MSG_error_t MSG_main(void)
355 m_process_t process = NULL;
357 double elapsed_time = 0.0;
358 int state_modifications = 1;
360 /* Prepare to display some more info when dying on Ctrl-C pressing */
361 signal(SIGINT,inthandler);
363 /* Clean IO before the run */
367 surf_solve(); /* Takes traces into account. Returns 0.0 */
368 /* xbt_fifo_size(msg_global->process_to_run) */
370 xbt_context_empty_trash();
371 if(xbt_fifo_size(msg_global->process_to_run) && (elapsed_time>0)) {
372 DEBUG0("**************************************************");
374 if((__stop_at_time>0) && (MSG_get_clock() >= __stop_at_time)) {
375 DEBUG0("Let's stop here!");
378 while ((process = xbt_fifo_pop(msg_global->process_to_run))) {
379 DEBUG3("Scheduling %s(%d) on %s",
380 process->name,process->simdata->PID,
381 process->simdata->host->name);
382 msg_global->current_process = process;
384 xbt_context_schedule(process->simdata->context);
385 msg_global->current_process = NULL;
389 surf_action_t action = NULL;
390 surf_resource_t resource = NULL;
391 m_task_t task = NULL;
396 xbt_dynar_foreach(resource_list, i, resource) {
397 if(xbt_swag_size(resource->common_public->states.failed_action_set) ||
398 xbt_swag_size(resource->common_public->states.done_action_set))
399 state_modifications = 1;
402 if(!state_modifications) {
403 DEBUG1("%f : Calling surf_solve",MSG_get_clock());
404 elapsed_time = surf_solve();
405 DEBUG1("Elapsed_time %f",elapsed_time);
407 if (elapsed_time<0.0) {
408 /* fprintf(stderr, "We're done %g\n",elapsed_time); */
413 while (surf_timer_resource->extension_public->get(&fun,(void*)&arg)) {
414 DEBUG2("got %p %p", fun, arg);
415 if(fun==MSG_process_create_with_arguments) {
416 process_arg_t args = arg;
417 DEBUG2("Launching %s on %s", args->name, args->host->name);
418 process = MSG_process_create_with_arguments(args->name, args->code,
419 args->data, args->host,
420 args->argc,args->argv);
421 if(args->kill_time > MSG_get_clock()) {
422 surf_timer_resource->extension_public->set(args->kill_time,
423 (void*) &MSG_process_kill,
428 if(fun==MSG_process_kill) {
430 DEBUG3("Killing %s(%d) on %s", process->name, process->simdata->PID,
431 process->simdata->host->name);
432 MSG_process_kill(process);
436 xbt_dynar_foreach(resource_list, i, resource) {
438 xbt_swag_extract(resource->common_public->states.
439 failed_action_set))) {
443 DEBUG1("** %s failed **",task->name);
444 xbt_dynar_foreach(task->simdata->sleeping,_cursor,process) {
445 DEBUG3("\t preparing to wake up %s(%d) on %s",
446 process->name,process->simdata->PID,
447 process->simdata->host->name);
448 xbt_fifo_unshift(msg_global->process_to_run, process);
454 xbt_swag_extract(resource->common_public->states.
459 DEBUG1("** %s done **",task->name);
460 xbt_dynar_foreach(task->simdata->sleeping,_cursor,process) {
461 DEBUG3("\t preparing to wake up %s(%d) on %s",
462 process->name,process->simdata->PID,
463 process->simdata->host->name);
464 xbt_fifo_unshift(msg_global->process_to_run, process);
471 state_modifications = 0;
474 if (xbt_fifo_size(msg_global->process_list) == 0) {
475 INFO0("Congratulations ! Simulation terminated : all processes are over");
478 INFO0("Oops ! Deadlock or code not perfectly clean.");
479 __MSG_display_process_status();
480 if(XBT_LOG_ISENABLED(msg, xbt_log_priority_debug) ||
481 XBT_LOG_ISENABLED(msg_kernel, xbt_log_priority_debug)) {
486 INFO0("Return a Warning.");
491 /** \ingroup msg_simulation
492 * \brief Kill all running process
494 * \param reset_PIDs should we reset the PID numbers. A negative
495 * number means no reset and a positive number will be used to set the PID
496 * of the next newly created process.
498 int MSG_process_killall(int reset_PIDs)
500 m_process_t p = NULL;
501 m_process_t self = MSG_process_self();
503 while((p=xbt_fifo_pop(msg_global->process_list))) {
504 if(p!=self) MSG_process_kill(p);
508 msg_global->PID = reset_PIDs;
509 msg_global->session++;
512 xbt_context_empty_trash();
518 return msg_global->PID;
521 /** \ingroup msg_simulation
522 * \brief Clean the MSG simulation
524 MSG_error_t MSG_clean(void)
526 xbt_fifo_item_t i = NULL;
528 m_process_t p = NULL;
531 while((p=xbt_fifo_pop(msg_global->process_list))) {
536 xbt_fifo_foreach(msg_global->host,i,h,m_host_t) {
537 __MSG_host_destroy(h);
539 xbt_fifo_free(msg_global->host);
540 xbt_fifo_free(msg_global->process_to_run);
541 xbt_fifo_free(msg_global->process_list);
542 xbt_dict_free(&(msg_global->registered_functions));
544 if(msg_global->paje_output) {
545 fclose(msg_global->paje_output);
546 msg_global->paje_output = NULL;
548 msg_config_finalize();
556 /** \ingroup msg_easier_life
557 * \brief A clock (in second).
559 double MSG_get_clock(void) {
560 return surf_get_clock();