Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
5c60759ce7855a53b8d0292bdb0fc6a533b27fd3
[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       
300       
301       INFO4("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             INFO1("\tListening on channel %d.",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                   INFO2("\tTrying to send a task to Host %s, channel %d.",
318                         p_simdata->put_host->name, p_simdata->put_channel);
319                } else {
320                   INFO1("Waiting for %s to finish.",p_simdata->waiting_task->name);
321                }
322             } else if (p_simdata->waiting_task->simdata->comm) {
323                INFO1("Waiting for %s to be finished transfered.",
324                      p_simdata->waiting_task->name);
325             } else {
326               INFO0("UNKNOWN STATUS. Please report this bug.");
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             INFO0("UNKNOWN STATUS. Please report this bug.");
334          }
335       } 
336    }
337 }
338
339 /* FIXME: Yeah, I'll do it in a portable maner one day [Mt] */
340 #include <signal.h>
341
342 static void inthandler(int ignored)
343 {
344    INFO0("CTRL-C pressed. Displaying status and bailing out");
345    __MSG_display_process_status();
346    exit(1);
347 }
348
349 /** \ingroup msg_simulation
350  * \brief Launch the MSG simulation
351  */
352 MSG_error_t MSG_main(void)
353 {
354   m_process_t process = NULL;
355   int i;
356   double elapsed_time = 0.0;
357   int state_modifications = 1;
358    
359   /* Prepare to display some more info when dying on Ctrl-C pressing */
360   signal(SIGINT,inthandler);
361    
362   /* Clean IO before the run */
363   fflush(stdout);
364   fflush(stderr);
365
366   surf_solve(); /* Takes traces into account. Returns 0.0 */
367 /* xbt_fifo_size(msg_global->process_to_run) */
368   while (1) {
369     xbt_context_empty_trash();
370     if(xbt_fifo_size(msg_global->process_to_run) && (elapsed_time>0)) {
371       DEBUG0("**************************************************");
372     }
373     if((__stop_at_time>0) && (MSG_get_clock() >= __stop_at_time)) {
374       DEBUG0("Let's stop here!");
375     }
376
377     while ((process = xbt_fifo_pop(msg_global->process_to_run))) {
378       DEBUG3("Scheduling %s(%d) on %s",      
379              process->name,process->simdata->PID,
380              process->simdata->host->name);
381       msg_global->current_process = process;
382 /*       fflush(NULL); */
383       xbt_context_schedule(process->simdata->context);
384       msg_global->current_process = NULL;
385     }
386     
387     {
388       surf_action_t action = NULL;
389       surf_resource_t resource = NULL;
390       m_task_t task = NULL;
391
392       void *fun = NULL;
393       void *arg = NULL;
394
395       xbt_dynar_foreach(resource_list, i, resource) {
396         if(xbt_swag_size(resource->common_public->states.failed_action_set) ||
397            xbt_swag_size(resource->common_public->states.done_action_set))
398           state_modifications = 1;
399       }
400       
401       if(!state_modifications) {
402         DEBUG1("%f : Calling surf_solve",MSG_get_clock());
403         elapsed_time = surf_solve();
404         DEBUG1("Elapsed_time %f",elapsed_time);
405         
406         if (elapsed_time<0.0) {
407           /*       fprintf(stderr, "We're done %g\n",elapsed_time); */
408           break;
409         }
410       }
411
412       while (surf_timer_resource->extension_public->get(&fun,(void*)&arg)) {
413         DEBUG2("got %p %p", fun, arg);
414         if(fun==MSG_process_create_with_arguments) {
415           process_arg_t args = arg;
416           DEBUG2("Launching %s on %s", args->name, args->host->name);
417           process = MSG_process_create_with_arguments(args->name, args->code, 
418                                                       args->data, args->host,
419                                                       args->argc,args->argv);
420           if(args->kill_time > MSG_get_clock()) {
421             surf_timer_resource->extension_public->set(args->kill_time, 
422                                                        (void*) &MSG_process_kill,
423                                                        (void*) process);
424           }
425           xbt_free(args);
426         }
427         if(fun==MSG_process_kill) {
428           process = arg;
429           DEBUG3("Killing %s(%d) on %s", process->name, process->simdata->PID, 
430                  process->simdata->host->name);
431           MSG_process_kill(process);
432         }
433       }
434       
435       xbt_dynar_foreach(resource_list, i, resource) {
436         while ((action =
437                 xbt_swag_extract(resource->common_public->states.
438                                  failed_action_set))) {
439           task = action->data;
440           if(task) {
441             int _cursor;
442             DEBUG1("** %s failed **",task->name);
443             xbt_dynar_foreach(task->simdata->sleeping,_cursor,process) {
444               DEBUG3("\t preparing to wake up %s(%d) on %s",         
445                      process->name,process->simdata->PID,
446                      process->simdata->host->name);
447               xbt_fifo_unshift(msg_global->process_to_run, process);
448             }
449             process=NULL;
450           }
451         }
452         while ((action =
453                 xbt_swag_extract(resource->common_public->states.
454                                  done_action_set))) {
455           task = action->data;
456           if(task) {
457             int _cursor;
458             DEBUG1("** %s done **",task->name);
459             xbt_dynar_foreach(task->simdata->sleeping,_cursor,process) {
460               DEBUG3("\t preparing to wake up %s(%d) on %s",         
461                      process->name,process->simdata->PID,
462                      process->simdata->host->name);
463               xbt_fifo_unshift(msg_global->process_to_run, process);
464             }
465             process=NULL;
466           }
467         }
468       }
469     }
470     state_modifications = 0;
471   }
472
473   if (xbt_fifo_size(msg_global->process_list) == 0) {
474     INFO0("Congratulations ! Simulation terminated : all process are over");
475     return MSG_OK;
476   } else {
477     INFO0("Oops ! Deadlock or code not perfectly clean.");
478     __MSG_display_process_status();
479     if(XBT_LOG_ISENABLED(msg, xbt_log_priority_debug) ||
480        XBT_LOG_ISENABLED(msg_kernel, xbt_log_priority_debug)) {
481       DEBUG0("Aborting!");
482       xbt_abort();
483     }
484
485     INFO0("Return a Warning.");
486     return MSG_WARNING;
487   }
488 }
489
490 /** \ingroup msg_simulation
491  * \brief Kill all running process
492
493  * \param reset_PIDs should we reset the PID numbers. A negative
494  *   number means no reset and a positive number will be used to set the PID
495  *   of the next newly created process.
496  */
497 int MSG_process_killall(int reset_PIDs)
498 {
499   m_process_t p = NULL;
500   m_process_t self = MSG_process_self();
501
502   while((p=xbt_fifo_pop(msg_global->process_list))) {
503     if(p!=self) MSG_process_kill(p);
504   }
505
506   if(reset_PIDs>0) {
507     msg_global->PID = reset_PIDs; 
508     msg_global->session++;
509  }
510
511   xbt_context_empty_trash();
512
513   if(self) {
514     xbt_context_yield();
515   }
516
517   return msg_global->PID;
518 }
519
520 /** \ingroup msg_simulation
521  * \brief Clean the MSG simulation
522  */
523 MSG_error_t MSG_clean(void)
524 {
525   xbt_fifo_item_t i = NULL;
526   m_host_t h = NULL;
527   m_process_t p = NULL;
528
529
530   while((p=xbt_fifo_pop(msg_global->process_list))) {
531     MSG_process_kill(p);
532   }
533   xbt_context_exit();
534
535   xbt_fifo_foreach(msg_global->host,i,h,m_host_t) {
536     __MSG_host_destroy(h);
537   }
538   xbt_fifo_free(msg_global->host);
539   xbt_fifo_free(msg_global->process_to_run);
540   xbt_fifo_free(msg_global->process_list);
541   xbt_dict_free(&(msg_global->registered_functions));
542
543   if(msg_global->paje_output) {
544     fclose(msg_global->paje_output);
545     msg_global->paje_output = NULL;
546   }
547   msg_config_finalize();
548   free(msg_global);
549   surf_exit();
550
551   return MSG_OK;
552 }
553
554
555 /** \ingroup msg_easier_life
556  * \brief A clock (in second).
557  */
558 double MSG_get_clock(void) {
559   return surf_get_clock();
560 }
561