Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
added MPI_Wtime()
[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
210   s_SD_task_t task;
211
212   xbt_assert0(!SD_INITIALISED(), "SD_init() already called");
213
214   sd_global = xbt_new(s_SD_global_t, 1);
215   sd_global->workstations = xbt_dict_new();
216   sd_global->workstation_count = 0;
217   sd_global->workstation_list = NULL;
218   sd_global->links = xbt_dict_new();
219   sd_global->link_count = 0;
220   sd_global->link_list = NULL;
221   sd_global->recyclable_route = NULL;
222   sd_global->watch_point_reached = 0;
223
224   sd_global->not_scheduled_task_set =
225     xbt_swag_new(xbt_swag_offset(task, state_hookup));
226   sd_global->scheduled_task_set =
227     xbt_swag_new(xbt_swag_offset(task, state_hookup));
228   sd_global->ready_task_set =
229     xbt_swag_new(xbt_swag_offset(task, state_hookup));
230   sd_global->in_fifo_task_set =
231     xbt_swag_new(xbt_swag_offset(task, state_hookup));
232   sd_global->running_task_set =
233     xbt_swag_new(xbt_swag_offset(task, state_hookup));
234   sd_global->done_task_set =
235     xbt_swag_new(xbt_swag_offset(task, state_hookup));
236   sd_global->failed_task_set =
237     xbt_swag_new(xbt_swag_offset(task, state_hookup));
238   sd_global->task_number = 0;
239
240   surf_init(argc, argv);
241   sd_cfg_init(argc, argv);
242 }
243
244 /**
245  * \brief Reinits the application part of the simulation (experimental feature)
246  * 
247  * This function allows you to run several simulations on the same platform 
248  * by resetting the part describing the application. 
249  * 
250  * @warning: this function is still experimental and not perfect. For example,
251  * the simulation clock (and traces usage) is not reset. So, do not use it if
252  * you use traces in your simulation, and do not use absolute timing after using it.
253  * That being said, this function is still precious if you want to compare a bunch of
254  * heuristics on the same platforms.
255  */
256 void SD_application_reinit(void)
257 {
258
259   s_SD_task_t task;
260
261   if (SD_INITIALISED()) {
262     DEBUG0("Recreating the swags...");
263     xbt_swag_free(sd_global->not_scheduled_task_set);
264     xbt_swag_free(sd_global->scheduled_task_set);
265     xbt_swag_free(sd_global->ready_task_set);
266     xbt_swag_free(sd_global->in_fifo_task_set);
267     xbt_swag_free(sd_global->running_task_set);
268     xbt_swag_free(sd_global->done_task_set);
269     xbt_swag_free(sd_global->failed_task_set);
270
271     sd_global->not_scheduled_task_set =
272       xbt_swag_new(xbt_swag_offset(task, state_hookup));
273     sd_global->scheduled_task_set =
274       xbt_swag_new(xbt_swag_offset(task, state_hookup));
275     sd_global->ready_task_set =
276       xbt_swag_new(xbt_swag_offset(task, state_hookup));
277     sd_global->in_fifo_task_set =
278       xbt_swag_new(xbt_swag_offset(task, state_hookup));
279     sd_global->running_task_set =
280       xbt_swag_new(xbt_swag_offset(task, state_hookup));
281     sd_global->done_task_set =
282       xbt_swag_new(xbt_swag_offset(task, state_hookup));
283     sd_global->failed_task_set =
284       xbt_swag_new(xbt_swag_offset(task, state_hookup));
285     sd_global->task_number = 0;
286   } else {
287     WARN0("SD_application_reinit called before initialization of SimDag");
288     /* we cannot use exceptions here because xbt is not running! */
289   }
290
291 }
292
293 /**
294  * \brief Creates the environment
295  *
296  * The environment (i.e. the \ref SD_workstation_management "workstations" and the
297  * \ref SD_link_management "links") is created with the data stored in the given XML
298  * platform file.
299  *
300  * \param platform_file name of an XML file describing the environment to create
301  * \see SD_workstation_management, SD_link_management
302  *
303  * The XML file follows this DTD:
304  *
305  *     \include simgrid.dtd
306  *
307  * Here is a small example of such a platform: 
308  *
309  *     \include small_platform.xml
310  */
311 void SD_create_environment(const char *platform_file)
312 {
313   xbt_dict_cursor_t cursor = NULL;
314   char *name = NULL;
315   void *surf_workstation = NULL;
316   void *surf_link = NULL;
317   char *workstation_model_name;
318   int workstation_id = -1;
319
320   SD_CHECK_INIT_DONE();
321
322   DEBUG0("SD_create_environment");
323
324   sd_config_init();
325   surf_timer_model_init(platform_file);
326
327   workstation_model_name =
328     xbt_cfg_get_string(_sd_cfg_set, "workstation_model");
329
330   DEBUG1("Model : %s", workstation_model_name);
331   workstation_id =
332     find_model_description(surf_workstation_model_description,
333                            workstation_model_name);
334   if (!strcmp(workstation_model_name, "compound")) {
335     xbt_ex_t e;
336     char *network_model_name = NULL;
337     char *cpu_model_name = NULL;
338     int network_id = -1;
339     int cpu_id = -1;
340
341     TRY {
342       cpu_model_name = xbt_cfg_get_string(_sd_cfg_set, "cpu_model");
343     } CATCH(e) {
344       if (e.category == bound_error) {
345         xbt_assert0(0,
346                     "Set a cpu model to use with the 'compound' workstation model");
347         xbt_ex_free(e);
348       } else {
349         RETHROW;
350       }
351     }
352
353     TRY {
354       network_model_name = xbt_cfg_get_string(_sd_cfg_set, "network_model");
355     }
356     CATCH(e) {
357       if (e.category == bound_error) {
358         xbt_assert0(0,
359                     "Set a network model to use with the 'compound' workstation model");
360         xbt_ex_free(e);
361       } else {
362         RETHROW;
363       }
364     }
365
366     network_id =
367       find_model_description(surf_network_model_description,
368                              network_model_name);
369     cpu_id =
370       find_model_description(surf_cpu_model_description, cpu_model_name);
371
372     surf_cpu_model_description[cpu_id].model_init(platform_file);
373     surf_network_model_description[network_id].model_init(platform_file);
374   }
375
376   DEBUG0("Call workstation_model_init");
377   surf_workstation_model_description[workstation_id].model_init
378     (platform_file);
379
380   parse_platform_file(platform_file);
381
382   _sd_init_status = 2;
383
384   /* now let's create the SD wrappers for workstations and links */
385   xbt_dict_foreach(workstation_set, cursor, name, surf_workstation) {
386     __SD_workstation_create(surf_workstation, NULL);
387   }
388
389   xbt_dict_foreach(link_set, cursor, name, surf_link) {
390     __SD_link_create(surf_link, NULL);
391   }
392
393   DEBUG2("Workstation number: %d, link number: %d",
394          SD_workstation_get_number(), SD_link_get_number());
395 }
396
397 /**
398  * \brief Launches the simulation.
399  *
400  * The function will execute the \ref SD_READY ready tasks.
401  * The simulation will be stopped when its time reaches \a how_long,
402  * when a watch point is reached, or when no more task can be executed.
403  * Then you can call SD_simulate() again.
404  * 
405  * \param how_long maximum duration of the simulation (a negative value means no time limit)
406  * \return a NULL-terminated array of \ref SD_task_t whose state has changed.
407  * \see SD_task_schedule(), SD_task_watch()
408  */
409 SD_task_t *SD_simulate(double how_long)
410 {
411   double total_time = 0.0;      /* we stop the simulation when total_time >= how_long */
412   double elapsed_time = 0.0;
413   SD_task_t task, task_safe, dst;
414   SD_dependency_t dependency;
415   surf_action_t action;
416   SD_task_t *res = NULL;
417   xbt_dynar_t changed_tasks = xbt_dynar_new(sizeof(SD_task_t), NULL);
418   unsigned int iter;
419   static int first_time = 1;
420
421   SD_CHECK_INIT_DONE();
422
423   INFO0("Starting simulation...");
424
425   if (first_time) {
426     surf_presolve();            /* Takes traces into account */
427     first_time = 0;
428   }
429
430   if (how_long > 0) {
431     surf_timer_model->extension_public->set(surf_get_clock() + how_long,
432                                             NULL, NULL);
433   }
434   sd_global->watch_point_reached = 0;
435
436   /* explore the ready tasks */
437   xbt_swag_foreach_safe(task, task_safe, sd_global->ready_task_set) {
438     INFO1("Executing task '%s'", SD_task_get_name(task));
439     if (__SD_task_try_to_run(task) && !xbt_dynar_member(changed_tasks, &task))
440       xbt_dynar_push(changed_tasks, &task);
441   }
442
443   /* main loop */
444   elapsed_time = 0.0;
445   while (elapsed_time >= 0.0 &&
446          (how_long < 0.0 || total_time < how_long) &&
447          !sd_global->watch_point_reached) {
448     surf_model_t model = NULL;
449     /* dumb variables */
450     void *fun = NULL;
451     void *arg = NULL;
452
453
454     DEBUG1("Total time: %f", total_time);
455
456     elapsed_time = surf_solve();
457     DEBUG1("surf_solve() returns %f", elapsed_time);
458     if (elapsed_time > 0.0)
459       total_time += elapsed_time;
460
461     /* let's see which tasks are done */
462     xbt_dynar_foreach(model_list, iter, model) {
463       while ((action =
464               xbt_swag_extract(model->common_public->states.
465                                done_action_set))) {
466         task = action->data;
467         INFO1("Task '%s' done", SD_task_get_name(task));
468         DEBUG0("Calling __SD_task_just_done");
469         __SD_task_just_done(task);
470         DEBUG1("__SD_task_just_done called on task '%s'",
471                SD_task_get_name(task));
472
473         /* the state has changed */
474         if (!xbt_dynar_member(changed_tasks, &task))
475           xbt_dynar_push(changed_tasks, &task);
476
477         /* remove the dependencies after this task */
478         while (xbt_dynar_length(task->tasks_after) > 0) {
479           xbt_dynar_get_cpy(task->tasks_after, 0, &dependency);
480           dst = dependency->dst;
481           SD_task_dependency_remove(task, dst);
482
483           /* is dst ready now? */
484           if (__SD_task_is_ready(dst) && !sd_global->watch_point_reached) {
485             INFO1("Executing task '%s'", SD_task_get_name(dst));
486             if (__SD_task_try_to_run(dst) &&
487                 !xbt_dynar_member(changed_tasks, &task))
488               xbt_dynar_push(changed_tasks, &task);
489           }
490         }
491       }
492
493       /* let's see which tasks have just failed */
494       while ((action =
495               xbt_swag_extract(model->common_public->states.
496                                failed_action_set))) {
497         task = action->data;
498         INFO1("Task '%s' failed", SD_task_get_name(task));
499         __SD_task_set_state(task, SD_FAILED);
500         surf_workstation_model->common_public->action_free(action);
501         task->surf_action = NULL;
502
503         if (!xbt_dynar_member(changed_tasks, &task))
504           xbt_dynar_push(changed_tasks, &task);
505       }
506     }
507
508     while (surf_timer_model->extension_public->get(&fun, (void *) &arg)) {
509     }
510   }
511
512   res = xbt_new0(SD_task_t, (xbt_dynar_length(changed_tasks) + 1));
513
514   xbt_dynar_foreach(changed_tasks, iter, task) {
515     res[iter] = task;
516   }
517   xbt_dynar_free(&changed_tasks);
518
519   INFO0("Simulation finished");
520   DEBUG3("elapsed_time = %f, total_time = %f, watch_point_reached = %d",
521          elapsed_time, total_time, sd_global->watch_point_reached);
522   DEBUG1("current time = %f", surf_get_clock());
523
524   return res;
525 }
526
527 /**
528  * \brief Returns the current clock
529  *
530  * \return the current clock, in second
531  */
532 double SD_get_clock(void)
533 {
534   SD_CHECK_INIT_DONE();
535
536   return surf_get_clock();
537 }
538
539 /**
540  * \brief Destroys all SD internal data
541  *
542  * This function should be called when the simulation is over. Don't forget also to destroy
543  * the tasks.
544  *
545  * \see SD_init(), SD_task_destroy()
546  */
547 void SD_exit(void)
548 {
549   if (SD_INITIALISED()) {
550     DEBUG0("Destroying workstation and link dictionaries...");
551     xbt_dict_free(&sd_global->workstations);
552     xbt_dict_free(&sd_global->links);
553
554     DEBUG0("Destroying workstation and link arrays if necessary...");
555     if (sd_global->workstation_list != NULL)
556       xbt_free(sd_global->workstation_list);
557
558     if (sd_global->link_list != NULL)
559       xbt_free(sd_global->link_list);
560
561     if (sd_global->recyclable_route != NULL)
562       xbt_free(sd_global->recyclable_route);
563
564     DEBUG0("Destroying the swags...");
565     xbt_swag_free(sd_global->not_scheduled_task_set);
566     xbt_swag_free(sd_global->scheduled_task_set);
567     xbt_swag_free(sd_global->ready_task_set);
568     xbt_swag_free(sd_global->in_fifo_task_set);
569     xbt_swag_free(sd_global->running_task_set);
570     xbt_swag_free(sd_global->done_task_set);
571     xbt_swag_free(sd_global->failed_task_set);
572
573     xbt_free(sd_global);
574     sd_global = NULL;
575
576     DEBUG0("Exiting Surf...");
577     surf_exit();
578   } else {
579     WARN0("SD_exit() called, but SimDag is not running");
580     /* we cannot use exceptions here because xbt is not running! */
581   }
582 }