Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Documentation fixups: Marc was a bit quick at copy/pasting (+ DTD renamed)
[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 *changed_tasks = NULL;
408   int changed_task_number = 0;
409   int changed_task_capacity = sd_global->task_number + 1;
410   unsigned int iter;
411   static int first_time = 1;
412
413   SD_CHECK_INIT_DONE();
414
415   INFO0("Starting simulation...");
416
417   /* create the array that will be returned */
418   changed_tasks = xbt_new(SD_task_t, changed_task_capacity);
419   changed_tasks[0] = NULL;
420
421   if (first_time) {
422     surf_solve(); /* Takes traces into account. Returns 0.0 */
423     first_time = 0;
424   }
425
426   if(how_long>0) {
427     surf_timer_model->extension_public->set(surf_get_clock()+how_long,
428                                                NULL,NULL);
429   }
430   sd_global->watch_point_reached = 0;
431
432   /* explore the ready tasks */
433   xbt_swag_foreach_safe(task, task_safe, sd_global->ready_task_set) {
434     INFO1("Executing task '%s'", SD_task_get_name(task));
435     if ((task->state_changed = __SD_task_try_to_run(task))) {
436       changed_tasks[changed_task_number++] = task; /* replace NULL by the task */
437       /*
438       if (changed_task_number == changed_task_capacity) {
439         changed_task_capacity *= 2;
440         changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
441       }
442       */
443       changed_tasks[changed_task_number] = NULL;
444     }
445   }
446
447   /* main loop */
448   elapsed_time = 0.0;
449   while (elapsed_time >= 0.0 &&
450          (how_long < 0.0 || total_time < how_long) &&
451          !sd_global->watch_point_reached) {
452     surf_model_t model = NULL;
453     /* dumb variables */
454     void *fun = NULL;
455     void *arg = NULL;
456
457
458     DEBUG1("Total time: %f", total_time);
459
460     elapsed_time = surf_solve();
461     DEBUG1("surf_solve() returns %f", elapsed_time);
462     if (elapsed_time > 0.0)
463       total_time += elapsed_time;
464
465     /* let's see which tasks are done */
466     xbt_dynar_foreach(model_list, iter, model) {
467       while ((action = xbt_swag_extract(model->common_public->
468                                         states.done_action_set))) {
469         task = action->data;
470         INFO1("Task '%s' done", SD_task_get_name(task));
471         DEBUG0("Calling __SD_task_just_done");
472         __SD_task_just_done(task);
473         DEBUG1("__SD_task_just_done called on task '%s'", SD_task_get_name(task));
474         
475         /* the state has changed */
476         if (!task->state_changed) {
477           task->state_changed = 1;
478           changed_tasks[changed_task_number++] = task;
479           /*
480             if (changed_task_number == changed_task_capacity) {
481             changed_task_capacity *= 2;
482             changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
483             }
484           */
485           changed_tasks[changed_task_number] = NULL;
486         }
487
488         /* remove the dependencies after this task */
489         while (xbt_dynar_length(task->tasks_after) > 0) {
490           xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
491           dst = dependency->dst;
492           SD_task_dependency_remove(task, dst);
493           
494           /* is dst ready now? */
495           if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) {
496             INFO1("Executing task '%s'", SD_task_get_name(dst));
497             if (__SD_task_try_to_run(dst)) {
498               changed_tasks[changed_task_number++] = dst;
499               /*
500                 if (changed_task_number == changed_task_capacity) {
501                 changed_task_capacity *= 2;
502                 changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
503                 }
504               */
505               changed_tasks[changed_task_number] = NULL;
506             }
507           }
508         }
509       }
510
511       /* let's see which tasks have just failed */
512       while ((action = xbt_swag_extract(model->common_public->states.failed_action_set))) {
513         task = action->data;
514         INFO1("Task '%s' failed", SD_task_get_name(task));
515         __SD_task_set_state(task, SD_FAILED);
516         surf_workstation_model->common_public->action_free(action);
517         task->surf_action = NULL;
518         
519         if (!task->state_changed) {
520           task->state_changed = 1;
521           changed_tasks[changed_task_number++] = task;
522           /*
523             if (changed_task_number == changed_task_capacity) {
524             changed_task_capacity *= 2;
525             changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
526             }
527           */
528           changed_tasks[changed_task_number] = NULL;
529         }
530       }
531     }
532
533     while (surf_timer_model->extension_public->get(&fun,(void*)&arg)) {
534     }
535   }
536
537   /* we must reset every task->state_changed */
538   iter = 0;
539   while (changed_tasks[iter] != NULL) {
540     changed_tasks[iter]->state_changed = 0;
541     iter++;
542   }
543
544   INFO0("Simulation finished");
545   DEBUG3("elapsed_time = %f, total_time = %f, watch_point_reached = %d", elapsed_time, total_time, sd_global->watch_point_reached);
546   DEBUG1("current time = %f", surf_get_clock());
547
548   return changed_tasks;
549 }
550
551 /**
552  * \brief Returns the current clock
553  *
554  * \return the current clock, in second
555  */
556 double SD_get_clock(void) {
557   SD_CHECK_INIT_DONE();
558
559   return surf_get_clock();
560 }
561
562 /**
563  * \brief Destroys all SD internal data
564  *
565  * This function should be called when the simulation is over. Don't forget also to destroy
566  * the tasks.
567  *
568  * \see SD_init(), SD_task_destroy()
569  */
570 void SD_exit(void) {
571   if (SD_INITIALISED()) {
572     DEBUG0("Destroying workstation and link dictionaries...");
573     xbt_dict_free(&sd_global->workstations);
574     xbt_dict_free(&sd_global->links);
575
576     DEBUG0("Destroying workstation and link arrays if necessary...");
577     if (sd_global->workstation_list != NULL)
578       xbt_free(sd_global->workstation_list);
579
580     if (sd_global->link_list != NULL)
581       xbt_free(sd_global->link_list);
582
583     if (sd_global->recyclable_route != NULL)
584       xbt_free(sd_global->recyclable_route);
585
586     DEBUG0("Destroying the swags...");
587     xbt_swag_free(sd_global->not_scheduled_task_set);
588     xbt_swag_free(sd_global->scheduled_task_set);
589     xbt_swag_free(sd_global->ready_task_set);
590     xbt_swag_free(sd_global->in_fifo_task_set);
591     xbt_swag_free(sd_global->running_task_set);
592     xbt_swag_free(sd_global->done_task_set);
593     xbt_swag_free(sd_global->failed_task_set);
594
595     xbt_free(sd_global);
596     sd_global = NULL;
597
598     DEBUG0("Exiting Surf...");
599     surf_exit();
600   }
601   else {
602     WARN0("SD_exit() called, but SimDag is not running");
603     /* we cannot use exceptions here because xbt is not running! */
604   }
605 }