Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Rework the MSG navbar
[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 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(global, msg,
12                                 "Logging specific to MSG (global)");
13
14 int __stop_at_time = -1.0 ;
15
16 MSG_Global_t msg_global = NULL;
17
18 /* static void MarkAsFailed(m_task_t t, TBX_HashTable_t failedProcessList); */
19 /* static xbt_fifo_t MSG_buildFailedHostList(double a, double b); */
20
21 /** \defgroup msg_simulation   MSG simulation Functions
22  *  \brief This section describes the functions you need to know to
23  *  set up a simulation. You should have a look at \ref MSG_examples 
24  *  to have an overview of their usage.
25  *    \htmlonly <!-- DOXYGEN_NAVBAR_LABEL="Simulation functions" --> \endhtmlonly
26  */
27
28 /********************************* MSG **************************************/
29
30 /** \ingroup msg_simulation
31  * \brief Initialize some MSG internal data.
32  */
33 void MSG_global_init_args(int *argc, char **argv)
34 {
35   MSG_global_init(argc,argv);
36 }
37
38 /** \ingroup msg_simulation
39  * \brief Initialize some MSG internal data.
40  */
41 void MSG_global_init(int *argc, char **argv)
42 {
43   if (!msg_global) {
44     surf_init(argc, argv);      /* Initialize some common structures. Warning, it sets msg_global=NULL */
45      
46     msg_global = xbt_new0(s_MSG_Global_t,1);
47
48     xbt_context_init();
49     msg_global->host = xbt_fifo_new();
50     msg_global->process_to_run = xbt_fifo_new();
51     msg_global->process_list = xbt_fifo_new();
52     msg_global->max_channel = 0;
53     msg_global->current_process = NULL;
54     msg_global->registered_functions = xbt_dict_new();
55     msg_global->PID = 1;
56   }
57 }
58
59 /** \ingroup msg_easier_life
60  * \brief Traces MSG events in the Paje format.
61  */
62 void MSG_paje_output(const char *filename)
63 {
64   int i;
65   const char *paje_preembule="%EventDef SetLimits       0\n"
66     "%  StartTime       date\n"
67     "%  EndTime date\n"
68     "%EndEventDef\n"
69     "%EventDef  PajeDefineContainerType 1\n"
70     "%  NewType string\n"
71     "%  ContainerType   string\n"
72     "%  NewName string\n"
73     "%EndEventDef\n"
74     "%EventDef  PajeDefineEventType     2\n"
75     "%  NewType string\n"
76     "%  ContainerType   string\n"
77     "%  NewName string\n"
78     "%EndEventDef\n"
79     "%EventDef  PajeDefineStateType     3\n"
80     "%  NewType string\n"
81     "%  ContainerType   string\n"
82     "%  NewName string\n"
83     "%EndEventDef\n"
84     "%EventDef  PajeDefineVariableType  4\n"
85     "%  NewType string\n"
86     "%  ContainerType   string\n"
87     "%  NewName string\n"
88     "%EndEventDef\n"
89     "%EventDef  PajeDefineLinkType      5\n"
90     "%  NewType string\n"
91     "%  ContainerType   string\n"
92     "%  SourceContainerType     string\n"
93     "%  DestContainerType       string\n"
94     "%  NewName string\n"
95     "%EndEventDef\n"
96     "%EventDef  PajeDefineEntityValue   6\n"
97     "%  NewValue        string\n"
98     "%  EntityType      string\n"
99     "%  NewName string\n"
100     "%EndEventDef\n"
101     "%EventDef  PajeCreateContainer     7\n"
102     "%  Time    date\n"
103     "%  NewContainer    string\n"
104     "%  NewContainerType        string\n"
105     "%  Container       string\n"
106     "%  NewName string\n"
107     "%EndEventDef\n"
108     "%EventDef  PajeDestroyContainer    8\n"
109     "%  Time    date\n"
110     "%  Name    string\n"
111     "%  Type    string\n"
112     "%EndEventDef\n"
113     "%EventDef  PajeNewEvent    9\n"
114     "%  Time    date\n"
115     "%  EntityType      string\n"
116     "%  Container       string\n"
117     "%  Value   string\n"
118     "%EndEventDef\n"
119     "%EventDef  PajeSetState    10\n"
120     "%  Time    date\n"
121     "%  EntityType      string\n"
122     "%  Container       string\n"
123     "%  Value   string\n"
124     "%EndEventDef\n"
125     "%EventDef  PajeSetState    101\n"
126     "%  Time    date\n"
127     "%  EntityType      string\n"
128     "%  Container       string\n"
129     "%  Value   string\n"
130     "%  FileName        string\n"
131     "%  LineNumber      int\n"
132     "%EndEventDef\n"
133     "%EventDef  PajePushState   111\n"
134     "%  Time    date\n"
135     "%  EntityType      string\n"
136     "%  Container       string\n"
137     "%  Value   string\n"
138     "%  FileName        string\n"
139     "%  LineNumber      int\n"
140     "%EndEventDef\n"
141     "%EventDef  PajePushState   11\n"
142     "%  Time    date\n"
143     "%  EntityType      string\n"
144     "%  Container       string\n"
145     "%  Value   string\n"
146     "%EndEventDef\n"
147     "%EventDef  PajePopState    12\n"
148     "%  Time    date\n"
149     "%  EntityType      string\n"
150     "%  Container       string\n"
151     "%EndEventDef\n"
152     "%EventDef  PajeSetVariable 13\n"
153     "%  Time    date\n"
154     "%  EntityType      string\n"
155     "%  Container       string\n"
156     "%  Value   double\n"
157     "%EndEventDef\n"
158     "%EventDef  PajeAddVariable 14\n"
159     "%  Time    date\n"
160     "%  EntityType      string\n"
161     "%  Container       string\n"
162     "%  Value   double\n"
163     "%EndEventDef\n"
164     "%EventDef  PajeSubVariable 15\n"
165     "%  Time    date\n"
166     "%  EntityType      string\n"
167     "%  Container       string\n"
168     "%  Value   double\n"
169     "%EndEventDef\n"
170     "%EventDef  PajeStartLink   16\n"
171     "%  Time    date\n"
172     "%  EntityType      string\n"
173     "%  Container       string\n"
174     "%  Value   string\n"
175     "%  SourceContainer string\n"
176     "%  Key     string\n"
177     "%EndEventDef\n"
178     "%EventDef  PajeEndLink     17\n"
179     "%  Time    date\n"
180     "%  EntityType      string\n"
181     "%  Container       string\n"
182     "%  Value   string\n"
183     "%  DestContainer   string\n"
184     "%  Key     string\n"
185     "%EndEventDef\n";
186
187   const char *type_definitions = "1     Sim_t   0       Simulation_t\n"
188     "1  H_t     Sim_t   m_host_t\n"
189     "1  P_t     H_t     m_process_t\n"
190     "3  S_t     P_t     \"Process State\"\n"
191     "6  E       S_t     Executing\n"
192     "6  B       S_t     Blocked\n"
193     "6  C       S_t     Communicating\n"
194     "5  Comm    Sim_t   P_t     P_t     Communication_t\n";
195
196   const char *ext = ".trace";
197   int ext_len = strlen(ext);
198   int len;
199   m_host_t host;
200   m_process_t process;
201   xbt_fifo_item_t item = NULL;
202
203   xbt_assert0(msg_global, "Initialize MSG first\n");
204   xbt_assert0(!msg_global->paje_output, "Paje output already defined\n");
205   xbt_assert0(filename, "Need a real file name\n");
206
207   len = strlen(filename);
208   if((len<ext_len) || (strncmp(filename+len-ext_len,ext,ext_len))) {
209     CRITICAL2("The name of the Paje trace file \"%s\" does not end by \"%s\". Paje will cause difficulties to read it.\n",
210               filename,ext);
211   }
212
213   msg_global->paje_output=fopen(filename,"w");
214   xbt_assert1(msg_global->paje_output, "Failed to open %s \n",filename);
215
216   fprintf(msg_global->paje_output,"%s",paje_preembule);
217   fprintf(msg_global->paje_output,"%s",type_definitions);
218
219   /*    Channels    */
220   for(i=0; i<msg_global->max_channel; i++) {
221     fprintf(msg_global->paje_output, "6 COMM_%d Comm    \"Channel %d\"\n" ,i,i);
222   }
223   fprintf(msg_global->paje_output,
224           "7    0.0     CUR     Sim_t   0       \"MSG simulation\"\n");
225
226   /*    Hosts       */
227   xbt_fifo_foreach(msg_global->host,item,host,m_host_t) {
228     PAJE_HOST_NEW(host);
229   }
230
231   /*    Process       */
232   xbt_fifo_foreach(msg_global->process_list,item,process,m_process_t) {
233     PAJE_PROCESS_NEW(process);
234   }
235 }
236
237 /** \defgroup m_channel_management    Understanding channels
238  *  \brief This section briefly describes the channel notion of MSG
239  *  (#m_channel_t).
240  *    \htmlonly <!-- DOXYGEN_NAVBAR_LABEL="Channels" --> \endhtmlonly
241  * 
242  *
243  *  For convenience, the simulator provides the notion of channel
244  *  that is close to the tag notion in MPI. A channel is not a
245  *  socket. It doesn't need to be opened neither closed. It rather
246  *  corresponds to the ports opened on the different machines.
247  */
248
249
250 /** \ingroup m_channel_management
251  * \brief Set the number of channel in the simulation.
252  *
253  * This function has to be called to fix the number of channel in the
254    simulation before creating any host. Indeed, each channel is
255    represented by a different mailbox on each #m_host_t. This
256    function can then be called only once. This function takes only one
257    parameter.
258  * \param number the number of channel in the simulation. It has to be >0
259  */
260 MSG_error_t MSG_set_channel_number(int number)
261 {
262   xbt_assert0((msg_global) && (msg_global->max_channel == 0), "Channel number already set!");
263
264   msg_global->max_channel = number;
265
266   return MSG_OK;
267 }
268
269 /** \ingroup m_channel_management
270  * \brief Return the number of channel in the simulation.
271  *
272  * This function has to be called once the number of channel is fixed. I can't 
273    figure out a reason why anyone would like to call this function but nevermind.
274  * \return the number of channel in the simulation.
275  */
276 int MSG_get_channel_number(void)
277 {
278   xbt_assert0((msg_global)&&(msg_global->max_channel != 0), "Channel number not set yet!");
279
280   return msg_global->max_channel;
281 }
282
283 /** \ingroup msg_simulation
284  * \brief Launch the MSG simulation
285  */
286 MSG_error_t MSG_main(void)
287 {
288   m_process_t process = NULL;
289   int nbprocess,i;
290   double elapsed_time = 0.0;
291   int state_modifications = 1;
292   /* Clean IO before the run */
293   fflush(stdout);
294   fflush(stderr);
295
296   surf_solve(); /* Takes traces into account. Returns 0.0 */
297 /* xbt_fifo_size(msg_global->process_to_run) */
298   while (1) {
299     xbt_context_empty_trash();
300     if(xbt_fifo_size(msg_global->process_to_run) && (elapsed_time>0)) {
301       DEBUG0("**************************************************");
302     }
303     if((__stop_at_time>0) && (MSG_get_clock() >= __stop_at_time)) {
304       DEBUG0("Let's stop here!");
305     }
306
307     while ((process = xbt_fifo_pop(msg_global->process_to_run))) {
308       DEBUG3("Scheduling %s(%d) on %s",      
309              process->name,process->simdata->PID,
310              process->simdata->host->name);
311       msg_global->current_process = process;
312 /*       fflush(NULL); */
313       xbt_context_schedule(process->simdata->context);
314       msg_global->current_process = NULL;
315     }
316     
317     {
318       surf_action_t action = NULL;
319       surf_resource_t resource = NULL;
320       m_task_t task = NULL;
321
322       void *fun = NULL;
323       void *arg = NULL;
324
325       xbt_dynar_foreach(resource_list, i, resource) {
326         if(xbt_swag_size(resource->common_public->states.failed_action_set) ||
327            xbt_swag_size(resource->common_public->states.done_action_set))
328           state_modifications = 1;
329       }
330       
331       if(!state_modifications) {
332         DEBUG1("%g : Calling surf_solve",MSG_get_clock());
333         elapsed_time = surf_solve();
334         DEBUG1("Elapsed_time %g",elapsed_time);
335         
336         if (elapsed_time<0.0) {
337           /*       fprintf(stderr, "We're done %g\n",elapsed_time); */
338           break;
339         }
340       }
341
342       while (surf_timer_resource->extension_public->get(&fun,(void*)&arg)) {
343         DEBUG2("got %p %p", fun, arg);
344         if(fun==MSG_process_create_with_arguments) {
345           process_arg_t args = arg;
346           DEBUG2("Launching %s on %s", args->name, args->host->name);
347           process = MSG_process_create_with_arguments(args->name, args->code, 
348                                                       args->data, args->host,
349                                                       args->argc,args->argv);
350           if(args->kill_time > MSG_get_clock()) {
351             surf_timer_resource->extension_public->set(args->kill_time, 
352                                                        (void*) &MSG_process_kill,
353                                                        (void*) process);
354           }
355           xbt_free(args);
356         }
357         if(fun==MSG_process_kill) {
358           process = arg;
359           DEBUG3("Killing %s(%d) on %s", process->name, process->simdata->PID, 
360                  process->simdata->host->name);
361           MSG_process_kill(process);
362         }
363       }
364       
365       xbt_dynar_foreach(resource_list, i, resource) {
366         while ((action =
367                 xbt_swag_extract(resource->common_public->states.
368                                  failed_action_set))) {
369           task = action->data;
370           if(task) {
371             int _cursor;
372             DEBUG1("** %s failed **",task->name);
373             xbt_dynar_foreach(task->simdata->sleeping,_cursor,process) {
374               DEBUG3("\t preparing to wake up %s(%d) on %s",         
375                      process->name,process->simdata->PID,
376                      process->simdata->host->name);
377               xbt_fifo_unshift(msg_global->process_to_run, process);
378             }
379             process=NULL;
380           }
381         }
382         while ((action =
383                 xbt_swag_extract(resource->common_public->states.
384                                  done_action_set))) {
385           task = action->data;
386           if(task) {
387             int _cursor;
388             DEBUG1("** %s done **",task->name);
389             xbt_dynar_foreach(task->simdata->sleeping,_cursor,process) {
390               DEBUG3("\t preparing to wake up %s(%d) on %s",         
391                      process->name,process->simdata->PID,
392                      process->simdata->host->name);
393               xbt_fifo_unshift(msg_global->process_to_run, process);
394             }
395             process=NULL;
396           }
397         }
398       }
399     }
400     state_modifications = 0;
401   }
402
403   if ((nbprocess=xbt_fifo_size(msg_global->process_list)) == 0) {
404     INFO0("Congratulations ! Simulation terminated : all process are over");
405     return MSG_OK;
406   } else {
407     xbt_fifo_item_t item = NULL;
408     INFO0("Oops ! Deadlock or code not perfectly clean.");
409     INFO1("MSG: %d processes are still running, waiting for something.",
410           nbprocess);
411     /*  List the process and their state */
412     INFO0("MSG: <process>(<pid>) on <host>: <status>.");
413     xbt_fifo_foreach(msg_global->process_list,item,process,m_process_t) {
414       simdata_process_t p_simdata = (simdata_process_t) process->simdata;
415       simdata_host_t h_simdata=(simdata_host_t)p_simdata->host->simdata;
416       
417
418       INFO4("MSG:  %s(%d) on %s: %s",
419              process->name,p_simdata->PID,
420             p_simdata->host->name,
421             (process->simdata->blocked)?"[blocked] "
422             :((process->simdata->suspended)?"[suspended] ":""));
423
424       for (i=0; i<msg_global->max_channel; i++) {
425         if (h_simdata->sleeping[i] == process) {
426           INFO1("\tListening on channel %d.",i);
427           break;
428         }
429       }
430       if (i==msg_global->max_channel) {
431         if(p_simdata->waiting_task) {
432           if(p_simdata->waiting_task->simdata->compute) {
433             if(p_simdata->put_host) 
434               INFO2("\tTrying to send a task to Host %s, channel %d.",
435                     p_simdata->put_host->name, p_simdata->put_channel);
436             else 
437               INFO1("Waiting for %s to finish.",p_simdata->waiting_task->name);
438           } else if (p_simdata->waiting_task->simdata->comm)
439             INFO1("Waiting for %s to be finished transfered.",
440                     p_simdata->waiting_task->name);
441           else
442             INFO0("UNKNOWN STATUS. Please report this bug.");
443         }
444         else { /* Must be trying to put a task somewhere */
445           INFO0("UNKNOWN STATUS. Please report this bug.");
446         }
447       } 
448     }
449     if(XBT_LOG_ISENABLED(msg, xbt_log_priority_debug) ||
450        XBT_LOG_ISENABLED(global, xbt_log_priority_debug)) {
451       DEBUG0("Aborting!");
452       xbt_abort();
453     }
454
455     INFO0("Return a Warning.");
456     return MSG_WARNING;
457   }
458 }
459
460 /** \ingroup msg_simulation
461  * \brief Kill all running process
462
463  * \param reset_PIDs should we reset the PID numbers. A negative
464  *   number means no reset and a positive number will be used to set the PID
465  *   of the next newly created process.
466  */
467 int MSG_process_killall(int reset_PIDs)
468 {
469   m_process_t p = NULL;
470   m_process_t self = MSG_process_self();
471
472   while((p=xbt_fifo_pop(msg_global->process_list))) {
473     if(p!=self) MSG_process_kill(p);
474   }
475
476   if(reset_PIDs>0) {
477     msg_global->PID = reset_PIDs; 
478     msg_global->session++;
479  }
480
481   xbt_context_empty_trash();
482
483   if(self) {
484     xbt_context_yield();
485   }
486
487   return msg_global->PID;
488 }
489
490 /** \ingroup msg_simulation
491  * \brief Clean the MSG simulation
492  */
493 MSG_error_t MSG_clean(void)
494 {
495   xbt_fifo_item_t i = NULL;
496   m_host_t h = NULL;
497   m_process_t p = NULL;
498
499
500   while((p=xbt_fifo_pop(msg_global->process_list))) {
501     MSG_process_kill(p);
502   }
503   xbt_context_exit();
504
505   xbt_fifo_foreach(msg_global->host,i,h,m_host_t) {
506     __MSG_host_destroy(h);
507   }
508   xbt_fifo_free(msg_global->host);
509   xbt_fifo_free(msg_global->process_to_run);
510   xbt_fifo_free(msg_global->process_list);
511   xbt_dict_free(&(msg_global->registered_functions));
512
513   if(msg_global->paje_output) {
514     fclose(msg_global->paje_output);
515     msg_global->paje_output = NULL;
516   }
517   msg_config_finalize();
518   free(msg_global);
519   surf_exit();
520
521   return MSG_OK;
522 }
523
524
525 /** \ingroup msg_easier_life
526  * \brief A clock (in second).
527  */
528 double MSG_get_clock(void) {
529   return surf_get_clock();
530 }
531