Logo AND Algorithmique Numérique Distribuée

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