Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
3910a414e1dee03feaa32a5a30e9fdaa1dba5e3b
[simgrid.git] / src / msg / global.c
1 /*      $Id$     */
2
3 /* Copyright (c) 2002,2003,2004 Arnaud Legrand. All rights reserved.        */
4
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. */
7
8 #include "private.h"
9 #include "xbt/sysdep.h"
10 #include "xbt/log.h"
11 #include "xbt/ex.h" /* ex_backtrace_display */
12 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_kernel, msg,
13                                 "Logging specific to MSG (kernel)");
14
15 int __stop_at_time = -1.0 ;
16
17 MSG_Global_t msg_global = NULL;
18
19 /* static void MarkAsFailed(m_task_t t, TBX_HashTable_t failedProcessList); */
20 /* static xbt_fifo_t MSG_buildFailedHostList(double a, double b); */
21
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
27  */
28
29 /********************************* MSG **************************************/
30
31 /** \ingroup msg_simulation
32  * \brief Initialize some MSG internal data.
33  */
34 void MSG_global_init_args(int *argc, char **argv)
35 {
36   MSG_global_init(argc,argv);
37 }
38
39 /** \ingroup msg_simulation
40  * \brief Initialize some MSG internal data.
41  */
42 void MSG_global_init(int *argc, char **argv)
43 {
44   if (!msg_global) {
45     surf_init(argc, argv);      /* Initialize some common structures. Warning, it sets msg_global=NULL */
46      
47     msg_global = xbt_new0(s_MSG_Global_t,1);
48
49     xbt_context_init();
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();
56     msg_global->PID = 1;
57   }
58 }
59
60 /** \ingroup msg_easier_life
61  * \brief Traces MSG events in the Paje format.
62  */
63 void MSG_paje_output(const char *filename)
64 {
65   int i;
66   const char *paje_preembule="%EventDef SetLimits       0\n"
67     "%  StartTime       date\n"
68     "%  EndTime date\n"
69     "%EndEventDef\n"
70     "%EventDef  PajeDefineContainerType 1\n"
71     "%  NewType string\n"
72     "%  ContainerType   string\n"
73     "%  NewName string\n"
74     "%EndEventDef\n"
75     "%EventDef  PajeDefineEventType     2\n"
76     "%  NewType string\n"
77     "%  ContainerType   string\n"
78     "%  NewName string\n"
79     "%EndEventDef\n"
80     "%EventDef  PajeDefineStateType     3\n"
81     "%  NewType string\n"
82     "%  ContainerType   string\n"
83     "%  NewName string\n"
84     "%EndEventDef\n"
85     "%EventDef  PajeDefineVariableType  4\n"
86     "%  NewType string\n"
87     "%  ContainerType   string\n"
88     "%  NewName string\n"
89     "%EndEventDef\n"
90     "%EventDef  PajeDefineLinkType      5\n"
91     "%  NewType string\n"
92     "%  ContainerType   string\n"
93     "%  SourceContainerType     string\n"
94     "%  DestContainerType       string\n"
95     "%  NewName string\n"
96     "%EndEventDef\n"
97     "%EventDef  PajeDefineEntityValue   6\n"
98     "%  NewValue        string\n"
99     "%  EntityType      string\n"
100     "%  NewName string\n"
101     "%EndEventDef\n"
102     "%EventDef  PajeCreateContainer     7\n"
103     "%  Time    date\n"
104     "%  NewContainer    string\n"
105     "%  NewContainerType        string\n"
106     "%  Container       string\n"
107     "%  NewName string\n"
108     "%EndEventDef\n"
109     "%EventDef  PajeDestroyContainer    8\n"
110     "%  Time    date\n"
111     "%  Name    string\n"
112     "%  Type    string\n"
113     "%EndEventDef\n"
114     "%EventDef  PajeNewEvent    9\n"
115     "%  Time    date\n"
116     "%  EntityType      string\n"
117     "%  Container       string\n"
118     "%  Value   string\n"
119     "%EndEventDef\n"
120     "%EventDef  PajeSetState    10\n"
121     "%  Time    date\n"
122     "%  EntityType      string\n"
123     "%  Container       string\n"
124     "%  Value   string\n"
125     "%EndEventDef\n"
126     "%EventDef  PajeSetState    101\n"
127     "%  Time    date\n"
128     "%  EntityType      string\n"
129     "%  Container       string\n"
130     "%  Value   string\n"
131     "%  FileName        string\n"
132     "%  LineNumber      int\n"
133     "%EndEventDef\n"
134     "%EventDef  PajePushState   111\n"
135     "%  Time    date\n"
136     "%  EntityType      string\n"
137     "%  Container       string\n"
138     "%  Value   string\n"
139     "%  FileName        string\n"
140     "%  LineNumber      int\n"
141     "%EndEventDef\n"
142     "%EventDef  PajePushState   11\n"
143     "%  Time    date\n"
144     "%  EntityType      string\n"
145     "%  Container       string\n"
146     "%  Value   string\n"
147     "%  TaskName        string\n"
148     "%EndEventDef\n"
149     "%EventDef  PajePopState    12\n"
150     "%  Time    date\n"
151     "%  EntityType      string\n"
152     "%  Container       string\n"
153     "%EndEventDef\n"
154     "%EventDef  PajeSetVariable 13\n"
155     "%  Time    date\n"
156     "%  EntityType      string\n"
157     "%  Container       string\n"
158     "%  Value   double\n"
159     "%EndEventDef\n"
160     "%EventDef  PajeAddVariable 14\n"
161     "%  Time    date\n"
162     "%  EntityType      string\n"
163     "%  Container       string\n"
164     "%  Value   double\n"
165     "%EndEventDef\n"
166     "%EventDef  PajeSubVariable 15\n"
167     "%  Time    date\n"
168     "%  EntityType      string\n"
169     "%  Container       string\n"
170     "%  Value   double\n"
171     "%EndEventDef\n"
172     "%EventDef  PajeStartLink   16\n"
173     "%  Time    date\n"
174     "%  EntityType      string\n"
175     "%  Container       string\n"
176     "%  Value   string\n"
177     "%  SourceContainer string\n"
178     "%  Key     string\n"
179     "%EndEventDef\n"
180     "%EventDef  PajeEndLink     17\n"
181     "%  Time    date\n"
182     "%  EntityType      string\n"
183     "%  Container       string\n"
184     "%  Value   string\n"
185     "%  DestContainer   string\n"
186     "%  Key     string\n"
187     "%EndEventDef\n";
188
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"
194     "6  B       S_t     Blocked\n"
195     "6  C       S_t     Communicating\n"
196     "5  Comm    Sim_t   P_t     P_t     Communication_t\n";
197
198   const char *ext = ".trace";
199   int ext_len = strlen(ext);
200   int len;
201   m_host_t host;
202   m_process_t process;
203   xbt_fifo_item_t item = NULL;
204
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");
208
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",
212               filename,ext);
213   }
214
215   msg_global->paje_output=fopen(filename,"w");
216   xbt_assert1(msg_global->paje_output, "Failed to open %s \n",filename);
217
218   fprintf(msg_global->paje_output,"%s",paje_preembule);
219   fprintf(msg_global->paje_output,"%s",type_definitions);
220
221   /*    Channels    */
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);
224   }
225   fprintf(msg_global->paje_output,
226           "7    0.0     CUR     Sim_t   0       \"MSG simulation\"\n");
227
228   /*    Hosts       */
229   xbt_fifo_foreach(msg_global->host,item,host,m_host_t) {
230     PAJE_HOST_NEW(host);
231   }
232
233   /*    Process       */
234   xbt_fifo_foreach(msg_global->process_list,item,process,m_process_t) {
235     PAJE_PROCESS_NEW(process);
236   }
237 }
238
239 /** \defgroup m_channel_management    Understanding channels
240  *  \brief This section briefly describes the channel notion of MSG
241  *  (#m_channel_t).
242  *    \htmlonly <!-- DOXYGEN_NAVBAR_LABEL="Channels" --> \endhtmlonly
243  * 
244  *
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.
249  */
250
251
252 /** \ingroup m_channel_management
253  * \brief Set the number of channel in the simulation.
254  *
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
259    parameter.
260  * \param number the number of channel in the simulation. It has to be >0
261  */
262 MSG_error_t MSG_set_channel_number(int number)
263 {
264   xbt_assert0((msg_global) && (msg_global->max_channel == 0), "Channel number already set!");
265
266   msg_global->max_channel = number;
267
268   return MSG_OK;
269 }
270
271 /** \ingroup m_channel_management
272  * \brief Return the number of channel in the simulation.
273  *
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.
277  */
278 int MSG_get_channel_number(void)
279 {
280   xbt_assert0((msg_global)&&(msg_global->max_channel != 0), "Channel number not set yet!");
281
282   return msg_global->max_channel;
283 }
284
285 void __MSG_display_process_status(void)
286 {
287    m_process_t process = NULL;
288    xbt_fifo_item_t item = NULL;
289    int i;
290    int nbprocess=xbt_fifo_size(msg_global->process_list);
291    
292    INFO1("MSG: %d processes are still running, waiting for something.",
293          nbprocess);
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;
299       char *who;
300         
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] ":""));
306       
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);
310             break;
311          }
312       }
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);
319                } else {
320                   INFO2("%s\tWaiting for %s to finish.",who,p_simdata->waiting_task->name);
321                }
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);
325             } else {
326               INFO1("%s\tUNKNOWN STATUS. Please report this bug.",who);
327             }
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);
334          }
335       }
336       free(who);
337    }
338 }
339
340 /* FIXME: Yeah, I'll do it in a portable maner one day [Mt] */
341 #include <signal.h>
342
343 static void inthandler(int ignored)
344 {
345    INFO0("CTRL-C pressed. Displaying status and bailing out");
346    __MSG_display_process_status();
347    exit(1);
348 }
349
350 /** \ingroup msg_simulation
351  * \brief Launch the MSG simulation
352  */
353 MSG_error_t MSG_main(void)
354 {
355   m_process_t process = NULL;
356   int i;
357   double elapsed_time = 0.0;
358   int state_modifications = 1;
359    
360   /* Prepare to display some more info when dying on Ctrl-C pressing */
361   signal(SIGINT,inthandler);
362    
363   /* Clean IO before the run */
364   fflush(stdout);
365   fflush(stderr);
366
367   surf_solve(); /* Takes traces into account. Returns 0.0 */
368 /* xbt_fifo_size(msg_global->process_to_run) */
369   while (1) {
370     xbt_context_empty_trash();
371     if(xbt_fifo_size(msg_global->process_to_run) && (elapsed_time>0)) {
372       DEBUG0("**************************************************");
373     }
374     if((__stop_at_time>0) && (MSG_get_clock() >= __stop_at_time)) {
375       DEBUG0("Let's stop here!");
376     }
377
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;
383 /*       fflush(NULL); */
384       xbt_context_schedule(process->simdata->context);
385       msg_global->current_process = NULL;
386     }
387     
388     {
389       surf_action_t action = NULL;
390       surf_resource_t resource = NULL;
391       m_task_t task = NULL;
392
393       void *fun = NULL;
394       void *arg = NULL;
395
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;
400       }
401       
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);
406         
407         if (elapsed_time<0.0) {
408           /*       fprintf(stderr, "We're done %g\n",elapsed_time); */
409           break;
410         }
411       }
412
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,
424                                                        (void*) process);
425           }
426           xbt_free(args);
427         }
428         if(fun==MSG_process_kill) {
429           process = arg;
430           DEBUG3("Killing %s(%d) on %s", process->name, process->simdata->PID, 
431                  process->simdata->host->name);
432           MSG_process_kill(process);
433         }
434       }
435       
436       xbt_dynar_foreach(resource_list, i, resource) {
437         while ((action =
438                 xbt_swag_extract(resource->common_public->states.
439                                  failed_action_set))) {
440           task = action->data;
441           if(task) {
442             int _cursor;
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);
449             }
450             process=NULL;
451           }
452         }
453         while ((action =
454                 xbt_swag_extract(resource->common_public->states.
455                                  done_action_set))) {
456           task = action->data;
457           if(task) {
458             int _cursor;
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);
465             }
466             process=NULL;
467           }
468         }
469       }
470     }
471     state_modifications = 0;
472   }
473
474   if (xbt_fifo_size(msg_global->process_list) == 0) {
475     INFO0("Congratulations ! Simulation terminated : all processes are over");
476     return MSG_OK;
477   } else {
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)) {
482       DEBUG0("Aborting!");
483       xbt_abort();
484     }
485
486     INFO0("Return a Warning.");
487     return MSG_WARNING;
488   }
489 }
490
491 /** \ingroup msg_simulation
492  * \brief Kill all running process
493
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.
497  */
498 int MSG_process_killall(int reset_PIDs)
499 {
500   m_process_t p = NULL;
501   m_process_t self = MSG_process_self();
502
503   while((p=xbt_fifo_pop(msg_global->process_list))) {
504     if(p!=self) MSG_process_kill(p);
505   }
506
507   if(reset_PIDs>0) {
508     msg_global->PID = reset_PIDs; 
509     msg_global->session++;
510  }
511
512   xbt_context_empty_trash();
513
514   if(self) {
515     xbt_context_yield();
516   }
517
518   return msg_global->PID;
519 }
520
521 /** \ingroup msg_simulation
522  * \brief Clean the MSG simulation
523  */
524 MSG_error_t MSG_clean(void)
525 {
526   xbt_fifo_item_t i = NULL;
527   m_host_t h = NULL;
528   m_process_t p = NULL;
529
530
531   while((p=xbt_fifo_pop(msg_global->process_list))) {
532     MSG_process_kill(p);
533   }
534   xbt_context_exit();
535
536   xbt_fifo_foreach(msg_global->host,i,h,m_host_t) {
537     __MSG_host_destroy(h);
538   }
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));
543
544   if(msg_global->paje_output) {
545     fclose(msg_global->paje_output);
546     msg_global->paje_output = NULL;
547   }
548   msg_config_finalize();
549   free(msg_global);
550   surf_exit();
551
552   return MSG_OK;
553 }
554
555
556 /** \ingroup msg_easier_life
557  * \brief A clock (in second).
558  */
559 double MSG_get_clock(void) {
560   return surf_get_clock();
561 }
562