Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Use the modular surf resource mechanism to allow SD users to change the resource...
[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     /* dumb variables */
441     void *fun = NULL;
442     void *arg = NULL;
443
444
445     DEBUG1("Total time: %f", total_time);
446
447     elapsed_time = surf_solve();
448     DEBUG1("surf_solve() returns %f", elapsed_time);
449     if (elapsed_time > 0.0)
450       total_time += elapsed_time;
451
452     /* let's see which tasks are done */
453     while ((action = xbt_swag_extract(surf_workstation_resource->common_public->states.done_action_set))) {
454       task = action->data;
455       INFO1("Task '%s' done", SD_task_get_name(task));
456       DEBUG0("Calling __SD_task_just_done");
457       __SD_task_just_done(task);
458       DEBUG1("__SD_task_just_done called on task '%s'", SD_task_get_name(task));
459
460       /* the state has changed */
461       if (!task->state_changed) {
462         task->state_changed = 1;
463         changed_tasks[changed_task_number++] = task;
464         /*
465         if (changed_task_number == changed_task_capacity) {
466           changed_task_capacity *= 2;
467           changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
468         }
469         */
470         changed_tasks[changed_task_number] = NULL;
471       }
472
473       /* remove the dependencies after this task */
474       while (xbt_dynar_length(task->tasks_after) > 0) {
475         xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
476         dst = dependency->dst;
477         SD_task_dependency_remove(task, dst);
478         
479         /* is dst ready now? */
480         if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) {
481           INFO1("Executing task '%s'", SD_task_get_name(dst));
482           if (__SD_task_try_to_run(dst)) {
483             changed_tasks[changed_task_number++] = dst;
484             /*
485             if (changed_task_number == changed_task_capacity) {
486               changed_task_capacity *= 2;
487               changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
488             }
489             */
490             changed_tasks[changed_task_number] = NULL;
491           }
492         }
493       }
494     }
495
496     /* let's see which tasks have just failed */
497     while ((action = xbt_swag_extract(surf_workstation_resource->common_public->states.failed_action_set))) {
498       task = action->data;
499       INFO1("Task '%s' failed", SD_task_get_name(task));
500       __SD_task_set_state(task, SD_FAILED);
501       surf_workstation_resource->common_public->action_free(action);
502       task->surf_action = NULL;
503
504       if (!task->state_changed) {
505         task->state_changed = 1;
506         changed_tasks[changed_task_number++] = task;
507         /*
508         if (changed_task_number == changed_task_capacity) {
509           changed_task_capacity *= 2;
510           changed_tasks = xbt_realloc(changed_tasks, sizeof(SD_task_t) * changed_task_capacity);
511         }
512         */
513         changed_tasks[changed_task_number] = NULL;
514       }
515     }
516
517     while (surf_timer_resource->extension_public->get(&fun,(void*)&arg)) {
518     }
519   }
520
521   /* we must reset every task->state_changed */
522   i = 0;
523   while (changed_tasks[i] != NULL) {
524     changed_tasks[i]->state_changed = 0;
525     i++;
526   }
527
528   INFO0("Simulation finished");
529   DEBUG3("elapsed_time = %f, total_time = %f, watch_point_reached = %d", elapsed_time, total_time, sd_global->watch_point_reached);
530   DEBUG1("current time = %f", surf_get_clock());
531
532   return changed_tasks;
533 }
534
535 /**
536  * \brief Returns the current clock
537  *
538  * \return the current clock, in second
539  */
540 double SD_get_clock(void) {
541   SD_CHECK_INIT_DONE();
542
543   return surf_get_clock();
544 }
545
546 /**
547  * \brief Destroys all SD internal data
548  *
549  * This function should be called when the simulation is over. Don't forget also to destroy
550  * the tasks.
551  *
552  * \see SD_init(), SD_task_destroy()
553  */
554 void SD_exit(void) {
555   if (SD_INITIALISED()) {
556     DEBUG0("Destroying workstation and link dictionaries...");
557     xbt_dict_free(&sd_global->workstations);
558     xbt_dict_free(&sd_global->links);
559
560     DEBUG0("Destroying workstation and link arrays if necessary...");
561     if (sd_global->workstation_list != NULL)
562       xbt_free(sd_global->workstation_list);
563
564     if (sd_global->link_list != NULL)
565       xbt_free(sd_global->link_list);
566
567     if (sd_global->recyclable_route != NULL)
568       xbt_free(sd_global->recyclable_route);
569
570     DEBUG0("Destroying the swags...");
571     xbt_swag_free(sd_global->not_scheduled_task_set);
572     xbt_swag_free(sd_global->scheduled_task_set);
573     xbt_swag_free(sd_global->ready_task_set);
574     xbt_swag_free(sd_global->in_fifo_task_set);
575     xbt_swag_free(sd_global->running_task_set);
576     xbt_swag_free(sd_global->done_task_set);
577     xbt_swag_free(sd_global->failed_task_set);
578
579     xbt_free(sd_global);
580     sd_global = NULL;
581
582     DEBUG0("Exiting Surf...");
583     surf_exit();
584   }
585   else {
586     WARN0("SD_exit() called, but SimDag is not running");
587     /* we cannot use exceptions here because xbt is not running! */
588   }
589 }