Logo AND Algorithmique Numérique Distribuée

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