Logo AND Algorithmique Numérique Distribuée

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