Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Fix the bug raised by Benjamin Depardon.
[simgrid.git] / src / simdag / sd_global.c
1 #include "private.h"
2 #include "xbt/sysdep.h"
3 #include "xbt/dynar.h"
4 #include "surf/surf.h"
5 #include "xbt/ex.h"
6 #include "xbt/log.h"
7 #include "xbt/str.h"
8 #include "xbt/config.h"
9
10 XBT_LOG_NEW_CATEGORY(sd,"Logging specific to SimDag");
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_kernel,sd,
12                                 "Logging specific to SimDag (kernel)");
13
14 SD_global_t sd_global = NULL;
15
16 /* $Id$ */
17
18 /* Copyright (c) 2007 Arnaud Legrand.
19    All rights reserved.                                          */
20
21 /* This program is free software; you can redistribute it and/or modify it
22  * under the terms of the license (GNU LGPL) which comes with this package. */
23
24 static int _sd_init_status = 0; /* 0: beginning of time; 
25                                    1: pre-inited (cfg_set created); 
26                                    2: inited (running) */
27 static xbt_cfg_t _sd_cfg_set = NULL;
28
29 /* callback of the workstation_model variable */
30 static void _sd_cfg_cb__workstation_model(const char *name, int pos)
31 {
32   char *val;
33
34   xbt_assert0(_sd_init_status < 2,
35               "Cannot change the model after the initialization");
36
37   val = xbt_cfg_get_string(_sd_cfg_set, name);
38   find_model_description(surf_workstation_model_description,
39                             surf_workstation_model_description_size,
40                             val);
41 }
42
43 /* callback of the cpu_model variable */
44 static void _sd_cfg_cb__cpu_model(const char *name, int pos)
45 {
46   char *val;
47
48   xbt_assert0(_sd_init_status < 2,
49               "Cannot change the model after the initialization");
50
51   val = xbt_cfg_get_string(_sd_cfg_set, name);
52   find_model_description(surf_cpu_model_description,
53                             surf_cpu_model_description_size, val);
54 }
55
56 /* callback of the workstation_model variable */
57 static void _sd_cfg_cb__network_model(const char *name, int pos)
58 {
59   char *val;
60
61   xbt_assert0(_sd_init_status < 2,
62               "Cannot change the model after the initialization");
63
64   val = xbt_cfg_get_string(_sd_cfg_set, name);
65   find_model_description(surf_network_model_description,
66                             surf_network_model_description_size, val);
67 }
68
69 XBT_LOG_EXTERNAL_CATEGORY(sd_kernel);
70 XBT_LOG_EXTERNAL_CATEGORY(sd_task);
71 XBT_LOG_EXTERNAL_CATEGORY(sd_workstation);
72
73 /* create the config set and register what should be */
74 static void sd_config_init(void)
75 {
76
77   if (_sd_init_status)
78     return;                     /* Already inited, nothing to do */
79
80   /* Connect our log channels: that must be done manually under windows */
81   XBT_LOG_CONNECT(sd_kernel, sd);
82   XBT_LOG_CONNECT(sd_task, sd);
83   XBT_LOG_CONNECT(sd_workstation, sd);
84    
85   _sd_init_status = 1;
86   _sd_cfg_set = xbt_cfg_new();
87
88   xbt_cfg_register(_sd_cfg_set,
89                    "workstation_model", xbt_cfgelm_string, 1, 1,
90                    &_sd_cfg_cb__workstation_model, NULL);
91
92   xbt_cfg_register(_sd_cfg_set,
93                    "cpu_model", xbt_cfgelm_string, 1, 1,
94                    &_sd_cfg_cb__cpu_model, NULL);
95   xbt_cfg_register(_sd_cfg_set,
96                    "network_model", xbt_cfgelm_string, 1, 1,
97                    &_sd_cfg_cb__network_model, NULL);
98
99   xbt_cfg_set_string(_sd_cfg_set, "workstation_model", "ptask_L07");
100 }
101
102 static void sd_config_finalize(void)
103 {
104
105   if (!_sd_init_status)
106     return;                     /* Not initialized yet. Nothing to do */
107
108   xbt_cfg_free(&_sd_cfg_set);
109   _sd_init_status = 0;
110 }
111
112 static void sd_config(const char *name, va_list pa)
113 {
114   if (!_sd_init_status) {
115     sd_config_init();
116   }
117   xbt_cfg_set_vargs(_sd_cfg_set, name, pa);
118 }
119
120
121 static void __sd_config_helper(const char *name, ...)
122 {
123   va_list pa;
124   va_start(pa, name);
125
126   sd_config(name, pa);
127
128   va_end(pa);
129 }
130
131 static void sd_cfg_control_set(const char *control_string)
132 {
133   /* To split the string in commands, and the cursors */
134   xbt_dynar_t set_strings;
135   char *str;
136   unsigned int cpt;
137
138   if (!control_string)
139     return;
140   DEBUG1("Parse log settings '%s'", control_string);
141
142   /* split the string, and remove empty entries */
143   set_strings = xbt_str_split_quoted(control_string);
144
145   if (xbt_dynar_length(set_strings) == 0) {     /* vicious user! */
146     xbt_dynar_free(&set_strings);
147     return;
148   }
149   /* Parse each entry and either use it right now (if the category was already
150      created), or store it for further use */
151   xbt_dynar_foreach(set_strings, cpt, str) {
152     char *control_string, *control_string_sav, *name, *value;
153
154
155     control_string = control_string_sav = strdup(str);
156     control_string += strspn(control_string, " ");
157     name = control_string;
158     control_string += strcspn(str, ":=");
159     value = control_string;
160     *value = 0;
161     value++;
162
163     xbt_assert1(strlen(name) != 0, "Invalid name for configuration: '%s'",
164                 name);
165     xbt_assert1(strlen(value) != 0,
166                 "Invalid value for configuration: '%s'", value);
167     INFO2("setting '%s' to '%s'", name, value);
168
169     __sd_config_helper(name, value);
170
171     free(control_string_sav);
172   }
173   xbt_dynar_free(&set_strings);
174 }
175
176 static void sd_cfg_init(int *argc, char **argv)
177 {
178   int i, j;
179   char *opt;
180
181   for (i = 1; i < *argc; i++) {
182     if (!strncmp(argv[i], "--cfg=", strlen("--cfg="))) {
183       opt = strchr(argv[i], '=');
184       opt++;
185
186       sd_cfg_control_set(opt);
187       DEBUG1("Did apply '%s' as config setting", opt);
188       /*remove this from argv */
189
190       for (j = i + 1; j < *argc; j++) {
191         argv[j - 1] = argv[j];
192       }
193
194       argv[j - 1] = NULL;
195       (*argc)--;
196       i--;                      /* compensate effect of next loop incrementation */
197     }
198   }
199 }
200
201 /**
202  * \brief Initialises SD internal data
203  *
204  * This function must be called before any other SD function. Then you
205  * should call SD_create_environment().
206  *
207  * \param argc argument number
208  * \param argv argument list
209  * \see SD_create_environment(), SD_exit()
210  */
211 void SD_init(int *argc, char **argv) {
212
213   s_SD_task_t task;
214   
215   xbt_assert0( !SD_INITIALISED() , "SD_init() already called");
216
217   sd_global = xbt_new(s_SD_global_t, 1);
218   sd_global->workstations = xbt_dict_new();
219   sd_global->workstation_count = 0;
220   sd_global->workstation_list = NULL;
221   sd_global->links = xbt_dict_new();
222   sd_global->link_count = 0;
223   sd_global->link_list = NULL;
224   sd_global->recyclable_route = NULL;
225   sd_global->watch_point_reached = 0;
226
227   sd_global->not_scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
228   sd_global->scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
229   sd_global->ready_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
230   sd_global->in_fifo_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
231   sd_global->running_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
232   sd_global->done_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
233   sd_global->failed_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
234   sd_global->task_number = 0;
235
236   surf_init(argc, argv);
237   sd_cfg_init(argc, argv);
238 }
239
240 /**
241  * \brief Reinits the application part of the simulation (experimental feature)
242  * 
243  * This function allows you to run several simulations on the same platform 
244  * by resetting the part describing the application. 
245  * 
246  * @warning: this function is still experimental and not perfect. For example,
247  * the simulation clock (and traces usage) is not reset. So, do not use it if
248  * you use traces in your simulation, and do not use absolute timing after using it.
249  * That being said, this function is still precious if you want to compare a bunch of
250  * heuristics on the same platforms.
251  */
252 void SD_application_reinit(void) {
253    
254   s_SD_task_t task;
255    
256   if (SD_INITIALISED()) {
257     DEBUG0("Recreating the swags...");
258     xbt_swag_free(sd_global->not_scheduled_task_set);
259     xbt_swag_free(sd_global->scheduled_task_set);
260     xbt_swag_free(sd_global->ready_task_set);
261     xbt_swag_free(sd_global->in_fifo_task_set);
262     xbt_swag_free(sd_global->running_task_set);
263     xbt_swag_free(sd_global->done_task_set);
264     xbt_swag_free(sd_global->failed_task_set);
265
266     sd_global->not_scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
267     sd_global->scheduled_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
268     sd_global->ready_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
269     sd_global->in_fifo_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
270     sd_global->running_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
271     sd_global->done_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
272     sd_global->failed_task_set = xbt_swag_new(xbt_swag_offset(task, state_hookup));
273     sd_global->task_number = 0;
274   } else {
275     WARN0("SD_application_reinit called before initialization of SimDag");
276     /* we cannot use exceptions here because xbt is not running! */
277   }
278
279 }
280
281 /**
282  * \brief Creates the environment
283  *
284  * The environment (i.e. the \ref SD_workstation_management "workstations" and the
285  * \ref SD_link_management "links") is created with the data stored in the given XML
286  * platform file.
287  *
288  * \param platform_file name of an XML file describing the environment to create
289  * \see SD_workstation_management, SD_link_management
290  *
291  * The XML file follows this DTD:
292  *
293  *     \include simgrid.dtd
294  *
295  * Here is a small example of such a platform: 
296  *
297  *     \include small_platform.xml
298  */
299 void SD_create_environment(const char *platform_file) {
300   xbt_dict_cursor_t cursor = NULL;
301   char *name = NULL;
302   void *surf_workstation = NULL;
303   void *surf_link = NULL;
304   char *workstation_model_name;
305   int workstation_id = -1;
306
307   SD_CHECK_INIT_DONE();
308
309   DEBUG0("SD_create_environment");
310
311   sd_config_init();
312   surf_timer_model_init(platform_file);
313
314   workstation_model_name =
315       xbt_cfg_get_string(_sd_cfg_set, "workstation_model");
316
317   DEBUG1("Model : %s", workstation_model_name);
318   workstation_id =
319       find_model_description(surf_workstation_model_description,
320                                 surf_workstation_model_description_size,
321                                 workstation_model_name);
322   if (!strcmp(workstation_model_name, "compound")) {
323     xbt_ex_t e;
324     char *network_model_name = NULL;
325     char *cpu_model_name = NULL;
326     int network_id = -1;
327     int cpu_id = -1;
328
329     TRY {
330       cpu_model_name = xbt_cfg_get_string(_sd_cfg_set, "cpu_model");
331     } CATCH(e) {
332       if (e.category == bound_error) {
333         xbt_assert0(0,
334                     "Set a cpu model to use with the 'compound' workstation model");
335         xbt_ex_free(e);
336       } else {
337         RETHROW;
338       }
339     }
340
341     TRY {
342       network_model_name =
343           xbt_cfg_get_string(_sd_cfg_set, "network_model");
344     }
345     CATCH(e) {
346       if (e.category == bound_error) {
347         xbt_assert0(0,
348                     "Set a network model to use with the 'compound' workstation model");
349         xbt_ex_free(e);
350       } else {
351         RETHROW;
352       }
353     }
354
355     network_id =
356         find_model_description(surf_network_model_description,
357                                   surf_network_model_description_size,
358                                   network_model_name);
359     cpu_id =
360         find_model_description(surf_cpu_model_description,
361                                   surf_cpu_model_description_size,
362                                   cpu_model_name);
363
364     surf_cpu_model_description[cpu_id].model_init(platform_file);
365     surf_network_model_description[network_id].model_init(platform_file);
366   }
367
368   DEBUG0("Call workstation_model_init");
369   surf_workstation_model_description[workstation_id].
370       model_init(platform_file);
371
372   parse_platform_file(platform_file);
373
374   _sd_init_status = 2;
375
376   /* now let's create the SD wrappers for workstations and links */
377   xbt_dict_foreach(workstation_set, cursor, name, surf_workstation) {
378     __SD_workstation_create(surf_workstation, NULL);
379   }
380
381   xbt_dict_foreach(link_set, cursor, name, surf_link) {
382     __SD_link_create(surf_link, NULL);
383   }
384
385   DEBUG2("Workstation number: %d, link number: %d", SD_workstation_get_number(), SD_link_get_number());
386 }
387
388 /**
389  * \brief Launches the simulation.
390  *
391  * The function will execute the \ref SD_READY ready tasks.
392  * The simulation will be stopped when its time reaches \a how_long,
393  * when a watch point is reached, or when no more task can be executed.
394  * Then you can call SD_simulate() again.
395  * 
396  * \param how_long maximum duration of the simulation (a negative value means no time limit)
397  * \return a NULL-terminated array of \ref SD_task_t whose state has changed.
398  * \see SD_task_schedule(), SD_task_watch()
399  */
400 SD_task_t* SD_simulate(double how_long)
401 {
402   double total_time = 0.0; /* we stop the simulation when total_time >= how_long */
403   double elapsed_time = 0.0;
404   SD_task_t task, task_safe, dst;
405   SD_dependency_t dependency;
406   surf_action_t action;
407   SD_task_t *res=NULL;
408   xbt_dynar_t changed_tasks = xbt_dynar_new (sizeof(SD_task_t), NULL);
409   unsigned int iter;
410   static int first_time = 1;
411
412   SD_CHECK_INIT_DONE();
413
414   INFO0("Starting simulation...");
415
416   if (first_time) {
417     surf_presolve(); /* Takes traces into account */
418     first_time = 0;
419   }
420
421   if(how_long>0) {
422     surf_timer_model->extension_public->set(surf_get_clock()+how_long,
423                                                NULL,NULL);
424   }
425   sd_global->watch_point_reached = 0;
426
427   /* explore the ready tasks */
428   xbt_swag_foreach_safe(task, task_safe, sd_global->ready_task_set) {
429     INFO1("Executing task '%s'", SD_task_get_name(task));
430     if(__SD_task_try_to_run(task) && 
431        !xbt_dynar_member(changed_tasks,&task))
432       xbt_dynar_push (changed_tasks, &task);
433   }
434
435   /* main loop */
436   elapsed_time = 0.0;
437   while (elapsed_time >= 0.0 &&
438          (how_long < 0.0 || total_time < how_long) &&
439          !sd_global->watch_point_reached) {
440     surf_model_t model = NULL;
441     /* dumb variables */
442     void *fun = NULL;
443     void *arg = NULL;
444
445
446     DEBUG1("Total time: %f", total_time);
447
448     elapsed_time = surf_solve();
449     DEBUG1("surf_solve() returns %f", elapsed_time);
450     if (elapsed_time > 0.0)
451       total_time += elapsed_time;
452
453     /* let's see which tasks are done */
454     xbt_dynar_foreach(model_list, iter, model) {
455       while ((action = xbt_swag_extract(model->common_public->
456                                         states.done_action_set))) {
457         task = action->data;
458         INFO1("Task '%s' done", SD_task_get_name(task));
459         DEBUG0("Calling __SD_task_just_done");
460         __SD_task_just_done(task);
461         DEBUG1("__SD_task_just_done called on task '%s'", SD_task_get_name(task));
462         
463         /* the state has changed */
464         if(!xbt_dynar_member(changed_tasks,&task))
465           xbt_dynar_push (changed_tasks, &task);
466
467         /* remove the dependencies after this task */
468         while (xbt_dynar_length(task->tasks_after) > 0) {
469           xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
470           dst = dependency->dst;
471           SD_task_dependency_remove(task, dst);
472           
473           /* is dst ready now? */
474           if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) {
475             INFO1("Executing task '%s'", SD_task_get_name(dst));
476             if (__SD_task_try_to_run(dst) &&
477                 !xbt_dynar_member(changed_tasks,&task))
478               xbt_dynar_push(changed_tasks, &task);
479           }
480         }
481       }
482
483       /* let's see which tasks have just failed */
484       while ((action = xbt_swag_extract(model->common_public->states.failed_action_set))) {
485         task = action->data;
486         INFO1("Task '%s' failed", SD_task_get_name(task));
487         __SD_task_set_state(task, SD_FAILED);
488         surf_workstation_model->common_public->action_free(action);
489         task->surf_action = NULL;
490         
491         if(!xbt_dynar_member(changed_tasks,&task))
492           xbt_dynar_push (changed_tasks, &task);
493       }
494     }
495
496     while (surf_timer_model->extension_public->get(&fun,(void*)&arg)) {
497     }
498   }
499
500   res = xbt_new0(SD_task_t,(xbt_dynar_length(changed_tasks)+1));
501
502   xbt_dynar_foreach(changed_tasks,iter,task) {
503     res[iter]=task;
504   }
505   xbt_dynar_free(&changed_tasks);
506
507   INFO0("Simulation finished");
508   DEBUG3("elapsed_time = %f, total_time = %f, watch_point_reached = %d", elapsed_time, total_time, sd_global->watch_point_reached);
509   DEBUG1("current time = %f", surf_get_clock());
510
511   return res;
512 }
513
514 /**
515  * \brief Returns the current clock
516  *
517  * \return the current clock, in second
518  */
519 double SD_get_clock(void) {
520   SD_CHECK_INIT_DONE();
521
522   return surf_get_clock();
523 }
524
525 /**
526  * \brief Destroys all SD internal data
527  *
528  * This function should be called when the simulation is over. Don't forget also to destroy
529  * the tasks.
530  *
531  * \see SD_init(), SD_task_destroy()
532  */
533 void SD_exit(void) {
534   if (SD_INITIALISED()) {
535     DEBUG0("Destroying workstation and link dictionaries...");
536     xbt_dict_free(&sd_global->workstations);
537     xbt_dict_free(&sd_global->links);
538
539     DEBUG0("Destroying workstation and link arrays if necessary...");
540     if (sd_global->workstation_list != NULL)
541       xbt_free(sd_global->workstation_list);
542
543     if (sd_global->link_list != NULL)
544       xbt_free(sd_global->link_list);
545
546     if (sd_global->recyclable_route != NULL)
547       xbt_free(sd_global->recyclable_route);
548
549     DEBUG0("Destroying the swags...");
550     xbt_swag_free(sd_global->not_scheduled_task_set);
551     xbt_swag_free(sd_global->scheduled_task_set);
552     xbt_swag_free(sd_global->ready_task_set);
553     xbt_swag_free(sd_global->in_fifo_task_set);
554     xbt_swag_free(sd_global->running_task_set);
555     xbt_swag_free(sd_global->done_task_set);
556     xbt_swag_free(sd_global->failed_task_set);
557
558     xbt_free(sd_global);
559     sd_global = NULL;
560
561     DEBUG0("Exiting Surf...");
562     surf_exit();
563   }
564   else {
565     WARN0("SD_exit() called, but SimDag is not running");
566     /* we cannot use exceptions here because xbt is not running! */
567   }
568 }