Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
0f7a75dc0e14defd718cedf767cb2f2696263327
[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_resource_description(surf_workstation_resource_description,
38                             surf_workstation_resource_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_resource_description(surf_cpu_resource_description,
52                             surf_cpu_resource_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_resource_description(surf_network_resource_description,
65                             surf_network_resource_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   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_resource_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_resource_description(surf_workstation_resource_description,
310                                 surf_workstation_resource_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_resource_description(surf_network_resource_description,
347                                   surf_network_resource_description_size,
348                                   network_model_name);
349     cpu_id =
350         find_resource_description(surf_cpu_resource_description,
351                                   surf_cpu_resource_description_size,
352                                   cpu_model_name);
353
354     surf_cpu_resource_description[cpu_id].resource_init(platform_file);
355     surf_network_resource_description[network_id].resource_init(platform_file);
356   }
357
358   DEBUG0("Call workstation_resource_init");
359   surf_workstation_resource_description[workstation_id].
360       resource_init(platform_file);
361
362   _sd_init_status = 2;
363
364   /* now let's create the SD wrappers for workstations and links */
365   xbt_dict_foreach(workstation_set, cursor, name, surf_workstation) {
366     __SD_workstation_create(surf_workstation, NULL);
367   }
368
369   xbt_dict_foreach(network_link_set, cursor, name, surf_link) {
370     __SD_link_create(surf_link, NULL);
371   }
372
373   DEBUG2("Workstation number: %d, link number: %d", SD_workstation_get_number(), SD_link_get_number());
374 }
375
376 /**
377  * \brief Launches the simulation.
378  *
379  * The function will execute the \ref SD_READY ready tasks.
380  * The simulation will be stopped when its time reaches \a how_long,
381  * when a watch point is reached, or when no more task can be executed.
382  * Then you can call SD_simulate() again.
383  * 
384  * \param how_long maximum duration of the simulation (a negative value means no time limit)
385  * \return a NULL-terminated array of \ref SD_task_t whose state has changed.
386  * \see SD_task_schedule(), SD_task_watch()
387  */
388 SD_task_t* SD_simulate(double how_long)
389 {
390   double total_time = 0.0; /* we stop the simulation when total_time >= how_long */
391   double elapsed_time = 0.0;
392   SD_task_t task, dst;
393   SD_dependency_t dependency;
394   surf_action_t action;
395   SD_task_t *changed_tasks = NULL;
396   int changed_task_number = 0;
397   int changed_task_capacity = sd_global->task_number + 1;
398   int i;
399   static int first_time = 1;
400
401   SD_CHECK_INIT_DONE();
402
403   INFO0("Starting simulation...");
404
405   /* create the array that will be returned */
406   changed_tasks = xbt_new(SD_task_t, changed_task_capacity);
407   changed_tasks[0] = NULL;
408
409   if (first_time) {
410     surf_solve(); /* Takes traces into account. Returns 0.0 */
411     first_time = 0;
412   }
413
414   if(how_long>0) {
415     surf_timer_resource->extension_public->set(surf_get_clock()+how_long,
416                                                NULL,NULL);
417   }
418   sd_global->watch_point_reached = 0;
419
420   /* explore the ready tasks */
421   xbt_swag_foreach(task, sd_global->ready_task_set) {
422     INFO1("Executing task '%s'", SD_task_get_name(task));
423     if ((task->state_changed = __SD_task_try_to_run(task))) {
424       changed_tasks[changed_task_number++] = task; /* replace NULL by the task */
425       /*
426       if (changed_task_number == changed_task_capacity) {
427         changed_task_capacity *= 2;
428         changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
429       }
430       */
431       changed_tasks[changed_task_number] = NULL;
432     }
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_resource_t resource = 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(resource_list, i, resource) {
455       while ((action = xbt_swag_extract(resource->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 (!task->state_changed) {
465           task->state_changed = 1;
466           changed_tasks[changed_task_number++] = task;
467           /*
468             if (changed_task_number == changed_task_capacity) {
469             changed_task_capacity *= 2;
470             changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
471             }
472           */
473           changed_tasks[changed_task_number] = NULL;
474         }
475
476         /* remove the dependencies after this task */
477         while (xbt_dynar_length(task->tasks_after) > 0) {
478           xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
479           dst = dependency->dst;
480           SD_task_dependency_remove(task, dst);
481           
482           /* is dst ready now? */
483           if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) {
484             INFO1("Executing task '%s'", SD_task_get_name(dst));
485             if (__SD_task_try_to_run(dst)) {
486               changed_tasks[changed_task_number++] = dst;
487               /*
488                 if (changed_task_number == changed_task_capacity) {
489                 changed_task_capacity *= 2;
490                 changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
491                 }
492               */
493               changed_tasks[changed_task_number] = NULL;
494             }
495           }
496         }
497       }
498
499       /* let's see which tasks have just failed */
500       while ((action = xbt_swag_extract(resource->common_public->states.failed_action_set))) {
501         task = action->data;
502         INFO1("Task '%s' failed", SD_task_get_name(task));
503         __SD_task_set_state(task, SD_FAILED);
504         surf_workstation_resource->common_public->action_free(action);
505         task->surf_action = NULL;
506         
507         if (!task->state_changed) {
508           task->state_changed = 1;
509           changed_tasks[changed_task_number++] = task;
510           /*
511             if (changed_task_number == changed_task_capacity) {
512             changed_task_capacity *= 2;
513             changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
514             }
515           */
516           changed_tasks[changed_task_number] = NULL;
517         }
518       }
519     }
520
521     while (surf_timer_resource->extension_public->get(&fun,(void*)&arg)) {
522     }
523   }
524
525   /* we must reset every task->state_changed */
526   i = 0;
527   while (changed_tasks[i] != NULL) {
528     changed_tasks[i]->state_changed = 0;
529     i++;
530   }
531
532   INFO0("Simulation finished");
533   DEBUG3("elapsed_time = %f, total_time = %f, watch_point_reached = %d", elapsed_time, total_time, sd_global->watch_point_reached);
534   DEBUG1("current time = %f", surf_get_clock());
535
536   return changed_tasks;
537 }
538
539 /**
540  * \brief Returns the current clock
541  *
542  * \return the current clock, in second
543  */
544 double SD_get_clock(void) {
545   SD_CHECK_INIT_DONE();
546
547   return surf_get_clock();
548 }
549
550 /**
551  * \brief Destroys all SD internal data
552  *
553  * This function should be called when the simulation is over. Don't forget also to destroy
554  * the tasks.
555  *
556  * \see SD_init(), SD_task_destroy()
557  */
558 void SD_exit(void) {
559   if (SD_INITIALISED()) {
560     DEBUG0("Destroying workstation and link dictionaries...");
561     xbt_dict_free(&sd_global->workstations);
562     xbt_dict_free(&sd_global->links);
563
564     DEBUG0("Destroying workstation and link arrays if necessary...");
565     if (sd_global->workstation_list != NULL)
566       xbt_free(sd_global->workstation_list);
567
568     if (sd_global->link_list != NULL)
569       xbt_free(sd_global->link_list);
570
571     if (sd_global->recyclable_route != NULL)
572       xbt_free(sd_global->recyclable_route);
573
574     DEBUG0("Destroying the swags...");
575     xbt_swag_free(sd_global->not_scheduled_task_set);
576     xbt_swag_free(sd_global->scheduled_task_set);
577     xbt_swag_free(sd_global->ready_task_set);
578     xbt_swag_free(sd_global->in_fifo_task_set);
579     xbt_swag_free(sd_global->running_task_set);
580     xbt_swag_free(sd_global->done_task_set);
581     xbt_swag_free(sd_global->failed_task_set);
582
583     xbt_free(sd_global);
584     sd_global = NULL;
585
586     DEBUG0("Exiting Surf...");
587     surf_exit();
588   }
589   else {
590     WARN0("SD_exit() called, but SimDag is not running");
591     /* we cannot use exceptions here because xbt is not running! */
592   }
593 }