Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Remove the surf_*_model_description_size constants. They were hard to compute when...
[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, val);
39 }
40
41 /* callback of the cpu_model variable */
42 static void _sd_cfg_cb__cpu_model(const char *name, int pos)
43 {
44   char *val;
45
46   xbt_assert0(_sd_init_status < 2,
47               "Cannot change the model after the initialization");
48
49   val = xbt_cfg_get_string(_sd_cfg_set, name);
50   find_model_description(surf_cpu_model_description, val);
51 }
52
53 /* callback of the workstation_model variable */
54 static void _sd_cfg_cb__network_model(const char *name, int pos)
55 {
56   char *val;
57
58   xbt_assert0(_sd_init_status < 2,
59               "Cannot change the model after the initialization");
60
61   val = xbt_cfg_get_string(_sd_cfg_set, name);
62   find_model_description(surf_network_model_description, val);
63 }
64
65 XBT_LOG_EXTERNAL_CATEGORY(sd_kernel);
66 XBT_LOG_EXTERNAL_CATEGORY(sd_task);
67 XBT_LOG_EXTERNAL_CATEGORY(sd_workstation);
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 simgrid.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                              workstation_model_name);
317   if (!strcmp(workstation_model_name, "compound")) {
318     xbt_ex_t e;
319     char *network_model_name = NULL;
320     char *cpu_model_name = NULL;
321     int network_id = -1;
322     int cpu_id = -1;
323
324     TRY {
325       cpu_model_name = xbt_cfg_get_string(_sd_cfg_set, "cpu_model");
326     } CATCH(e) {
327       if (e.category == bound_error) {
328         xbt_assert0(0,
329                     "Set a cpu model to use with the 'compound' workstation model");
330         xbt_ex_free(e);
331       } else {
332         RETHROW;
333       }
334     }
335
336     TRY {
337       network_model_name =
338           xbt_cfg_get_string(_sd_cfg_set, "network_model");
339     }
340     CATCH(e) {
341       if (e.category == bound_error) {
342         xbt_assert0(0,
343                     "Set a network model to use with the 'compound' workstation model");
344         xbt_ex_free(e);
345       } else {
346         RETHROW;
347       }
348     }
349
350     network_id =
351         find_model_description(surf_network_model_description,
352                                network_model_name);
353     cpu_id =
354         find_model_description(surf_cpu_model_description,
355                                cpu_model_name);
356
357     surf_cpu_model_description[cpu_id].model_init(platform_file);
358     surf_network_model_description[network_id].model_init(platform_file);
359   }
360
361   DEBUG0("Call workstation_model_init");
362   surf_workstation_model_description[workstation_id].
363       model_init(platform_file);
364
365   parse_platform_file(platform_file);
366
367   _sd_init_status = 2;
368
369   /* now let's create the SD wrappers for workstations and links */
370   xbt_dict_foreach(workstation_set, cursor, name, surf_workstation) {
371     __SD_workstation_create(surf_workstation, NULL);
372   }
373
374   xbt_dict_foreach(link_set, cursor, name, surf_link) {
375     __SD_link_create(surf_link, NULL);
376   }
377
378   DEBUG2("Workstation number: %d, link number: %d", SD_workstation_get_number(), SD_link_get_number());
379 }
380
381 /**
382  * \brief Launches the simulation.
383  *
384  * The function will execute the \ref SD_READY ready tasks.
385  * The simulation will be stopped when its time reaches \a how_long,
386  * when a watch point is reached, or when no more task can be executed.
387  * Then you can call SD_simulate() again.
388  * 
389  * \param how_long maximum duration of the simulation (a negative value means no time limit)
390  * \return a NULL-terminated array of \ref SD_task_t whose state has changed.
391  * \see SD_task_schedule(), SD_task_watch()
392  */
393 SD_task_t* SD_simulate(double how_long)
394 {
395   double total_time = 0.0; /* we stop the simulation when total_time >= how_long */
396   double elapsed_time = 0.0;
397   SD_task_t task, task_safe, dst;
398   SD_dependency_t dependency;
399   surf_action_t action;
400   SD_task_t *res=NULL;
401   xbt_dynar_t changed_tasks = xbt_dynar_new (sizeof(SD_task_t), NULL);
402   unsigned int iter;
403   static int first_time = 1;
404
405   SD_CHECK_INIT_DONE();
406
407   INFO0("Starting simulation...");
408
409   if (first_time) {
410     surf_presolve(); /* Takes traces into account */
411     first_time = 0;
412   }
413
414   if(how_long>0) {
415     surf_timer_model->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_safe(task, task_safe, sd_global->ready_task_set) {
422     INFO1("Executing task '%s'", SD_task_get_name(task));
423     if(__SD_task_try_to_run(task) && 
424        !xbt_dynar_member(changed_tasks,&task))
425       xbt_dynar_push (changed_tasks, &task);
426   }
427
428   /* main loop */
429   elapsed_time = 0.0;
430   while (elapsed_time >= 0.0 &&
431          (how_long < 0.0 || total_time < how_long) &&
432          !sd_global->watch_point_reached) {
433     surf_model_t model = NULL;
434     /* dumb variables */
435     void *fun = NULL;
436     void *arg = NULL;
437
438
439     DEBUG1("Total time: %f", total_time);
440
441     elapsed_time = surf_solve();
442     DEBUG1("surf_solve() returns %f", elapsed_time);
443     if (elapsed_time > 0.0)
444       total_time += elapsed_time;
445
446     /* let's see which tasks are done */
447     xbt_dynar_foreach(model_list, iter, model) {
448       while ((action = xbt_swag_extract(model->common_public->
449                                         states.done_action_set))) {
450         task = action->data;
451         INFO1("Task '%s' done", SD_task_get_name(task));
452         DEBUG0("Calling __SD_task_just_done");
453         __SD_task_just_done(task);
454         DEBUG1("__SD_task_just_done called on task '%s'", SD_task_get_name(task));
455         
456         /* the state has changed */
457         if(!xbt_dynar_member(changed_tasks,&task))
458           xbt_dynar_push (changed_tasks, &task);
459
460         /* remove the dependencies after this task */
461         while (xbt_dynar_length(task->tasks_after) > 0) {
462           xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
463           dst = dependency->dst;
464           SD_task_dependency_remove(task, dst);
465           
466           /* is dst ready now? */
467           if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) {
468             INFO1("Executing task '%s'", SD_task_get_name(dst));
469             if (__SD_task_try_to_run(dst) &&
470                 !xbt_dynar_member(changed_tasks,&task))
471               xbt_dynar_push(changed_tasks, &task);
472           }
473         }
474       }
475
476       /* let's see which tasks have just failed */
477       while ((action = xbt_swag_extract(model->common_public->states.failed_action_set))) {
478         task = action->data;
479         INFO1("Task '%s' failed", SD_task_get_name(task));
480         __SD_task_set_state(task, SD_FAILED);
481         surf_workstation_model->common_public->action_free(action);
482         task->surf_action = NULL;
483         
484         if(!xbt_dynar_member(changed_tasks,&task))
485           xbt_dynar_push (changed_tasks, &task);
486       }
487     }
488
489     while (surf_timer_model->extension_public->get(&fun,(void*)&arg)) {
490     }
491   }
492
493   res = xbt_new0(SD_task_t,(xbt_dynar_length(changed_tasks)+1));
494
495   xbt_dynar_foreach(changed_tasks,iter,task) {
496     res[iter]=task;
497   }
498   xbt_dynar_free(&changed_tasks);
499
500   INFO0("Simulation finished");
501   DEBUG3("elapsed_time = %f, total_time = %f, watch_point_reached = %d", elapsed_time, total_time, sd_global->watch_point_reached);
502   DEBUG1("current time = %f", surf_get_clock());
503
504   return res;
505 }
506
507 /**
508  * \brief Returns the current clock
509  *
510  * \return the current clock, in second
511  */
512 double SD_get_clock(void) {
513   SD_CHECK_INIT_DONE();
514
515   return surf_get_clock();
516 }
517
518 /**
519  * \brief Destroys all SD internal data
520  *
521  * This function should be called when the simulation is over. Don't forget also to destroy
522  * the tasks.
523  *
524  * \see SD_init(), SD_task_destroy()
525  */
526 void SD_exit(void) {
527   if (SD_INITIALISED()) {
528     DEBUG0("Destroying workstation and link dictionaries...");
529     xbt_dict_free(&sd_global->workstations);
530     xbt_dict_free(&sd_global->links);
531
532     DEBUG0("Destroying workstation and link arrays if necessary...");
533     if (sd_global->workstation_list != NULL)
534       xbt_free(sd_global->workstation_list);
535
536     if (sd_global->link_list != NULL)
537       xbt_free(sd_global->link_list);
538
539     if (sd_global->recyclable_route != NULL)
540       xbt_free(sd_global->recyclable_route);
541
542     DEBUG0("Destroying the swags...");
543     xbt_swag_free(sd_global->not_scheduled_task_set);
544     xbt_swag_free(sd_global->scheduled_task_set);
545     xbt_swag_free(sd_global->ready_task_set);
546     xbt_swag_free(sd_global->in_fifo_task_set);
547     xbt_swag_free(sd_global->running_task_set);
548     xbt_swag_free(sd_global->done_task_set);
549     xbt_swag_free(sd_global->failed_task_set);
550
551     xbt_free(sd_global);
552     sd_global = NULL;
553
554     DEBUG0("Exiting Surf...");
555     surf_exit();
556   }
557   else {
558     WARN0("SD_exit() called, but SimDag is not running");
559     /* we cannot use exceptions here because xbt is not running! */
560   }
561 }